SPRAAK
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
Compiler hints and C-extensions

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; // 32bits pointer
...
};
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)); // retry until we succeed
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 // must reside in 1 cache-line or access will not be atomic!
{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:
// Code not fit for production!
// To make these routines safe, once should at least make a copy of <name>
// and check+act on all possible error return values.
#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,...)
// Note: going with an inline function makes that all arguments are always
// evaluated, even if in 99%+ of the cases nothing needs to be printed
{SprStream *fd;
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.

New base types

SPRaak defines the following new base types:

SprDynStr
SprStream
SprKeySet
SprDT
SprMsgId