]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - gmqcc.h
Test cases for -fcorrect-logic
[xonotic/gmqcc.git] / gmqcc.h
diff --git a/gmqcc.h b/gmqcc.h
index df123c6c42713c733446ee21c1eb8c1773cf4409..af98f3f3b74bb1c924a74196ae2b2e1c952e24e4 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
  * of my time.
  */
 #ifdef _MSC_VER
-#      pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */
-#      pragma warning(disable : 4018 ) /* signed/unsigned mismatch                                */
-#      pragma warning(disable : 4996 ) /* This function or variable may be unsafe                 */
-#      pragma warning(disable : 4700 ) /* uninitialized local variable used                       */
+#   pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */
+#   pragma warning(disable : 4018 ) /* signed/unsigned mismatch                                */
+#   pragma warning(disable : 4996 ) /* This function or variable may be unsafe                 */
 #endif
 
 #define GMQCC_VERSION_MAJOR 0
@@ -76,6 +75,8 @@
 #   endif /* !__STDC_VERSION__ */
 #endif    /* !__cplusplus      */
 
+
+
 /*
  * Of some functions which are generated we want to make sure
  * that the result isn't ignored. To find such function calls,
  * I suspect it also has just __inline of some sort, but our use
  * of inline is correct (not guessed), WE WANT IT TO BE INLINE
  */
-#elseif defined(_MSC_VER)
+#elif defined(_MSC_VER)
 #    define GMQCC_INLINE __forceinline
 #else
 #    define GMQCC_INLINE
 #    define GMQCC_NORETURN
 #endif
 
+#ifndef _MSC_VER
+#   include <stdint.h>
+#else
+    typedef unsigned __int8  uint8_t;
+    typedef unsigned __int16 uint16_t;
+    typedef unsigned __int32 uint32_t;
+    typedef unsigned __int64 uint64_t;
+
+    typedef __int16          int16_t;
+    typedef __int32          int32_t;
+    typedef __int64          int64_t;
+#endif
+
+/* 
+ *windows makes these prefixed because they're C99
+ * TODO: utility versions that are type-safe and not
+ * just plain textual subsitution.
+ */
+#ifdef _MSC_VER
+#      define snprintf(X, Y, Z, ...) _snprintf(X, Y, Z, __VA_ARGS__)
+    /* strtof doesn't exist -> strtod does though :) */
+#      define strtof(X, Y)          (float)(strtod(X, Y))
+#endif
+
+
 /*
- * stdint.h and inttypes.h -less subset
- * for systems that don't have it, which we must
- * assume is all systems. (int8_t not required)
+ * Very roboust way at determining endianess at compile time: this handles
+ * almost every possible situation.  Otherwise a runtime check has to be
+ * performed.
  */
-#if   CHAR_MIN  == -128
-    typedef unsigned char  uint8_t; /* same as below */
-#elif SCHAR_MIN == -128
-    typedef unsigned char  uint8_t; /* same as above */
+#define GMQCC_BYTE_ORDER_LITTLE 1234
+#define GMQCC_BYTE_ORDER_BIG    4321
+
+#if defined (__GNUC__) || defined (__GNU_LIBRARY__)
+#   if defined (__FreeBSD__) || defined (__OpenBSD__)
+#       include <sys/endian.h>
+#   elif defined (BSD) && (BSD >= 199103) || defined (__DJGPP__) || defined (__CYGWIN32__)
+#       include <machine/endiane.h>
+#   elif defined (__APPLE__)
+#       if defined (__BIG_ENDIAN__) && !defined(BIG_ENDIAN)
+#           define BIG_ENDIAN
+#       elif defined (__LITTLE_ENDIAN__) && !defined (LITTLE_ENDIAN)
+#           define LITTLE_ENDIAN
+#       endif
+#   elif !defined (__MINGW32__)
+#       include <endian.h>
+#       if !defined (__BEOS__)
+#           include <byteswap.h>
+#       endif
+#   endif
 #endif
-#if   SHRT_MAX  == 0x7FFF
-    typedef short          int16_t;
-    typedef unsigned short uint16_t;
-#elif INT_MAX   == 0x7FFF
-    typedef int            int16_t;
-    typedef unsigned int   uint16_t;
+#if !defined(PLATFORM_BYTE_ORDER)
+#   if defined (LITTLE_ENDIAN) || defined (BIG_ENDIAN)
+#       if defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif !defined (LITTLE_ENDIAN) && defined (BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       elif defined (BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif defined (BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       endif
+#   elif defined (_LITTLE_ENDIAN) || defined (_BIG_ENDIAN)
+#       if defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif !defined (_LITTLE_ENDIAN) && defined (_BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _LITTLE_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       endif
+#   elif defined (__LITTLE_ENDIAN__) || defined (__BIG_ENDIAN__)
+#       if defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif !defined (__LITTLE_ENDIAN__) && defined (__BIG_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __LITTLE_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       endif
+#   endif
 #endif
