]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - util.c
Allow negation to propagate inexactness in constant folder by using neg(x) = x*-1
[xonotic/gmqcc.git] / util.c
diff --git a/util.c b/util.c
index c73b3beec48e6e0455a193bcd7b1d4518401979a..b1d5c5ba37bc589e89611358fac2fd3c783e727d 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013
+ * Copyright (C) 2012, 2013, 2014
  *     Dale Weiler
  *     Wolfgang Bumiller
  *
@@ -22,6 +22,7 @@
  * SOFTWARE.
  */
 #define GMQCC_PLATFORM_HEADER
+#include <stdlib.h>
 #include "gmqcc.h"
 #include "platform.h"
 
@@ -57,7 +58,7 @@ const char *util_instr_str[VINSTR_END] = {
  * only required if big endian .. otherwise no need to swap
  * data.
  */
-#if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_BIG
+#if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_BIG || PLATFORM_BYTE_ORDER == -1
     static GMQCC_INLINE void util_swap16(uint16_t *d, size_t l) {
         while (l--) {
             d[l] = (d[l] << 8) | (d[l] >> 8);
@@ -85,6 +86,7 @@ const char *util_instr_str[VINSTR_END] = {
         }
         */
         size_t i;
+        l *= 2;
         for (i = 0; i < l; i += 2) {
             uint32_t v1 = d[i];
             d[i] = d[i+1];
@@ -94,73 +96,161 @@ const char *util_instr_str[VINSTR_END] = {
     }
 #endif
 
-void util_endianswap(void *_data, size_t length, unsigned int typesize) {
+void util_endianswap(void *_data, size_t count, unsigned int typesize) {
 #   if PLATFORM_BYTE_ORDER == -1 /* runtime check */
     if (*((char*)&typesize))
         return;
 #else
-    /* prevent unused warnings */
-    (void) _data;
-    (void) length;
-    (void) typesize;
 
 #   if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_LITTLE
+        /* prevent unused warnings */
+        (void) _data;
+        (void) count;
+        (void) typesize;
         return;
 #   else
         switch (typesize) {
             case 1: return;
             case 2:
-                util_swap16((uint16_t*)_data, length>>1);
+                util_swap16((uint16_t*)_data, count);
                 return;
             case 4:
-                util_swap32((uint32_t*)_data, length>>2);
+                util_swap32((uint32_t*)_data, count);
                 return;
             case 8:
-                util_swap64((uint32_t*)_data, length>>3);
+                util_swap64((uint32_t*)_data, count);
                 return;
 
-            default: exit(EXIT_FAILURE); /* please blow the fuck up! */
+            default:
+                con_err ("util_endianswap: I don't know how to swap a %u byte structure!\n", typesize);
+                exit(EXIT_FAILURE); /* please blow the fuck up! */
         }
 #   endif
 #endif
 }
 
+void util_swap_header(prog_header_t *code_header) {
+    util_endianswap(&code_header->version,              1, sizeof(code_header->version));
+    util_endianswap(&code_header->crc16,                1, sizeof(code_header->crc16));
+    util_endianswap(&code_header->statements.offset,    1, sizeof(code_header->statements.offset));
+    util_endianswap(&code_header->statements.length,    1, sizeof(code_header->statements.length));
+    util_endianswap(&code_header->defs.offset,          1, sizeof(code_header->defs.offset));
+    util_endianswap(&code_header->defs.length,          1, sizeof(code_header->defs.length));
+    util_endianswap(&code_header->fields.offset,        1, sizeof(code_header->fields.offset));
+    util_endianswap(&code_header->fields.length,        1, sizeof(code_header->fields.length));
+    util_endianswap(&code_header->functions.offset,     1, sizeof(code_header->functions.offset));
+    util_endianswap(&code_header->functions.length,     1, sizeof(code_header->functions.length));
+    util_endianswap(&code_header->strings.offset,       1, sizeof(code_header->strings.offset));
+    util_endianswap(&code_header->strings.length,       1, sizeof(code_header->strings.length));
+    util_endianswap(&code_header->globals.offset,       1, sizeof(code_header->globals.offset));
+    util_endianswap(&code_header->globals.length,       1, sizeof(code_header->globals.length));
+    util_endianswap(&code_header->entfield,             1, sizeof(code_header->entfield));
+}
+
+void util_swap_statements(prog_section_statement_t *statements) {
+    size_t i;
+
+    for (i = 0; i < vec_size(statements); ++i) {
+        util_endianswap(&statements[i].opcode,  1, sizeof(statements[i].opcode));
+        util_endianswap(&statements[i].o1,      1, sizeof(statements[i].o1));
+        util_endianswap(&statements[i].o2,      1, sizeof(statements[i].o2));
+        util_endianswap(&statements[i].o3,      1, sizeof(statements[i].o3));
+    }
+}
+
+void util_swap_defs_fields(prog_section_both_t *section) {
+    size_t i;
+
+    for (i = 0; i < vec_size(section); ++i) {
+        util_endianswap(&section[i].type,   1, sizeof(section[i].type));
+        util_endianswap(&section[i].offset, 1, sizeof(section[i].offset));
+        util_endianswap(&section[i].name,   1, sizeof(section[i].name));
+    }
+}
+
+void util_swap_functions(prog_section_function_t *functions) {
+    size_t i;
+
+    for (i = 0; i < vec_size(functions); ++i) {
+        util_endianswap(&functions[i].entry,        1, sizeof(functions[i].entry));
+        util_endianswap(&functions[i].firstlocal,   1, sizeof(functions[i].firstlocal));
+        util_endianswap(&functions[i].locals,       1, sizeof(functions[i].locals));
+        util_endianswap(&functions[i].profile,      1, sizeof(functions[i].profile));
+        util_endianswap(&functions[i].name,         1, sizeof(functions[i].name));
+        util_endianswap(&functions[i].file,         1, sizeof(functions[i].file));
+        util_endianswap(&functions[i].nargs,        1, sizeof(functions[i].nargs));
+        /* Don't swap argsize[] - it's just a byte array, which Quake uses only as such. */
+    }
+}
+
+void util_swap_globals(int32_t *globals) {
+    util_endianswap(globals, vec_size(globals), sizeof(int32_t));
+}
+
 /*
- * Based On:
- *      Slicing-by-8 algorithms by Michael E.
- *      Kounavis and Frank L. Berry from Intel Corp.
- *          http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
- *
- *  This code was made to be slightly less confusing with macros, which
- *  I suppose is somewhat ironic.
- *
- *  The code had to be changed for non reflected on the output register
- *  since that's the method Quake uses.
- *
- *  The code also had to be changed for CRC16, which is slightly harder
- *  since the CRC32 method in the original Intel paper used a different
- *  bit order convention.
- *
- *  The table can be computed with:
- *      u16 table[8][256];
- *      for (i = 0; i < 0x100; ++i) {
- *          u16 x = i << 8;
- *          for (j = 0; j < 8; j++)
- *              x = (x << 1) ^ ((x & 0x8000) ? 0x1021 : 0);
- *          table[0][i] = x;
- *      }
- *      for (i = 0; i < 0x100; ++i) {
- *          u16 c = (*table)[i];
- *          for (j = 1; j < 8; ++j)
- *              table[j][i] = c = (*table)[c >> 8] ^ (c << 8));
- *      }
+* Based On:
+*   Slicing-by-8 algorithms by Michael E.
+*       Kounavis and Frank L. Berry from Intel Corp.
+*       http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
+*
+*   This code was made to be slightly less confusing with macros, which
+*   I suppose is somewhat ironic.
+*
+*   The code had to be changed for non reflected on the output register
+*   since that's the method Quake uses.
+*
+*   The code also had to be changed for CRC16, which is slightly harder
+*   since the CRC32 method in the original Intel paper used a different
+*   bit order convention.
+*
+* Notes about the table:
+*   - It's exactly 4K in size
+*   - 64 elements fit in a cache line
+*   - can do 8 iterations unrolled 8 times for free
+*   - The first 256 elements of the table are standard CRC16 table
+*
+* Table can be generated with the following utility:
+*/
+#if 0
+#include <stdio.h>
+#include <stdint.h>
+int main(void) {
+    for (unsigned i = 0; i < 0x100; ++i) {
+        uint16_t x = i << 8;
+        for (int j = 0; j < 8; ++j)
+            x = (x << 1) ^ ((x & 0x8000) ? 0x1021 : 0);
+        tab[0][i] = x;
+    }
+    for (unsigned i = 0; i < 0x100; ++i) {
+        uint16_t c = tab[0][i];
+        for (unsigned j = 1; j < 8; ++j) {
+            c = tab[0][c >> 8] ^ (c << 8);
+            tab[j][i] = c;
+        }
+    }
+    printf("static const uint16_t util_crc16_table[8][256] = {");
+    for (int i = 0; i < 8; ++i) {
+        printf("{\n");
+        for (int j = 0; j < 0x100; ++j) {
+            printf((j & 7) ? " " : "    ");
+            printf((j != 0x100-1) ? "0x%04X," : "0x%04X", tab[i][j]);
+            if ((j & 7) == 7)
+                printf("\n");
+        }
+        printf((i != 7) ? "}," : "}");
+    }
+    printf("};\n");
+    return 0;
+}
+#endif
+/*
+ * Non-Reflective version is present as well as a reference.
  *
- *  Notes about the table:
- *      - It's exactly 4K in size
- *      - 64 elements fit in a cache line
- *      - can do 8 iterations unrolled 8 times for free
- *      - The first 256 elements of the table are standard CRC16 table
+ * TODO:
+ *  combine the crc16 into u32s and mask off low high for byte order
+ *  to make the arrays smaller.
  */
+
 static const uint16_t util_crc16_table[8][256] = {{
     0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
     0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
@@ -427,14 +517,20 @@ static const uint16_t util_crc16_table[8][256] = {{
     0x5357, 0x1484, 0xDCF1, 0x9B22, 0x5C3A, 0x1BE9, 0xD39C, 0x944F
 }};
 
-uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
-    /* keep in register for fast cascade */
+/* Non - Reflected */
+uint16_t util_crc16(uint16_t current, const char *GMQCC_RESTRICT k, size_t len) {
     register uint16_t h = current;
 
     /* don't load twice */
-    uint8_t *GMQCC_RESTRICT data = (uint8_t *GMQCC_RESTRICT)k;
+    const uint8_t *GMQCC_RESTRICT data = (const uint8_t *GMQCC_RESTRICT)k;
     size_t n;
 
+    /* deal with the first bytes as bytes until we reach an 8 byte boundary */
+    while (len & 7) {
+        h = (uint16_t)(h << 8) ^ (*util_crc16_table)[(h >> 8) ^ *data++];
+        --len;
+    }
+
     #define SELECT_BULK(X, MOD) util_crc16_table[(X)][data[7-(X)] ^ (MOD)]
     #define SELECT_DATA(X)      util_crc16_table[(X)][data[7-(X)]]
 
@@ -445,12 +541,17 @@ uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
             SELECT_DATA(4) ^
             SELECT_DATA(3) ^
             SELECT_DATA(2) ^
-            SELECT_DATA(1);
+            SELECT_DATA(1) ^
+            SELECT_DATA(0);
         data += 8;
+        len  -= 8;
     }
 
+    #undef SELECT_BULK
+    #undef SELECT_DATA
+
     /* deal with the rest with the byte method */
-    for (n &= 7; n; --n)
+    for (n = len & 7; n; --n)
         h = (uint16_t)(h << 8) ^ (*util_crc16_table)[(h >> 8) ^ *data++];
 
     return h;
@@ -460,7 +561,7 @@ uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
  * modifier is the match to make and the transposition from it, while add is the upper-value that determines the
  * transposition from uppercase to lower case.
  */
-static GMQCC_INLINE size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
+static size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
     size_t sz = 1;
     for (; *in && sz < outsz; ++in, ++out, ++sz) {
         *out = (*in == mod[0])