Compiler hints are optional keywords or constructs ment to help the compiler in producing more efficient code or to suppress compiler warnings.
The C-extensions provide functionality missing in C99. Some extensions are required. These extensions are provided by every major compiler and hence will probabely be included in the next updated definition of C. Other extensions are optional. The corresponding macro's will be set when the functionality is available and will be undefined otherwise.
Function related compiler hints
- spr_always_inline
- a strong hint to always inline this function
- spr_noinline
- a strong hint to never inline this function (e.g. error code)
- spr_pure_func
- indicates that the function has no side-effects and that the return value depends on the arguments only
- spr_const_func
- indicates that the function has no side-effects and that the return value depends on the arguments and on global variables only
- spr_nu
- argument is not used in this function (may prevent compiler warnings)
- spr_return
- argument (always a pointer) is used to return values only
- spr_ret_restrict_ptr
- the pointer returned by this function points to a unique chunk of memory (guaranteed not to overlap with any memory accessed via other pointers)
Other compiler hints
This markup is mainly ment to help the compiler in producing more efficient code or to enforce additional argument checking.
- spr_ptr32
- for efficiency reasons, this pointer can best be stored as a 32bits pointer, even on a 64bits platform
Example: struct MyCompactData
{int spr_ptr32(*) x;
...
};
- Note
- 32bits pointers should only be used in structures that are both frequently accessed and are used in (very) large numbers – only there the gain (less memory access) outweighs the overhead (special allocation and free routines, possible overhead when accessing such pointers, ...)
-
Few 64 bits platforms support mixing 32bits and 64bits pointers.
- spr_expect
- inform the compiler that a condition is usually true or false
Example: while(spr_exepect(try_something()==-1,0));
- spr_assume
- inform the compiler about some known constraints on the value of variables
Example: spr_assume(type_of_thing>=0);
spr_assume(type_of_thing<3);
switch(type_of_thing)
{case 0: do_thing0(); break;
case 1: do_thing1(); break;
case 2: do_thing2(); break;
}
- spr_gcc_attribute
- maps to the gcc atribute() construct when compiling with gcc and to nothing otherwise; this allows us to use gcc-specific markup (e.g. fprintf format string info or last argument must be NULL) to functions providing extra checks in the normal development platform (which uses gcc)
- spr_clang_attribute
- maps to the clang atribute() construct when compiling with clang and to nothing otherwise; this allows us to use clang-specific markup (e.g. fprintf format string info or last argument must be NULL) to functions providing extra checks in the normal development platform (which uses clang)
Required C-extensions
- spr_align
- assure that a variable is aligned to a more conservative boundary than required by that datatype; typically used for atomic operations
Example: typedef struct
{intptr_t spr_align(2*sizeof(intptr_t)) key;
intptr_t val;
} AtomicCacheEl;
- spr_alignof
- query the alignment requirements of a certain data structure (cf. sizeof())
Optional C-extensions
- spr_thread_var
- if this macro is defined then the platfrom allows thread-specific static variables (which makes coding for a MT-environment a lot easier)
Example:
#ifdef spr_thread_var
spr_thread_var static ThreadInfo thread_info = empty_thread_info;
#else
static pthread_key_t thread_info_key;
static pthread_once_t thread_info_key_once = PTHREAD_ONCE_INIT;
static void make_thread_info_key(void)
{pthread_key_create(&thread_info_key,NULL);
}
#endif
void init_thread_info(const char *name)
{
#ifdef spr_thread_var
thread_info.name = name;
#else
ThreadInfo *thread_info;
pthread_once(&thread_info_key_once,&make_thread_info_key);
thread_info = malloc(sizeof(ThreadInfo));
thread_info = empty_thread_info;
thread_info->name = name;
pthread_setspecific(thread_info_key,thread_info);
#endif
}
const char *get_thread_name(void)
{
#ifdef spr_thread_var
return(thread_info.name);
#else
ThreadInfo *thread_info = pthread_getspecific(thread_info_key);
return(thread_info->name);
#endif
}
- spr_statements_as_expr
- if this macro is defined then the compiler allows a set of statements (including the definition of local variables) to act as an expression
Example: #ifdef spr_statements_as_expr
#define conditional_print(id_code,fmt,...) spr_statements_as_expr(SprStream *fd;,((fd=id2stream(id_code))!=NULL)?spr_fprintf(fd,fmt,__VA_ARGS__):0)
#else
static inline int conditional_print(const char *id_code,fmt,...)
va_list argptr;
int rv;
va_start(argptr,fmt);
rv = ((fd=id2stream(id_code))==NULL)?0:
spr_vfprintf(fd,fmt,argptr);
va_end(argptr);
return(rv);
}
#endif
- vector extensions
- defines the following types (as macro to allow testing if they exist):
- spr_v16i8
- vector of 16 signed 8-bit integers
- spr_v16u8
- vector of 16 unsigned 8-bit integers
- spr_v4i32
- vector of 4 signed 32-bit integers
- spr_v4u32
- vector of 4 unsigned 32-bit integers
- spr_v4f32
- vector of 4 floats (single precision floating point number)
- spr_v2i64
- vector of 2 signed 64-bit integers
- spr_v2u64
- vector of 2 unsigned 64-bit integers
- spr_v2f64
- vector of 2 doubles (double precision floating point number)
- spr_v4i64
- vector of 4 signed 64-bit integers
- spr_v4u64
- vector of 4 unsigned 64-bit integers
- spr_v4f64
- vector of 4 doubles (double precision floating point number)
Also defines the one (or more) macro's of the type SPR_VECEXT_{GCC,CLANG,...}
to specify how the vector extensions are implemented (there is no standard yet).
Additional low-level functions
The C99 (+posix) standard still lacks some low-level routines for which a C-implementation is nowehere as efficient as assembler code. Whether this is the case for a certain operation depends on the platform, and hence compiler support is typically platfom dependent to.
- Note
- A collection of such functions can be found in elementary_instr.c and atomic.c These functions are not part of 'spraak/def.h', they are only mentioned here for the sake for completeness.
Missing standard functions
When necessary, missing stantard functions are imlemented using whatever functionality that is present on that platform. Below, you can find a list of functions that were implemented on at least one of the supported platform (and the limitations of these re-implementations).
- TODO
- Note
- When necesary, missing include files are include in SPRAAK as well.
Handy and frequently used macro's
The list also contains some macro that are defined in other core modules (usually for dependecy reasons), but that are general enough to be mentioned in this list.
-
The macro's SPR_CPP_CAT1, SPR_CPP_CAT2, SPR_CPP_CAT3, and SPR_CPP_CAT3 allow you to create variable, function, ... names that contain the value of macro constants (e.g. dependent on SPR_PTR_SZ).
-
The macro SPR_CPP_M2STR allow you to create strings that contain the value of macro constants (e.g. dependent on SPR_PTR_SZ).
-
The macro's SPR_INT64_GET_LO32 SPR_INT64_GET_HI32 and SPR_INT64_MAKE provide a standardized method to convert between 64 and 32 bits quantities.
-
The macro's SPR_DEBUG_LVL, spr_debug_do_lvl1, spr_debug_do_lvl2, spr_debug_do_lvl3, spr_assert1, spr_assert2 and spr_assert3 provide a framework for adding optional extra checks (depending on the compile flags) in the code. SPR_DEBUG_LVL can be set to 3 values
- 0
- ignore all extra checks, ment for production code
- 1
- add checks that have minimal (<10%) overhead
- 2
- add checks that have reasonable (<100%) overhead
- 3
- add checks that have high (>100%) overhead
The spr_debug_do_lvlX(code) macro's will excecute the code code if and only if SPR_DEBUG_LVL >= X.
The spr_assertX(routine,test) macro's check the condition test and give a warning using the call spr_warning(routine,...) if test equals 0 (false). This implies that a variable routine must exist and must be properly initialized! The spr_assertX() macro's are defined in msg.c.
-
The macro's SPR_TO_UPPER and SPR_TO_LOWER convert an ASCII alphabetic character (i.e. a character in the range 'a'-'z' or 'A'-'Z') to upper or lower case respectively. The effect on any other character is undefined.
-
The macro's SPR_NOT_DEFINED equals (-9) and is typically used as the illegal or not initialized value for integer variables.
New base types
SPRaak defines the following new base types:
- SprDynStr
- SprStream
- SprKeySet
- SprDT
- SprMsgId