-#if   INT_MAX   == 0x7FFFFFFF
-    typedef int            int32_t;
-    typedef unsigned int   uint32_t;
-#elif LONG_MAX  == 0x7FFFFFFF
-    typedef long           int32_t;
-    typedef unsigned long  uint32_t;
+#if !defined (PLATFORM_BYTE_ORDER)
+#   if   defined (__alpha__) || defined (__alpha)    || defined (i386)       || \
+         defined (__i386__)  || defined (_M_I86)     || defined (_M_IX86)    || \
+         defined (__OS2__)   || defined (sun386)     || defined (__TURBOC__) || \
+         defined (vax)       || defined (vms)        || defined (VMS)        || \
+         defined (__VMS)     || defined (__x86_64__) || defined (_M_IA64)    || \
+         defined (_M_X64)    || defined (__i386)     || defined (__x86_64)
+#       define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#   elif defined (AMIGA)     || defined (applec)     || defined (__AS400__)  || \
+         defined (_CRAY)     || defined (__hppa)     || defined (__hp9000)   || \
+         defined (ibm370)    || defined (mc68000)    || defined (m68k)       || \
+         defined (__MRC__)   || defined (__MVS__)    || defined (__MWERKS__) || \
+         defined (sparc)     || defined (__sparc)    || defined (SYMANTEC_C) || \
+         defined (__TANDEM)  || defined (THINK_C)    || defined (__VMCMS__)  || \
+         defined (__PPC__)   || defined (__PPC)      || defined (PPC)
+#       define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#   else
+#       define PLATFORM_BYTE_ORDER -1
+#   endif
 #endif
 
 
-#if defined(__GNUC__) || defined (__CLANG__)
-       typedef int              int64_t  __attribute__((__mode__(__DI__)));
-       typedef unsigned int     uint64_t __attribute__((__mode__(__DI__)));
-#elif defined(_MSC_VER)
-       typedef __int64          int64_t;
-       typedef unsigned __int64 uint64_t;
-#else
-    /*
-    * Incorrectly size the types so static assertions below will
-    * fail.  There is no valid way to get a 64bit type at this point
-    * without making assumptions of too many things.
-    */
-    typedef struct { char _fail : 0; } int64_t;
-    typedef struct { char _fail : 0; } uint64_t;
-#endif
-#ifdef _LP64 /* long pointer == 64 */
-    typedef unsigned long  uintptr_t;
-    typedef long           intptr_t;
-#else
-    typedef unsigned int   uintptr_t;
-    typedef int            intptr_t;
-#endif
-/* Ensure type sizes are correct: */
-typedef char uint8_size_is_correct  [sizeof(uint8_t)  == 1?1:-1];
-typedef char uint16_size_is_correct [sizeof(uint16_t) == 2?1:-1];
-typedef char uint32_size_is_correct [sizeof(uint32_t) == 4?1:-1];
-typedef char uint64_size_is_correct [sizeof(uint64_t) == 8?1:-1];
-typedef char int16_size_if_correct  [sizeof(int16_t)  == 2?1:-1];
-typedef char int32_size_is_correct  [sizeof(int32_t)  == 4?1:-1];
-typedef char int64_size_is_correct  [sizeof(int64_t)  >= 8?1:-1];
-/* intptr_t / uintptr_t correct size check */
-typedef char uintptr_size_is_correct[sizeof(intptr_t) == sizeof(int*)?1:-1];
-typedef char intptr_size_is_correct [sizeof(uintptr_t)== sizeof(int*)?1:-1];
 
 /*===================================================================*/
 /*=========================== util.c ================================*/
@@ -207,39 +255,55 @@ void  util_meminfo       ();
 bool  util_filexists     (const char *);
 bool  util_strupper      (const char *);
 bool  util_strdigit      (const char *);
-bool  util_strncmpexact  (const char *, const char *, size_t);
 char *util_strdup        (const char *);
-char *util_strrq         (const char *);
-char *util_strrnl        (const char *);
-char *util_strsws        (const char *);
-char *util_strchp        (const char *, const char *);
 void  util_debug         (const char *, const char *, ...);
 int   util_getline       (char **, size_t *, FILE *);
