BeRTOS
compiler.h
Go to the documentation of this file.
00001 
00039 #ifndef BERTOS_COMPILER_H
00040 #define BERTOS_COMPILER_H
00041 
00042 #include <cpu/detect.h>
00043 
00044 
00045 #if defined __GNUC__ && defined __GNUC_MINOR__
00046     #define GNUC_PREREQ(maj, min) \
00047         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
00048 #else
00049     #define GNUC_PREREQ(maj, min) 0
00050 #endif
00051 
00052 /* Some CW versions do not allow enabling C99 from the settings panel. */
00053 #if defined(__MWERKS__)
00054     #pragma c99 on
00055 #endif
00056 
00057 #if defined(__STDC_VERSION__)
00058     #if (__STDC_VERSION__ == 199409L) // IAR
00059         #define COMPILER_C99      1  // not true, because partial C99, avoid miscompilation
00060     #elif (__STDC_VERSION__ >= 199901L) // GCC
00061         #define COMPILER_C99      1
00062     #else
00063         #define COMPILER_C99      0
00064     #endif
00065 #endif
00066 
00067 
00069 #define PP_CAT(x,y)         PP_CAT__(x,y)
00070 #define PP_CAT__(x,y)       x ## y
00071 #define PP_CAT3(x,y,z)      PP_CAT(PP_CAT(x,y),z)
00072 #define PP_CAT4(x,y,z,w)    PP_CAT(PP_CAT3(x,y,z),w)
00073 #define PP_CAT5(x,y,z,w,j)  PP_CAT(PP_CAT4(x,y,z,w),j)
00074 
00076 #define PP_STRINGIZE(x)     PP_STRINGIZE__(x)
00077 #define PP_STRINGIZE__(x)   #x
00078 
00079 
00082 #if COMPILER_C99
00083     #define COUNT_PARMS2(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _, ...) _
00084     #define COUNT_PARMS(...) \
00085             COUNT_PARMS2(11 , ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
00086 
00094 #else
00095     #define COUNT_PARMS2(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _, ...) _
00096     #define COUNT_PARMS(args...) \
00097             COUNT_PARMS2(11 , ## args, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
00098 
00106 #endif
00107 
00108 #if defined(__IAR_SYSTEMS_ICC) || defined(__IAR_SYSTEMS_ICC__)
00109 
00110     #pragma language=extended
00111 
00112     /* IAR iccarm specific functions */
00113     #include <intrinsics.h>
00114     #pragma diag_suppress=Pe940
00115     #pragma inline = forced
00116 
00117     #define MEMORY_BARRIER      asm("")
00118 
00119     #if CPU_ARM || CPU_CM3
00120 
00121         #define COMPILER_VARIADIC_MACROS 1
00122 
00123         #define INTERRUPT(x)  __irq __arm void x (void)
00124         #define INLINE        static inline
00125         #define NAKED
00126 
00127         /* Include some standard C89/C99 stuff */
00128         #include <stddef.h>
00129         #include <stdint.h>
00130         #include <stdbool.h>
00131 
00132     #elif CPU_I196
00133 
00134         // IAR has size_t as built-in type, but does not define this symbol.
00135         #define _SIZE_T_DEFINED
00136 
00137         #define INTERRUPT(x)  interrupt [x]
00138         #define REGISTER      shortad
00139         #define INLINE        /* unsupported */
00140 
00141         /*
00142          * Imported from <longjmp.h>. Unfortunately, we can't just include
00143          * this header because it typedefs jmp_buf to be an array of chars.
00144          * This would allow the compiler to place the buffer on an odd address.
00145          * The CPU _should_ be able to perform word accesses to
00146          * unaligned data, but there are *BUGS* in the 80196KC with
00147          * some combinations of opcodes and addressing modes. One of
00148          * these, "ST SP,[?GR]+" is used in the longjmp() implementation
00149          * provided by the IAR compiler ANSI C library. When ?GR contains
00150          * an odd address, surprisingly the CPU will copy the high order
00151          * byte of the source operand (SP) in the low order byte of the
00152          * destination operand (the memory location pointed to by ?GR).
00153          *
00154          * We also need to replace the library setjmp()/longjmp() with
00155          * our own versions because the IAR implementation "forgets" to
00156          * save the contents of local registers (?LR).
00157          */
00158         struct _JMP_BUF
00159         {
00160             void *sp;           /* Stack pointer */
00161             void *return_addr;  /* Return address */
00162             int lr[6];          /* 6 local registers */
00163         };
00164 
00165         typedef struct _JMP_BUF jmp_buf[1];
00166 
00167         int setjmp(jmp_buf env);
00168         void longjmp(jmp_buf env, int val);
00169 
00170         /* Fake bool support */
00171         #define true (1==1)
00172         #define false (1!=1)
00173         typedef unsigned char bool;
00174 
00175     #else
00176         #error Unsupported CPU
00177     #endif
00178 
00179 #elif defined(_MSC_VER) /* Win32 emulation support */
00180 
00181     /* MSVC doesn't provide <stdbool.h>. */
00182     #ifndef __cplusplus
00183         #define true (1==1)
00184         #define false (1!=1)
00185         typedef int bool;
00186     #endif /* !__cplusplus */
00187 
00188     /* These C99 functions are oddly named in MSVCRT32.lib */
00189     #define snprintf _snprintf
00190     #define vsnprintf _vsnprintf
00191 
00192     /* MSVC doesn't support C99's __func__, but has a similar extension. */
00193     #define __func__ __FUNCTION__
00194 
00195     /* MSVC doesn't support C99's inline keyword */
00196     #ifndef __cplusplus
00197         #define INLINE __inline
00198     #endif
00199 
00200 #elif defined(__GNUC__)
00201 
00202     /* Compiler features */
00203     #define COMPILER_VARIADIC_MACROS 1 /* Even in C++ */
00204     #define COMPILER_TYPEOF 1
00205     #define COMPILER_STATEMENT_EXPRESSIONS 1
00206 
00207     /* GCC attributes */
00208     #define FORMAT(type,fmt,first)  __attribute__((__format__(type, fmt, first)))
00209     #define NORETURN                __attribute__((__noreturn__))
00210     #define UNUSED_ARG(type,arg)    __attribute__((__unused__)) type arg
00211     #define UNUSED_VAR(type,name)   __attribute__((__unused__)) type name
00212     #define USED_VAR(type,name)     __attribute__((__used__)) type name
00213     #define INLINE                  static inline __attribute__((__always_inline__))
00214     #define NOINLINE                __attribute__((noinline))
00215     #define LIKELY(x)               __builtin_expect(!!(x), 1)
00216     #define UNLIKELY(x)             __builtin_expect(!!(x), 0)
00217     #define PURE_FUNC               __attribute__((pure))
00218     #define CONST_FUNC              __attribute__((const))
00219     #define UNUSED_FUNC             __attribute__((unused))
00220     #define USED_FUNC               __attribute__((__used__))
00221     #define RESTRICT                __restrict__
00222     #define MUST_CHECK              __attribute__((warn_unused_result))
00223     #define PACKED                  __attribute__((packed))
00224     #define ALIGNED(x)              __attribute__ ((__aligned__(x)))
00225     #if CPU_ARM | CPU_CM3
00226         #define NAKED       __attribute__((naked))
00227     #else
00228         #define NAKED
00229     #endif
00230 
00234     #define MEMORY_BARRIER           asm volatile ("" : : : "memory")
00235 
00236     #if GNUC_PREREQ(3,1)
00237         #define DEPRECATED  __attribute__((__deprecated__))
00238     #endif
00239 
00240     #if GNUC_PREREQ(4,5)
00241         #define UNREACHABLE() __builtin_unreachable()
00242     #endif
00243 
00244     #ifndef __cplusplus
00245         #define ASSERT_TYPE_EQUAL(var1, var2) \
00246             STATIC_ASSERT(__builtin_types_compatible_p(typeof(var1), typeof(var2)))
00247         #define ASSERT_TYPE_IS(var, type) \
00248             STATIC_ASSERT(__builtin_types_compatible_p(typeof(var), type))
00249     #endif
00250 
00251     /* Include some standard C89/C99 stuff */
00252     #include <stddef.h>
00253     #include <stdint.h>
00254     #include <stdbool.h>
00255     #if !CPU_AVR
00256     #include <sys/types.h> /* for ssize_t */
00257     #endif
00258 
00259     #ifndef __cplusplus
00260         /*
00261          * Disallow some C++ keywords as identifiers in C programs,
00262          * for improved portability.
00263          */
00264         #pragma GCC poison new delete class template typename
00265         #pragma GCC poison private protected public operator
00266         #pragma GCC poison friend mutable using namespace
00267         #pragma GCC poison cin cout cerr clog
00268     #endif
00269 
00270 
00271 
00272 #elif defined(__MWERKS__)
00273 
00274     /* Compiler features */
00275     #define COMPILER_VARIADIC_MACROS 1
00276     #define COMPILER_TYPEOF 1
00277     #define COMPILER_STATEMENT_EXPRESSIONS 1
00278 
00279     #define typeof __typeof__
00280 
00281     #define UNUSED_ARG(type,arg)    type
00282 
00283     #include <stddef.h>
00284     #include <stdint.h>
00285     #include <stdbool.h>
00286 
00287     // CodeWarrior has size_t as built-in type, but does not define this symbol.
00288     #define _SIZE_T_DEFINED
00289 
00290 #else
00291     #error unknown compiler
00292 #endif
00293 
00294 
00295 /* Defaults for compiler extensions. */
00296 
00301 #ifndef COMPILER_VARIADIC_MACROS
00302 #define COMPILER_VARIADIC_MACROS (COMPILER_C99 != 0)
00303 #endif
00304 
00309 #ifndef COMPILER_TYPEOF
00310 #define COMPILER_TYPEOF 0
00311 #endif
00312 
00317 #ifndef COMPILER_STATEMENT_EXPRESSIONS
00318 #define COMPILER_STATEMENT_EXPRESSIONS 0
00319 #endif
00320 
00321 /* A few defaults for missing compiler features. */
00322 #ifndef INLINE
00323 #define INLINE                 static inline
00324 #endif
00325 #ifndef NOINLINE
00326 #define NOINLINE               /* nothing */
00327 #endif
00328 #ifndef NORETURN
00329 #define NORETURN               /* nothing */
00330 #endif
00331 #ifndef FORMAT
00332 #define FORMAT(type,fmt,first) /* nothing */
00333 #endif
00334 #ifndef DEPRECATED
00335 #define DEPRECATED             /* nothing */
00336 #endif
00337 #ifndef UNUSED_ARG
00338 #define UNUSED_ARG(type,arg)   type arg
00339 #endif
00340 #ifndef UNUSED_VAR
00341 #define UNUSED_VAR(type,name)  type name
00342 #endif
00343 #ifndef USED_VAR
00344 #define USED_VAR(type,name)    type name
00345 #endif
00346 #ifndef REGISTER
00347 #define REGISTER               /* nothing */
00348 #endif
00349 #ifndef LIKELY
00350 #define LIKELY(x)              x
00351 #endif
00352 #ifndef UNLIKELY
00353 #define UNLIKELY(x)            x
00354 #endif
00355 #ifndef PURE_FUNC
00356 #define PURE_FUNC              /* nothing */
00357 #endif
00358 #ifndef CONST_FUNC
00359 #define CONST_FUNC             /* nothing */
00360 #endif
00361 #ifndef UNUSED_FUNC
00362 #define UNUSED_FUNC            /* nothing */
00363 #endif
00364 #ifndef USED_FUNC
00365 #define USED_FUNC              /* nothing */
00366 #endif
00367 #ifndef RESTRICT
00368 #define RESTRICT               /* nothing */
00369 #endif
00370 #ifndef MUST_CHECK
00371 #define MUST_CHECK             /* nothing */
00372 #endif
00373 #ifndef PACKED
00374 #define PACKED                 /* nothing */
00375 #endif
00376 #ifndef ALIGNED
00377 #define ALIGNED                /* nothing */
00378 #endif
00379 #ifndef MEMORY_BARRIER
00380 #define MEMORY_BARRIER         /* nothing */
00381 #warning No memory barrier defined for select compiler. If you use the kernel check it.
00382 #endif
00383 #ifndef UNREACHABLE
00384 #define UNREACHABLE() for (;;)
00385 #endif
00386 
00387 
00388 /* Misc definitions */
00389 #ifndef NULL
00390 #define NULL  (void *)0
00391 #endif
00392 #ifndef EOF
00393 #define EOF   (-1)
00394 #endif
00395 
00396 /* Support for hybrid C/C++ applications. */
00397 #ifdef __cplusplus
00398     #define EXTERN_C        extern "C"
00399     #define EXTERN_C_BEGIN  extern "C" {
00400     #define EXTERN_C_END    }
00401     #define EXTERN_CONST    extern const
00402     #define CONST_CAST(TYPE,EXPR)   (const_cast<TYPE>(EXPR))
00403 #else
00404     #define EXTERN_C        extern
00405     #define EXTERN_C_BEGIN  /* nothing */
00406     #define EXTERN_C_END    /* nothing */
00407     #define EXTERN_CONST    const
00408     #define CONST_CAST(TYPE,EXPR)   ((TYPE)(EXPR)) /* FIXME: How can we suppress the warning in C? */
00409 #endif
00410 
00411 
00412 #if defined(_MSC_VER) \
00413     || ((defined(__IAR_SYSTEMS_ICC) || defined(__IAR_SYSTEMS_ICC__)) && CPU_I196)
00414 
00420     typedef signed char         int8_t;
00421     typedef unsigned char       uint8_t;
00422     typedef short int           int16_t;
00423     typedef unsigned short int  uint16_t;
00424     typedef long int            int32_t; /* _WIN64 safe */
00425     typedef unsigned long int   uint32_t; /* _WIN64 safe */
00426 
00427     #ifdef _MSC_VER
00428         typedef __int64              int64_t;
00429         typedef unsigned __int64     uint64_t;
00430     #else
00431         typedef long long            int64_t;
00432         typedef unsigned long long   uint64_t;
00433     #endif
00434     /* \} */
00435 #else
00436     /* This is the standard location. */
00437     #include <stdint.h>
00438 #endif
00439 
00440 #if CPU_AVR_ATMEGA8
00441     /*
00442      * The ATmega8 has a very small Flash, so we can't afford
00443      * to link in support routines for 32bit integer arithmetic.
00444      */
00445     typedef int16_t ticks_t;  
00446     typedef int16_t mtime_t;  
00447     typedef int16_t utime_t;  
00448     #define SIZEOF_MTIME_T (16 / CPU_BITS_PER_CHAR)
00449     #define SIZEOF_UTIME_T (16 / CPU_BITS_PER_CHAR)
00450     #define MTIME_INFINITE 0x7FFFL
00451 #else
00452     typedef int32_t ticks_t;  
00454     typedef int32_t utime_t;  
00455     #define SIZEOF_UTIME_T (32 / CPU_BITS_PER_CHAR)
00456 
00457     #ifndef DEVLIB_MTIME_DEFINED
00458         #define DEVLIB_MTIME_DEFINED 1 /* Resolve conflict with <os/hptime.h> */
00459         typedef int32_t mtime_t;  
00460         #define SIZEOF_MTIME_T (32 / CPU_BITS_PER_CHAR)
00461         #define MTIME_INFINITE 0x7FFFFFFFL
00462     #endif
00463 #endif
00464 
00466 typedef void (*Hook)(void *);
00467 
00469 typedef void * iptr_t;
00470 
00472 typedef const void * const_iptr_t;
00473 
00474 typedef unsigned char sigbit_t;  
00475 typedef unsigned char sigmask_t; 
00480 typedef struct Signal
00481 {
00482     sigmask_t    wait;    
00483     sigmask_t    recv;    
00484 } Signal;
00485 
00500 #if !(defined(size_t) || defined(_SIZE_T_DEFINED) || defined(_BSD_SIZE_T_DEFINED_) \
00501     || defined(_SIZE_T))
00502     #if CPU_X86
00503         /* 32bit or 64bit (32bit for _WIN64). */
00504         typedef unsigned long size_t;
00505     #else
00506         #error Unknown CPU
00507     #endif
00508 #endif
00509 
00510 #if !(defined(ssize_t) || defined(_SSIZE_T) || defined(__ssize_t_defined))
00511     #if CPU_X86
00512         /* 32bit or 64bit (32bit for _WIN64). */
00513         typedef long ssize_t;
00514     #elif CPU_ARM || CPU_CM3
00515         typedef int ssize_t;
00516     #elif CPU_AVR || CPU_MSP430
00517         /* 16bit (missing in avr-/msp430-libc's sys/types.h). */
00518         typedef int ssize_t;
00519     #else
00520         #error Unknown CPU
00521     #endif
00522 #endif
00523 /*\}*/
00524 
00525 
00534 #if CPU_DSP56K
00535     /* Registers can be accessed only through 16-bit pointers */
00536     typedef volatile uint16_t  reg16_t;
00537 #else
00538     typedef volatile uint8_t   reg8_t;
00539     typedef volatile uint16_t  reg16_t;
00540     typedef volatile uint32_t  reg32_t;
00541 #endif
00542 /*\}*/
00543 
00544 
00545 /* Quasi-ANSI macros */
00546 #ifndef offsetof
00547 
00553     #define offsetof(s,m)  (size_t)&(((s *)0)->m)
00554 #endif
00555 #ifndef countof
00556 
00561     #if defined(__GNUC__) && !defined(__cplusplus)
00562         /*
00563          * Perform a compile time type checking: countof() can only
00564          * work with static arrays, so throw a compile time error if a
00565          * pointer is passed as argument.
00566          *
00567          * NOTE: the construct __builtin_types_compatible_p() is only
00568          * available for C.
00569          */
00570         #define countof(a) (sizeof(a) / sizeof(*(a)) +      \
00571                 STATIC_ASSERT_EXPR(         \
00572                     !__builtin_types_compatible_p(  \
00573                         typeof(a), typeof(&a[0]))))
00574     #else
00575         #define countof(a)  (sizeof(a) / sizeof(*(a)))
00576     #endif
00577 #endif
00578 #ifndef alignof
00579 
00586     #define alignof(type) offsetof(struct { char c; type member; }, member)
00587 #endif
00588 
00596 #if COMPILER_TYPEOF && COMPILER_STATEMENT_EXPRESSIONS
00597     #define containerof(ptr, type, member) ({ \
00598         typeof( ((type *)0)->member ) *_mptr = (ptr); /* type check */ \
00599         (type *)(void *)((char *)_mptr - offsetof(type, member)); \
00600     })
00601 #else
00602     #define containerof(ptr, type, member) \
00603         ( (type *)(void *)((char *)(ptr) - offsetof(type, member)) )
00604 #endif
00605 
00607 #define STATIC_ASSERT(condition)  \
00608     UNUSED_VAR(extern char, STATIC_ASSERTION_FAILED__[(condition) ? 1 : -1])
00609 
00614 #define STATIC_ASSERT_EXPR(__cond) \
00615     (sizeof(struct { int STATIC_ASSERTION_FAILED__:!!(__cond); }) * 0)
00616 
00617 #ifndef ASSERT_TYPE_EQUAL
00618 
00619     #define ASSERT_TYPE_EQUAL(var1, var2)  \
00620             do { (void)(&(var1) == &(var2)); } while(0)
00621 #endif
00622 
00623 #ifndef ASSERT_TYPE_IS
00624 
00625     #define ASSERT_TYPE_IS(var, type)  \
00626             do { (void)(&(var) == (type *)0); } while(0)
00627 #endif
00628 
00634 #ifdef __ICCARM__
00635 #define ACCESS_SAFE(x) x
00636 #else
00637 #define ACCESS_SAFE(x) (*(volatile typeof(x) *)&(x))
00638 #endif
00639 
00640 #endif /* BERTOS_COMPILER_H */