-void  util_endianswap    (void *,  int, int);
+void  util_endianswap    (void *,  size_t, unsigned int);
 
 size_t util_strtocmd    (const char *, char *, size_t);
 size_t util_strtononcmd (const char *, char *, size_t);
 
 uint16_t util_crc16(uint16_t crc, const char *data, size_t len);
-uint32_t util_crc32(uint32_t crc, const char *data, size_t len);
+
+/*
+ * If we're compiling as C++ code we need to fix some subtle issues regarding casts between mem_a/mem_d
+ * since C++ doesn't allow implicit conversions between void*
+ */
+#ifdef __cplusplus
+        /*
+         * void * will be implicitally converted to gmqcc_voidptr using gmqcc_voidptr(void*).  This is what
+         * essentially allows us to allow implicit conversion to whatever pointer type we're trying to assign
+         * to because it acks as a default assignment constructor.
+         */
+        class gmqcc_voidptr {
+            void *m_pointer;
+        public:
+            gmqcc_voidptr(void *pointer) :
+                m_pointer(pointer)
+            { };
+
+            template <typename T>
+            GMQCC_INLINE operator T *() {
+                return m_pointer;
+            }
+        };
+
+#      define GMQCC_IMPLICIT_POINTER(X) (gmqcc_voidptr(X))
+#else
+#      define GMQCC_IMPLICIT_POINTER(X) (X)
+#endif
 
 #ifdef NOTRACK
-#    define mem_a(x)    malloc (x)
-#    define mem_d(x)    free   (x)
-#    define mem_r(x, n) realloc(x, n)
+#    define mem_a(x)    GMQCC_IMPLICIT_POINTER(malloc (x))
+#    define mem_d(x)    free   ((void*)x)
+#    define mem_r(x, n) realloc((void*)x, n)
 #else
-#    define mem_a(x)    util_memory_a((x), __LINE__, __FILE__)
-#    define mem_d(x)    util_memory_d((x), __LINE__, __FILE__)
-#    define mem_r(x, n) util_memory_r((x), (n), __LINE__, __FILE__)
+#    define mem_a(x)    GMQCC_IMPLICIT_POINTER(util_memory_a((x), __LINE__, __FILE__))
+#    define mem_d(x)    util_memory_d((void*)(x),      __LINE__, __FILE__)
+#    define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__)
 #endif
 
-/*
- * TODO: make these safer to use.  Currently this only works on
- * x86 and x86_64, some systems will likely not like this. Such
- * as BE systems.
- */
-#define FLT2INT(Y) *((int32_t*)&(Y))
-#define INT2FLT(Y) *((float  *)&(Y))
+/** TODO: Cleanup this whole mess {{{ */
 
 /* New flexible vector implementation from Dale */
 #define _vec_raw(A) (((size_t*)(void*)(A)) - 2)
@@ -250,6 +314,7 @@ uint32_t util_crc32(uint32_t crc, const char *data, size_t len);
 #define _vec_forcegrow(A,N) _util_vec_grow(((void**)&(A)), (N), sizeof(*(A)))
 #define _vec_remove(A,S,I,N) (memmove((char*)(A)+(I)*(S),(char*)(A)+((I)+(N))*(S),(S)*(_vec_end(A)-(I)-(N))), _vec_end(A)-=(N))
 void _util_vec_grow(void **a, size_t i, size_t s);
+
 /* exposed interface */
 #define vec_free(A)          ((A) ? (mem_d((void*)_vec_raw(A)), (A) = NULL) : 0)
 #define vec_push(A,V)        (_vec_mightgrow((A),1), (A)[_vec_end(A)++] = (V))
@@ -259,10 +324,12 @@ void _util_vec_grow(void **a, size_t i, size_t s);
 #define vec_append(A,N,S)    memcpy(vec_add((A), (N)), (S), N * sizeof(*(S)))
 #define vec_remove(A,I,N)    _vec_remove((A), sizeof(*(A)), (I), (N))
 #define vec_pop(A)           (_vec_end(A)-=1)
+
 /* these are supposed to NOT reallocate */
 #define vec_shrinkto(A,N)    (_vec_end(A) = (N))
 #define vec_shrinkby(A,N)    (_vec_end(A) -= (N))
 
+/* vec_upload needs to be cleaned up as well to be a function */
 #define vec_upload(X,Y,S)      \
     do {                       \
         size_t E = 0;          \
@@ -272,6 +339,8 @@ void _util_vec_grow(void **a, size_t i, size_t s);
         }                      \
     } while(0)
 
+/** }}} */
+
 typedef struct hash_table_t {
     size_t                size;
     struct hash_node_t **table;
@@ -338,14 +407,12 @@ enum {
 };
 
 /* const/var qualifiers */
-#define CV_NONE  0
-#define CV_CONST 1
-#define CV_VAR  -1
-/* magic number to help parsing */
-#define CV_WRONG  0x8000
+#define CV_NONE   0
+#define CV_CONST  1
+#define CV_VAR   -1
+#define CV_WRONG  0x8000 /* magic number to help parsing */
 
 extern const char *type_name        [TYPE_COUNT];
-extern size_t      type_sizeof      [TYPE_COUNT];
 extern uint16_t    type_store_instr [TYPE_COUNT];
 extern uint16_t    field_store_instr[TYPE_COUNT];
 
@@ -546,9 +613,15 @@ enum {
      */
     VINSTR_PHI,
     VINSTR_JUMP,
-    VINSTR_COND
+    VINSTR_COND,
+    /* A never returning CALL.
+     * Creating this causes IR blocks to be marked as 'final'.
+     * No-Return-Call
+     */
+    VINSTR_NRCALL
 };
 
+/* TODO: cleanup this mess */
 extern prog_section_statement *code_statements;
 extern int                    *code_linenums;
 extern prog_section_def       *code_defs;
@@ -558,6 +631,7 @@ extern int                    *code_globals;
 extern char                   *code_chars;
 extern uint16_t code_crc;
 
+/* uhh? */
 typedef float   qcfloat;
 typedef int32_t qcint;
 
@@ -632,6 +706,7 @@ bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_
 /*===================================================================*/
 /*========================= assembler.c =============================*/
 /*===================================================================*/
+/* TODO: remove this ... */
 static const struct {
     const char  *m; /* menomic     */
     const size_t o; /* operands    */
@@ -841,14 +916,14 @@ bool parser_compile_string_len(const char *name, const char *str, size_t len);
 /*===================================================================*/
 /*====================== ftepp.c commandline ========================*/
 /*===================================================================*/
-bool ftepp_init             ();
-bool ftepp_preprocess_file  (const char *filename);
-bool ftepp_preprocess_string(const char *name, const char *str);
-void ftepp_finish           ();
-const char *ftepp_get       ();
-void ftepp_flush            ();
-void ftepp_add_define       (const char *source, const char *name);
-void ftepp_add_macro        (const char *name,   const char *value);
+bool        ftepp_init             ();
+bool        ftepp_preprocess_file  (const char *filename);
+bool        ftepp_preprocess_string(const char *name, const char *str);
+void        ftepp_finish           ();
+const char *ftepp_get              ();
+void        ftepp_flush            ();
+void        ftepp_add_define       (const char *source, const char *name);
+void        ftepp_add_macro        (const char *name,   const char *value);
 
 /*===================================================================*/
 /*======================= main.c commandline ========================*/
@@ -876,9 +951,10 @@ typedef struct {
     longbit     bit;
 } opts_flag_def;
 
-bool opts_setflag (const char *, bool);
-bool opts_setwarn (const char *, bool);
-bool opts_setoptim(const char *, bool);
+bool opts_setflag  (const char *, bool);
+bool opts_setwarn  (const char *, bool);
+bool opts_setwerror(const char *, bool);
+bool opts_setoptim (const char *, bool);
 
 void opts_init         (const char *, int, size_t);
 void opts_set          (uint32_t   *, size_t, bool);
@@ -948,7 +1024,6 @@ typedef struct {
     bool        memchk;         /* -memchk       */
     bool        dumpfin;        /* -dumpfin      */
     bool        dump;           /* -dump         */
-    bool        werror;         /* -Werror       */
     bool        forcecrc;       /* --force-crc=  */
     uint16_t    forced_crc;     /* --force-crc=  */
     bool        pp_only;        /* -E            */
@@ -956,14 +1031,15 @@ typedef struct {
 
     uint32_t flags       [1 + (COUNT_FLAGS         / 32)];
     uint32_t warn        [1 + (COUNT_WARNINGS      / 32)];
+    uint32_t werror      [1 + (COUNT_WARNINGS      / 32)];
     uint32_t optimization[1 + (COUNT_OPTIMIZATIONS / 32)];
 } opts_cmd_t;
 
 extern opts_cmd_t opts;
 
-/*===================================================================*/
 #define OPTS_FLAG(i)         (!! (opts.flags       [(i)/32] & (1<< ((i)%32))))
 #define OPTS_WARN(i)         (!! (opts.warn        [(i)/32] & (1<< ((i)%32))))
+#define OPTS_WERROR(i)       (!! (opts.werror      [(i)/32] & (1<< ((i)%32))))
 #define OPTS_OPTIMIZATION(i) (!! (opts.optimization[(i)/32] & (1<< ((i)%32))))
 
 #endif