Home | History | Annotate | Download | only in libacc
      1 /*
      2  * Android "Almost" C Compiler.
      3  * This is a compiler for a small subset of the C language, intended for use
      4  * in scripting environments where speed and memory footprint are important.
      5  *
      6  * This code is based upon the "unobfuscated" version of the
      7  * Obfuscated Tiny C compiler, see the file LICENSE for details.
      8  *
      9  */
     10 
     11 #define LOG_TAG "acc"
     12 #include <cutils/log.h>
     13 
     14 #include <ctype.h>
     15 #include <errno.h>
     16 #include <limits.h>
     17 #include <stdarg.h>
     18 #include <stdint.h>
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 
     24 #include <cutils/hashmap.h>
     25 
     26 #include <sys/mman.h>
     27 
     28 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
     29 #define MAP_ANONYMOUS MAP_ANON
     30 #endif
     31 
     32 #if defined(__arm__)
     33 #define DEFAULT_ARM_CODEGEN
     34 #define PROVIDE_ARM_CODEGEN
     35 #elif defined(__i386__)
     36 #define DEFAULT_X86_CODEGEN
     37 #define PROVIDE_X86_CODEGEN
     38 #elif defined(__x86_64__)
     39 #define DEFAULT_X64_CODEGEN
     40 #define PROVIDE_X64_CODEGEN
     41 #endif
     42 
     43 #if (defined(__VFP_FP__) && !defined(__SOFTFP__))
     44 #define ARM_USE_VFP
     45 #endif
     46 
     47 #include <acc/acc.h>
     48 
     49 #define LOG_API(...) do {} while(0)
     50 // #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
     51 
     52 #define LOG_STACK(...) do {} while(0)
     53 // #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
     54 
     55 // #define PROVIDE_TRACE_CODEGEN
     56 
     57 // Uncomment to disable ARM peephole optimizations
     58 // #define DISABLE_ARM_PEEPHOLE
     59 
     60 // Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
     61 // #define DEBUG_SAVE_INPUT_TO_FILE
     62 
     63 #ifdef DEBUG_SAVE_INPUT_TO_FILE
     64 #ifdef ARM_USE_VFP
     65 #define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
     66 #else
     67 #define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
     68 #endif
     69 #endif
     70 
     71 #define assert(b) assertImpl(b, __LINE__)
     72 
     73 namespace acc {
     74 
     75 // Subset of STL vector.
     76 template<class E> class Vector {
     77     public:
     78     Vector() {
     79         mpBase = 0;
     80         mUsed = 0;
     81         mSize = 0;
     82     }
     83 
     84     ~Vector() {
     85         if (mpBase) {
     86             clear();
     87             free(mpBase);
     88         }
     89     }
     90 
     91     inline E& operator[](size_t i) {
     92         return mpBase[i];
     93     }
     94 
     95     inline E& front() {
     96         return mpBase[0];
     97     }
     98 
     99     inline E& back() {
    100         return mpBase[mUsed - 1];
    101     }
    102 
    103     void pop_back() {
    104         mUsed -= 1;
    105         mpBase[mUsed].~E();
    106     }
    107 
    108     void push_back(const E& item) {
    109         * ensure(1) = item;
    110     }
    111 
    112     inline size_t size() {
    113         return mUsed;
    114     }
    115 
    116     void clear() {
    117          if (mpBase) {
    118              size_t used = mUsed;
    119              for(size_t i = 0; i < used; i++) {
    120                  mpBase[i].~E();
    121              }
    122          }
    123          mUsed = 0;
    124      }
    125 
    126 private:
    127     E* ensure(int n) {
    128         size_t newUsed = mUsed + n;
    129         if (newUsed > mSize) {
    130             size_t newSize = mSize * 2 + 10;
    131             if (newSize < newUsed) {
    132                 newSize = newUsed;
    133             }
    134             mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
    135             mSize = newSize;
    136         }
    137         E* result = mpBase + mUsed;
    138         mUsed = newUsed;
    139         return result;
    140     }
    141 
    142     E* mpBase;
    143     size_t mUsed;
    144     size_t mSize;
    145 };
    146 
    147 class ErrorSink {
    148 public:
    149     void error(const char *fmt, ...) {
    150         va_list ap;
    151         va_start(ap, fmt);
    152         verror(fmt, ap);
    153         va_end(ap);
    154     }
    155 
    156     virtual ~ErrorSink() {}
    157     virtual void verror(const char* fmt, va_list ap) = 0;
    158 };
    159 
    160 class Compiler : public ErrorSink {
    161     typedef int tokenid_t;
    162     enum TypeTag {
    163         TY_UNKNOWN =     -1,
    164         TY_INT,       // 0
    165         TY_CHAR,      // 1
    166         TY_SHORT,     // 2
    167         TY_VOID,      // 3
    168         TY_FLOAT,     // 4
    169         TY_DOUBLE,    // 5
    170         TY_POINTER,   // 6
    171         TY_ARRAY,     // 7
    172         TY_STRUCT,    // 8
    173         TY_FUNC,      // 9
    174         TY_PARAM      // 10
    175     };
    176 
    177     enum StorageClass {
    178         SC_DEFAULT,  // 0
    179         SC_AUTO,     // 1
    180         SC_REGISTER, // 2
    181         SC_STATIC,   // 3
    182         SC_EXTERN,   // 4
    183         SC_TYPEDEF   // 5
    184     };
    185 
    186     struct Type {
    187         TypeTag tag;
    188         StorageClass  storageClass;
    189         tokenid_t id; // For function arguments, global vars, local vars, struct elements
    190         tokenid_t structTag; // For structs the name of the struct
    191         int length; // length of array, offset of struct element. -1 means struct is forward defined
    192         int alignment; // for structs only
    193         Type* pHead; // For a struct this is the prototype struct.
    194         Type* pTail;
    195     };
    196 
    197     enum ExpressionType {
    198         ET_RVALUE,
    199         ET_LVALUE
    200     };
    201 
    202     struct ExpressionValue {
    203         ExpressionValue() {
    204             et = ET_RVALUE;
    205             pType = NULL;
    206         }
    207         ExpressionType et;
    208         Type* pType;
    209     };
    210 
    211     class ICodeBuf {
    212     public:
    213         virtual ~ICodeBuf() {}
    214         virtual void init(int size) = 0;
    215         virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
    216         virtual void o4(int n) = 0;
    217         virtual void ob(int n) = 0;
    218         virtual void* getBase() = 0;
    219         virtual intptr_t getSize() = 0;
    220         virtual intptr_t getPC() = 0;
    221         // Call this before trying to modify code in the buffer.
    222         virtual void flush() = 0;
    223     };
    224 
    225     class CodeBuf : public ICodeBuf {
    226         char* ind; // Output code pointer
    227         char* pProgramBase;
    228         ErrorSink* mErrorSink;
    229         int mSize;
    230         bool mOverflowed;
    231 
    232         void release() {
    233             if (pProgramBase != 0) {
    234                 munmap(pProgramBase, mSize);
    235                 pProgramBase = 0;
    236             }
    237         }
    238 
    239         bool check(int n) {
    240             int newSize = ind - pProgramBase + n;
    241             bool overflow = newSize > mSize;
    242             if (overflow && !mOverflowed) {
    243                 mOverflowed = true;
    244                 if (mErrorSink) {
    245                     mErrorSink->error("Code too large: %d bytes", newSize);
    246                 }
    247             }
    248             return overflow;
    249         }
    250 
    251     public:
    252         CodeBuf() {
    253             pProgramBase = 0;
    254             ind = 0;
    255             mErrorSink = 0;
    256             mSize = 0;
    257             mOverflowed = false;
    258         }
    259 
    260         virtual ~CodeBuf() {
    261             release();
    262         }
    263 
    264         virtual void init(int size) {
    265             release();
    266             mSize = size;
    267             pProgramBase = (char*) mmap(NULL, size,
    268                 PROT_EXEC | PROT_READ | PROT_WRITE,
    269                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    270             ind = pProgramBase;
    271         }
    272 
    273         virtual void setErrorSink(ErrorSink* pErrorSink) {
    274             mErrorSink = pErrorSink;
    275         }
    276 
    277         virtual void o4(int n) {
    278             if(check(4)) {
    279                 return;
    280             }
    281             * (int*) ind = n;
    282             ind += 4;
    283         }
    284 
    285         /*
    286          * Output a byte. Handles all values, 0..ff.
    287          */
    288         virtual void ob(int n) {
    289             if(check(1)) {
    290                 return;
    291             }
    292             *ind++ = n;
    293         }
    294 
    295         virtual void* getBase() {
    296             return (void*) pProgramBase;
    297         }
    298 
    299         virtual intptr_t getSize() {
    300             return ind - pProgramBase;
    301         }
    302 
    303         virtual intptr_t getPC() {
    304             return (intptr_t) ind;
    305         }
    306 
    307         virtual void flush() {}
    308     };
    309 
    310     /**
    311      * A code generator creates an in-memory program, generating the code on
    312      * the fly. There is one code generator implementation for each supported
    313      * architecture.
    314      *
    315      * The code generator implements the following abstract machine:
    316      * R0 - the accumulator.
    317      * FP - a frame pointer for accessing function arguments and local
    318      *      variables.
    319      * SP - a stack pointer for storing intermediate results while evaluating
    320      *      expressions. The stack pointer grows downwards.
    321      *
    322      * The function calling convention is that all arguments are placed on the
    323      * stack such that the first argument has the lowest address.
    324      * After the call, the result is in R0. The caller is responsible for
    325      * removing the arguments from the stack.
    326      * The R0 register is not saved across function calls. The
    327      * FP and SP registers are saved.
    328      */
    329 
    330     class CodeGenerator {
    331     public:
    332         CodeGenerator() {
    333             mErrorSink = 0;
    334             pCodeBuf = 0;
    335             pushType();
    336         }
    337         virtual ~CodeGenerator() {}
    338 
    339         virtual void init(ICodeBuf* pCodeBuf) {
    340             this->pCodeBuf = pCodeBuf;
    341             pCodeBuf->setErrorSink(mErrorSink);
    342         }
    343 
    344         virtual void setErrorSink(ErrorSink* pErrorSink) {
    345             mErrorSink = pErrorSink;
    346             if (pCodeBuf) {
    347                 pCodeBuf->setErrorSink(mErrorSink);
    348             }
    349         }
    350 
    351         /* Give the code generator some utility types so it can
    352          * use its own types as needed for the results of some
    353          * operations like gcmp.
    354          */
    355 
    356         void setTypes(Type* pInt) {
    357             mkpInt = pInt;
    358         }
    359 
    360         /* Emit a function prolog.
    361          * pDecl is the function declaration, which gives the arguments.
    362          * Save the old value of the FP.
    363          * Set the new value of the FP.
    364          * Convert from the native platform calling convention to
    365          * our stack-based calling convention. This may require
    366          * pushing arguments from registers to the stack.
    367          * Allocate "N" bytes of stack space. N isn't known yet, so
    368          * just emit the instructions for adjusting the stack, and return
    369          * the address to patch up. The patching will be done in
    370          * functionExit().
    371          * returns address to patch with local variable size.
    372         */
    373         virtual int functionEntry(Type* pDecl) = 0;
    374 
    375         /* Emit a function epilog.
    376          * Restore the old SP and FP register values.
    377          * Return to the calling function.
    378          * argCount - the number of arguments to the function.
    379          * localVariableAddress - returned from functionEntry()
    380          * localVariableSize - the size in bytes of the local variables.
    381          */
    382         virtual void functionExit(Type* pDecl, int localVariableAddress,
    383                                   int localVariableSize) = 0;
    384 
    385         /* load immediate value to R0 */
    386         virtual void li(int i) = 0;
    387 
    388         /* Load floating point value from global address. */
    389         virtual void loadFloat(int address, Type* pType) = 0;
    390 
    391         /* Add the struct offset in bytes to R0, change the type to pType */
    392         virtual void addStructOffsetR0(int offset, Type* pType) = 0;
    393 
    394         /* Jump to a target, and return the address of the word that
    395          * holds the target data, in case it needs to be fixed up later.
    396          */
    397         virtual int gjmp(int t) = 0;
    398 
    399         /* Test R0 and jump to a target if the test succeeds.
    400          * l = 0: je, l == 1: jne
    401          * Return the address of the word that holds the targed data, in
    402          * case it needs to be fixed up later.
    403          */
    404         virtual int gtst(bool l, int t) = 0;
    405 
    406         /* Compare TOS against R0, and store the boolean result in R0.
    407          * Pops TOS.
    408          * op specifies the comparison.
    409          */
    410         virtual void gcmp(int op) = 0;
    411 
    412         /* Perform the arithmetic op specified by op. TOS is the
    413          * left argument, R0 is the right argument.
    414          * Pops TOS.
    415          */
    416         virtual void genOp(int op) = 0;
    417 
    418         /* Compare 0 against R0, and store the boolean result in R0.
    419          * op specifies the comparison.
    420          */
    421         virtual void gUnaryCmp(int op) = 0;
    422 
    423         /* Perform the arithmetic op specified by op. 0 is the
    424          * left argument, R0 is the right argument.
    425          */
    426         virtual void genUnaryOp(int op) = 0;
    427 
    428         /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
    429          */
    430         virtual void pushR0() = 0;
    431 
    432         /* Turn R0, TOS into R0 TOS R0 */
    433 
    434         virtual void over() = 0;
    435 
    436         /* Pop R0 from the stack. (Also known as "drop")
    437          */
    438         virtual void popR0() = 0;
    439 
    440         /* Store R0 to the address stored in TOS.
    441          * The TOS is popped.
    442          */
    443         virtual void storeR0ToTOS() = 0;
    444 
    445         /* Load R0 from the address stored in R0.
    446          */
    447         virtual void loadR0FromR0() = 0;
    448 
    449         /* Load the absolute address of a variable to R0.
    450          * If ea <= LOCAL, then this is a local variable, or an
    451          * argument, addressed relative to FP.
    452          * else it is an absolute global address.
    453          *
    454          * et is ET_RVALUE for things like string constants, ET_LVALUE for
    455          * variables.
    456          */
    457         virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
    458 
    459         /* Load the pc-relative address of a forward-referenced variable to R0.
    460          * Return the address of the 4-byte constant so that it can be filled
    461          * in later.
    462          */
    463         virtual int leaForward(int ea, Type* pPointerType) = 0;
    464 
    465         /**
    466          * Convert R0 to the given type.
    467          */
    468 
    469         void convertR0(Type* pType) {
    470             convertR0Imp(pType, false);
    471         }
    472 
    473         void castR0(Type* pType) {
    474             convertR0Imp(pType, true);
    475         }
    476 
    477         virtual void convertR0Imp(Type* pType, bool isCast) = 0;
    478 
    479         /* Emit code to adjust the stack for a function call. Return the
    480          * label for the address of the instruction that adjusts the
    481          * stack size. This will be passed as argument "a" to
    482          * endFunctionCallArguments.
    483          */
    484         virtual int beginFunctionCallArguments() = 0;
    485 
    486         /* Emit code to store R0 to the stack at byte offset l.
    487          * Returns stack size of object (typically 4 or 8 bytes)
    488          */
    489         virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
    490 
    491         /* Patch the function call preamble.
    492          * a is the address returned from beginFunctionCallArguments
    493          * l is the number of bytes the arguments took on the stack.
    494          * Typically you would also emit code to convert the argument
    495          * list into whatever the native function calling convention is.
    496          * On ARM for example you would pop the first 5 arguments into
    497          * R0..R4
    498          */
    499         virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
    500 
    501         /* Emit a call to an unknown function. The argument "symbol" needs to
    502          * be stored in the location where the address should go. It forms
    503          * a chain. The address will be patched later.
    504          * Return the address of the word that has to be patched.
    505          */
    506         virtual int callForward(int symbol, Type* pFunc) = 0;
    507 
    508         /* Call a function pointer. L is the number of bytes the arguments
    509          * take on the stack. The address of the function is stored at
    510          * location SP + l.
    511          */
    512         virtual void callIndirect(int l, Type* pFunc) = 0;
    513 
    514         /* Adjust SP after returning from a function call. l is the
    515          * number of bytes of arguments stored on the stack. isIndirect
    516          * is true if this was an indirect call. (In which case the
    517          * address of the function is stored at location SP + l.)
    518          */
    519         virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
    520 
    521         /* Generate a symbol at the current PC. t is the head of a
    522          * linked list of addresses to patch.
    523          */
    524         virtual void gsym(int t) = 0;
    525 
    526         /* Resolve a forward reference function at the current PC.
    527          * t is the head of a
    528          * linked list of addresses to patch.
    529          * (Like gsym, but using absolute address, not PC relative address.)
    530          */
    531         virtual void resolveForward(int t) = 0;
    532 
    533         /*
    534          * Do any cleanup work required at the end of a compile.
    535          * For example, an instruction cache might need to be
    536          * invalidated.
    537          * Return non-zero if there is an error.
    538          */
    539         virtual int finishCompile() = 0;
    540 
    541         /**
    542          * Adjust relative branches by this amount.
    543          */
    544         virtual int jumpOffset() = 0;
    545 
    546         /**
    547          * Memory alignment (in bytes) for this type of data
    548          */
    549         virtual size_t alignmentOf(Type* type) = 0;
    550 
    551         /**
    552          * Array element alignment (in bytes) for this type of data.
    553          */
    554         virtual size_t sizeOf(Type* type) = 0;
    555 
    556         virtual Type* getR0Type() {
    557             return mExpressionStack.back().pType;
    558         }
    559 
    560         virtual ExpressionType getR0ExpressionType() {
    561             return mExpressionStack.back().et;
    562         }
    563 
    564         virtual void setR0ExpressionType(ExpressionType et) {
    565             mExpressionStack.back().et = et;
    566         }
    567 
    568         virtual size_t getExpressionStackDepth() {
    569             return mExpressionStack.size();
    570         }
    571 
    572         virtual void forceR0RVal() {
    573             if (getR0ExpressionType() == ET_LVALUE) {
    574                 loadR0FromR0();
    575             }
    576         }
    577 
    578     protected:
    579         /*
    580          * Output a byte. Handles all values, 0..ff.
    581          */
    582         void ob(int n) {
    583             pCodeBuf->ob(n);
    584         }
    585 
    586         void o4(int data) {
    587             pCodeBuf->o4(data);
    588         }
    589 
    590         intptr_t getBase() {
    591             return (intptr_t) pCodeBuf->getBase();
    592         }
    593 
    594         intptr_t getPC() {
    595             return pCodeBuf->getPC();
    596         }
    597 
    598         intptr_t getSize() {
    599             return pCodeBuf->getSize();
    600         }
    601 
    602         void flush() {
    603             pCodeBuf->flush();
    604         }
    605 
    606         void error(const char* fmt,...) {
    607             va_list ap;
    608             va_start(ap, fmt);
    609             mErrorSink->verror(fmt, ap);
    610             va_end(ap);
    611         }
    612 
    613         void assertImpl(bool test, int line) {
    614             if (!test) {
    615                 error("code generator assertion failed at line %s:%d.", __FILE__, line);
    616                 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
    617                 * (char*) 0 = 0;
    618             }
    619         }
    620 
    621         void setR0Type(Type* pType) {
    622             assert(pType != NULL);
    623             mExpressionStack.back().pType = pType;
    624             mExpressionStack.back().et = ET_RVALUE;
    625         }
    626 
    627         void setR0Type(Type* pType, ExpressionType et) {
    628             assert(pType != NULL);
    629             mExpressionStack.back().pType = pType;
    630             mExpressionStack.back().et = et;
    631         }
    632 
    633         Type* getTOSType() {
    634             return mExpressionStack[mExpressionStack.size()-2].pType;
    635         }
    636 
    637         void pushType() {
    638             if (mExpressionStack.size()) {
    639                 mExpressionStack.push_back(mExpressionStack.back());
    640             } else {
    641                 mExpressionStack.push_back(ExpressionValue());
    642             }
    643 
    644         }
    645 
    646         void overType() {
    647             size_t size = mExpressionStack.size();
    648             if (size >= 2) {
    649                 mExpressionStack.push_back(mExpressionStack.back());
    650                 mExpressionStack[size-1] = mExpressionStack[size-2];
    651                 mExpressionStack[size-2] = mExpressionStack[size];
    652             }
    653         }
    654 
    655         void popType() {
    656             mExpressionStack.pop_back();
    657         }
    658 
    659         bool bitsSame(Type* pA, Type* pB) {
    660             return collapseType(pA->tag) == collapseType(pB->tag);
    661         }
    662 
    663         TypeTag collapseType(TypeTag tag) {
    664             static const TypeTag collapsedTag[] = {
    665                     TY_INT,
    666                     TY_INT,
    667                     TY_INT,
    668                     TY_VOID,
    669                     TY_FLOAT,
    670                     TY_DOUBLE,
    671                     TY_INT,
    672                     TY_INT,
    673                     TY_VOID,
    674                     TY_VOID,
    675                     TY_VOID
    676                 };
    677             return collapsedTag[tag];
    678         }
    679 
    680         TypeTag collapseTypeR0() {
    681             return collapseType(getR0Type()->tag);
    682         }
    683 
    684         static bool isFloatType(Type* pType) {
    685             return isFloatTag(pType->tag);
    686         }
    687 
    688         static bool isFloatTag(TypeTag tag) {
    689             return tag == TY_FLOAT || tag == TY_DOUBLE;
    690         }
    691 
    692         static bool isPointerType(Type* pType) {
    693             return isPointerTag(pType->tag);
    694         }
    695 
    696         static bool isPointerTag(TypeTag tag) {
    697             return tag == TY_POINTER || tag == TY_ARRAY;
    698         }
    699 
    700         Type* getPointerArithmeticResultType(Type* a, Type* b) {
    701             TypeTag aTag = a->tag;
    702             TypeTag bTag = b->tag;
    703             if (aTag == TY_POINTER) {
    704                 return a;
    705             }
    706             if (bTag == TY_POINTER) {
    707                 return b;
    708             }
    709             if (aTag == TY_ARRAY) {
    710                 return a->pTail;
    711             }
    712             if (bTag == TY_ARRAY) {
    713                 return b->pTail;
    714             }
    715             return NULL;
    716         }
    717         Type* mkpInt;
    718 
    719     private:
    720         Vector<ExpressionValue> mExpressionStack;
    721         ICodeBuf* pCodeBuf;
    722         ErrorSink* mErrorSink;
    723     };
    724 
    725 #ifdef PROVIDE_ARM_CODEGEN
    726 
    727     static size_t rotateRight(size_t n, size_t rotate) {
    728         return (n >> rotate) | (n << (32 - rotate));
    729     }
    730 
    731     static size_t rotateLeft(size_t n, size_t rotate) {
    732         return (n << rotate) | (n >> (32 - rotate));
    733     }
    734 
    735     static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
    736         for(size_t i = 0; i < 16; i++) {
    737             size_t rotate = i * 2;
    738             size_t mask = rotateRight(0xff, rotate);
    739             if ((immediate | mask) == mask) {
    740                 size_t bits8 = rotateLeft(immediate, rotate);
    741                 // assert(bits8 <= 0xff);
    742                 *pResult = (i << 8) | bits8;
    743                 return true;
    744             }
    745         }
    746         return false;
    747     }
    748 
    749     static size_t decode12BitImmediate(size_t immediate) {
    750         size_t data = immediate & 0xff;
    751         size_t rotate = 2 * ((immediate >> 8) & 0xf);
    752         return rotateRight(data, rotate);
    753     }
    754 
    755     static bool isPowerOfTwo(size_t n) {
    756         return (n != 0) & ((n & (n-1)) == 0);
    757     }
    758 
    759     static size_t log2(size_t n) {
    760         int result = 0;
    761         while (n >>= 1) {
    762             result++;
    763         }
    764         return result;
    765     }
    766 
    767     class ARMCodeBuf : public ICodeBuf {
    768         ICodeBuf* mpBase;
    769         ErrorSink* mErrorSink;
    770 
    771         class CircularQueue {
    772             static const int SIZE = 16; // Must be power of 2
    773             static const int MASK = SIZE-1;
    774             unsigned int mBuf[SIZE];
    775             int mHead;
    776             int mCount;
    777 
    778         public:
    779             CircularQueue() {
    780                 mHead = 0;
    781                 mCount = 0;
    782             }
    783 
    784             void pushBack(unsigned int data) {
    785                 mBuf[(mHead + mCount) & MASK] = data;
    786                 mCount += 1;
    787             }
    788 
    789             unsigned int popFront() {
    790                 unsigned int result = mBuf[mHead];
    791                 mHead = (mHead + 1) & MASK;
    792                 mCount -= 1;
    793                 return result;
    794             }
    795 
    796             void popBack(int n) {
    797                 mCount -= n;
    798             }
    799 
    800             inline int count() {
    801                 return mCount;
    802             }
    803 
    804             bool empty() {
    805                 return mCount == 0;
    806             }
    807 
    808             bool full() {
    809                 return mCount == SIZE;
    810             }
    811 
    812             // The valid indexes are 1 - count() to 0
    813             unsigned int operator[](int i) {
    814                 return mBuf[(mHead + mCount + i) & MASK];
    815             }
    816         };
    817 
    818         CircularQueue mQ;
    819 
    820         void error(const char* fmt,...) {
    821             va_list ap;
    822             va_start(ap, fmt);
    823             mErrorSink->verror(fmt, ap);
    824             va_end(ap);
    825         }
    826 
    827         void flush() {
    828             while (!mQ.empty()) {
    829                 mpBase->o4(mQ.popFront());
    830             }
    831             mpBase->flush();
    832         }
    833 
    834     public:
    835         ARMCodeBuf(ICodeBuf* pBase) {
    836             mpBase = pBase;
    837         }
    838 
    839         virtual ~ARMCodeBuf() {
    840             delete mpBase;
    841         }
    842 
    843         void init(int size) {
    844             mpBase->init(size);
    845         }
    846 
    847         void setErrorSink(ErrorSink* pErrorSink) {
    848             mErrorSink = pErrorSink;
    849             mpBase->setErrorSink(pErrorSink);
    850         }
    851 
    852         void o4(int n) {
    853             if (mQ.full()) {
    854                 mpBase->o4(mQ.popFront());
    855             }
    856             mQ.pushBack(n);
    857 
    858 #ifndef DISABLE_ARM_PEEPHOLE
    859             // Peephole check
    860             bool didPeep;
    861             do {
    862                 static const unsigned int opMask = 0x01e00000;
    863                 static const unsigned int immediateMask = 0x00000fff;
    864                 static const unsigned int BMask = 0x00400000;
    865                 didPeep = false;
    866                 if (mQ.count() >= 4) {
    867 
    868                     // Operand by a small constant
    869                     // push;mov #imm;pop;op ==> op #imm
    870 
    871                     if (mQ[-4] == 0xe92d0001  && // stmfd    r13!, {r0}
    872                         (mQ[-3] & ~immediateMask) == 0xe3a00000  && // mov    r0, #X
    873                         mQ[-2] == 0xe8bd0002  && // ldmea    r13!, {r1}
    874                         (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) {  // OP    r0, r1, r0
    875                         unsigned int movConst = mQ[-3];
    876                         unsigned int op = mQ[-1];
    877                         unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
    878                         // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
    879                         if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
    880                             mQ.popBack(4);
    881                             mQ.pushBack(combined);
    882                             didPeep = true;
    883                         } else {
    884                             mQ.popBack(4);
    885                             didPeep = true;
    886                         }
    887                     }
    888                 }
    889 
    890                 // Load local variable
    891                 // sub r0,r11,#imm;ldr/ldrb r0,[r0]  ==> ldr/ldrb r0, [r11,#-imm]
    892                 if (mQ.count() >= 2) {
    893                     if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
    894                         const unsigned int encodedImmediate = mQ[-2] & immediateMask;
    895                         const unsigned int ld = mQ[-1];
    896                         if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
    897                             unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
    898                             mQ.popBack(2);
    899                             mQ.pushBack(combined);
    900                             didPeep = true;
    901                         } else if (ld == 0xedd07a00) {  // ldcl    p10, c7, [r0, #0x000]
    902                             unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
    903                             if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
    904                                 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl    p10, c7, [r11, #-0]
    905                                 mQ.popBack(2);
    906                                 mQ.pushBack(combined);
    907                                 didPeep = true;
    908                             }
    909                         }
    910                     }
    911                 }
    912 
    913                 // Constant array lookup
    914 
    915                 if (mQ.count() >= 6 &&
    916                     mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
    917                     (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
    918                     mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
    919                     (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
    920                     mQ[-2] == 0xe0000092 && // mul r0, r2, r0
    921                     mQ[-1] == 0xe0810000) { // add r0, r1, r0
    922                     unsigned int mov1 = mQ[-5];
    923                     unsigned int mov2 = mQ[-3];
    924                     unsigned int const1 = decode12BitImmediate(mov1);
    925                     unsigned int const2 = decode12BitImmediate(mov2);
    926                     unsigned int comboConst = const1 * const2;
    927                     size_t immediate = 0;
    928                     if (encode12BitImmediate(comboConst, &immediate)) {
    929                         mQ.popBack(6);
    930                         unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
    931                         if (comboConst) {
    932                             mQ.pushBack(add);
    933                         }
    934                         didPeep = true;
    935                     }
    936                 }
    937 
    938                 // Pointer arithmetic with a stride that is a power of two
    939 
    940                 if (mQ.count() >= 3 &&
    941                     (mQ[-3] & ~ immediateMask) == 0xe3a02000 &&  // mov    r2, #stride
    942                      mQ[-2] == 0xe0000092 && // mul    r0, r2, r0
    943                      mQ[-1] == 0xe0810000) {  // add r0, r1, r0
    944                     int stride = decode12BitImmediate(mQ[-3]);
    945                     if (isPowerOfTwo(stride)) {
    946                         mQ.popBack(3);
    947                         unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
    948                         mQ.pushBack(add);
    949                         didPeep = true;
    950                     }
    951                 }
    952 
    953             } while (didPeep);
    954 #endif
    955         }
    956 
    957         void ob(int n) {
    958             error("ob() not supported.");
    959         }
    960 
    961         void* getBase() {
    962             flush();
    963             return mpBase->getBase();
    964         }
    965 
    966         intptr_t getSize() {
    967             flush();
    968             return mpBase->getSize();
    969         }
    970 
    971         intptr_t getPC() {
    972             flush();
    973             return mpBase->getPC();
    974         }
    975     };
    976 
    977     class ARMCodeGenerator : public CodeGenerator {
    978     public:
    979         ARMCodeGenerator() {
    980 #ifdef ARM_USE_VFP
    981             // LOGD("Using ARM VFP hardware floating point.");
    982 #else
    983             // LOGD("Using ARM soft floating point.");
    984 #endif
    985         }
    986 
    987         virtual ~ARMCodeGenerator() {}
    988 
    989         /* returns address to patch with local variable size
    990         */
    991         virtual int functionEntry(Type* pDecl) {
    992             mStackUse = 0;
    993             // sp -> arg4 arg5 ...
    994             // Push our register-based arguments back on the stack
    995             int regArgCount = calcRegArgCount(pDecl);
    996             if (regArgCount > 0) {
    997                 mStackUse += regArgCount * 4;
    998                 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd    sp!, {}
    999             }
   1000             // sp -> arg0 arg1 ...
   1001             o4(0xE92D4800); // stmfd sp!, {fp, lr}
   1002             mStackUse += 2 * 4;
   1003             // sp, fp -> oldfp, retadr, arg0 arg1 ....
   1004             o4(0xE1A0B00D); // mov    fp, sp
   1005             LOG_STACK("functionEntry: %d\n", mStackUse);
   1006             int pc = getPC();
   1007             o4(0xE24DD000); // sub    sp, sp, # <local variables>
   1008             // We don't know how many local variables we are going to use,
   1009             // but we will round the allocation up to a multiple of
   1010             // STACK_ALIGNMENT, so it won't affect the stack alignment.
   1011             return pc;
   1012         }
   1013 
   1014         virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
   1015             // Round local variable size up to a multiple of stack alignment
   1016             localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
   1017                 STACK_ALIGNMENT) * STACK_ALIGNMENT;
   1018             // Patch local variable allocation code:
   1019             if (localVariableSize < 0 || localVariableSize > 255) {
   1020                 error("localVariables out of range: %d", localVariableSize);
   1021             }
   1022             *(char*) (localVariableAddress) = localVariableSize;
   1023 
   1024 #ifdef ARM_USE_VFP
   1025             {
   1026                 Type* pReturnType = pDecl->pHead;
   1027                 switch(pReturnType->tag) {
   1028                 case TY_FLOAT:
   1029                     o4(0xEE170A90); // fmrs    r0, s15
   1030                     break;
   1031                 case TY_DOUBLE:
   1032                     o4(0xEC510B17); // fmrrd r0, r1, d7
   1033                     break;
   1034                 default:
   1035                     break;
   1036                 }
   1037             }
   1038 #endif
   1039 
   1040             // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
   1041             o4(0xE1A0E00B); // mov lr, fp
   1042             o4(0xE59BB000); // ldr fp, [fp]
   1043             o4(0xE28ED004); // add sp, lr, #4
   1044             // sp -> retadr, arg0, ...
   1045             o4(0xE8BD4000); // ldmfd    sp!, {lr}
   1046             // sp -> arg0 ....
   1047 
   1048             // We store the PC into the lr so we can adjust the sp before
   1049             // returning. We need to pull off the registers we pushed
   1050             // earlier. We don't need to actually store them anywhere,
   1051             // just adjust the stack.
   1052             int regArgCount = calcRegArgCount(pDecl);
   1053             if (regArgCount) {
   1054                 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
   1055             }
   1056             o4(0xE12FFF1E); // bx lr
   1057         }
   1058 
   1059         /* load immediate value */
   1060         virtual void li(int t) {
   1061             liReg(t, 0);
   1062             setR0Type(mkpInt);
   1063         }
   1064 
   1065         virtual void loadFloat(int address, Type* pType) {
   1066             setR0Type(pType);
   1067             // Global, absolute address
   1068             o4(0xE59F0000); //        ldr r0, .L1
   1069             o4(0xEA000000); //        b .L99
   1070             o4(address);         // .L1:   .word ea
   1071                                  // .L99:
   1072 
   1073             switch (pType->tag) {
   1074             case TY_FLOAT:
   1075 #ifdef ARM_USE_VFP
   1076                 o4(0xEDD07A00);      // flds    s15, [r0]
   1077 #else
   1078                 o4(0xE5900000);      // ldr r0, [r0]
   1079 #endif
   1080                 break;
   1081             case TY_DOUBLE:
   1082 #ifdef ARM_USE_VFP
   1083                 o4(0xED907B00);      // fldd    d7, [r0]
   1084 #else
   1085                 o4(0xE1C000D0);      // ldrd r0, [r0]
   1086 #endif
   1087                 break;
   1088             default:
   1089                 assert(false);
   1090                 break;
   1091             }
   1092         }
   1093 
   1094 
   1095         virtual void addStructOffsetR0(int offset, Type* pType) {
   1096             if (offset) {
   1097                 size_t immediate = 0;
   1098                 if (encode12BitImmediate(offset, &immediate)) {
   1099                     o4(0xE2800000 | immediate); // add    r0, r0, #offset
   1100                 } else {
   1101                     error("structure offset out of range: %d", offset);
   1102                 }
   1103             }
   1104             setR0Type(pType, ET_LVALUE);
   1105         }
   1106 
   1107         virtual int gjmp(int t) {
   1108             int pc = getPC();
   1109             o4(0xEA000000 | encodeAddress(t)); // b .L33
   1110             return pc;
   1111         }
   1112 
   1113         /* l = 0: je, l == 1: jne */
   1114         virtual int gtst(bool l, int t) {
   1115             Type* pR0Type = getR0Type();
   1116             TypeTag tagR0 = pR0Type->tag;
   1117             switch(tagR0) {
   1118                 case TY_FLOAT:
   1119 #ifdef ARM_USE_VFP
   1120                     o4(0xEEF57A40); // fcmpzs    s15
   1121                     o4(0xEEF1FA10); // fmstat
   1122 #else
   1123                     callRuntime((void*) runtime_is_non_zero_f);
   1124                     o4(0xE3500000); // cmp r0,#0
   1125 #endif
   1126                     break;
   1127                 case TY_DOUBLE:
   1128 #ifdef ARM_USE_VFP
   1129                     o4(0xEEB57B40); // fcmpzd    d7
   1130                     o4(0xEEF1FA10); // fmstat
   1131 #else
   1132                     callRuntime((void*) runtime_is_non_zero_d);
   1133                     o4(0xE3500000); // cmp r0,#0
   1134 #endif
   1135                     break;
   1136                 default:
   1137                     o4(0xE3500000); // cmp r0,#0
   1138                     break;
   1139             }
   1140             int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
   1141             int pc = getPC();
   1142             o4(branch | encodeAddress(t));
   1143             return pc;
   1144         }
   1145 
   1146         virtual void gcmp(int op) {
   1147             Type* pR0Type = getR0Type();
   1148             Type* pTOSType = getTOSType();
   1149             TypeTag tagR0 = collapseType(pR0Type->tag);
   1150             TypeTag tagTOS = collapseType(pTOSType->tag);
   1151             if (tagR0 == TY_INT && tagTOS == TY_INT) {
   1152                 setupIntPtrArgs();
   1153                 o4(0xE1510000); // cmp r1, r1
   1154                 switch(op) {
   1155                 case OP_EQUALS:
   1156                     o4(0x03A00001); // moveq r0,#1
   1157                     o4(0x13A00000); // movne r0,#0
   1158                     break;
   1159                 case OP_NOT_EQUALS:
   1160                     o4(0x03A00000); // moveq r0,#0
   1161                     o4(0x13A00001); // movne r0,#1
   1162                     break;
   1163                 case OP_LESS_EQUAL:
   1164                     o4(0xD3A00001); // movle r0,#1
   1165                     o4(0xC3A00000); // movgt r0,#0
   1166                     break;
   1167                 case OP_GREATER:
   1168                     o4(0xD3A00000); // movle r0,#0
   1169                     o4(0xC3A00001); // movgt r0,#1
   1170                     break;
   1171                 case OP_GREATER_EQUAL:
   1172                     o4(0xA3A00001); // movge r0,#1
   1173                     o4(0xB3A00000); // movlt r0,#0
   1174                     break;
   1175                 case OP_LESS:
   1176                     o4(0xA3A00000); // movge r0,#0
   1177                     o4(0xB3A00001); // movlt r0,#1
   1178                     break;
   1179                 default:
   1180                     error("Unknown comparison op %d", op);
   1181                     break;
   1182                 }
   1183             } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
   1184                 setupDoubleArgs();
   1185 #ifdef ARM_USE_VFP
   1186                 o4(0xEEB46BC7); //         fcmped    d6, d7
   1187                    o4(0xEEF1FA10); // fmstat
   1188                 switch(op) {
   1189                 case OP_EQUALS:
   1190                     o4(0x03A00001); // moveq r0,#1
   1191                     o4(0x13A00000); // movne r0,#0
   1192                     break;
   1193                 case OP_NOT_EQUALS:
   1194                     o4(0x03A00000); // moveq r0,#0
   1195                     o4(0x13A00001); // movne r0,#1
   1196                     break;
   1197                 case OP_LESS_EQUAL:
   1198                     o4(0xD3A00001); // movle r0,#1
   1199                     o4(0xC3A00000); // movgt r0,#0
   1200                     break;
   1201                 case OP_GREATER:
   1202                     o4(0xD3A00000); // movle r0,#0
   1203                     o4(0xC3A00001); // movgt r0,#1
   1204                     break;
   1205                 case OP_GREATER_EQUAL:
   1206                     o4(0xA3A00001); // movge r0,#1
   1207                     o4(0xB3A00000); // movlt r0,#0
   1208                     break;
   1209                 case OP_LESS:
   1210                     o4(0xA3A00000); // movge r0,#0
   1211                     o4(0xB3A00001); // movlt r0,#1
   1212                     break;
   1213                 default:
   1214                     error("Unknown comparison op %d", op);
   1215                     break;
   1216                 }
   1217 #else
   1218                 switch(op) {
   1219                     case OP_EQUALS:
   1220                         callRuntime((void*) runtime_cmp_eq_dd);
   1221                         break;
   1222                     case OP_NOT_EQUALS:
   1223                         callRuntime((void*) runtime_cmp_ne_dd);
   1224                         break;
   1225                     case OP_LESS_EQUAL:
   1226                         callRuntime((void*) runtime_cmp_le_dd);
   1227                         break;
   1228                     case OP_GREATER:
   1229                         callRuntime((void*) runtime_cmp_gt_dd);
   1230                         break;
   1231                     case OP_GREATER_EQUAL:
   1232                         callRuntime((void*) runtime_cmp_ge_dd);
   1233                         break;
   1234                     case OP_LESS:
   1235                         callRuntime((void*) runtime_cmp_lt_dd);
   1236                         break;
   1237                     default:
   1238                         error("Unknown comparison op %d", op);
   1239                         break;
   1240                 }
   1241 #endif
   1242             } else {
   1243                 setupFloatArgs();
   1244 #ifdef ARM_USE_VFP
   1245                 o4(0xEEB47AE7); // fcmpes s14, s15
   1246                    o4(0xEEF1FA10); // fmstat
   1247                 switch(op) {
   1248                 case OP_EQUALS:
   1249                     o4(0x03A00001); // moveq r0,#1
   1250                     o4(0x13A00000); // movne r0,#0
   1251                     break;
   1252                 case OP_NOT_EQUALS:
   1253                     o4(0x03A00000); // moveq r0,#0
   1254                     o4(0x13A00001); // movne r0,#1
   1255                     break;
   1256                 case OP_LESS_EQUAL:
   1257                     o4(0xD3A00001); // movle r0,#1
   1258                     o4(0xC3A00000); // movgt r0,#0
   1259                     break;
   1260                 case OP_GREATER:
   1261                     o4(0xD3A00000); // movle r0,#0
   1262                     o4(0xC3A00001); // movgt r0,#1
   1263                     break;
   1264                 case OP_GREATER_EQUAL:
   1265                     o4(0xA3A00001); // movge r0,#1
   1266                     o4(0xB3A00000); // movlt r0,#0
   1267                     break;
   1268                 case OP_LESS:
   1269                     o4(0xA3A00000); // movge r0,#0
   1270                     o4(0xB3A00001); // movlt r0,#1
   1271                     break;
   1272                 default:
   1273                     error("Unknown comparison op %d", op);
   1274                     break;
   1275                 }
   1276 #else
   1277                 switch(op) {
   1278                     case OP_EQUALS:
   1279                         callRuntime((void*) runtime_cmp_eq_ff);
   1280                         break;
   1281                     case OP_NOT_EQUALS:
   1282                         callRuntime((void*) runtime_cmp_ne_ff);
   1283                         break;
   1284                     case OP_LESS_EQUAL:
   1285                         callRuntime((void*) runtime_cmp_le_ff);
   1286                         break;
   1287                     case OP_GREATER:
   1288                         callRuntime((void*) runtime_cmp_gt_ff);
   1289                         break;
   1290                     case OP_GREATER_EQUAL:
   1291                         callRuntime((void*) runtime_cmp_ge_ff);
   1292                         break;
   1293                     case OP_LESS:
   1294                         callRuntime((void*) runtime_cmp_lt_ff);
   1295                         break;
   1296                     default:
   1297                         error("Unknown comparison op %d", op);
   1298                         break;
   1299                 }
   1300 #endif
   1301             }
   1302             setR0Type(mkpInt);
   1303         }
   1304 
   1305         virtual void genOp(int op) {
   1306             Type* pR0Type = getR0Type();
   1307             Type* pTOSType = getTOSType();
   1308             TypeTag tagR0 = pR0Type->tag;
   1309             TypeTag tagTOS = pTOSType->tag;
   1310             bool isFloatR0 = isFloatTag(tagR0);
   1311             bool isFloatTOS = isFloatTag(tagTOS);
   1312             if (!isFloatR0 && !isFloatTOS) {
   1313                 setupIntPtrArgs();
   1314                 bool isPtrR0 = isPointerTag(tagR0);
   1315                 bool isPtrTOS = isPointerTag(tagTOS);
   1316                 if (isPtrR0 || isPtrTOS) {
   1317                     if (isPtrR0 && isPtrTOS) {
   1318                         if (op != OP_MINUS) {
   1319                             error("Unsupported pointer-pointer operation %d.", op);
   1320                         }
   1321                         if (! typeEqual(pR0Type, pTOSType)) {
   1322                             error("Incompatible pointer types for subtraction.");
   1323                         }
   1324                         o4(0xE0410000); // sub     r0,r1,r0
   1325                         setR0Type(mkpInt);
   1326                         int size = sizeOf(pR0Type->pHead);
   1327                         if (size != 1) {
   1328                             pushR0();
   1329                             li(size);
   1330                             // TODO: Optimize for power-of-two.
   1331                             genOp(OP_DIV);
   1332                         }
   1333                     } else {
   1334                         if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
   1335                             error("Unsupported pointer-scalar operation %d", op);
   1336                         }
   1337                         Type* pPtrType = getPointerArithmeticResultType(
   1338                                 pR0Type, pTOSType);
   1339                         int size = sizeOf(pPtrType->pHead);
   1340                         if (size != 1) {
   1341                             // TODO: Optimize for power-of-two.
   1342                             liReg(size, 2);
   1343                             if (isPtrR0) {
   1344                                 o4(0x0E0010192); // mul     r1,r2,r1
   1345                             } else {
   1346                                 o4(0x0E0000092); // mul     r0,r2,r0
   1347                             }
   1348                         }
   1349                         switch(op) {
   1350                             case OP_PLUS:
   1351                             o4(0xE0810000); // add     r0,r1,r0
   1352                             break;
   1353                             case OP_MINUS:
   1354                             o4(0xE0410000); // sub     r0,r1,r0
   1355                             break;
   1356                         }
   1357                         setR0Type(pPtrType);
   1358                     }
   1359                 } else {
   1360                     switch(op) {
   1361                         case OP_MUL:
   1362                         o4(0x0E0000091); // mul     r0,r1,r0
   1363                         break;
   1364                         case OP_DIV:
   1365                         callRuntime((void*) runtime_DIV);
   1366                         break;
   1367                         case OP_MOD:
   1368                         callRuntime((void*) runtime_MOD);
   1369                         break;
   1370                         case OP_PLUS:
   1371                         o4(0xE0810000); // add     r0,r1,r0
   1372                         break;
   1373                         case OP_MINUS:
   1374                         o4(0xE0410000); // sub     r0,r1,r0
   1375                         break;
   1376                         case OP_SHIFT_LEFT:
   1377                         o4(0xE1A00011); // lsl     r0,r1,r0
   1378                         break;
   1379                         case OP_SHIFT_RIGHT:
   1380                         o4(0xE1A00051); // asr     r0,r1,r0
   1381                         break;
   1382                         case OP_BIT_AND:
   1383                         o4(0xE0010000); // and     r0,r1,r0
   1384                         break;
   1385                         case OP_BIT_XOR:
   1386                         o4(0xE0210000); // eor     r0,r1,r0
   1387                         break;
   1388                         case OP_BIT_OR:
   1389                         o4(0xE1810000); // orr     r0,r1,r0
   1390                         break;
   1391                         case OP_BIT_NOT:
   1392                         o4(0xE1E00000); // mvn     r0, r0
   1393                         break;
   1394                         default:
   1395                         error("Unimplemented op %d\n", op);
   1396                         break;
   1397                     }
   1398                 }
   1399             } else {
   1400                 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
   1401                 if (pResultType->tag == TY_DOUBLE) {
   1402                     setupDoubleArgs();
   1403 
   1404                     switch(op) {
   1405                     case OP_MUL:
   1406 #ifdef ARM_USE_VFP
   1407                         o4(0xEE267B07); // fmuld d7, d6, d7
   1408 #else
   1409                         callRuntime((void*) runtime_op_mul_dd);
   1410 #endif
   1411                         break;
   1412                     case OP_DIV:
   1413 #ifdef ARM_USE_VFP
   1414                         o4(0xEE867B07); // fdivd d7, d6, d7
   1415 #else
   1416                         callRuntime((void*) runtime_op_div_dd);
   1417 #endif
   1418                         break;
   1419                     case OP_PLUS:
   1420 #ifdef ARM_USE_VFP
   1421                         o4(0xEE367B07); // faddd d7, d6, d7
   1422 #else
   1423                         callRuntime((void*) runtime_op_add_dd);
   1424 #endif
   1425                         break;
   1426                     case OP_MINUS:
   1427 #ifdef ARM_USE_VFP
   1428                         o4(0xEE367B47); // fsubd d7, d6, d7
   1429 #else
   1430                         callRuntime((void*) runtime_op_sub_dd);
   1431 #endif
   1432                         break;
   1433                     default:
   1434                         error("Unsupported binary floating operation %d\n", op);
   1435                         break;
   1436                     }
   1437                 } else {
   1438                     setupFloatArgs();
   1439                     switch(op) {
   1440                     case OP_MUL:
   1441 #ifdef ARM_USE_VFP
   1442                         o4(0xEE677A27); // fmuls s15, s14, s15
   1443 #else
   1444                         callRuntime((void*) runtime_op_mul_ff);
   1445 #endif
   1446                         break;
   1447                     case OP_DIV:
   1448 #ifdef ARM_USE_VFP
   1449                         o4(0xEEC77A27); // fdivs s15, s14, s15
   1450 #else
   1451                         callRuntime((void*) runtime_op_div_ff);
   1452 #endif
   1453                         break;
   1454                     case OP_PLUS:
   1455 #ifdef ARM_USE_VFP
   1456                         o4(0xEE777A27); // fadds s15, s14, s15
   1457 #else
   1458                         callRuntime((void*) runtime_op_add_ff);
   1459 #endif
   1460                         break;
   1461                     case OP_MINUS:
   1462 #ifdef ARM_USE_VFP
   1463                         o4(0xEE777A67); // fsubs s15, s14, s15
   1464 #else
   1465                         callRuntime((void*) runtime_op_sub_ff);
   1466 #endif
   1467                         break;
   1468                     default:
   1469                         error("Unsupported binary floating operation %d\n", op);
   1470                         break;
   1471                     }
   1472                 }
   1473                 setR0Type(pResultType);
   1474             }
   1475         }
   1476 
   1477         virtual void gUnaryCmp(int op) {
   1478             if (op != OP_LOGICAL_NOT) {
   1479                 error("Unknown unary cmp %d", op);
   1480             } else {
   1481                 Type* pR0Type = getR0Type();
   1482                 TypeTag tag = collapseType(pR0Type->tag);
   1483                 switch(tag) {
   1484                     case TY_INT:
   1485                         o4(0xE3A01000); // mov    r1, #0
   1486                         o4(0xE1510000); // cmp r1, r0
   1487                         o4(0x03A00001); // moveq r0,#1
   1488                         o4(0x13A00000); // movne r0,#0
   1489                         break;
   1490                     case TY_FLOAT:
   1491 #ifdef ARM_USE_VFP
   1492                         o4(0xEEF57A40); // fcmpzs s15
   1493                         o4(0xEEF1FA10); // fmstat
   1494                         o4(0x03A00001); // moveq r0,#1
   1495                         o4(0x13A00000); // movne r0,#0
   1496 #else
   1497                         callRuntime((void*) runtime_is_zero_f);
   1498 #endif
   1499                         break;
   1500                     case TY_DOUBLE:
   1501 #ifdef ARM_USE_VFP
   1502                         o4(0xEEB57B40); // fcmpzd d7
   1503                         o4(0xEEF1FA10); // fmstat
   1504                         o4(0x03A00001); // moveq r0,#1
   1505                         o4(0x13A00000); // movne r0,#0
   1506 #else
   1507                         callRuntime((void*) runtime_is_zero_d);
   1508 #endif
   1509                         break;
   1510                     default:
   1511                         error("gUnaryCmp unsupported type");
   1512                         break;
   1513                 }
   1514             }
   1515             setR0Type(mkpInt);
   1516         }
   1517 
   1518         virtual void genUnaryOp(int op) {
   1519             Type* pR0Type = getR0Type();
   1520             TypeTag tag = collapseType(pR0Type->tag);
   1521             switch(tag) {
   1522                 case TY_INT:
   1523                     switch(op) {
   1524                     case OP_MINUS:
   1525                         o4(0xE3A01000);  // mov    r1, #0
   1526                         o4(0xE0410000);  // sub     r0,r1,r0
   1527                         break;
   1528                     case OP_BIT_NOT:
   1529                         o4(0xE1E00000);  // mvn     r0, r0
   1530                         break;
   1531                     default:
   1532                         error("Unknown unary op %d\n", op);
   1533                         break;
   1534                     }
   1535                     break;
   1536                 case TY_FLOAT:
   1537                 case TY_DOUBLE:
   1538                     switch (op) {
   1539                         case OP_MINUS:
   1540                             if (tag == TY_FLOAT) {
   1541 #ifdef ARM_USE_VFP
   1542                                 o4(0xEEF17A67); // fnegs    s15, s15
   1543 #else
   1544                                 callRuntime((void*) runtime_op_neg_f);
   1545 #endif
   1546                             } else {
   1547 #ifdef ARM_USE_VFP
   1548                                 o4(0xEEB17B47); // fnegd    d7, d7
   1549 #else
   1550                                 callRuntime((void*) runtime_op_neg_d);
   1551 #endif
   1552                             }
   1553                             break;
   1554                         case OP_BIT_NOT:
   1555                             error("Can't apply '~' operator to a float or double.");
   1556                             break;
   1557                         default:
   1558                             error("Unknown unary op %d\n", op);
   1559                             break;
   1560                         }
   1561                     break;
   1562                 default:
   1563                     error("genUnaryOp unsupported type");
   1564                     break;
   1565             }
   1566         }
   1567 
   1568         virtual void pushR0() {
   1569             Type* pR0Type = getR0Type();
   1570             TypeTag r0ct = collapseType(pR0Type->tag);
   1571 
   1572 #ifdef ARM_USE_VFP
   1573             switch (r0ct ) {
   1574             case TY_FLOAT:
   1575                 o4(0xED6D7A01); // fstmfds   sp!,{s15}
   1576                 mStackUse += 4;
   1577                 break;
   1578             case TY_DOUBLE:
   1579                 o4(0xED2D7B02); // fstmfdd   sp!,{d7}
   1580                 mStackUse += 8;
   1581                 break;
   1582             default:
   1583                 o4(0xE92D0001);  // stmfd   sp!,{r0}
   1584                 mStackUse += 4;
   1585             }
   1586 #else
   1587 
   1588             if (r0ct != TY_DOUBLE) {
   1589                     o4(0xE92D0001);  // stmfd   sp!,{r0}
   1590                     mStackUse += 4;
   1591             } else {
   1592                     o4(0xE92D0003);  // stmfd   sp!,{r0,r1}
   1593                     mStackUse += 8;
   1594             }
   1595 #endif
   1596             pushType();
   1597             LOG_STACK("pushR0: %d\n", mStackUse);
   1598         }
   1599 
   1600         virtual void over() {
   1601             // We know it's only used for int-ptr ops (++/--)
   1602 
   1603             Type* pR0Type = getR0Type();
   1604             TypeTag r0ct = collapseType(pR0Type->tag);
   1605 
   1606             Type* pTOSType = getTOSType();
   1607             TypeTag tosct = collapseType(pTOSType->tag);
   1608 
   1609             assert (r0ct == TY_INT  && tosct == TY_INT);
   1610 
   1611             o4(0xE8BD0002);  // ldmfd   sp!,{r1}
   1612             o4(0xE92D0001);  // stmfd   sp!,{r0}
   1613             o4(0xE92D0002);  // stmfd   sp!,{r1}
   1614             overType();
   1615             mStackUse += 4;
   1616         }
   1617 
   1618         virtual void popR0() {
   1619             Type* pTOSType = getTOSType();
   1620             TypeTag tosct = collapseType(pTOSType->tag);
   1621 #ifdef ARM_USE_VFP
   1622             if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
   1623                 error("Unsupported popR0 float/double");
   1624             }
   1625 #endif
   1626             switch (tosct){
   1627                 case TY_INT:
   1628                 case TY_FLOAT:
   1629                     o4(0xE8BD0001);  // ldmfd   sp!,{r0}
   1630                     mStackUse -= 4;
   1631                     break;
   1632                 case TY_DOUBLE:
   1633                     o4(0xE8BD0003);  // ldmfd   sp!,{r0, r1}  // Restore R0
   1634                         mStackUse -= 8;
   1635                     break;
   1636                 default:
   1637                     error("Can't pop this type.");
   1638                     break;
   1639             }
   1640             popType();
   1641             LOG_STACK("popR0: %d\n", mStackUse);
   1642         }
   1643 
   1644         virtual void storeR0ToTOS() {
   1645             Type* pPointerType = getTOSType();
   1646             assert(pPointerType->tag == TY_POINTER);
   1647             Type* pDestType = pPointerType->pHead;
   1648             convertR0(pDestType);
   1649             o4(0xE8BD0004);  // ldmfd   sp!,{r2}
   1650             popType();
   1651             mStackUse -= 4;
   1652             switch (pDestType->tag) {
   1653                 case TY_POINTER:
   1654                 case TY_INT:
   1655                     o4(0xE5820000); // str r0, [r2]
   1656                     break;
   1657                 case TY_FLOAT:
   1658 #ifdef ARM_USE_VFP
   1659                     o4(0xEDC27A00); // fsts    s15, [r2, #0]
   1660 #else
   1661                     o4(0xE5820000); // str r0, [r2]
   1662 #endif
   1663                     break;
   1664                 case TY_SHORT:
   1665                     o4(0xE1C200B0); // strh r0, [r2]
   1666                     break;
   1667                 case TY_CHAR:
   1668                     o4(0xE5C20000); // strb r0, [r2]
   1669                     break;
   1670                 case TY_DOUBLE:
   1671 #ifdef ARM_USE_VFP
   1672                     o4(0xED827B00); // fstd    d7, [r2, #0]
   1673 #else
   1674                     o4(0xE1C200F0); // strd r0, [r2]
   1675 #endif
   1676                     break;
   1677                 case TY_STRUCT:
   1678                 {
   1679                     int size = sizeOf(pDestType);
   1680                     if (size > 0) {
   1681                         liReg(size, 1);
   1682                         callRuntime((void*) runtime_structCopy);
   1683                     }
   1684                 }
   1685                     break;
   1686                 default:
   1687                     error("storeR0ToTOS: unimplemented type %d",
   1688                             pDestType->tag);
   1689                     break;
   1690             }
   1691             setR0Type(pDestType);
   1692         }
   1693 
   1694         virtual void loadR0FromR0() {
   1695             Type* pPointerType = getR0Type();
   1696             assert(pPointerType->tag == TY_POINTER);
   1697             Type* pNewType = pPointerType->pHead;
   1698             TypeTag tag = pNewType->tag;
   1699             switch (tag) {
   1700                 case TY_POINTER:
   1701                 case TY_INT:
   1702                     o4(0xE5900000); // ldr r0, [r0]
   1703                     break;
   1704                 case TY_FLOAT:
   1705 #ifdef ARM_USE_VFP
   1706                     o4(0xEDD07A00); // flds    s15, [r0, #0]
   1707 #else
   1708                     o4(0xE5900000); // ldr r0, [r0]
   1709 #endif
   1710                     break;
   1711                 case TY_SHORT:
   1712                     o4(0xE1D000F0); // ldrsh r0, [r0]
   1713                     break;
   1714                 case TY_CHAR:
   1715                     o4(0xE5D00000); // ldrb r0, [r0]
   1716                     break;
   1717                 case TY_DOUBLE:
   1718 #ifdef ARM_USE_VFP
   1719                     o4(0xED907B00); // fldd    d7, [r0, #0]
   1720 #else
   1721                     o4(0xE1C000D0); // ldrd   r0, [r0]
   1722 #endif
   1723                     break;
   1724                 case TY_ARRAY:
   1725                     pNewType = pNewType->pTail;
   1726                     break;
   1727                 case TY_STRUCT:
   1728                     break;
   1729                 default:
   1730                     error("loadR0FromR0: unimplemented type %d", tag);
   1731                     break;
   1732             }
   1733             setR0Type(pNewType);
   1734         }
   1735 
   1736         virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
   1737             if (ea > -LOCAL && ea < LOCAL) {
   1738                 // Local, fp relative
   1739 
   1740                 size_t immediate = 0;
   1741                 bool inRange = false;
   1742                 if (ea < 0) {
   1743                     inRange = encode12BitImmediate(-ea, &immediate);
   1744                     o4(0xE24B0000 | immediate); // sub    r0, fp, #ea
   1745                 } else {
   1746                     inRange = encode12BitImmediate(ea, &immediate);
   1747                     o4(0xE28B0000 | immediate); // add    r0, fp, #ea
   1748                 }
   1749                 if (! inRange) {
   1750                     error("Offset out of range: %08x", ea);
   1751                 }
   1752             } else {
   1753                 // Global, absolute.
   1754                 o4(0xE59F0000); //        ldr    r0, .L1
   1755                 o4(0xEA000000); //        b .L99
   1756                 o4(ea);         // .L1:   .word 0
   1757                                 // .L99:
   1758             }
   1759             setR0Type(pPointerType, et);
   1760         }
   1761 
   1762         virtual int leaForward(int ea, Type* pPointerType) {
   1763             setR0Type(pPointerType);
   1764             int result = ea;
   1765             int pc = getPC();
   1766             int offset = 0;
   1767             if (ea) {
   1768                 offset = (pc - ea - 8) >> 2;
   1769                 if ((offset & 0xffff) != offset) {
   1770                     error("function forward reference out of bounds");
   1771                 }
   1772             } else {
   1773                 offset = 0;
   1774             }
   1775             o4(0xE59F0000 | offset); //        ldr    r0, .L1
   1776 
   1777             if (ea == 0) {
   1778                 o4(0xEA000000); //        b .L99
   1779                 result = getPC();
   1780                 o4(ea);         // .L1:   .word 0
   1781                             // .L99:
   1782             }
   1783             return result;
   1784         }
   1785 
   1786         virtual void convertR0Imp(Type* pType, bool isCast){
   1787             Type* pR0Type = getR0Type();
   1788             if (isPointerType(pType) && isPointerType(pR0Type)) {
   1789                 Type* pA = pR0Type;
   1790                 Type* pB = pType;
   1791                 // Array decays to pointer
   1792                 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
   1793                     pA = pA->pTail;
   1794                 }
   1795                 if (! (typeEqual(pA, pB)
   1796                         || pB->pHead->tag == TY_VOID
   1797                         || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
   1798                     )) {
   1799                     error("Incompatible pointer or array types");
   1800                 }
   1801             } else if (bitsSame(pType, pR0Type)) {
   1802                 // do nothing special
   1803             } else {
   1804                 TypeTag r0Tag = collapseType(pR0Type->tag);
   1805                 TypeTag destTag = collapseType(pType->tag);
   1806                 if (r0Tag == TY_INT) {
   1807                     if (destTag == TY_FLOAT) {
   1808 #ifdef ARM_USE_VFP
   1809                         o4(0xEE070A90); // fmsr    s15, r0
   1810                         o4(0xEEF87AE7); // fsitos s15, s15
   1811 
   1812 #else
   1813                         callRuntime((void*) runtime_int_to_float);
   1814 #endif
   1815                     } else {
   1816                         assert(destTag == TY_DOUBLE);
   1817 #ifdef ARM_USE_VFP
   1818                         o4(0xEE070A90); // fmsr s15, r0
   1819                         o4(0xEEB87BE7); // fsitod d7, s15
   1820 
   1821 #else
   1822                         callRuntime((void*) runtime_int_to_double);
   1823 #endif
   1824                     }
   1825                 } else if (r0Tag == TY_FLOAT) {
   1826                     if (destTag == TY_INT) {
   1827 #ifdef ARM_USE_VFP
   1828                         o4(0xEEFD7AE7); // ftosizs s15, s15
   1829                         o4(0xEE170A90); // fmrs r0, s15
   1830 #else
   1831                         callRuntime((void*) runtime_float_to_int);
   1832 #endif
   1833                     } else {
   1834                         assert(destTag == TY_DOUBLE);
   1835 #ifdef ARM_USE_VFP
   1836                         o4(0xEEB77AE7); // fcvtds    d7, s15
   1837 #else
   1838                         callRuntime((void*) runtime_float_to_double);
   1839 #endif
   1840                     }
   1841                 } else {
   1842                     if (r0Tag == TY_DOUBLE) {
   1843                         if (destTag == TY_INT) {
   1844 #ifdef ARM_USE_VFP
   1845                             o4(0xEEFD7BC7); // ftosizd s15, d7
   1846                             o4(0xEE170A90); // fmrs r0, s15
   1847 #else
   1848                             callRuntime((void*) runtime_double_to_int);
   1849 #endif
   1850                         } else {
   1851                             if(destTag == TY_FLOAT) {
   1852 #ifdef ARM_USE_VFP
   1853                                 o4(0xEEF77BC7); // fcvtsd s15, d7
   1854 #else
   1855                                 callRuntime((void*) runtime_double_to_float);
   1856 #endif
   1857                             } else {
   1858                                 incompatibleTypes(pR0Type, pType);
   1859                             }
   1860                         }
   1861                     } else {
   1862                         incompatibleTypes(pR0Type, pType);
   1863                     }
   1864                 }
   1865             }
   1866             setR0Type(pType);
   1867         }
   1868 
   1869         virtual int beginFunctionCallArguments() {
   1870             int pc = getPC();
   1871             o4(0xE24DDF00); // Placeholder sub  sp, sp, #0
   1872             return pc;
   1873         }
   1874 
   1875         virtual size_t storeR0ToArg(int l, Type* pArgType) {
   1876             convertR0(pArgType);
   1877             Type* pR0Type = getR0Type();
   1878             TypeTag r0ct = collapseType(pR0Type->tag);
   1879 #ifdef ARM_USE_VFP
   1880             switch(r0ct) {
   1881                 case TY_INT:
   1882                     if (l < 0 || l > 4096-4) {
   1883                         error("l out of range for stack offset: 0x%08x", l);
   1884                     }
   1885                     o4(0xE58D0000 | l); // str r0, [sp, #l]
   1886                     return 4;
   1887                 case TY_FLOAT:
   1888                     if (l < 0 || l > 1020 || (l & 3)) {
   1889                         error("l out of range for stack offset: 0x%08x", l);
   1890                     }
   1891                     o4(0xEDCD7A00 | (l >> 2)); // fsts    s15, [sp, #l]
   1892                     return 4;
   1893                 case TY_DOUBLE: {
   1894                     // Align to 8 byte boundary
   1895                     int l2 = (l + 7) & ~7;
   1896                     if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
   1897                         error("l out of range for stack offset: 0x%08x", l);
   1898                     }
   1899                     o4(0xED8D7B00 | (l2 >> 2)); // fstd    d7, [sp, #l2]
   1900                     return (l2 - l) + 8;
   1901                 }
   1902                 default:
   1903                     assert(false);
   1904                     return 0;
   1905             }
   1906 #else
   1907             switch(r0ct) {
   1908                 case TY_INT:
   1909                 case TY_FLOAT:
   1910                     if (l < 0 || l > 4096-4) {
   1911                         error("l out of range for stack offset: 0x%08x", l);
   1912                     }
   1913                     o4(0xE58D0000 + l); // str r0, [sp, #l]
   1914                     return 4;
   1915                 case TY_DOUBLE: {
   1916                     // Align to 8 byte boundary
   1917                     int l2 = (l + 7) & ~7;
   1918                     if (l2 < 0 || l2 > 4096-8) {
   1919                         error("l out of range for stack offset: 0x%08x", l);
   1920                     }
   1921                     o4(0xE58D0000 + l2); // str r0, [sp, #l]
   1922                     o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
   1923                     return (l2 - l) + 8;
   1924                 }
   1925                 default:
   1926                     assert(false);
   1927                     return 0;
   1928             }
   1929 #endif
   1930         }
   1931 
   1932         virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
   1933             int argumentStackUse = l;
   1934             // Have to calculate register arg count from actual stack size,
   1935             // in order to properly handle ... functions.
   1936             int regArgCount = l >> 2;
   1937             if (regArgCount > 4) {
   1938                 regArgCount = 4;
   1939             }
   1940             if (regArgCount > 0) {
   1941                 argumentStackUse -= regArgCount * 4;
   1942                 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd   sp!,{}
   1943             }
   1944             mStackUse += argumentStackUse;
   1945 
   1946             // Align stack.
   1947             int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
   1948                     * STACK_ALIGNMENT);
   1949             mStackAlignmentAdjustment = 0;
   1950             if (missalignment > 0) {
   1951                 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
   1952             }
   1953             l += mStackAlignmentAdjustment;
   1954 
   1955             if (l < 0 || l > 0x3FC) {
   1956                 error("L out of range for stack adjustment: 0x%08x", l);
   1957             }
   1958             flush();
   1959             * (int*) a = 0xE24DDF00 | (l >> 2); // sub    sp, sp, #0 << 2
   1960             mStackUse += mStackAlignmentAdjustment;
   1961             LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
   1962                       mStackUse, mStackAlignmentAdjustment);
   1963         }
   1964 
   1965         virtual int callForward(int symbol, Type* pFunc) {
   1966             setR0Type(pFunc->pHead);
   1967             // Forward calls are always short (local)
   1968             int pc = getPC();
   1969             o4(0xEB000000 | encodeAddress(symbol));
   1970             return pc;
   1971         }
   1972 
   1973         virtual void callIndirect(int l, Type* pFunc) {
   1974             assert(pFunc->tag == TY_FUNC);
   1975             popType(); // Get rid of indirect fn pointer type
   1976             int argCount = l >> 2;
   1977             int poppedArgs = argCount > 4 ? 4 : argCount;
   1978             int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
   1979             if (adjustedL < 0 || adjustedL > 4096-4) {
   1980                 error("l out of range for stack offset: 0x%08x", l);
   1981             }
   1982             o4(0xE59DC000 | (0xfff & adjustedL)); // ldr    r12, [sp,#adjustedL]
   1983             o4(0xE12FFF3C); // blx r12
   1984             Type* pReturnType = pFunc->pHead;
   1985             setR0Type(pReturnType);
   1986 #ifdef ARM_USE_VFP
   1987             switch(pReturnType->tag) {
   1988             case TY_FLOAT:
   1989                 o4(0xEE070A90); // fmsr s15, r0
   1990                 break;
   1991             case TY_DOUBLE:
   1992                 o4(0xEC410B17); // fmdrr d7, r0, r1
   1993                 break;
   1994             default:
   1995                 break;
   1996             }
   1997 #endif
   1998         }
   1999 
   2000         virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
   2001             int argCount = l >> 2;
   2002             // Have to calculate register arg count from actual stack size,
   2003             // in order to properly handle ... functions.
   2004             int regArgCount = l >> 2;
   2005             if (regArgCount > 4) {
   2006                 regArgCount = 4;
   2007             }
   2008             int stackArgs = argCount - regArgCount;
   2009             int stackUse =  stackArgs + (isIndirect ? 1 : 0)
   2010                 + (mStackAlignmentAdjustment >> 2);
   2011             if (stackUse) {
   2012                 if (stackUse < 0 || stackUse > 255) {
   2013                     error("L out of range for stack adjustment: 0x%08x", l);
   2014                 }
   2015                 o4(0xE28DDF00 | stackUse); // add    sp, sp, #stackUse << 2
   2016                 mStackUse -= stackUse * 4;
   2017                 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
   2018             }
   2019         }
   2020 
   2021         virtual int jumpOffset() {
   2022             return 8;
   2023         }
   2024 
   2025         /* output a symbol and patch all calls to it */
   2026         virtual void gsym(int t) {
   2027             int n;
   2028             int base = getBase();
   2029             int pc = getPC();
   2030             while (t) {
   2031                 int data = * (int*) t;
   2032                 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
   2033                 if (decodedOffset == 0) {
   2034                     n = 0;
   2035                 } else {
   2036                     n = base + decodedOffset; /* next value */
   2037                 }
   2038                 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
   2039                     | encodeRelAddress(pc - t - 8);
   2040                 t = n;
   2041             }
   2042         }
   2043 
   2044         /* output a symbol and patch all calls to it */
   2045         virtual void resolveForward(int t) {
   2046             if (t) {
   2047                 int pc = getPC();
   2048                 *(int *) t = pc;
   2049             }
   2050         }
   2051 
   2052         virtual int finishCompile() {
   2053 #if defined(__arm__)
   2054             const long base = long(getBase());
   2055             const long curr = long(getPC());
   2056             int err = cacheflush(base, curr, 0);
   2057             return err;
   2058 #else
   2059             return 0;
   2060 #endif
   2061         }
   2062 
   2063         /**
   2064          * alignment (in bytes) for this type of data
   2065          */
   2066         virtual size_t alignmentOf(Type* pType){
   2067             switch(pType->tag) {
   2068                 case TY_CHAR:
   2069                     return 1;
   2070                 case TY_SHORT:
   2071                     return 2;
   2072                 case TY_DOUBLE:
   2073                     return 8;
   2074                 case TY_ARRAY:
   2075                     return alignmentOf(pType->pHead);
   2076                 case TY_STRUCT:
   2077                     return pType->pHead->alignment & 0x7fffffff;
   2078                 case TY_FUNC:
   2079                     error("alignment of func not supported");
   2080                     return 1;
   2081                 default:
   2082                     return 4;
   2083             }
   2084         }
   2085 
   2086         /**
   2087          * Array element alignment (in bytes) for this type of data.
   2088          */
   2089         virtual size_t sizeOf(Type* pType){
   2090             switch(pType->tag) {
   2091                 case TY_INT:
   2092                     return 4;
   2093                 case TY_SHORT:
   2094                     return 2;
   2095                 case TY_CHAR:
   2096                     return 1;
   2097                 case TY_FLOAT:
   2098                     return 4;
   2099                 case TY_DOUBLE:
   2100                     return 8;
   2101                 case TY_POINTER:
   2102                     return 4;
   2103                 case TY_ARRAY:
   2104                     return pType->length * sizeOf(pType->pHead);
   2105                 case TY_STRUCT:
   2106                     return pType->pHead->length;
   2107                 default:
   2108                     error("Unsupported type %d", pType->tag);
   2109                     return 0;
   2110             }
   2111         }
   2112 
   2113     private:
   2114 
   2115         static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
   2116 
   2117         /** Encode a relative address that might also be
   2118          * a label.
   2119          */
   2120         int encodeAddress(int value) {
   2121             int base = getBase();
   2122             if (value >= base && value <= getPC() ) {
   2123                 // This is a label, encode it relative to the base.
   2124                 value = value - base;
   2125             }
   2126             return encodeRelAddress(value);
   2127         }
   2128 
   2129         int encodeRelAddress(int value) {
   2130             return BRANCH_REL_ADDRESS_MASK & (value >> 2);
   2131         }
   2132 
   2133         int calcRegArgCount(Type* pDecl) {
   2134             int reg = 0;
   2135             Type* pArgs = pDecl->pTail;
   2136             while (pArgs && reg < 4) {
   2137                 Type* pArg = pArgs->pHead;
   2138                 if ( pArg->tag == TY_DOUBLE) {
   2139                     int evenReg = (reg + 1) & ~1;
   2140                     if (evenReg >= 4) {
   2141                         break;
   2142                     }
   2143                     reg = evenReg + 2;
   2144                 } else {
   2145                     reg++;
   2146                 }
   2147                 pArgs = pArgs->pTail;
   2148             }
   2149             return reg;
   2150         }
   2151 
   2152         void setupIntPtrArgs() {
   2153             o4(0xE8BD0002);  // ldmfd   sp!,{r1}
   2154             mStackUse -= 4;
   2155             popType();
   2156         }
   2157 
   2158         /* Pop TOS to R1 (use s14 if VFP)
   2159          * Make sure both R0 and TOS are floats. (Could be ints)
   2160          * We know that at least one of R0 and TOS is already a float
   2161          */
   2162         void setupFloatArgs() {
   2163             Type* pR0Type = getR0Type();
   2164             Type* pTOSType = getTOSType();
   2165             TypeTag tagR0 = collapseType(pR0Type->tag);
   2166             TypeTag tagTOS = collapseType(pTOSType->tag);
   2167             if (tagR0 != TY_FLOAT) {
   2168                 assert(tagR0 == TY_INT);
   2169 #ifdef ARM_USE_VFP
   2170                 o4(0xEE070A90); // fmsr    s15, r0
   2171                 o4(0xEEF87AE7); // fsitos s15, s15
   2172 #else
   2173                 callRuntime((void*) runtime_int_to_float);
   2174 #endif
   2175             }
   2176             if (tagTOS != TY_FLOAT) {
   2177                 assert(tagTOS == TY_INT);
   2178                 assert(tagR0 == TY_FLOAT);
   2179 #ifdef ARM_USE_VFP
   2180                 o4(0xECBD7A01); // fldmfds sp!, {s14}
   2181                 o4(0xEEB87AC7); // fsitos s14, s14
   2182 #else
   2183                 o4(0xE92D0001);  // stmfd   sp!,{r0}  // push R0
   2184                 o4(0xE59D0004);  // ldr     r0, [sp, #4]
   2185                 callRuntime((void*) runtime_int_to_float);
   2186                 o4(0xE1A01000);  // mov r1, r0
   2187                 o4(0xE8BD0001);  // ldmfd   sp!,{r0}  // pop R0
   2188                 o4(0xE28DD004);  // add sp, sp, #4 // Pop sp
   2189 #endif
   2190             } else {
   2191                 // Pop TOS
   2192 #ifdef ARM_USE_VFP
   2193                 o4(0xECBD7A01); // fldmfds sp!, {s14}
   2194 
   2195 #else
   2196                 o4(0xE8BD0002);  // ldmfd   sp!,{r1}
   2197 #endif
   2198             }
   2199             mStackUse -= 4;
   2200             popType();
   2201         }
   2202 
   2203         /* Pop TOS into R2..R3 (use D6 if VFP)
   2204          * Make sure both R0 and TOS are doubles. Could be floats or ints.
   2205          * We know that at least one of R0 and TOS are already a double.
   2206          */
   2207 
   2208         void setupDoubleArgs() {
   2209             Type* pR0Type = getR0Type();
   2210             Type* pTOSType = getTOSType();
   2211             TypeTag tagR0 = collapseType(pR0Type->tag);
   2212             TypeTag tagTOS = collapseType(pTOSType->tag);
   2213             if (tagR0 != TY_DOUBLE) {
   2214                 if (tagR0 == TY_INT) {
   2215 #ifdef ARM_USE_VFP
   2216                     o4(0xEE070A90); // fmsr s15, r0
   2217                     o4(0xEEB87BE7); // fsitod d7, s15
   2218 
   2219 #else
   2220                     callRuntime((void*) runtime_int_to_double);
   2221 #endif
   2222                 } else {
   2223                     assert(tagR0 == TY_FLOAT);
   2224 #ifdef ARM_USE_VFP
   2225                     o4(0xEEB77AE7); // fcvtds    d7, s15
   2226 #else
   2227                     callRuntime((void*) runtime_float_to_double);
   2228 #endif
   2229                 }
   2230             }
   2231             if (tagTOS != TY_DOUBLE) {
   2232 #ifdef ARM_USE_VFP
   2233                 if (tagTOS == TY_INT) {
   2234                     o4(0xECFD6A01);  // fldmfds sp!,{s13}
   2235                     o4(0xEEB86BE6);  // fsitod  d6, s13
   2236                 } else {
   2237                     assert(tagTOS == TY_FLOAT);
   2238                     o4(0xECFD6A01);  // fldmfds sp!,{s13}
   2239                     o4(0xEEB76AE6);  // fcvtds    d6, s13
   2240                 }
   2241 #else
   2242                 o4(0xE92D0003);  // stmfd   sp!,{r0,r1}  // push r0,r1
   2243                 o4(0xE59D0008);  // ldr     r0, [sp, #8]
   2244                 if (tagTOS == TY_INT) {
   2245                     callRuntime((void*) runtime_int_to_double);
   2246                 } else {
   2247                     assert(tagTOS == TY_FLOAT);
   2248                     callRuntime((void*) runtime_float_to_double);
   2249                 }
   2250                 o4(0xE1A02000);  // mov r2, r0
   2251                 o4(0xE1A03001);  // mov r3, r1
   2252                 o4(0xE8BD0003);  // ldmfd   sp!,{r0, r1}  // Restore R0
   2253                 o4(0xE28DD004);  // add sp, sp, #4 // Pop sp
   2254 #endif
   2255                 mStackUse -= 4;
   2256             } else {
   2257 #ifdef ARM_USE_VFP
   2258                 o4(0xECBD6B02);  // fldmfdd    sp!, {d6}
   2259 #else
   2260                 o4(0xE8BD000C);  // ldmfd   sp!,{r2,r3}
   2261 #endif
   2262                 mStackUse -= 8;
   2263             }
   2264             popType();
   2265         }
   2266 
   2267         void liReg(int t, int reg) {
   2268             assert(reg >= 0 && reg < 16);
   2269             int rN = (reg & 0xf) << 12;
   2270             size_t encodedImmediate;
   2271             if (encode12BitImmediate(t, &encodedImmediate)) {
   2272                  o4(0xE3A00000 | encodedImmediate | rN); // mov    rN, #0
   2273             } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
   2274                 // mvn means move constant ^ ~0
   2275                 o4(0xE3E00000 | encodedImmediate | rN); // mvn    rN, #0
   2276             } else {
   2277                 o4(0xE51F0000 | rN); //         ldr    rN, .L3
   2278                 o4(0xEA000000); //         b .L99
   2279                 o4(t);          // .L3:   .word 0
   2280                                   // .L99:
   2281             }
   2282         }
   2283 
   2284         void incompatibleTypes(Type* pR0Type, Type* pType) {
   2285             error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
   2286         }
   2287 
   2288         void callRuntime(void* fn) {
   2289             o4(0xE59FC000); // ldr    r12, .L1
   2290             o4(0xEA000000); // b      .L99
   2291             o4((int) fn);   //.L1:  .word  fn
   2292             o4(0xE12FFF3C); //.L99: blx    r12
   2293         }
   2294 
   2295         // Integer math:
   2296 
   2297         static int runtime_DIV(int b, int a) {
   2298             return a / b;
   2299         }
   2300 
   2301         static int runtime_MOD(int b, int a) {
   2302             return a % b;
   2303         }
   2304 
   2305         static void runtime_structCopy(void* src, size_t size, void* dest) {
   2306             memcpy(dest, src, size);
   2307         }
   2308 
   2309 #ifndef ARM_USE_VFP
   2310 
   2311         // Comparison to zero
   2312 
   2313         static int runtime_is_non_zero_f(float a) {
   2314             return a != 0;
   2315         }
   2316 
   2317         static int runtime_is_non_zero_d(double a) {
   2318             return a != 0;
   2319         }
   2320 
   2321         // Comparison to zero
   2322 
   2323         static int runtime_is_zero_f(float a) {
   2324             return a == 0;
   2325         }
   2326 
   2327         static int runtime_is_zero_d(double a) {
   2328             return a == 0;
   2329         }
   2330 
   2331         // Type conversion
   2332 
   2333         static int runtime_float_to_int(float a) {
   2334             return (int) a;
   2335         }
   2336 
   2337         static double runtime_float_to_double(float a) {
   2338             return (double) a;
   2339         }
   2340 
   2341         static int runtime_double_to_int(double a) {
   2342             return (int) a;
   2343         }
   2344 
   2345         static float runtime_double_to_float(double a) {
   2346             return (float) a;
   2347         }
   2348 
   2349         static float runtime_int_to_float(int a) {
   2350             return (float) a;
   2351         }
   2352 
   2353         static double runtime_int_to_double(int a) {
   2354             return (double) a;
   2355         }
   2356 
   2357         // Comparisons float
   2358 
   2359         static int runtime_cmp_eq_ff(float b, float a) {
   2360             return a == b;
   2361         }
   2362 
   2363         static int runtime_cmp_ne_ff(float b, float a) {
   2364             return a != b;
   2365         }
   2366 
   2367         static int runtime_cmp_lt_ff(float b, float a) {
   2368             return a < b;
   2369         }
   2370 
   2371         static int runtime_cmp_le_ff(float b, float a) {
   2372             return a <= b;
   2373         }
   2374 
   2375         static int runtime_cmp_ge_ff(float b, float a) {
   2376             return a >= b;
   2377         }
   2378 
   2379         static int runtime_cmp_gt_ff(float b, float a) {
   2380             return a > b;
   2381         }
   2382 
   2383         // Comparisons double
   2384 
   2385         static int runtime_cmp_eq_dd(double b, double a) {
   2386             return a == b;
   2387         }
   2388 
   2389         static int runtime_cmp_ne_dd(double b, double a) {
   2390             return a != b;
   2391         }
   2392 
   2393         static int runtime_cmp_lt_dd(double b, double a) {
   2394             return a < b;
   2395         }
   2396 
   2397         static int runtime_cmp_le_dd(double b, double a) {
   2398             return a <= b;
   2399         }
   2400 
   2401         static int runtime_cmp_ge_dd(double b, double a) {
   2402             return a >= b;
   2403         }
   2404 
   2405         static int runtime_cmp_gt_dd(double b, double a) {
   2406             return a > b;
   2407         }
   2408 
   2409         // Math float
   2410 
   2411         static float runtime_op_add_ff(float b, float a) {
   2412             return a + b;
   2413         }
   2414 
   2415         static float runtime_op_sub_ff(float b, float a) {
   2416             return a - b;
   2417         }
   2418 
   2419         static float runtime_op_mul_ff(float b, float a) {
   2420             return a * b;
   2421         }
   2422 
   2423         static float runtime_op_div_ff(float b, float a) {
   2424             return a / b;
   2425         }
   2426 
   2427         static float runtime_op_neg_f(float a) {
   2428             return -a;
   2429         }
   2430 
   2431         // Math double
   2432 
   2433         static double runtime_op_add_dd(double b, double a) {
   2434             return a + b;
   2435         }
   2436 
   2437         static double runtime_op_sub_dd(double b, double a) {
   2438             return a - b;
   2439         }
   2440 
   2441         static double runtime_op_mul_dd(double b, double a) {
   2442             return a * b;
   2443         }
   2444 
   2445         static double runtime_op_div_dd(double b, double a) {
   2446             return a / b;
   2447         }
   2448 
   2449         static double runtime_op_neg_d(double a) {
   2450             return -a;
   2451         }
   2452 
   2453 #endif
   2454 
   2455         static const int STACK_ALIGNMENT = 8;
   2456         int mStackUse;
   2457         // This variable holds the amount we adjusted the stack in the most
   2458         // recent endFunctionCallArguments call. It's examined by the
   2459         // following adjustStackAfterCall call.
   2460         int mStackAlignmentAdjustment;
   2461     };
   2462 
   2463 #endif // PROVIDE_ARM_CODEGEN
   2464 
   2465 #ifdef PROVIDE_X86_CODEGEN
   2466 
   2467     class X86CodeGenerator : public CodeGenerator {
   2468     public:
   2469         X86CodeGenerator() {}
   2470         virtual ~X86CodeGenerator() {}
   2471 
   2472         /* returns address to patch with local variable size
   2473         */
   2474         virtual int functionEntry(Type* pDecl) {
   2475             o(0xe58955); /* push   %ebp, mov %esp, %ebp */
   2476             return oad(0xec81, 0); /* sub $xxx, %esp */
   2477         }
   2478 
   2479         virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
   2480             o(0xc3c9); /* leave, ret */
   2481             *(int *) localVariableAddress = localVariableSize; /* save local variables */
   2482         }
   2483 
   2484         /* load immediate value */
   2485         virtual void li(int i) {
   2486             oad(0xb8, i); /* mov $xx, %eax */
   2487             setR0Type(mkpInt);
   2488         }
   2489 
   2490         virtual void loadFloat(int address, Type* pType) {
   2491             setR0Type(pType);
   2492             switch (pType->tag) {
   2493             case TY_FLOAT:
   2494                 oad(0x05D9, address);      // flds
   2495                 break;
   2496             case TY_DOUBLE:
   2497                 oad(0x05DD, address);      // fldl
   2498                 break;
   2499             default:
   2500                 assert(false);
   2501                 break;
   2502             }
   2503         }
   2504 
   2505         virtual void addStructOffsetR0(int offset, Type* pType) {
   2506             if (offset) {
   2507                 oad(0x05, offset); // addl offset, %eax
   2508             }
   2509             setR0Type(pType, ET_LVALUE);
   2510         }
   2511 
   2512         virtual int gjmp(int t) {
   2513             return psym(0xe9, t);
   2514         }
   2515 
   2516         /* l = 0: je, l == 1: jne */
   2517         virtual int gtst(bool l, int t) {
   2518             Type* pR0Type = getR0Type();
   2519             TypeTag tagR0 = pR0Type->tag;
   2520             bool isFloatR0 = isFloatTag(tagR0);
   2521             if (isFloatR0) {
   2522                 o(0xeed9); // fldz
   2523                 o(0xe9da); // fucompp
   2524                 o(0xe0df); // fnstsw %ax
   2525                 o(0x9e);   // sahf
   2526             } else {
   2527                 o(0xc085); // test %eax, %eax
   2528             }
   2529             // Use two output statements to generate one instruction.
   2530             o(0x0f);   // je/jne xxx
   2531             return psym(0x84 + l, t);
   2532         }
   2533 
   2534         virtual void gcmp(int op) {
   2535             Type* pR0Type = getR0Type();
   2536             Type* pTOSType = getTOSType();
   2537             TypeTag tagR0 = pR0Type->tag;
   2538             TypeTag tagTOS = pTOSType->tag;
   2539             bool isFloatR0 = isFloatTag(tagR0);
   2540             bool isFloatTOS = isFloatTag(tagTOS);
   2541             if (!isFloatR0 && !isFloatTOS) {
   2542                 int t = decodeOp(op);
   2543                 o(0x59); /* pop %ecx */
   2544                 o(0xc139); /* cmp %eax,%ecx */
   2545                 li(0);
   2546                 o(0x0f); /* setxx %al */
   2547                 o(t + 0x90);
   2548                 o(0xc0);
   2549                 popType();
   2550             } else {
   2551                 setupFloatOperands();
   2552                 switch (op) {
   2553                     case OP_EQUALS:
   2554                         o(0xe9da);   // fucompp
   2555                         o(0xe0df);   // fnstsw %ax
   2556                         o(0x9e);     // sahf
   2557                         o(0xc0940f); // sete %al
   2558                         o(0xc29b0f); // setnp %dl
   2559                         o(0xd021);   // andl %edx, %eax
   2560                         break;
   2561                     case OP_NOT_EQUALS:
   2562                         o(0xe9da);   // fucompp
   2563                         o(0xe0df);   // fnstsw %ax
   2564                         o(0x9e);     // sahf
   2565                         o(0xc0950f); // setne %al
   2566                         o(0xc29a0f); // setp %dl
   2567                         o(0xd009);   // orl %edx, %eax
   2568                         break;
   2569                     case OP_GREATER_EQUAL:
   2570                         o(0xe9da);   // fucompp
   2571                         o(0xe0df);   // fnstsw %ax
   2572                         o(0x05c4f6); // testb $5, %ah
   2573                         o(0xc0940f); // sete %al
   2574                         break;
   2575                     case OP_LESS:
   2576                         o(0xc9d9);   // fxch %st(1)
   2577                         o(0xe9da);   // fucompp
   2578                         o(0xe0df);   // fnstsw %ax
   2579                         o(0x9e);     // sahf
   2580                         o(0xc0970f); // seta %al
   2581                         break;
   2582                     case OP_LESS_EQUAL:
   2583                         o(0xc9d9);   // fxch %st(1)
   2584                         o(0xe9da);   // fucompp
   2585                         o(0xe0df);   // fnstsw %ax
   2586                         o(0x9e);     // sahf
   2587                         o(0xc0930f); // setea %al
   2588                         break;
   2589                     case OP_GREATER:
   2590                         o(0xe9da);   // fucompp
   2591                         o(0xe0df);   // fnstsw %ax
   2592                         o(0x45c4f6); // testb $69, %ah
   2593                         o(0xc0940f); // sete %al
   2594                         break;
   2595                     default:
   2596                         error("Unknown comparison op");
   2597                 }
   2598                 o(0xc0b60f); // movzbl %al, %eax
   2599             }
   2600             setR0Type(mkpInt);
   2601         }
   2602 
   2603         virtual void genOp(int op) {
   2604             Type* pR0Type = getR0Type();
   2605             Type* pTOSType = getTOSType();
   2606             TypeTag tagR0 = pR0Type->tag;
   2607             TypeTag tagTOS = pTOSType->tag;
   2608             bool isFloatR0 = isFloatTag(tagR0);
   2609             bool isFloatTOS = isFloatTag(tagTOS);
   2610             if (!isFloatR0 && !isFloatTOS) {
   2611                 bool isPtrR0 = isPointerTag(tagR0);
   2612                 bool isPtrTOS = isPointerTag(tagTOS);
   2613                 if (isPtrR0 || isPtrTOS) {
   2614                     if (isPtrR0 && isPtrTOS) {
   2615                         if (op != OP_MINUS) {
   2616                             error("Unsupported pointer-pointer operation %d.", op);
   2617                         }
   2618                         if (! typeEqual(pR0Type, pTOSType)) {
   2619                             error("Incompatible pointer types for subtraction.");
   2620                         }
   2621                         o(0x59); /* pop %ecx */
   2622                         o(decodeOp(op));
   2623                         popType();
   2624                         setR0Type(mkpInt);
   2625                         int size = sizeOf(pR0Type->pHead);
   2626                         if (size != 1) {
   2627                             pushR0();
   2628                             li(size);
   2629                             // TODO: Optimize for power-of-two.
   2630                             genOp(OP_DIV);
   2631                         }
   2632                     } else {
   2633                         if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
   2634                             error("Unsupported pointer-scalar operation %d", op);
   2635                         }
   2636                         Type* pPtrType = getPointerArithmeticResultType(
   2637                                 pR0Type, pTOSType);
   2638                         o(0x59); /* pop %ecx */
   2639                         int size = sizeOf(pPtrType->pHead);
   2640                         if (size != 1) {
   2641                             // TODO: Optimize for power-of-two.
   2642                             if (isPtrR0) {
   2643                                 oad(0xC969, size); // imull $size, %ecx
   2644                             } else {
   2645                                 oad(0xC069, size); // mul $size, %eax
   2646                             }
   2647                         }
   2648                         o(decodeOp(op));
   2649                         popType();
   2650                         setR0Type(pPtrType);
   2651                     }
   2652                 } else {
   2653                     o(0x59); /* pop %ecx */
   2654                     o(decodeOp(op));
   2655                     if (op == OP_MOD)
   2656                         o(0x92); /* xchg %edx, %eax */
   2657                     popType();
   2658                 }
   2659             } else {
   2660                 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
   2661                 setupFloatOperands();
   2662                 // Both float. x87 R0 == left hand, x87 R1 == right hand
   2663                 switch (op) {
   2664                     case OP_MUL:
   2665                         o(0xc9de); // fmulp
   2666                         break;
   2667                     case OP_DIV:
   2668                         o(0xf1de); // fdivp
   2669                         break;
   2670                     case OP_PLUS:
   2671                         o(0xc1de); // faddp
   2672                         break;
   2673                     case OP_MINUS:
   2674                         o(0xe1de); // fsubp
   2675                         break;
   2676                     default:
   2677                         error("Unsupported binary floating operation.");
   2678                         break;
   2679                 }
   2680                 setR0Type(pResultType);
   2681             }
   2682         }
   2683 
   2684         virtual void gUnaryCmp(int op) {
   2685             if (op != OP_LOGICAL_NOT) {
   2686                 error("Unknown unary cmp %d", op);
   2687             } else {
   2688                 Type* pR0Type = getR0Type();
   2689                 TypeTag tag = collapseType(pR0Type->tag);
   2690                 switch(tag) {
   2691                     case TY_INT: {
   2692                             oad(0xb9, 0); /* movl $0, %ecx */
   2693                             int t = decodeOp(op);
   2694                             o(0xc139); /* cmp %eax,%ecx */
   2695                             li(0);
   2696                             o(0x0f); /* setxx %al */
   2697                             o(t + 0x90);
   2698                             o(0xc0);
   2699                         }
   2700                         break;
   2701                     case TY_FLOAT:
   2702                     case TY_DOUBLE:
   2703                         o(0xeed9);   // fldz
   2704                         o(0xe9da);   // fucompp
   2705                         o(0xe0df);   // fnstsw %ax
   2706                         o(0x9e);     // sahf
   2707                         o(0xc0950f); // setne %al
   2708                         o(0xc29a0f); // setp %dl
   2709                         o(0xd009);   // orl %edx, %eax
   2710                         o(0xc0b60f); // movzbl %al, %eax
   2711                         o(0x01f083); // xorl $1,  %eax
   2712                         break;
   2713                     default:
   2714                         error("gUnaryCmp unsupported type");
   2715                         break;
   2716                 }
   2717             }
   2718             setR0Type(mkpInt);
   2719         }
   2720 
   2721         virtual void genUnaryOp(int op) {
   2722             Type* pR0Type = getR0Type();
   2723             TypeTag tag = collapseType(pR0Type->tag);
   2724             switch(tag) {
   2725                 case TY_INT:
   2726                     oad(0xb9, 0); /* movl $0, %ecx */
   2727                     o(decodeOp(op));
   2728                     break;
   2729                 case TY_FLOAT:
   2730                 case TY_DOUBLE:
   2731                     switch (op) {
   2732                         case OP_MINUS:
   2733                             o(0xe0d9);  // fchs
   2734                             break;
   2735                         case OP_BIT_NOT:
   2736                             error("Can't apply '~' operator to a float or double.");
   2737                             break;
   2738                         default:
   2739                             error("Unknown unary op %d\n", op);
   2740                             break;
   2741                         }
   2742                     break;
   2743                 default:
   2744                     error("genUnaryOp unsupported type");
   2745                     break;
   2746             }
   2747         }
   2748 
   2749         virtual void pushR0() {
   2750             Type* pR0Type = getR0Type();
   2751             TypeTag r0ct = collapseType(pR0Type->tag);
   2752             switch(r0ct) {
   2753                 case TY_INT:
   2754                     o(0x50); /* push %eax */
   2755                     break;
   2756                 case TY_FLOAT:
   2757                     o(0x50); /* push %eax */
   2758                     o(0x241cd9); // fstps 0(%esp)
   2759                     break;
   2760                 case TY_DOUBLE:
   2761                     o(0x50); /* push %eax */
   2762                     o(0x50); /* push %eax */
   2763                     o(0x241cdd); // fstpl 0(%esp)
   2764                     break;
   2765                 default:
   2766                     error("pushR0 unsupported type %d", r0ct);
   2767                     break;
   2768             }
   2769             pushType();
   2770         }
   2771 
   2772         virtual void over() {
   2773             // We know it's only used for int-ptr ops (++/--)
   2774 
   2775             Type* pR0Type = getR0Type();
   2776             TypeTag r0ct = collapseType(pR0Type->tag);
   2777 
   2778             Type* pTOSType = getTOSType();
   2779             TypeTag tosct = collapseType(pTOSType->tag);
   2780 
   2781             assert (r0ct == TY_INT && tosct == TY_INT);
   2782 
   2783             o(0x59); /* pop %ecx */
   2784             o(0x50); /* push %eax */
   2785             o(0x51); /* push %ecx */
   2786 
   2787             overType();
   2788         }
   2789 
   2790         virtual void popR0() {
   2791             Type* pR0Type = getR0Type();
   2792             TypeTag r0ct = collapseType(pR0Type->tag);
   2793             switch(r0ct) {
   2794                 case TY_INT:
   2795                     o(0x58); /* popl %eax */
   2796                     break;
   2797                 case TY_FLOAT:
   2798                     o(0x2404d9); // flds (%esp)
   2799                     o(0x58); /* popl %eax */
   2800                     break;
   2801                 case TY_DOUBLE:
   2802                     o(0x2404dd); // fldl (%esp)
   2803                     o(0x58); /* popl %eax */
   2804                     o(0x58); /* popl %eax */
   2805                     break;
   2806                 default:
   2807                     error("popR0 unsupported type %d", r0ct);
   2808                     break;
   2809             }
   2810             popType();
   2811         }
   2812 
   2813         virtual void storeR0ToTOS() {
   2814             Type* pPointerType = getTOSType();
   2815             assert(pPointerType->tag == TY_POINTER);
   2816             Type* pTargetType = pPointerType->pHead;
   2817             convertR0(pTargetType);
   2818             o(0x59); /* pop %ecx */
   2819             popType();
   2820             switch (pTargetType->tag) {
   2821                 case TY_POINTER:
   2822                 case TY_INT:
   2823                     o(0x0189); /* movl %eax/%al, (%ecx) */
   2824                     break;
   2825                 case TY_SHORT:
   2826                     o(0x018966); /* movw %ax, (%ecx) */
   2827                     break;
   2828                 case TY_CHAR:
   2829                     o(0x0188); /* movl %eax/%al, (%ecx) */
   2830                     break;
   2831                 case TY_FLOAT:
   2832                     o(0x19d9); /* fstps (%ecx) */
   2833                     break;
   2834                 case TY_DOUBLE:
   2835                     o(0x19dd); /* fstpl (%ecx) */
   2836                     break;
   2837                 case TY_STRUCT:
   2838                 {
   2839                     // TODO: use alignment information to use movsw/movsl instead of movsb
   2840                     int size = sizeOf(pTargetType);
   2841                     if (size > 0) {
   2842                         o(0x9c);         // pushf
   2843                         o(0x57);         // pushl %edi
   2844                         o(0x56);         // pushl %esi
   2845                         o(0xcf89);       // movl %ecx, %edi
   2846                         o(0xc689);       // movl %eax, %esi
   2847                         oad(0xb9, size);  // mov #size, %ecx
   2848                         o(0xfc);         // cld
   2849                         o(0xf3);         // rep
   2850                         o(0xa4);         // movsb
   2851                         o(0x5e);         // popl %esi
   2852                         o(0x5f);         // popl %edi
   2853                         o(0x9d);         // popf
   2854                     }
   2855                 }
   2856                     break;
   2857                 default:
   2858                     error("storeR0ToTOS: unsupported type %d",
   2859                             pTargetType->tag);
   2860                     break;
   2861             }
   2862             setR0Type(pTargetType);
   2863         }
   2864 
   2865         virtual void loadR0FromR0() {
   2866             Type* pPointerType = getR0Type();
   2867             assert(pPointerType->tag == TY_POINTER);
   2868             Type* pNewType = pPointerType->pHead;
   2869             TypeTag tag = pNewType->tag;
   2870             switch (tag) {
   2871                 case TY_POINTER:
   2872                 case TY_INT:
   2873                     o2(0x008b); /* mov (%eax), %eax */
   2874                     break;
   2875                 case TY_SHORT:
   2876                     o(0xbf0f); /* movswl (%eax), %eax */
   2877                     ob(0);
   2878                     break;
   2879                 case TY_CHAR:
   2880                     o(0xbe0f); /* movsbl (%eax), %eax */
   2881                     ob(0); /* add zero in code */
   2882                     break;
   2883                 case TY_FLOAT:
   2884                     o2(0x00d9); // flds (%eax)
   2885                     break;
   2886                 case TY_DOUBLE:
   2887                     o2(0x00dd); // fldl (%eax)
   2888                     break;
   2889                 case TY_ARRAY:
   2890                     pNewType = pNewType->pTail;
   2891                     break;
   2892                 case TY_STRUCT:
   2893                     break;
   2894                 default:
   2895                     error("loadR0FromR0: unsupported type %d", tag);
   2896                     break;
   2897             }
   2898             setR0Type(pNewType);
   2899         }
   2900 
   2901         virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
   2902             gmov(10, ea); /* leal EA, %eax */
   2903             setR0Type(pPointerType, et);
   2904         }
   2905 
   2906         virtual int leaForward(int ea, Type* pPointerType) {
   2907             oad(0xb8, ea); /* mov $xx, %eax */
   2908             setR0Type(pPointerType);
   2909             return getPC() - 4;
   2910         }
   2911 
   2912         virtual void convertR0Imp(Type* pType, bool isCast){
   2913             Type* pR0Type = getR0Type();
   2914             if (pR0Type == NULL) {
   2915                 assert(false);
   2916                 setR0Type(pType);
   2917                 return;
   2918             }
   2919             if (isPointerType(pType) && isPointerType(pR0Type)) {
   2920                 Type* pA = pR0Type;
   2921                 Type* pB = pType;
   2922                 // Array decays to pointer
   2923                 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
   2924                     pA = pA->pTail;
   2925                 }
   2926                 if (! (typeEqual(pA, pB)
   2927                         || pB->pHead->tag == TY_VOID
   2928                         || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
   2929                     )) {
   2930                     error("Incompatible pointer or array types");
   2931                 }
   2932             } else if (bitsSame(pType, pR0Type)) {
   2933                 // do nothing special
   2934             } else if (isFloatType(pType) && isFloatType(pR0Type)) {
   2935                 // do nothing special, both held in same register on x87.
   2936             } else {
   2937                 TypeTag r0Tag = collapseType(pR0Type->tag);
   2938                 TypeTag destTag = collapseType(pType->tag);
   2939                 if (r0Tag == TY_INT && isFloatTag(destTag)) {
   2940                     // Convert R0 from int to float
   2941                     o(0x50);      // push %eax
   2942                     o(0x2404DB);  // fildl 0(%esp)
   2943                     o(0x58);      // pop %eax
   2944                 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
   2945                     // Convert R0 from float to int. Complicated because
   2946                     // need to save and restore the rounding mode.
   2947                     o(0x50);       // push %eax
   2948                     o(0x50);       // push %eax
   2949                     o(0x02247cD9); // fnstcw 2(%esp)
   2950                     o(0x2444b70f); // movzwl 2(%esp), %eax
   2951                     o(0x02);
   2952                     o(0x0cb4);     // movb $12, %ah
   2953                     o(0x24048966); // movw %ax, 0(%esp)
   2954                     o(0x242cd9);   // fldcw 0(%esp)
   2955                     o(0x04245cdb); // fistpl 4(%esp)
   2956                     o(0x02246cd9); // fldcw  2(%esp)
   2957                     o(0x58); // pop %eax
   2958                     o(0x58); // pop %eax
   2959                 } else {
   2960                     error("Incompatible types old: %d new: %d",
   2961                           pR0Type->tag, pType->tag);
   2962                 }
   2963             }
   2964             setR0Type(pType);
   2965         }
   2966 
   2967         virtual int beginFunctionCallArguments() {
   2968             return oad(0xec81, 0); /* sub $xxx, %esp */
   2969         }
   2970 
   2971         virtual size_t storeR0ToArg(int l, Type* pArgType) {
   2972             convertR0(pArgType);
   2973             Type* pR0Type = getR0Type();
   2974             TypeTag r0ct = collapseType(pR0Type->tag);
   2975             switch(r0ct) {
   2976                 case TY_INT:
   2977                     oad(0x248489, l); /* movl %eax, xxx(%esp) */
   2978                     return 4;
   2979                 case TY_FLOAT:
   2980                     oad(0x249CD9, l); /* fstps   xxx(%esp) */
   2981                     return 4;
   2982                 case TY_DOUBLE:
   2983                     oad(0x249CDD, l); /* fstpl   xxx(%esp) */
   2984                     return 8;
   2985                 default:
   2986                     assert(false);
   2987                     return 0;
   2988             }
   2989         }
   2990 
   2991         virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
   2992             * (int*) a = l;
   2993         }
   2994 
   2995         virtual int callForward(int symbol, Type* pFunc) {
   2996             assert(pFunc->tag == TY_FUNC);
   2997             setR0Type(pFunc->pHead);
   2998             return psym(0xe8, symbol); /* call xxx */
   2999         }
   3000 
   3001         virtual void callIndirect(int l, Type* pFunc) {
   3002             assert(pFunc->tag == TY_FUNC);
   3003             popType(); // Get rid of indirect fn pointer type
   3004             setR0Type(pFunc->pHead);
   3005             oad(0x2494ff, l); /* call *xxx(%esp) */
   3006         }
   3007 
   3008         virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
   3009             assert(pDecl->tag == TY_FUNC);
   3010             if (isIndirect) {
   3011                 l += 4;
   3012             }
   3013             if (l > 0) {
   3014                 oad(0xc481, l); /* add $xxx, %esp */
   3015             }
   3016         }
   3017 
   3018         virtual int jumpOffset() {
   3019             return 5;
   3020         }
   3021 
   3022         /* output a symbol and patch all calls to it */
   3023         virtual void gsym(int t) {
   3024             int n;
   3025             int pc = getPC();
   3026             while (t) {
   3027                 n = *(int *) t; /* next value */
   3028                 *(int *) t = pc - t - 4;
   3029                 t = n;
   3030             }
   3031         }
   3032 
   3033         /* output a symbol and patch all calls to it, using absolute address */
   3034         virtual void resolveForward(int t) {
   3035             int n;
   3036             int pc = getPC();
   3037             while (t) {
   3038                 n = *(int *) t; /* next value */
   3039                 *(int *) t = pc;
   3040                 t = n;
   3041             }
   3042         }
   3043 
   3044         virtual int finishCompile() {
   3045             size_t pagesize = 4096;
   3046             size_t base = (size_t) getBase() & ~ (pagesize - 1);
   3047             size_t top =  ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
   3048             int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
   3049             if (err) {
   3050                error("mprotect() failed: %d", errno);
   3051             }
   3052             return err;
   3053         }
   3054 
   3055         /**
   3056          * Alignment (in bytes) for this type of data
   3057          */
   3058         virtual size_t alignmentOf(Type* pType){
   3059             switch (pType->tag) {
   3060             case TY_CHAR:
   3061                 return 1;
   3062             case TY_SHORT:
   3063                 return 2;
   3064             case TY_ARRAY:
   3065                 return alignmentOf(pType->pHead);
   3066             case TY_STRUCT:
   3067                 return pType->pHead->alignment & 0x7fffffff;
   3068             case TY_FUNC:
   3069                 error("alignment of func not supported");
   3070                 return 1;
   3071             default:
   3072                 return 4;
   3073             }
   3074         }
   3075 
   3076         /**
   3077          * Array element alignment (in bytes) for this type of data.
   3078          */
   3079         virtual size_t sizeOf(Type* pType){
   3080             switch(pType->tag) {
   3081                 case TY_INT:
   3082                     return 4;
   3083                 case TY_SHORT:
   3084                     return 2;
   3085                 case TY_CHAR:
   3086                     return 1;
   3087                 case TY_FLOAT:
   3088                     return 4;
   3089                 case TY_DOUBLE:
   3090                     return 8;
   3091                 case TY_POINTER:
   3092                     return 4;
   3093                 case TY_ARRAY:
   3094                     return pType->length * sizeOf(pType->pHead);
   3095                 case TY_STRUCT:
   3096                     return pType->pHead->length;
   3097                 default:
   3098                     error("Unsupported type %d", pType->tag);
   3099                     return 0;
   3100             }
   3101         }
   3102 
   3103     private:
   3104 
   3105         /** Output 1 to 4 bytes.
   3106          *
   3107          */
   3108         void o(int n) {
   3109             /* cannot use unsigned, so we must do a hack */
   3110             while (n && n != -1) {
   3111                 ob(n & 0xff);
   3112                 n = n >> 8;
   3113             }
   3114         }
   3115 
   3116         /* Output exactly 2 bytes
   3117          */
   3118         void o2(int n) {
   3119             ob(n & 0xff);
   3120             ob(0xff & (n >> 8));
   3121         }
   3122 
   3123         /* psym is used to put an instruction with a data field which is a
   3124          reference to a symbol. It is in fact the same as oad ! */
   3125         int psym(int n, int t) {
   3126             return oad(n, t);
   3127         }
   3128 
   3129         /* instruction + address */
   3130         int oad(int n, int t) {
   3131             o(n);
   3132             int result = getPC();
   3133             o4(t);
   3134             return result;
   3135         }
   3136 
   3137         static const int operatorHelper[];
   3138 
   3139         int decodeOp(int op) {
   3140             if (op < 0 || op > OP_COUNT) {
   3141                 error("Out-of-range operator: %d\n", op);
   3142                 op = 0;
   3143             }
   3144             return operatorHelper[op];
   3145         }
   3146 
   3147         void gmov(int l, int t) {
   3148             o(l + 0x83);
   3149             oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
   3150         }
   3151 
   3152         void setupFloatOperands() {
   3153             Type* pR0Type = getR0Type();
   3154             Type* pTOSType = getTOSType();
   3155             TypeTag tagR0 = pR0Type->tag;
   3156             TypeTag tagTOS = pTOSType->tag;
   3157             bool isFloatR0 = isFloatTag(tagR0);
   3158             bool isFloatTOS = isFloatTag(tagTOS);
   3159             if (! isFloatR0) {
   3160                 // Convert R0 from int to float
   3161                 o(0x50);      // push %eax
   3162                 o(0x2404DB);  // fildl 0(%esp)
   3163                 o(0x58);      // pop %eax
   3164             }
   3165             if (! isFloatTOS){
   3166                 o(0x2404DB);  // fildl 0(%esp);
   3167                 o(0x58);      // pop %eax
   3168             } else {
   3169                 if (tagTOS == TY_FLOAT) {
   3170                     o(0x2404d9);  // flds (%esp)
   3171                     o(0x58);      // pop %eax
   3172                 } else {
   3173                     o(0x2404dd);  // fldl (%esp)
   3174                     o(0x58);      // pop %eax
   3175                     o(0x58);      // pop %eax
   3176                 }
   3177             }
   3178             popType();
   3179         }
   3180     };
   3181 
   3182 #endif // PROVIDE_X86_CODEGEN
   3183 
   3184 #ifdef PROVIDE_TRACE_CODEGEN
   3185     class TraceCodeGenerator : public CodeGenerator {
   3186     private:
   3187         CodeGenerator* mpBase;
   3188 
   3189     public:
   3190         TraceCodeGenerator(CodeGenerator* pBase) {
   3191             mpBase = pBase;
   3192         }
   3193 
   3194         virtual ~TraceCodeGenerator() {
   3195             delete mpBase;
   3196         }
   3197 
   3198         virtual void init(ICodeBuf* pCodeBuf) {
   3199             mpBase->init(pCodeBuf);
   3200         }
   3201 
   3202         void setErrorSink(ErrorSink* pErrorSink) {
   3203             mpBase->setErrorSink(pErrorSink);
   3204         }
   3205 
   3206         /* returns address to patch with local variable size
   3207         */
   3208         virtual int functionEntry(Type* pDecl) {
   3209             int result = mpBase->functionEntry(pDecl);
   3210             fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
   3211             return result;
   3212         }
   3213 
   3214         virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
   3215             fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
   3216                     localVariableAddress, localVariableSize);
   3217             mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
   3218         }
   3219 
   3220         /* load immediate value */
   3221         virtual void li(int t) {
   3222             fprintf(stderr, "li(%d)\n", t);
   3223             mpBase->li(t);
   3224         }
   3225 
   3226         virtual void loadFloat(int address, Type* pType) {
   3227             fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
   3228             mpBase->loadFloat(address, pType);
   3229         }
   3230 
   3231         virtual void addStructOffsetR0(int offset, Type* pType) {
   3232             fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
   3233             mpBase->addStructOffsetR0(offset, pType);
   3234         }
   3235 
   3236         virtual int gjmp(int t) {
   3237             int result = mpBase->gjmp(t);
   3238             fprintf(stderr, "gjmp(%d) = %d\n", t, result);
   3239             return result;
   3240         }
   3241 
   3242         /* l = 0: je, l == 1: jne */
   3243         virtual int gtst(bool l, int t) {
   3244             int result = mpBase->gtst(l, t);
   3245             fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
   3246             return result;
   3247         }
   3248 
   3249         virtual void gcmp(int op) {
   3250             fprintf(stderr, "gcmp(%d)\n", op);
   3251             mpBase->gcmp(op);
   3252         }
   3253 
   3254         virtual void genOp(int op) {
   3255             fprintf(stderr, "genOp(%d)\n", op);
   3256             mpBase->genOp(op);
   3257         }
   3258 
   3259 
   3260         virtual void gUnaryCmp(int op) {
   3261             fprintf(stderr, "gUnaryCmp(%d)\n", op);
   3262             mpBase->gUnaryCmp(op);
   3263         }
   3264 
   3265         virtual void genUnaryOp(int op) {
   3266             fprintf(stderr, "genUnaryOp(%d)\n", op);
   3267             mpBase->genUnaryOp(op);
   3268         }
   3269 
   3270         virtual void pushR0() {
   3271             fprintf(stderr, "pushR0()\n");
   3272             mpBase->pushR0();
   3273         }
   3274 
   3275         virtual void over() {
   3276             fprintf(stderr, "over()\n");
   3277             mpBase->over();
   3278         }
   3279 
   3280         virtual void popR0() {
   3281             fprintf(stderr, "popR0()\n");
   3282             mpBase->popR0();
   3283         }
   3284 
   3285         virtual void storeR0ToTOS() {
   3286             fprintf(stderr, "storeR0ToTOS()\n");
   3287             mpBase->storeR0ToTOS();
   3288         }
   3289 
   3290         virtual void loadR0FromR0() {
   3291             fprintf(stderr, "loadR0FromR0()\n");
   3292             mpBase->loadR0FromR0();
   3293         }
   3294 
   3295         virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
   3296             fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
   3297                     pPointerType->pHead->tag, et);
   3298             mpBase->leaR0(ea, pPointerType, et);
   3299         }
   3300 
   3301         virtual int leaForward(int ea, Type* pPointerType) {
   3302             fprintf(stderr, "leaForward(%d)\n", ea);
   3303             return mpBase->leaForward(ea, pPointerType);
   3304         }
   3305 
   3306         virtual void convertR0Imp(Type* pType, bool isCast){
   3307             fprintf(stderr, "convertR0(pType tag=%d, %d)\n",  pType->tag, isCast);
   3308             mpBase->convertR0Imp(pType, isCast);
   3309         }
   3310 
   3311         virtual int beginFunctionCallArguments() {
   3312             int result = mpBase->beginFunctionCallArguments();
   3313             fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
   3314             return result;
   3315         }
   3316 
   3317         virtual size_t storeR0ToArg(int l, Type* pArgType) {
   3318             fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
   3319                     pArgType->tag);
   3320             return mpBase->storeR0ToArg(l, pArgType);
   3321         }
   3322 
   3323         virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
   3324             fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
   3325             mpBase->endFunctionCallArguments(pDecl, a, l);
   3326         }
   3327 
   3328         virtual int callForward(int symbol, Type* pFunc) {
   3329             int result = mpBase->callForward(symbol, pFunc);
   3330             fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
   3331             return result;
   3332         }
   3333 
   3334         virtual void callIndirect(int l, Type* pFunc) {
   3335             fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
   3336                     pFunc->pHead->tag);
   3337             mpBase->callIndirect(l, pFunc);
   3338         }
   3339 
   3340         virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
   3341             fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
   3342             mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
   3343         }
   3344 
   3345         virtual int jumpOffset() {
   3346             return mpBase->jumpOffset();
   3347         }
   3348 
   3349         /* output a symbol and patch all calls to it */
   3350         virtual void gsym(int t) {
   3351             fprintf(stderr, "gsym(%d)\n", t);
   3352             mpBase->gsym(t);
   3353         }
   3354 
   3355         virtual void resolveForward(int t) {
   3356             mpBase->resolveForward(t);
   3357         }
   3358 
   3359         virtual int finishCompile() {
   3360             int result = mpBase->finishCompile();
   3361             fprintf(stderr, "finishCompile() = %d\n", result);
   3362             return result;
   3363         }
   3364 
   3365         /**
   3366          * Alignment (in bytes) for this type of data
   3367          */
   3368         virtual size_t alignmentOf(Type* pType){
   3369             return mpBase->alignmentOf(pType);
   3370         }
   3371 
   3372         /**
   3373          * Array element alignment (in bytes) for this type of data.
   3374          */
   3375         virtual size_t sizeOf(Type* pType){
   3376             return mpBase->sizeOf(pType);
   3377         }
   3378 
   3379         virtual Type* getR0Type() {
   3380             return mpBase->getR0Type();
   3381         }
   3382 
   3383         virtual ExpressionType getR0ExpressionType() {
   3384             return mpBase->getR0ExpressionType();
   3385         }
   3386 
   3387         virtual void setR0ExpressionType(ExpressionType et) {
   3388             mpBase->setR0ExpressionType(et);
   3389         }
   3390 
   3391         virtual size_t getExpressionStackDepth() {
   3392             return mpBase->getExpressionStackDepth();
   3393         }
   3394 
   3395         virtual void forceR0RVal() {
   3396             return mpBase->forceR0RVal();
   3397         }
   3398     };
   3399 
   3400 #endif // PROVIDE_TRACE_CODEGEN
   3401 
   3402     class Arena {
   3403     public:
   3404         // Used to record a given allocation amount.
   3405         // Used:
   3406         // Mark mark = arena.mark();
   3407         // ... lots of arena.allocate()
   3408         // arena.free(mark);
   3409 
   3410         struct Mark {
   3411             size_t chunk;
   3412             size_t offset;
   3413         };
   3414 
   3415         Arena() {
   3416             mCurrentChunk = 0;
   3417             Chunk start(CHUNK_SIZE);
   3418             mData.push_back(start);
   3419         }
   3420 
   3421         ~Arena() {
   3422             for(size_t i = 0; i < mData.size(); i++) {
   3423                 mData[i].free();
   3424             }
   3425         }
   3426 
   3427         // Alloc using the standard alignment size safe for any variable
   3428         void* alloc(size_t size) {
   3429             return alloc(size, 8);
   3430         }
   3431 
   3432         Mark mark(){
   3433             Mark result;
   3434             result.chunk = mCurrentChunk;
   3435             result.offset = mData[mCurrentChunk].mOffset;
   3436             return result;
   3437         }
   3438 
   3439         void freeToMark(const Mark& mark) {
   3440             mCurrentChunk = mark.chunk;
   3441             mData[mCurrentChunk].mOffset = mark.offset;
   3442         }
   3443 
   3444     private:
   3445         // Allocate memory aligned to a given size
   3446         // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
   3447         // Memory is not zero filled.
   3448 
   3449         void* alloc(size_t size, size_t alignment) {
   3450             while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
   3451                 if (mCurrentChunk + 1 < mData.size()) {
   3452                     mCurrentChunk++;
   3453                 } else {
   3454                     size_t allocSize = CHUNK_SIZE;
   3455                     if (allocSize < size + alignment - 1) {
   3456                         allocSize = size + alignment - 1;
   3457                     }
   3458                     Chunk chunk(allocSize);
   3459                     mData.push_back(chunk);
   3460                     mCurrentChunk++;
   3461                 }
   3462             }
   3463             return mData[mCurrentChunk].allocate(size, alignment);
   3464         }
   3465 
   3466         static const size_t CHUNK_SIZE = 128*1024;
   3467         // Note: this class does not deallocate its
   3468         // memory when it's destroyed. It depends upon
   3469         // its parent to deallocate the memory.
   3470         struct Chunk {
   3471             Chunk() {
   3472                 mpData = 0;
   3473                 mSize = 0;
   3474                 mOffset = 0;
   3475             }
   3476 
   3477             Chunk(size_t size) {
   3478                 mSize = size;
   3479                 mpData = (char*) malloc(size);
   3480                 mOffset = 0;
   3481             }
   3482 
   3483             ~Chunk() {
   3484                 // Doesn't deallocate memory.
   3485             }
   3486 
   3487             void* allocate(size_t size, size_t alignment) {
   3488                 size_t alignedOffset = aligned(mOffset, alignment);
   3489                 void* result = mpData + alignedOffset;
   3490                 mOffset = alignedOffset + size;
   3491                 return result;
   3492             }
   3493 
   3494             void free() {
   3495                 if (mpData) {
   3496                     ::free(mpData);
   3497                     mpData = 0;
   3498                 }
   3499             }
   3500 
   3501             size_t remainingCapacity(size_t alignment) {
   3502                 return aligned(mSize, alignment) - aligned(mOffset, alignment);
   3503             }
   3504 
   3505             // Assume alignment is a power of two
   3506             inline size_t aligned(size_t v, size_t alignment) {
   3507                 size_t mask = alignment-1;
   3508                 return (v + mask) & ~mask;
   3509             }
   3510 
   3511             char* mpData;
   3512             size_t mSize;
   3513             size_t mOffset;
   3514         };
   3515 
   3516         size_t mCurrentChunk;
   3517 
   3518         Vector<Chunk> mData;
   3519     };
   3520 
   3521     struct VariableInfo;
   3522 
   3523     struct Token {
   3524         int hash;
   3525         size_t length;
   3526         char* pText;
   3527         tokenid_t id;
   3528 
   3529         // Current values for the token
   3530         char* mpMacroDefinition;
   3531         VariableInfo* mpVariableInfo;
   3532         VariableInfo* mpStructInfo;
   3533     };
   3534 
   3535     class TokenTable {
   3536     public:
   3537         // Don't use 0..0xff, allows characters and operators to be tokens too.
   3538 
   3539         static const int TOKEN_BASE = 0x100;
   3540         TokenTable() {
   3541             mpMap = hashmapCreate(128, hashFn, equalsFn);
   3542         }
   3543 
   3544         ~TokenTable() {
   3545             hashmapFree(mpMap);
   3546         }
   3547 
   3548         void setArena(Arena* pArena) {
   3549             mpArena = pArena;
   3550         }
   3551 
   3552         // Returns a token for a given string of characters.
   3553         tokenid_t intern(const char* pText, size_t length) {
   3554             Token probe;
   3555             int hash = hashmapHash((void*) pText, length);
   3556             {
   3557                 Token probe;
   3558                 probe.hash = hash;
   3559                 probe.length = length;
   3560                 probe.pText = (char*) pText;
   3561                 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
   3562                 if (pValue) {
   3563                     return pValue->id;
   3564                 }
   3565             }
   3566 
   3567             Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
   3568             memset(pToken, 0, sizeof(*pToken));
   3569             pToken->hash = hash;
   3570             pToken->length = length;
   3571             pToken->pText = (char*) mpArena->alloc(length + 1);
   3572             memcpy(pToken->pText, pText, length);
   3573             pToken->pText[length] = 0;
   3574             pToken->id = mTokens.size() + TOKEN_BASE;
   3575             mTokens.push_back(pToken);
   3576             hashmapPut(mpMap, pToken, pToken);
   3577             return pToken->id;
   3578         }
   3579 
   3580         // Return the Token for a given tokenid.
   3581         Token& operator[](tokenid_t id) {
   3582             return *mTokens[id - TOKEN_BASE];
   3583         }
   3584 
   3585         inline size_t size() {
   3586             return mTokens.size();
   3587         }
   3588 
   3589     private:
   3590 
   3591         static int hashFn(void* pKey) {
   3592             Token* pToken = (Token*) pKey;
   3593             return pToken->hash;
   3594         }
   3595 
   3596         static bool equalsFn(void* keyA, void* keyB) {
   3597             Token* pTokenA = (Token*) keyA;
   3598             Token* pTokenB = (Token*) keyB;
   3599             // Don't need to compare hash values, they should always be equal
   3600             return pTokenA->length == pTokenB->length
   3601                 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
   3602         }
   3603 
   3604         Hashmap* mpMap;
   3605         Vector<Token*> mTokens;
   3606         Arena* mpArena;
   3607     };
   3608 
   3609     class InputStream {
   3610     public:
   3611         virtual ~InputStream() {}
   3612         virtual int getChar() = 0;
   3613     };
   3614 
   3615     class TextInputStream : public InputStream {
   3616     public:
   3617         TextInputStream(const char* text, size_t textLength)
   3618             : pText(text), mTextLength(textLength), mPosition(0) {
   3619         }
   3620 
   3621         virtual int getChar() {
   3622             return mPosition < mTextLength ? pText[mPosition++] : EOF;
   3623         }
   3624 
   3625     private:
   3626         const char* pText;
   3627         size_t mTextLength;
   3628         size_t mPosition;
   3629     };
   3630 
   3631     class String {
   3632     public:
   3633         String() {
   3634             mpBase = 0;
   3635             mUsed = 0;
   3636             mSize = 0;
   3637         }
   3638 
   3639         String(const char* item, int len, bool adopt) {
   3640             if (len < 0) {
   3641                 len = strlen(item);
   3642             }
   3643             if (adopt) {
   3644                 mpBase = (char*) item;
   3645                 mUsed = len;
   3646                 mSize = len + 1;
   3647             } else {
   3648                 mpBase = 0;
   3649                 mUsed = 0;
   3650                 mSize = 0;
   3651                 appendBytes(item, len);
   3652             }
   3653         }
   3654 
   3655         String(const String& other) {
   3656             mpBase = 0;
   3657             mUsed = 0;
   3658             mSize = 0;
   3659             appendBytes(other.getUnwrapped(), other.len());
   3660         }
   3661 
   3662         ~String() {
   3663             if (mpBase) {
   3664                 free(mpBase);
   3665             }
   3666         }
   3667 
   3668         String& operator=(const String& other) {
   3669             clear();
   3670             appendBytes(other.getUnwrapped(), other.len());
   3671             return *this;
   3672         }
   3673 
   3674         inline char* getUnwrapped() const {
   3675             return mpBase;
   3676         }
   3677 
   3678         void clear() {
   3679             mUsed = 0;
   3680             if (mSize > 0) {
   3681                 mpBase[0] = 0;
   3682             }
   3683         }
   3684 
   3685         void appendCStr(const char* s) {
   3686             appendBytes(s, strlen(s));
   3687         }
   3688 
   3689         void appendBytes(const char* s, int n) {
   3690             memcpy(ensure(n), s, n + 1);
   3691         }
   3692 
   3693         void append(char c) {
   3694             * ensure(1) = c;
   3695         }
   3696 
   3697         void append(String& other) {
   3698             appendBytes(other.getUnwrapped(), other.len());
   3699         }
   3700 
   3701         char* orphan() {
   3702             char* result = mpBase;
   3703             mpBase = 0;
   3704             mUsed = 0;
   3705             mSize = 0;
   3706             return result;
   3707         }
   3708 
   3709         void printf(const char* fmt,...) {
   3710             va_list ap;
   3711             va_start(ap, fmt);
   3712             vprintf(fmt, ap);
   3713             va_end(ap);
   3714         }
   3715 
   3716         void vprintf(const char* fmt, va_list ap) {
   3717             char* temp;
   3718             int numChars = vasprintf(&temp, fmt, ap);
   3719             memcpy(ensure(numChars), temp, numChars+1);
   3720             free(temp);
   3721         }
   3722 
   3723         inline size_t len() const {
   3724             return mUsed;
   3725         }
   3726 
   3727     private:
   3728         char* ensure(int n) {
   3729             size_t newUsed = mUsed + n;
   3730             if (newUsed > mSize) {
   3731                 size_t newSize = mSize * 2 + 10;
   3732                 if (newSize < newUsed) {
   3733                     newSize = newUsed;
   3734                 }
   3735                 mpBase = (char*) realloc(mpBase, newSize + 1);
   3736                 mSize = newSize;
   3737             }
   3738             mpBase[newUsed] = '\0';
   3739             char* result = mpBase + mUsed;
   3740             mUsed = newUsed;
   3741             return result;
   3742         }
   3743 
   3744         char* mpBase;
   3745         size_t mUsed;
   3746         size_t mSize;
   3747     };
   3748 
   3749     void internKeywords() {
   3750         // Note: order has to match TOK_ constants
   3751         static const char* keywords[] = {
   3752             "int",
   3753             "char",
   3754             "void",
   3755             "if",
   3756             "else",
   3757             "while",
   3758             "break",
   3759             "return",
   3760             "for",
   3761             "auto",
   3762             "case",
   3763             "const",
   3764             "continue",
   3765             "default",
   3766             "do",
   3767             "double",
   3768             "enum",
   3769             "extern",
   3770             "float",
   3771             "goto",
   3772             "long",
   3773             "register",
   3774             "short",
   3775             "signed",
   3776             "sizeof",
   3777             "static",
   3778             "struct",
   3779             "switch",
   3780             "typedef",
   3781             "union",
   3782             "unsigned",
   3783             "volatile",
   3784             "_Bool",
   3785             "_Complex",
   3786             "_Imaginary",
   3787             "inline",
   3788             "restrict",
   3789 
   3790             // predefined tokens that can also be symbols start here:
   3791             "pragma",
   3792             "define",
   3793             "line",
   3794             0};
   3795 
   3796         for(int i = 0; keywords[i]; i++) {
   3797             mTokenTable.intern(keywords[i], strlen(keywords[i]));
   3798         }
   3799     }
   3800 
   3801     struct InputState {
   3802         InputStream* pStream;
   3803         int oldCh;
   3804     };
   3805 
   3806     struct VariableInfo {
   3807         void* pAddress;
   3808         void* pForward; // For a forward direction, linked list of data to fix up
   3809         tokenid_t tok;
   3810         size_t level;
   3811         VariableInfo* pOldDefinition;
   3812         Type* pType;
   3813         bool isStructTag;
   3814     };
   3815 
   3816     class SymbolStack {
   3817     public:
   3818         SymbolStack() {
   3819             mpArena = 0;
   3820             mpTokenTable = 0;
   3821         }
   3822 
   3823         void setArena(Arena* pArena) {
   3824             mpArena = pArena;
   3825         }
   3826 
   3827         void setTokenTable(TokenTable* pTokenTable) {
   3828             mpTokenTable = pTokenTable;
   3829         }
   3830 
   3831         void pushLevel() {
   3832             Mark mark;
   3833             mark.mArenaMark = mpArena->mark();
   3834             mark.mSymbolHead = mStack.size();
   3835             mLevelStack.push_back(mark);
   3836         }
   3837 
   3838         void popLevel() {
   3839             // Undo any shadowing that was done:
   3840             Mark mark = mLevelStack.back();
   3841             mLevelStack.pop_back();
   3842             while (mStack.size() > mark.mSymbolHead) {
   3843                 VariableInfo* pV = mStack.back();
   3844                 mStack.pop_back();
   3845                 if (pV->isStructTag) {
   3846                     (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
   3847                 } else {
   3848                     (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
   3849                 }
   3850             }
   3851             mpArena->freeToMark(mark.mArenaMark);
   3852         }
   3853 
   3854         bool isDefinedAtCurrentLevel(tokenid_t tok) {
   3855             VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
   3856             return pV && pV->level == level();
   3857         }
   3858 
   3859         bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
   3860             VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
   3861             return pV && pV->level == level();
   3862         }
   3863 
   3864         VariableInfo* add(tokenid_t tok) {
   3865             Token& token = (*mpTokenTable)[tok];
   3866             VariableInfo* pOldV = token.mpVariableInfo;
   3867             VariableInfo* pNewV =
   3868                 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
   3869             memset(pNewV, 0, sizeof(VariableInfo));
   3870             pNewV->tok = tok;
   3871             pNewV->level = level();
   3872             pNewV->pOldDefinition = pOldV;
   3873             token.mpVariableInfo = pNewV;
   3874             mStack.push_back(pNewV);
   3875             return pNewV;
   3876         }
   3877 
   3878         VariableInfo* addStructTag(tokenid_t tok) {
   3879             Token& token = (*mpTokenTable)[tok];
   3880             VariableInfo* pOldS = token.mpStructInfo;
   3881             VariableInfo* pNewS =
   3882                 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
   3883             memset(pNewS, 0, sizeof(VariableInfo));
   3884             pNewS->tok = tok;
   3885             pNewS->level = level();
   3886             pNewS->isStructTag = true;
   3887             pNewS->pOldDefinition = pOldS;
   3888             token.mpStructInfo = pNewS;
   3889             mStack.push_back(pNewS);
   3890             return pNewS;
   3891         }
   3892 
   3893         VariableInfo* add(Type* pType) {
   3894             VariableInfo* pVI = add(pType->id);
   3895             pVI->pType = pType;
   3896             return pVI;
   3897         }
   3898 
   3899         void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
   3900             for (size_t i = 0; i < mStack.size(); i++) {
   3901                 if (! fn(mStack[i], context)) {
   3902                     break;
   3903                 }
   3904             }
   3905         }
   3906 
   3907     private:
   3908         inline size_t level() {
   3909             return mLevelStack.size();
   3910         }
   3911 
   3912         struct Mark {
   3913             Arena::Mark mArenaMark;
   3914             size_t mSymbolHead;
   3915         };
   3916 
   3917         Arena* mpArena;
   3918         TokenTable* mpTokenTable;
   3919         Vector<VariableInfo*> mStack;
   3920         Vector<Mark> mLevelStack;
   3921     };
   3922 
   3923     struct MacroState {
   3924         tokenid_t name; // Name of the current macro we are expanding
   3925         char* dptr; // point to macro text during macro playback
   3926         int dch; // Saves old value of ch during a macro playback
   3927     };
   3928 
   3929 #define MACRO_NESTING_MAX 32
   3930     MacroState macroState[MACRO_NESTING_MAX];
   3931     int macroLevel; // -1 means not playing any macro.
   3932 
   3933     int ch; // Current input character, or EOF
   3934     tokenid_t tok;      // token
   3935     intptr_t tokc;    // token extra info
   3936     double tokd;     // floating point constant value
   3937     int tokl;         // token operator level
   3938     intptr_t rsym; // return symbol
   3939     Type* pReturnType; // type of the current function's return.
   3940     intptr_t loc; // local variable index
   3941     char* glo;  // global variable index
   3942     String mTokenString;
   3943     bool mbSuppressMacroExpansion;
   3944     char* pGlobalBase;
   3945     ACCSymbolLookupFn mpSymbolLookupFn;
   3946     void* mpSymbolLookupContext;
   3947 
   3948     // Arena for the duration of the compile
   3949     Arena mGlobalArena;
   3950     // Arena for data that's only needed when compiling a single function
   3951     Arena mLocalArena;
   3952 
   3953     Arena* mpCurrentArena;
   3954 
   3955     TokenTable mTokenTable;
   3956     SymbolStack mGlobals;
   3957     SymbolStack mLocals;
   3958 
   3959     SymbolStack* mpCurrentSymbolStack;
   3960 
   3961     // Prebuilt types, makes things slightly faster.
   3962     Type* mkpInt;        // int
   3963     Type* mkpShort;      // short
   3964     Type* mkpChar;       // char
   3965     Type* mkpVoid;       // void
   3966     Type* mkpFloat;
   3967     Type* mkpDouble;
   3968     Type* mkpIntFn;
   3969     Type* mkpIntPtr;
   3970     Type* mkpCharPtr;
   3971     Type* mkpFloatPtr;
   3972     Type* mkpDoublePtr;
   3973     Type* mkpPtrIntFn;
   3974 
   3975     InputStream* file;
   3976     int mLineNumber;
   3977     bool mbBumpLine;
   3978 
   3979     ICodeBuf* pCodeBuf;
   3980     CodeGenerator* pGen;
   3981 
   3982     String mErrorBuf;
   3983 
   3984     String mPragmas;
   3985     int mPragmaStringCount;
   3986     int mCompileResult;
   3987 
   3988     static const int ALLOC_SIZE = 99999;
   3989 
   3990     static const int TOK_DUMMY = 1;
   3991     static const int TOK_NUM = 2;
   3992     static const int TOK_NUM_FLOAT = 3;
   3993     static const int TOK_NUM_DOUBLE = 4;
   3994     static const int TOK_OP_ASSIGNMENT = 5;
   3995     static const int TOK_OP_ARROW = 6;
   3996 
   3997     // 3..255 are character and/or operators
   3998 
   3999     // Keywords start at 0x100 and increase by 1
   4000     // Order has to match string list in "internKeywords".
   4001     enum {
   4002         TOK_KEYWORD = TokenTable::TOKEN_BASE,
   4003         TOK_INT = TOK_KEYWORD,
   4004         TOK_CHAR,
   4005         TOK_VOID,
   4006         TOK_IF,
   4007         TOK_ELSE,
   4008         TOK_WHILE,
   4009         TOK_BREAK,
   4010         TOK_RETURN,
   4011         TOK_FOR,
   4012         TOK_AUTO,
   4013         TOK_CASE,
   4014         TOK_CONST,
   4015         TOK_CONTINUE,
   4016         TOK_DEFAULT,
   4017         TOK_DO,
   4018         TOK_DOUBLE,
   4019         TOK_ENUM,
   4020         TOK_EXTERN,
   4021         TOK_FLOAT,
   4022         TOK_GOTO,
   4023         TOK_LONG,
   4024         TOK_REGISTER,
   4025         TOK_SHORT,
   4026         TOK_SIGNED,
   4027         TOK_SIZEOF,
   4028         TOK_STATIC,
   4029         TOK_STRUCT,
   4030         TOK_SWITCH,
   4031         TOK_TYPEDEF,
   4032         TOK_UNION,
   4033         TOK_UNSIGNED,
   4034         TOK_VOLATILE,
   4035         TOK__BOOL,
   4036         TOK__COMPLEX,
   4037         TOK__IMAGINARY,
   4038         TOK_INLINE,
   4039         TOK_RESTRICT,
   4040 
   4041         // Symbols start after keywords
   4042 
   4043         TOK_SYMBOL,
   4044         TOK_PRAGMA = TOK_SYMBOL,
   4045         TOK_DEFINE,
   4046         TOK_LINE
   4047     };
   4048 
   4049     static const int LOCAL = 0x200;
   4050 
   4051     /* tokens in string heap */
   4052     static const int TAG_TOK = ' ';
   4053 
   4054     static const int OP_INCREMENT = 0;
   4055     static const int OP_DECREMENT = 1;
   4056     static const int OP_MUL = 2;
   4057     static const int OP_DIV = 3;
   4058     static const int OP_MOD = 4;
   4059     static const int OP_PLUS = 5;
   4060     static const int OP_MINUS = 6;
   4061     static const int OP_SHIFT_LEFT = 7;
   4062     static const int OP_SHIFT_RIGHT = 8;
   4063     static const int OP_LESS_EQUAL = 9;
   4064     static const int OP_GREATER_EQUAL = 10;
   4065     static const int OP_LESS = 11;
   4066     static const int OP_GREATER = 12;
   4067     static const int OP_EQUALS = 13;
   4068     static const int OP_NOT_EQUALS = 14;
   4069     static const int OP_LOGICAL_AND = 15;
   4070     static const int OP_LOGICAL_OR = 16;
   4071     static const int OP_BIT_AND = 17;
   4072     static const int OP_BIT_XOR = 18;
   4073     static const int OP_BIT_OR = 19;
   4074     static const int OP_BIT_NOT = 20;
   4075     static const int OP_LOGICAL_NOT = 21;
   4076     static const int OP_COUNT = 22;
   4077 
   4078     /* Operators are searched from front, the two-character operators appear
   4079      * before the single-character operators with the same first character.
   4080      * @ is used to pad out single-character operators.
   4081      */
   4082     static const char* operatorChars;
   4083     static const char operatorLevel[];
   4084 
   4085     /* Called when we detect an internal problem. Does nothing in production.
   4086      *
   4087      */
   4088     void internalError() {
   4089         * (char*) 0 = 0;
   4090     }
   4091 
   4092     void assertImpl(bool isTrue, int line) {
   4093         if (!isTrue) {
   4094             LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
   4095             internalError();
   4096         }
   4097     }
   4098 
   4099     bool isSymbol(tokenid_t t) {
   4100         return t >= TOK_SYMBOL &&
   4101             ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
   4102     }
   4103 
   4104     bool isSymbolOrKeyword(tokenid_t t) {
   4105         return t >= TOK_KEYWORD &&
   4106             ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
   4107     }
   4108 
   4109     VariableInfo* VI(tokenid_t t) {
   4110         assert(isSymbol(t));
   4111         VariableInfo* pV = mTokenTable[t].mpVariableInfo;
   4112         if (pV && pV->tok != t) {
   4113             internalError();
   4114         }
   4115         return pV;
   4116     }
   4117 
   4118     inline bool isDefined(tokenid_t t) {
   4119         return t >= TOK_SYMBOL && VI(t) != 0;
   4120     }
   4121 
   4122     const char* nameof(tokenid_t t) {
   4123         assert(isSymbolOrKeyword(t));
   4124         return mTokenTable[t].pText;
   4125     }
   4126 
   4127     void pdef(int t) {
   4128         mTokenString.append(t);
   4129     }
   4130 
   4131     void inp() {
   4132         // Close any totally empty macros. We leave them on the stack until now
   4133         // so that we know which macros are being expanded when checking if the
   4134         // last token in the macro is a macro that's already being expanded.
   4135         while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
   4136             macroLevel--;
   4137         }
   4138         if (macroLevel >= 0) {
   4139             ch = *macroState[macroLevel].dptr++;
   4140             if (ch == 0) {
   4141                 ch = macroState[macroLevel].dch;
   4142                 macroState[macroLevel].dptr = NULL; // This macro's done
   4143             }
   4144         } else {
   4145             if (mbBumpLine) {
   4146                 mLineNumber++;
   4147                 mbBumpLine = false;
   4148             }
   4149             ch = file->getChar();
   4150             if (ch == '\n') {
   4151                 mbBumpLine = true;
   4152             }
   4153         }
   4154 #if 0
   4155         printf("ch='%c' 0x%x\n", ch, ch);
   4156 #endif
   4157     }
   4158 
   4159     int isid() {
   4160         return isalnum(ch) | (ch == '_');
   4161     }
   4162 
   4163     int decodeHex(int c) {
   4164         if (isdigit(c)) {
   4165             c -= '0';
   4166         } else if (c <= 'F') {
   4167             c = c - 'A' + 10;
   4168         } else {
   4169             c =c - 'a' + 10;
   4170         }
   4171         return c;
   4172     }
   4173 
   4174     /* read a character constant, advances ch to after end of constant */
   4175     int getq() {
   4176         int val = ch;
   4177         if (ch == '\\') {
   4178             inp();
   4179             if (isoctal(ch)) {
   4180                 // 1 to 3 octal characters.
   4181                 val = 0;
   4182                 for(int i = 0; i < 3; i++) {
   4183                     if (isoctal(ch)) {
   4184                         val = (val << 3) + ch - '0';
   4185                         inp();
   4186                     }
   4187                 }
   4188                 return val;
   4189             } else if (ch == 'x' || ch == 'X') {
   4190                 // N hex chars
   4191                 inp();
   4192                 if (! isxdigit(ch)) {
   4193                     error("'x' character escape requires at least one digit.");
   4194                 } else {
   4195                     val = 0;
   4196                     while (isxdigit(ch)) {
   4197                         val = (val << 4) + decodeHex(ch);
   4198                         inp();
   4199                     }
   4200                 }
   4201             } else {
   4202                 int val = ch;
   4203                 switch (ch) {
   4204                     case 'a':
   4205                         val = '\a';
   4206                         break;
   4207                     case 'b':
   4208                         val = '\b';
   4209                         break;
   4210                     case 'f':
   4211                         val = '\f';
   4212                         break;
   4213                     case 'n':
   4214                         val = '\n';
   4215                         break;
   4216                     case 'r':
   4217                         val = '\r';
   4218                         break;
   4219                     case 't':
   4220                         val = '\t';
   4221                         break;
   4222                     case 'v':
   4223                         val = '\v';
   4224                         break;
   4225                     case '\\':
   4226                         val = '\\';
   4227                         break;
   4228                     case '\'':
   4229                         val = '\'';
   4230                         break;
   4231                     case '"':
   4232                         val = '"';
   4233                         break;
   4234                     case '?':
   4235                         val = '?';
   4236                         break;
   4237                     default:
   4238                         error("Undefined character escape %c", ch);
   4239                         break;
   4240                 }
   4241                 inp();
   4242                 return val;
   4243             }
   4244         } else {
   4245             inp();
   4246         }
   4247         return val;
   4248     }
   4249 
   4250     static bool isoctal(int ch) {
   4251         return ch >= '0' && ch <= '7';
   4252     }
   4253 
   4254     bool acceptCh(int c) {
   4255         bool result = c == ch;
   4256         if (result) {
   4257             pdef(ch);
   4258             inp();
   4259         }
   4260         return result;
   4261     }
   4262 
   4263     bool acceptDigitsCh() {
   4264         bool result = false;
   4265         while (isdigit(ch)) {
   4266             result = true;
   4267             pdef(ch);
   4268             inp();
   4269         }
   4270         return result;
   4271     }
   4272 
   4273     void parseFloat() {
   4274         tok = TOK_NUM_DOUBLE;
   4275         // mTokenString already has the integral part of the number.
   4276         if(mTokenString.len() == 0) {
   4277             mTokenString.append('0');
   4278         }
   4279         acceptCh('.');
   4280         acceptDigitsCh();
   4281         if (acceptCh('e') || acceptCh('E')) {
   4282             acceptCh('-') || acceptCh('+');
   4283             acceptDigitsCh();
   4284         }
   4285         if (ch == 'f' || ch == 'F') {
   4286             tok = TOK_NUM_FLOAT;
   4287             inp();
   4288         } else if (ch == 'l' || ch == 'L') {
   4289             inp();
   4290             error("Long floating point constants not supported.");
   4291         }
   4292         char* pText = mTokenString.getUnwrapped();
   4293         char* pEnd = pText + strlen(pText);
   4294         char* pEndPtr = 0;
   4295         errno = 0;
   4296         if (tok == TOK_NUM_FLOAT) {
   4297             tokd = strtof(pText, &pEndPtr);
   4298         } else {
   4299             tokd = strtod(pText, &pEndPtr);
   4300         }
   4301         if (errno || pEndPtr != pEnd) {
   4302             error("Can't parse constant: %s", pText);
   4303         }
   4304         // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
   4305     }
   4306 
   4307     bool currentlyBeingExpanded(tokenid_t id) {
   4308         for (int i = 0; i <= macroLevel; i++) {
   4309             if (macroState[macroLevel].name == id) {
   4310                 return true;
   4311             }
   4312         }
   4313         return false;
   4314     }
   4315 
   4316     void next() {
   4317         int l, a;
   4318 
   4319         while (isspace(ch) | (ch == '#')) {
   4320             if (ch == '#') {
   4321                 inp();
   4322                 next();
   4323                 if (tok == TOK_DEFINE) {
   4324                     doDefine();
   4325                 } else if (tok == TOK_PRAGMA) {
   4326                     doPragma();
   4327                 } else if (tok == TOK_LINE) {
   4328                     doLine();
   4329                 } else {
   4330                     error("Unsupported preprocessor directive \"%s\"",
   4331                           mTokenString.getUnwrapped());
   4332                 }
   4333             }
   4334             inp();
   4335         }
   4336         tokl = 0;
   4337         tok = ch;
   4338         /* encode identifiers & numbers */
   4339         if (isdigit(ch) || ch == '.') {
   4340             // Start of a numeric constant. Could be integer, float, or
   4341             // double, won't know until we look further.
   4342             mTokenString.clear();
   4343             pdef(ch);
   4344             inp();
   4345             if (tok == '.' && !isdigit(ch)) {
   4346                 goto done;
   4347             }
   4348             int base = 10;
   4349             if (tok == '0') {
   4350                 if (ch == 'x' || ch == 'X') {
   4351                     base = 16;
   4352                     tok = TOK_NUM;
   4353                     tokc = 0;
   4354                     inp();
   4355                     while ( isxdigit(ch) ) {
   4356                         tokc = (tokc << 4) + decodeHex(ch);
   4357                         inp();
   4358                     }
   4359                 } else if (isoctal(ch)){
   4360                     base = 8;
   4361                     tok = TOK_NUM;
   4362                     tokc = 0;
   4363                     while ( isoctal(ch) ) {
   4364                         tokc = (tokc << 3) + (ch - '0');
   4365                         inp();
   4366                     }
   4367                 }
   4368             } else if (isdigit(tok)){
   4369                 acceptDigitsCh();
   4370             }
   4371             if (base == 10) {
   4372                 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
   4373                     parseFloat();
   4374                 } else {
   4375                     // It's an integer constant
   4376                     char* pText = mTokenString.getUnwrapped();
   4377                     char* pEnd = pText + strlen(pText);
   4378                     char* pEndPtr = 0;
   4379                     errno = 0;
   4380                     tokc = strtol(pText, &pEndPtr, base);
   4381                     if (errno || pEndPtr != pEnd) {
   4382                         error("Can't parse constant: %s %d %d", pText, base, errno);
   4383                     }
   4384                     tok = TOK_NUM;
   4385                 }
   4386             }
   4387         } else if (isid()) {
   4388             mTokenString.clear();
   4389             while (isid()) {
   4390                 pdef(ch);
   4391                 inp();
   4392             }
   4393             tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
   4394             if (! mbSuppressMacroExpansion) {
   4395                 // Is this a macro?
   4396                 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
   4397                 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
   4398                     // Yes, it is a macro
   4399 #if 0
   4400                     printf("Expanding macro %s -> %s",
   4401                             mTokenString.getUnwrapped(), pMacroDefinition);
   4402 #endif
   4403                     if (macroLevel >= MACRO_NESTING_MAX-1) {
   4404                         error("Too many levels of macro recursion.");
   4405                     } else {
   4406                         macroLevel++;
   4407                         macroState[macroLevel].name = tok;
   4408                         macroState[macroLevel].dptr = pMacroDefinition;
   4409                         macroState[macroLevel].dch = ch;
   4410                         inp();
   4411                         next();
   4412                     }
   4413                 }
   4414             }
   4415         } else {
   4416             inp();
   4417             if (tok == '\'') {
   4418                 tok = TOK_NUM;
   4419                 tokc = getq();
   4420                 if (ch != '\'') {
   4421                     error("Expected a ' character, got %c", ch);
   4422                 } else {
   4423                   inp();
   4424                 }
   4425             } else if ((tok == '/') & (ch == '*')) {
   4426                 inp();
   4427                 while (ch && ch != EOF) {
   4428                     while (ch != '*' && ch != EOF)
   4429                         inp();
   4430                     inp();
   4431                     if (ch == '/')
   4432                         ch = 0;
   4433                 }
   4434                 if (ch == EOF) {
   4435                     error("End of file inside comment.");
   4436                 }
   4437                 inp();
   4438                 next();
   4439             } else if ((tok == '/') & (ch == '/')) {
   4440                 inp();
   4441                 while (ch && (ch != '\n') && (ch != EOF)) {
   4442                     inp();
   4443                 }
   4444                 inp();
   4445                 next();
   4446             } else if ((tok == '-') & (ch == '>')) {
   4447                 inp();
   4448                 tok = TOK_OP_ARROW;
   4449             } else {
   4450                 const char* t = operatorChars;
   4451                 int opIndex = 0;
   4452                 while ((l = *t++) != 0) {
   4453                     a = *t++;
   4454                     tokl = operatorLevel[opIndex];
   4455                     tokc = opIndex;
   4456                     if ((l == tok) & ((a == ch) | (a == '@'))) {
   4457 #if 0
   4458                         printf("%c%c -> tokl=%d tokc=0x%x\n",
   4459                                 l, a, tokl, tokc);
   4460 #endif
   4461                         if (a == ch) {
   4462                             inp();
   4463                             tok = TOK_DUMMY; /* dummy token for double tokens */
   4464                         }
   4465                         /* check for op=, valid for * / % + - << >> & ^ | */
   4466                         if (ch == '=' &&
   4467                                 ((tokl >= 1 && tokl <= 3)
   4468                                         || (tokl >=6 && tokl <= 8)) ) {
   4469                             inp();
   4470                             tok = TOK_OP_ASSIGNMENT;
   4471                         }
   4472                         break;
   4473                     }
   4474                     opIndex++;
   4475                 }
   4476                 if (l == 0) {
   4477                     tokl = 0;
   4478                     tokc = 0;
   4479                 }
   4480             }
   4481         }
   4482 
   4483     done: ;
   4484 #if 0
   4485         {
   4486             String buf;
   4487             decodeToken(buf, tok, true);
   4488             fprintf(stderr, "%s\n", buf.getUnwrapped());
   4489         }
   4490 #endif
   4491     }
   4492 
   4493     void doDefine() {
   4494         mbSuppressMacroExpansion = true;
   4495         next();
   4496         mbSuppressMacroExpansion = false;
   4497         tokenid_t name = tok;
   4498         if (ch == '(') {
   4499             error("Defines with arguments not supported");
   4500             return;
   4501         }
   4502         while (isspace(ch)) {
   4503             inp();
   4504         }
   4505         String value;
   4506         bool appendToValue = true;
   4507         while (ch != '\n' && ch != EOF) {
   4508             // Check for '//' comments.
   4509             if (appendToValue && ch == '/') {
   4510                 inp();
   4511                 if (ch == '/') {
   4512                     appendToValue = false;
   4513                 } else {
   4514                     value.append('/');
   4515                 }
   4516             }
   4517             if (appendToValue && ch != EOF) {
   4518                 value.append(ch);
   4519             }
   4520             inp();
   4521         }
   4522         char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
   4523         memcpy(pDefn, value.getUnwrapped(), value.len());
   4524         pDefn[value.len()] = 0;
   4525         mTokenTable[name].mpMacroDefinition = pDefn;
   4526 #if 0
   4527         {
   4528             String buf;
   4529             decodeToken(buf, name, true);
   4530             fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
   4531         }
   4532 #endif
   4533     }
   4534 
   4535     void doPragma() {
   4536         // # pragma name(val)
   4537         int state = 0;
   4538         while(ch != EOF && ch != '\n' && state < 10) {
   4539             switch(state) {
   4540                 case 0:
   4541                     if (isspace(ch)) {
   4542                         inp();
   4543                     } else {
   4544                         state++;
   4545                     }
   4546                     break;
   4547                 case 1:
   4548                     if (isalnum(ch)) {
   4549                         mPragmas.append(ch);
   4550                         inp();
   4551                     } else if (ch == '(') {
   4552                         mPragmas.append(0);
   4553                         inp();
   4554                         state++;
   4555                     } else {
   4556                         state = 11;
   4557                     }
   4558                     break;
   4559                 case 2:
   4560                     if (isalnum(ch)) {
   4561                         mPragmas.append(ch);
   4562                         inp();
   4563                     } else if (ch == ')') {
   4564                         mPragmas.append(0);
   4565                         inp();
   4566                         state = 10;
   4567                     } else {
   4568                         state = 11;
   4569                     }
   4570                     break;
   4571             }
   4572         }
   4573         if(state != 10) {
   4574             error("Unexpected pragma syntax");
   4575         }
   4576         mPragmaStringCount += 2;
   4577     }
   4578 
   4579     void doLine() {
   4580         // # line number { "filename "}
   4581         next();
   4582         if (tok != TOK_NUM) {
   4583             error("Expected a line-number");
   4584         } else {
   4585             mLineNumber = tokc-1; // The end-of-line will increment it.
   4586         }
   4587         while(ch != EOF && ch != '\n') {
   4588             inp();
   4589         }
   4590     }
   4591 
   4592     virtual void verror(const char* fmt, va_list ap) {
   4593         mErrorBuf.printf("%ld: ", mLineNumber);
   4594         mErrorBuf.vprintf(fmt, ap);
   4595         mErrorBuf.printf("\n");
   4596     }
   4597 
   4598     void skip(intptr_t c) {
   4599         if (!accept(c)) {
   4600             error("'%c' expected", c);
   4601         }
   4602     }
   4603 
   4604     bool accept(intptr_t c) {
   4605         if (tok == c) {
   4606             next();
   4607             return true;
   4608         }
   4609         return false;
   4610     }
   4611 
   4612     bool acceptStringLiteral() {
   4613         if (tok == '"') {
   4614             pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
   4615             // This while loop merges multiple adjacent string constants.
   4616             while (tok == '"') {
   4617                 while (ch != '"' && ch != EOF) {
   4618                     *allocGlobalSpace(1,1) = getq();
   4619                 }
   4620                 if (ch != '"') {
   4621                     error("Unterminated string constant.");
   4622                 }
   4623                 inp();
   4624                 next();
   4625             }
   4626             /* Null terminate */
   4627             *glo = 0;
   4628             /* align heap */
   4629             allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
   4630 
   4631             return true;
   4632         }
   4633         return false;
   4634     }
   4635 
   4636     void linkGlobal(tokenid_t t, bool isFunction) {
   4637         VariableInfo* pVI = VI(t);
   4638         void* n = NULL;
   4639         if (mpSymbolLookupFn) {
   4640             n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
   4641         }
   4642         if (pVI->pType == NULL) {
   4643             if (isFunction) {
   4644                 pVI->pType = mkpIntFn;
   4645             } else {
   4646                 pVI->pType = mkpInt;
   4647             }
   4648         }
   4649         pVI->pAddress = n;
   4650     }
   4651 
   4652     void unaryOrAssignment() {
   4653         unary();
   4654         if (accept('=')) {
   4655             checkLVal();
   4656             pGen->pushR0();
   4657             expr();
   4658             pGen->forceR0RVal();
   4659             pGen->storeR0ToTOS();
   4660         } else if (tok == TOK_OP_ASSIGNMENT) {
   4661             int t = tokc;
   4662             next();
   4663             checkLVal();
   4664             pGen->pushR0();
   4665             pGen->forceR0RVal();
   4666             pGen->pushR0();
   4667             expr();
   4668             pGen->forceR0RVal();
   4669             pGen->genOp(t);
   4670             pGen->storeR0ToTOS();
   4671         }
   4672     }
   4673 
   4674     /* Parse and evaluate a unary expression.
   4675      */
   4676     void unary() {
   4677         tokenid_t t;
   4678         intptr_t a;
   4679         t = 0;
   4680         if (acceptStringLiteral()) {
   4681             // Nothing else to do.
   4682         } else {
   4683             int c = tokl;
   4684             a = tokc;
   4685             double ad = tokd;
   4686             t = tok;
   4687             next();
   4688             if (t == TOK_NUM) {
   4689                 pGen->li(a);
   4690             } else if (t == TOK_NUM_FLOAT) {
   4691                 // Align to 4-byte boundary
   4692                 glo = (char*) (((intptr_t) glo + 3) & -4);
   4693                 * (float*) glo = (float) ad;
   4694                 pGen->loadFloat((int) glo, mkpFloat);
   4695                 glo += 4;
   4696             } else if (t == TOK_NUM_DOUBLE) {
   4697                 // Align to 8-byte boundary
   4698                 glo = (char*) (((intptr_t) glo + 7) & -8);
   4699                 * (double*) glo = ad;
   4700                 pGen->loadFloat((int) glo, mkpDouble);
   4701                 glo += 8;
   4702             } else if (c == 2) {
   4703                 /* -, +, !, ~ */
   4704                 unary();
   4705                 pGen->forceR0RVal();
   4706                 if (t == '!')
   4707                     pGen->gUnaryCmp(a);
   4708                 else if (t == '+') {
   4709                     // ignore unary plus.
   4710                 } else {
   4711                     pGen->genUnaryOp(a);
   4712                 }
   4713             } else if (c == 11) {
   4714                 // pre increment / pre decrement
   4715                 unary();
   4716                 doIncDec(a == OP_INCREMENT, 0);
   4717             }
   4718             else if (t == '(') {
   4719                 // It's either a cast or an expression
   4720                 Type* pCast = acceptCastTypeDeclaration();
   4721                 if (pCast) {
   4722                     skip(')');
   4723                     unary();
   4724                     pGen->forceR0RVal();
   4725                     pGen->castR0(pCast);
   4726                 } else {
   4727                     commaExpr();
   4728                     skip(')');
   4729                 }
   4730             } else if (t == '*') {
   4731                 /* This is a pointer dereference.
   4732                  */
   4733                 unary();
   4734                 doPointer();
   4735             } else if (t == '&') {
   4736                 unary();
   4737                 doAddressOf();
   4738             } else if (t == EOF ) {
   4739                 error("Unexpected EOF.");
   4740             } else if (t == ';') {
   4741                 error("Unexpected ';'");
   4742             } else if (!checkSymbol(t)) {
   4743                 // Don't have to do anything special here, the error
   4744                 // message was printed by checkSymbol() above.
   4745             } else {
   4746                 if (!isDefined(t)) {
   4747                     mGlobals.add(t);
   4748                     // printf("Adding new global function %s\n", nameof(t));
   4749                 }
   4750                 VariableInfo* pVI = VI(t);
   4751                 int n = (intptr_t) pVI->pAddress;
   4752                 /* forward reference: try our lookup function */
   4753                 if (!n) {
   4754                     linkGlobal(t, tok == '(');
   4755                     n = (intptr_t) pVI->pAddress;
   4756                     if (!n && tok != '(') {
   4757                         error("Undeclared variable %s", nameof(t));
   4758                     }
   4759                 }
   4760                 if (tok != '(') {
   4761                     /* variable or function name */
   4762                     if (!n) {
   4763                         linkGlobal(t, false);
   4764                         n = (intptr_t) pVI->pAddress;
   4765                         if (!n) {
   4766                             error("Undeclared variable %s", nameof(t));
   4767                         }
   4768                     }
   4769                 }
   4770                 // load a variable
   4771                 Type* pVal;
   4772                 ExpressionType et;
   4773                 if (pVI->pType->tag == TY_ARRAY) {
   4774                     pVal = pVI->pType;
   4775                     et = ET_RVALUE;
   4776                 } else {
   4777                     pVal = createPtrType(pVI->pType);
   4778                     et = ET_LVALUE;
   4779                 }
   4780                 if (n) {
   4781                     int tag = pVal->pHead->tag;
   4782                     if (tag == TY_FUNC) {
   4783                         et = ET_RVALUE;
   4784                     }
   4785                     pGen->leaR0(n, pVal, et);
   4786                 } else {
   4787                     pVI->pForward = (void*) pGen->leaForward(
   4788                             (int) pVI->pForward, pVal);
   4789                 }
   4790             }
   4791         }
   4792 
   4793         /* Now handle postfix operators */
   4794         for(;;) {
   4795             if (tokl == 11) {
   4796                 // post inc / post dec
   4797                 doIncDec(tokc == OP_INCREMENT, true);
   4798                 next();
   4799             } else if (accept('[')) {
   4800                 // Array reference
   4801                 pGen->forceR0RVal();
   4802                 pGen->pushR0();
   4803                 commaExpr();
   4804                 pGen->forceR0RVal();
   4805                 pGen->genOp(OP_PLUS);
   4806                 doPointer();
   4807                 skip(']');
   4808             } else if (accept('.')) {
   4809                 // struct element
   4810                 pGen->forceR0RVal();
   4811                 Type* pStruct = pGen->getR0Type();
   4812                 if (pStruct->tag == TY_STRUCT) {
   4813                     doStructMember(pStruct, true);
   4814                 } else {
   4815                     error("expected a struct value to the left of '.'");
   4816                 }
   4817             } else if (accept(TOK_OP_ARROW)) {
   4818                 pGen->forceR0RVal();
   4819                 Type* pPtr = pGen->getR0Type();
   4820                 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
   4821                     pGen->loadR0FromR0();
   4822                     doStructMember(pPtr->pHead, false);
   4823                 } else {
   4824                     error("Expected a pointer to a struct to the left of '->'");
   4825                 }
   4826             } else  if (accept('(')) {
   4827                 /* function call */
   4828                 Type* pDecl = NULL;
   4829                 VariableInfo* pVI = NULL;
   4830                 Type* pFn = pGen->getR0Type();
   4831                 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
   4832                     pDecl = pFn->pHead;
   4833                     pGen->pushR0();
   4834                     Type* pArgList = pDecl->pTail;
   4835                     bool varArgs = pArgList == NULL;
   4836                     /* push args and invert order */
   4837                     a = pGen->beginFunctionCallArguments();
   4838                     int l = 0;
   4839                     int argCount = 0;
   4840                     while (tok != ')' && tok != EOF) {
   4841                         if (! varArgs && !pArgList) {
   4842                             error("Unexpected argument.");
   4843                         }
   4844                         expr();
   4845                         pGen->forceR0RVal();
   4846                         Type* pTargetType;
   4847                         if (pArgList) {
   4848                             pTargetType = pArgList->pHead;
   4849                             pArgList = pArgList->pTail;
   4850                         } else {
   4851                             // This is a ... function, just pass arguments in their
   4852                             // natural type.
   4853                             pTargetType = pGen->getR0Type();
   4854                             if (pTargetType->tag == TY_FLOAT) {
   4855                                 pTargetType = mkpDouble;
   4856                             } else if (pTargetType->tag == TY_ARRAY) {
   4857                                 // Pass arrays by pointer.
   4858                                 pTargetType = pTargetType->pTail;
   4859                             }
   4860                         }
   4861                         if (pTargetType->tag == TY_VOID) {
   4862                             error("Can't pass void value for argument %d",
   4863                                   argCount + 1);
   4864                         } else {
   4865                             l += pGen->storeR0ToArg(l, pTargetType);
   4866                         }
   4867                         if (accept(',')) {
   4868                             // fine
   4869                         } else if ( tok != ')') {
   4870                             error("Expected ',' or ')'");
   4871                         }
   4872                         argCount += 1;
   4873                     }
   4874                     if (! varArgs && pArgList) {
   4875                         error("Expected more argument(s). Saw %d", argCount);
   4876                     }
   4877                     pGen->endFunctionCallArguments(pDecl, a, l);
   4878                     skip(')');
   4879                     pGen->callIndirect(l, pDecl);
   4880                     pGen->adjustStackAfterCall(pDecl, l, true);
   4881                 } else {
   4882                     error("Expected a function value to left of '('.");
   4883                 }
   4884             } else {
   4885                 break;
   4886             }
   4887         }
   4888     }
   4889 
   4890     void doStructMember(Type* pStruct, bool isDot) {
   4891         Type* pStructElement = lookupStructMember(pStruct, tok);
   4892         if (pStructElement) {
   4893             next();
   4894             pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
   4895         } else {
   4896             String buf;
   4897             decodeToken(buf, tok, true);
   4898             error("Expected a struct member to the right of '%s', got %s",
   4899                     isDot ? "." : "->", buf.getUnwrapped());
   4900         }
   4901     }
   4902 
   4903     void doIncDec(int isInc, int isPost) {
   4904         // R0 already has the lval
   4905         checkLVal();
   4906         int lit = isInc ? 1 : -1;
   4907         pGen->pushR0();
   4908         pGen->loadR0FromR0();
   4909         int tag = pGen->getR0Type()->tag;
   4910         if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
   4911                 tag == TY_POINTER)) {
   4912             error("++/-- illegal for this type. %d", tag);
   4913         }
   4914         if (isPost) {
   4915             pGen->over();
   4916             pGen->pushR0();
   4917             pGen->li(lit);
   4918             pGen->genOp(OP_PLUS);
   4919             pGen->storeR0ToTOS();
   4920             pGen->popR0();
   4921         } else {
   4922             pGen->pushR0();
   4923             pGen->li(lit);
   4924             pGen->genOp(OP_PLUS);
   4925             pGen->over();
   4926             pGen->storeR0ToTOS();
   4927             pGen->popR0();
   4928         }
   4929     }
   4930 
   4931     void doPointer() {
   4932         pGen->forceR0RVal();
   4933         Type* pR0Type = pGen->getR0Type();
   4934         if (pR0Type->tag != TY_POINTER) {
   4935             error("Expected a pointer type.");
   4936         } else {
   4937             if (pR0Type->pHead->tag != TY_FUNC) {
   4938                 pGen->setR0ExpressionType(ET_LVALUE);
   4939             }
   4940         }
   4941     }
   4942 
   4943     void doAddressOf() {
   4944         Type* pR0 = pGen->getR0Type();
   4945         bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
   4946         if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
   4947             error("Expected an lvalue");
   4948         }
   4949         Type* pR0Type = pGen->getR0Type();
   4950         pGen->setR0ExpressionType(ET_RVALUE);
   4951     }
   4952 
   4953     /* Recursive descent parser for binary operations.
   4954      */
   4955     void binaryOp(int level) {
   4956         intptr_t t, a;
   4957         t = 0;
   4958         if (level-- == 1)
   4959             unaryOrAssignment();
   4960         else {
   4961             binaryOp(level);
   4962             a = 0;
   4963             while (level == tokl) {
   4964                 t = tokc;
   4965                 next();
   4966                 pGen->forceR0RVal();
   4967                 if (level > 8) {
   4968                     a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
   4969                     binaryOp(level);
   4970                 } else {
   4971                     pGen->pushR0();
   4972                     binaryOp(level);
   4973                     // Check for syntax error.
   4974                     if (pGen->getR0Type() == NULL) {
   4975                         // We failed to parse a right-hand argument.
   4976                         // Push a dummy value so we don't fail
   4977                         pGen->li(0);
   4978                     }
   4979                     pGen->forceR0RVal();
   4980                     if ((level == 4) | (level == 5)) {
   4981                         pGen->gcmp(t);
   4982                     } else {
   4983                         pGen->genOp(t);
   4984                     }
   4985                 }
   4986             }
   4987             /* && and || output code generation */
   4988             if (a && level > 8) {
   4989                 pGen->forceR0RVal();
   4990                 a = pGen->gtst(t == OP_LOGICAL_OR, a);
   4991                 pGen->li(t != OP_LOGICAL_OR);
   4992                 int b = pGen->gjmp(0);
   4993                 pGen->gsym(a);
   4994                 pGen->li(t == OP_LOGICAL_OR);
   4995                 pGen->gsym(b);
   4996             }
   4997         }
   4998     }
   4999 
   5000     void commaExpr() {
   5001         for(;;) {
   5002             expr();
   5003             if (!accept(',')) {
   5004                 break;
   5005             }
   5006         }
   5007     }
   5008 
   5009     void expr() {
   5010         binaryOp(11);
   5011     }
   5012 
   5013     int test_expr() {
   5014         commaExpr();
   5015         pGen->forceR0RVal();
   5016         return pGen->gtst(0, 0);
   5017     }
   5018 
   5019     void block(intptr_t* breakLabel, intptr_t continueAddress, bool outermostFunctionBlock) {
   5020         intptr_t a, n, t;
   5021 
   5022         Type* pBaseType;
   5023         if ((pBaseType = acceptPrimitiveType(true))) {
   5024             /* declarations */
   5025             localDeclarations(pBaseType);
   5026         } else if (tok == TOK_IF) {
   5027             next();
   5028             skip('(');
   5029             a = test_expr();
   5030             skip(')');
   5031             block(breakLabel, continueAddress, false);
   5032             if (tok == TOK_ELSE) {
   5033                 next();
   5034                 n = pGen->gjmp(0); /* jmp */
   5035                 pGen->gsym(a);
   5036                 block(breakLabel, continueAddress, false);
   5037                 pGen->gsym(n); /* patch else jmp */
   5038             } else {
   5039                 pGen->gsym(a); /* patch if test */
   5040             }
   5041         } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
   5042             t = tok;
   5043             next();
   5044             skip('(');
   5045             if (t == TOK_WHILE) {
   5046                 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
   5047                 a = test_expr();
   5048             } else {
   5049                 if (tok != ';')
   5050                     commaExpr();
   5051                 skip(';');
   5052                 n = pCodeBuf->getPC();
   5053                 a = 0;
   5054                 if (tok != ';')
   5055                     a = test_expr();
   5056                 skip(';');
   5057                 if (tok != ')') {
   5058                     t = pGen->gjmp(0);
   5059                     commaExpr();
   5060                     pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
   5061                     pGen->gsym(t);
   5062                     n = t + 4;
   5063                 }
   5064             }
   5065             skip(')');
   5066             block(&a, n, false);
   5067             pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
   5068             pGen->gsym(a);
   5069         } else if (tok == '{') {
   5070             if (! outermostFunctionBlock) {
   5071                 mLocals.pushLevel();
   5072             }
   5073             next();
   5074             while (tok != '}' && tok != EOF)
   5075                 block(breakLabel, continueAddress, false);
   5076             skip('}');
   5077             if (! outermostFunctionBlock) {
   5078                 mLocals.popLevel();
   5079             }
   5080         } else {
   5081             if (accept(TOK_RETURN)) {
   5082                 if (tok != ';') {
   5083                     commaExpr();
   5084                     pGen->forceR0RVal();
   5085                     if (pReturnType->tag == TY_VOID) {
   5086                         error("Must not return a value from a void function");
   5087                     } else {
   5088                         pGen->convertR0(pReturnType);
   5089                     }
   5090                 } else {
   5091                     if (pReturnType->tag != TY_VOID) {
   5092                         error("Must specify a value here");
   5093                     }
   5094                 }
   5095                 rsym = pGen->gjmp(rsym); /* jmp */
   5096             } else if (accept(TOK_BREAK)) {
   5097                 if (breakLabel) {
   5098                     *breakLabel = pGen->gjmp(*breakLabel);
   5099                 } else {
   5100                     error("break statement must be within a for, do, while, or switch statement");
   5101                 }
   5102             } else if (accept(TOK_CONTINUE)) {
   5103                 if (continueAddress) {
   5104                     pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset());
   5105                 } else {
   5106                     error("continue statement must be within a for, do, or while statement");
   5107                 }
   5108             } else if (tok != ';')
   5109                 commaExpr();
   5110             skip(';');
   5111         }
   5112     }
   5113 
   5114     static bool typeEqual(Type* a, Type* b) {
   5115         if (a == b) {
   5116             return true;
   5117         }
   5118         if (a == NULL || b == NULL) {
   5119             return false;
   5120         }
   5121         TypeTag at = a->tag;
   5122         if (at != b->tag) {
   5123             return false;
   5124         }
   5125         if (at == TY_POINTER) {
   5126             return typeEqual(a->pHead, b->pHead);
   5127         } else if (at == TY_ARRAY) {
   5128             return a->length == b->length && typeEqual(a->pHead, b->pHead);
   5129         } else if (at == TY_FUNC || at == TY_PARAM) {
   5130             return typeEqual(a->pHead, b->pHead)
   5131                 && typeEqual(a->pTail, b->pTail);
   5132         } else if (at == TY_STRUCT) {
   5133             return a->pHead == b->pHead;
   5134         }
   5135         return true;
   5136     }
   5137 
   5138     Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
   5139         assert(tag >= TY_UNKNOWN && tag <= TY_PARAM);
   5140         Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
   5141         memset(pType, 0, sizeof(*pType));
   5142         pType->storageClass = SC_DEFAULT;
   5143         pType->tag = tag;
   5144         pType->pHead = pHead;
   5145         pType->pTail = pTail;
   5146         return pType;
   5147     }
   5148 
   5149     Type* createPtrType(Type* pType) {
   5150         return createType(TY_POINTER, pType, NULL);
   5151     }
   5152 
   5153     /**
   5154      * Try to print a type in declaration order
   5155      */
   5156     void decodeType(String& buffer, Type* pType) {
   5157         buffer.clear();
   5158         if (pType == NULL) {
   5159             buffer.appendCStr("null");
   5160             return;
   5161         }
   5162         decodeTypeImp(buffer, pType);
   5163     }
   5164 
   5165     void decodeTypeImp(String& buffer, Type* pType) {
   5166         decodeTypeImpPrefix(buffer, pType);
   5167         decodeId(buffer, pType->id);
   5168         decodeTypeImpPostfix(buffer, pType);
   5169     }
   5170 
   5171     void decodeId(String& buffer, tokenid_t id) {
   5172         if (id) {
   5173             String temp;
   5174             decodeToken(temp, id, false);
   5175             buffer.append(temp);
   5176         }
   5177     }
   5178 
   5179     void decodeTypeImpPrefix(String& buffer, Type* pType) {
   5180         TypeTag tag = pType->tag;
   5181 
   5182         if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
   5183             switch (tag) {
   5184                 case TY_INT:
   5185                     buffer.appendCStr("int");
   5186                     break;
   5187                 case TY_SHORT:
   5188                     buffer.appendCStr("short");
   5189                     break;
   5190                 case TY_CHAR:
   5191                     buffer.appendCStr("char");
   5192                     break;
   5193                 case TY_VOID:
   5194                     buffer.appendCStr("void");
   5195                     break;
   5196                 case TY_FLOAT:
   5197                     buffer.appendCStr("float");
   5198                     break;
   5199                 case TY_DOUBLE:
   5200                     buffer.appendCStr("double");
   5201                     break;
   5202                 case TY_STRUCT:
   5203                 {
   5204                     bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
   5205                     buffer.appendCStr(isStruct ? "struct" : "union");
   5206                     if (pType->pHead && pType->pHead->structTag) {
   5207                         buffer.append(' ');
   5208                         decodeId(buffer, pType->pHead->structTag);
   5209                     }
   5210                 }
   5211                     break;
   5212                 default:
   5213                     break;
   5214             }
   5215             buffer.append(' ');
   5216         }
   5217 
   5218         switch (tag) {
   5219             case TY_INT:
   5220                 break;
   5221             case TY_SHORT:
   5222                 break;
   5223             case TY_CHAR:
   5224                 break;
   5225             case TY_VOID:
   5226                  break;
   5227             case TY_FLOAT:
   5228                  break;
   5229             case TY_DOUBLE:
   5230                 break;
   5231             case TY_POINTER:
   5232                 decodeTypeImpPrefix(buffer, pType->pHead);
   5233                 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
   5234                     buffer.append('(');
   5235                 }
   5236                 buffer.append('*');
   5237                 break;
   5238             case TY_ARRAY:
   5239                 decodeTypeImpPrefix(buffer, pType->pHead);
   5240                 break;
   5241             case TY_STRUCT:
   5242                 break;
   5243             case TY_FUNC:
   5244                 decodeTypeImp(buffer, pType->pHead);
   5245                 break;
   5246             case TY_PARAM:
   5247                 decodeTypeImp(buffer, pType->pHead);
   5248                 break;
   5249             default:
   5250                 String temp;
   5251                 temp.printf("Unknown tag %d", pType->tag);
   5252                 buffer.append(temp);
   5253                 break;
   5254         }
   5255     }
   5256 
   5257     void decodeTypeImpPostfix(String& buffer, Type* pType) {
   5258         TypeTag tag = pType->tag;
   5259 
   5260         switch(tag) {
   5261             case TY_POINTER:
   5262                 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
   5263                     buffer.append(')');
   5264                 }
   5265                 decodeTypeImpPostfix(buffer, pType->pHead);
   5266                 break;
   5267             case TY_ARRAY:
   5268                 {
   5269                     String temp;
   5270                     temp.printf("[%d]", pType->length);
   5271                     buffer.append(temp);
   5272                 }
   5273                 break;
   5274             case TY_STRUCT:
   5275                 if (pType->pHead->length >= 0) {
   5276                     buffer.appendCStr(" {");
   5277                     for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
   5278                         decodeTypeImp(buffer, pArg->pHead);
   5279                         buffer.appendCStr(";");
   5280                     }
   5281                     buffer.append('}');
   5282                 }
   5283                 break;
   5284             case TY_FUNC:
   5285                 buffer.append('(');
   5286                 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
   5287                     decodeTypeImp(buffer, pArg);
   5288                     if (pArg->pTail) {
   5289                         buffer.appendCStr(", ");
   5290                     }
   5291                 }
   5292                 buffer.append(')');
   5293                 break;
   5294             default:
   5295                 break;
   5296         }
   5297     }
   5298 
   5299     void printType(Type* pType) {
   5300         String buffer;
   5301         decodeType(buffer, pType);
   5302         fprintf(stderr, "%s\n", buffer.getUnwrapped());
   5303     }
   5304 
   5305     void insertTypeSpecifier(Type** ppType, TypeTag tag) {
   5306         if (! *ppType) {
   5307             *ppType = createType(tag, NULL, NULL);
   5308         } else {
   5309             if ((*ppType)->tag != TY_UNKNOWN) {
   5310                 error("Only one type specifier allowed.");
   5311             } else {
   5312                 (*ppType)->tag = tag;
   5313             }
   5314         }
   5315     }
   5316 
   5317     void insertStorageClass(Type** ppType, StorageClass storageClass) {
   5318         if (! *ppType) {
   5319             *ppType = createType(TY_UNKNOWN, NULL, NULL);
   5320         }
   5321         if ((*ppType)->storageClass != SC_DEFAULT) {
   5322             error("Only one storage class allowed.");
   5323         } else {
   5324             (*ppType)->storageClass = storageClass;
   5325         }
   5326     }
   5327 
   5328     Type* acceptPrimitiveType(bool allowStorageClass) {
   5329         Type* pType = NULL;
   5330         for (bool keepGoing = true; keepGoing;) {
   5331             switch(tok) {
   5332             case TOK_AUTO:
   5333                 insertStorageClass(&pType, SC_AUTO);
   5334                 break;
   5335             case TOK_REGISTER:
   5336                 insertStorageClass(&pType, SC_REGISTER);
   5337                 break;
   5338             case TOK_STATIC:
   5339                 insertStorageClass(&pType, SC_STATIC);
   5340                 break;
   5341             case TOK_EXTERN:
   5342                 insertStorageClass(&pType, SC_EXTERN);
   5343                 break;
   5344             case TOK_TYPEDEF:
   5345                 insertStorageClass(&pType, SC_TYPEDEF);
   5346                 break;
   5347             case TOK_INT:
   5348                 insertTypeSpecifier(&pType, TY_INT);
   5349                 break;
   5350             case TOK_SHORT:
   5351                 insertTypeSpecifier(&pType, TY_SHORT);
   5352                 break;
   5353             case TOK_CHAR:
   5354                 insertTypeSpecifier(&pType, TY_CHAR);
   5355                 break;
   5356             case TOK_VOID:
   5357                 insertTypeSpecifier(&pType, TY_VOID);
   5358                 break;
   5359             case TOK_FLOAT:
   5360                 insertTypeSpecifier(&pType, TY_FLOAT);
   5361                 break;
   5362             case TOK_DOUBLE:
   5363                 insertTypeSpecifier(&pType, TY_DOUBLE);
   5364                 break;
   5365             case TOK_STRUCT:
   5366             case TOK_UNION:
   5367             {
   5368                 insertTypeSpecifier(&pType, TY_STRUCT);
   5369                 bool isStruct = (tok == TOK_STRUCT);
   5370                 next();
   5371                 pType = acceptStruct(pType, isStruct);
   5372                 keepGoing = false;
   5373             }
   5374                 break;
   5375             default:
   5376                 // Is it a typedef?
   5377                 if (isSymbol(tok)) {
   5378                     VariableInfo* pV = VI(tok);
   5379                     if (pV && pV->pType->storageClass == SC_TYPEDEF) {
   5380                         if (! pType) {
   5381                             pType = createType(TY_UNKNOWN, NULL, NULL);
   5382                         }
   5383                         StorageClass storageClass = pType->storageClass;
   5384                         *pType = *pV->pType;
   5385                         pType->storageClass = storageClass;
   5386                     } else {
   5387                         keepGoing = false;
   5388                     }
   5389                 } else {
   5390                     keepGoing = false;
   5391                 }
   5392             }
   5393             if (keepGoing) {
   5394                 next();
   5395             }
   5396         }
   5397         if (pType) {
   5398             if (pType->tag == TY_UNKNOWN) {
   5399                 pType->tag = TY_INT;
   5400             }
   5401             if (allowStorageClass) {
   5402                 switch(pType->storageClass) {
   5403                 case SC_AUTO: error("auto not supported."); break;
   5404                 case SC_REGISTER: error("register not supported."); break;
   5405                 case SC_STATIC: error("static not supported."); break;
   5406                 case SC_EXTERN: error("extern not supported."); break;
   5407                 default: break;
   5408                 }
   5409             } else {
   5410                 if (pType->storageClass != SC_DEFAULT) {
   5411                     error("An explicit storage class is not allowed in this type declaration");
   5412                 }
   5413             }
   5414         }
   5415         return pType;
   5416     }
   5417 
   5418     Type* acceptStruct(Type* pStructType, bool isStruct) {
   5419         tokenid_t structTag = acceptSymbol();
   5420         bool isDeclaration = accept('{');
   5421         bool fail = false;
   5422 
   5423         if (structTag) {
   5424             Token* pToken = &mTokenTable[structTag];
   5425             VariableInfo* pStructInfo = pToken->mpStructInfo;
   5426             bool needToDeclare = !pStructInfo;
   5427             if (pStructInfo) {
   5428                 if (isDeclaration) {
   5429                     if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
   5430                         if (pStructInfo->pType->pHead->length == -1) {
   5431                             // we're filling in a forward declaration.
   5432                             needToDeclare = false;
   5433                         } else {
   5434                             error("A struct with the same name is already defined at this level.");
   5435                             fail = true;
   5436                         }
   5437                     } else {
   5438                         needToDeclare = true;
   5439                     }
   5440                 }
   5441                 if (!fail) {
   5442                      assert(pStructInfo->isStructTag);
   5443                      pStructType->pHead = pStructInfo->pType;
   5444                      pStructType->pTail = pStructType->pHead->pTail;
   5445                 }
   5446             }
   5447 
   5448             if (needToDeclare) {
   5449                 // This is a new struct name
   5450                 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
   5451                 StorageClass storageClass = pStructType->storageClass;
   5452                 pStructType = createType(TY_STRUCT, NULL, NULL);
   5453                 pStructType->structTag = structTag;
   5454                 pStructType->pHead = pStructType;
   5455                 pStructType->storageClass = storageClass;
   5456                 if (! isDeclaration) {
   5457                     // A forward declaration
   5458                     pStructType->length = -1;
   5459                 }
   5460                 pToken->mpStructInfo->pType = pStructType;
   5461             }
   5462         } else {
   5463             // An anonymous struct
   5464             pStructType->pHead = pStructType;
   5465         }
   5466 
   5467         if (isDeclaration) {
   5468             size_t offset = 0;
   5469             size_t structSize = 0;
   5470             size_t structAlignment = 0;
   5471             Type** pParamHolder = & pStructType->pHead->pTail;
   5472             while (tok != '}' && tok != EOF) {
   5473                 Type* pPrimitiveType = expectPrimitiveType(false);
   5474                 if (pPrimitiveType) {
   5475                     while (tok != ';' && tok != EOF) {
   5476                         Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
   5477                         if (!pItem) {
   5478                             break;
   5479                         }
   5480                         if (lookupStructMember(pStructType, pItem->id)) {
   5481                             String buf;
   5482                             decodeToken(buf, pItem->id, false);
   5483                             error("Duplicate struct member %s", buf.getUnwrapped());
   5484                         }
   5485                         Type* pStructElement = createType(TY_PARAM, pItem, NULL);
   5486                         size_t alignment = pGen->alignmentOf(pItem);
   5487                         if (alignment > structAlignment) {
   5488                             structAlignment = alignment;
   5489                         }
   5490                         size_t alignmentMask = alignment - 1;
   5491                         offset = (offset + alignmentMask) & ~alignmentMask;
   5492                         pStructElement->length = offset;
   5493                         size_t size = pGen->sizeOf(pItem);
   5494                         if (isStruct) {
   5495                             offset += size;
   5496                             structSize = offset;
   5497                         } else {
   5498                             if (size >= structSize) {
   5499                                 structSize = size;
   5500                             }
   5501                         }
   5502                         *pParamHolder = pStructElement;
   5503                         pParamHolder = &pStructElement->pTail;
   5504                         accept(',');
   5505                     }
   5506                     skip(';');
   5507                 } else {
   5508                     // Some sort of syntax error, skip token and keep trying
   5509                     next();
   5510                 }
   5511             }
   5512             if (!fail) {
   5513                 pStructType->pHead->length = structSize;
   5514                 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
   5515             }
   5516             skip('}');
   5517         }
   5518         if (fail) {
   5519             pStructType = NULL;
   5520         }
   5521         return pStructType;
   5522     }
   5523 
   5524     Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
   5525         for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
   5526             if (pStructElement->pHead->id == memberId) {
   5527                 return pStructElement;
   5528             }
   5529         }
   5530         return NULL;
   5531     }
   5532 
   5533     Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
   5534         tokenid_t declName = 0;
   5535         bool reportFailure = false;
   5536         StorageClass storageClass = pType->storageClass;
   5537         pType = acceptDecl2(pType, declName, nameAllowed,
   5538                                   nameRequired, reportFailure);
   5539         if (declName) {
   5540             // Clone the parent type so we can set a unique ID
   5541             Type* pOldType = pType;
   5542             pType = createType(pType->tag, pType->pHead, pType->pTail);
   5543             *pType = *pOldType;
   5544             pType->id = declName;
   5545             pType->storageClass = storageClass;
   5546         } else if (nameRequired) {
   5547             error("Expected a variable name");
   5548         }
   5549 #if 0
   5550         fprintf(stderr, "Parsed a declaration:       ");
   5551         printType(pType);
   5552 #endif
   5553         if (reportFailure) {
   5554             return NULL;
   5555         }
   5556         return pType;
   5557     }
   5558 
   5559     Type* expectDeclaration(Type* pBaseType) {
   5560         bool nameRequired = pBaseType->tag != TY_STRUCT;
   5561         Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
   5562         if (! pType) {
   5563             error("Expected a declaration");
   5564         }
   5565         return pType;
   5566     }
   5567 
   5568     /* Used for accepting types that appear in casts */
   5569     Type* acceptCastTypeDeclaration() {
   5570         Type* pType = acceptPrimitiveType(false);
   5571         if (pType) {
   5572             pType = acceptDeclaration(pType, false, false);
   5573         }
   5574         return pType;
   5575     }
   5576 
   5577     Type* expectCastTypeDeclaration() {
   5578         Type* pType = acceptCastTypeDeclaration();
   5579         if (! pType) {
   5580             error("Expected a declaration");
   5581         }
   5582         return pType;
   5583     }
   5584 
   5585     Type* acceptDecl2(Type* pType, tokenid_t& declName,
   5586                       bool nameAllowed, bool nameRequired,
   5587                       bool& reportFailure) {
   5588         while (accept('*')) {
   5589             pType = createType(TY_POINTER, pType, NULL);
   5590         }
   5591         pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
   5592                             reportFailure);
   5593         return pType;
   5594     }
   5595 
   5596     Type* acceptDecl3(Type* pType, tokenid_t& declName,
   5597                       bool nameAllowed, bool nameRequired,
   5598                       bool& reportFailure) {
   5599         // direct-dcl :
   5600         //   name
   5601         //  (dcl)
   5602         //   direct-dcl()
   5603         //   direct-dcl[]
   5604         Type* pNewHead = NULL;
   5605         if (accept('(')) {
   5606             pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
   5607                                 nameRequired, reportFailure);
   5608             skip(')');
   5609         } else if ((declName = acceptSymbol()) != 0) {
   5610             if (nameAllowed == false && declName) {
   5611                 error("Symbol %s not allowed here", nameof(declName));
   5612                 reportFailure = true;
   5613             }
   5614         } else if (nameRequired && ! declName) {
   5615             String temp;
   5616             decodeToken(temp, tok, true);
   5617             error("Expected name. Got %s", temp.getUnwrapped());
   5618             reportFailure = true;
   5619         }
   5620         for(;;) {
   5621             if (accept('(')) {
   5622                 // Function declaration
   5623                 Type* pTail = acceptArgs(nameAllowed);
   5624                 pType = createType(TY_FUNC, pType, pTail);
   5625                 skip(')');
   5626             } if (accept('[')) {
   5627                 if (tok != ']') {
   5628                     if (tok != TOK_NUM || tokc <= 0) {
   5629                         error("Expected positive integer constant");
   5630                     } else {
   5631                         Type* pDecayType = createPtrType(pType);
   5632                         pType = createType(TY_ARRAY, pType, pDecayType);
   5633                         pType->length = tokc;
   5634                     }
   5635                     next();
   5636                 }
   5637                 skip(']');
   5638             } else {
   5639                 break;
   5640             }
   5641         }
   5642 
   5643         if (pNewHead) {
   5644             Type* pA = pNewHead;
   5645             while (pA->pHead) {
   5646                 pA = pA->pHead;
   5647             }
   5648             pA->pHead = pType;
   5649             pType = pNewHead;
   5650         }
   5651         return pType;
   5652     }
   5653 
   5654     Type* acceptArgs(bool nameAllowed) {
   5655         Type* pHead = NULL;
   5656         Type* pTail = NULL;
   5657         for(;;) {
   5658             Type* pBaseArg = acceptPrimitiveType(false);
   5659             if (pBaseArg) {
   5660                 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
   5661                 if (pArg) {
   5662                     Type* pParam = createType(TY_PARAM, pArg, NULL);
   5663                     if (!pHead) {
   5664                         pHead = pParam;
   5665                         pTail = pParam;
   5666                     } else {
   5667                         pTail->pTail = pParam;
   5668                         pTail = pParam;
   5669                     }
   5670                 }
   5671             }
   5672             if (! accept(',')) {
   5673                 break;
   5674             }
   5675         }
   5676         return pHead;
   5677     }
   5678 
   5679     Type* expectPrimitiveType(bool allowStorageClass) {
   5680         Type* pType = acceptPrimitiveType(allowStorageClass);
   5681         if (!pType) {
   5682             String buf;
   5683             decodeToken(buf, tok, true);
   5684             error("Expected a type, got %s", buf.getUnwrapped());
   5685         }
   5686         return pType;
   5687     }
   5688 
   5689     void checkLVal() {
   5690         if (pGen->getR0ExpressionType() != ET_LVALUE) {
   5691             error("Expected an lvalue");
   5692         }
   5693     }
   5694 
   5695     void addGlobalSymbol(Type* pDecl) {
   5696         tokenid_t t = pDecl->id;
   5697         VariableInfo* pVI = VI(t);
   5698         if(pVI && pVI->pAddress) {
   5699             reportDuplicate(t);
   5700         }
   5701         mGlobals.add(pDecl);
   5702     }
   5703 
   5704     void reportDuplicate(tokenid_t t) {
   5705         error("Duplicate definition of %s", nameof(t));
   5706     }
   5707 
   5708     void addLocalSymbol(Type* pDecl) {
   5709         tokenid_t t = pDecl->id;
   5710         if (mLocals.isDefinedAtCurrentLevel(t)) {
   5711             reportDuplicate(t);
   5712         }
   5713         mLocals.add(pDecl);
   5714     }
   5715 
   5716     bool checkUndeclaredStruct(Type* pBaseType) {
   5717         if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
   5718             String temp;
   5719             decodeToken(temp, pBaseType->structTag, false);
   5720             error("Undeclared struct %s", temp.getUnwrapped());
   5721             return true;
   5722         }
   5723         return false;
   5724     }
   5725 
   5726     void localDeclarations(Type* pBaseType) {
   5727         intptr_t a;
   5728 
   5729         while (pBaseType) {
   5730             while (tok != ';' && tok != EOF) {
   5731                 Type* pDecl = expectDeclaration(pBaseType);
   5732                 if (!pDecl) {
   5733                     break;
   5734                 }
   5735                 if (!pDecl->id) {
   5736                     break;
   5737                 }
   5738                 if (checkUndeclaredStruct(pDecl)) {
   5739                     break;
   5740                 }
   5741                 addLocalSymbol(pDecl);
   5742                 if (pDecl->tag == TY_FUNC) {
   5743                     if (tok == '{') {
   5744                         error("Nested functions are not allowed. Did you forget a '}' ?");
   5745                         break;
   5746                     }
   5747                     // Else it's a forward declaration of a function.
   5748                 } else if (pDecl->storageClass != SC_TYPEDEF) {
   5749                     int variableAddress = 0;
   5750                     size_t alignment = pGen->alignmentOf(pDecl);
   5751                     assert(alignment > 0);
   5752                     size_t alignmentMask = ~ (alignment - 1);
   5753                     size_t sizeOf = pGen->sizeOf(pDecl);
   5754                     assert(sizeOf > 0);
   5755                     loc = (loc + alignment - 1) & alignmentMask;
   5756                     size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
   5757                     loc = loc + alignedSize;
   5758                     variableAddress = -loc;
   5759                     VI(pDecl->id)->pAddress = (void*) variableAddress;
   5760                     if (accept('=')) {
   5761                         /* assignment */
   5762                         pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
   5763                         pGen->pushR0();
   5764                         expr();
   5765                         pGen->forceR0RVal();
   5766                         pGen->storeR0ToTOS();
   5767                     }
   5768                 }
   5769                 if (tok == ',')
   5770                     next();
   5771             }
   5772             skip(';');
   5773             pBaseType = acceptPrimitiveType(true);
   5774         }
   5775     }
   5776 
   5777     bool checkSymbol() {
   5778         return checkSymbol(tok);
   5779     }
   5780 
   5781     void decodeToken(String& buffer, tokenid_t token, bool quote) {
   5782         if (token == EOF ) {
   5783             buffer.printf("EOF");
   5784         } else if (token == TOK_NUM) {
   5785             buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
   5786         } else if (token == TOK_NUM_FLOAT) {
   5787             buffer.printf("numeric constant float %g", tokd);
   5788         } else if (token == TOK_NUM_DOUBLE) {
   5789             buffer.printf("numeric constant double %g", tokd);
   5790         }  else if (token >= 0 && token < 256) {
   5791             if (token < 32) {
   5792                 buffer.printf("'\\x%02x'", token);
   5793             } else {
   5794                 buffer.printf("'%c'", token);
   5795             }
   5796         } else {
   5797             if (quote) {
   5798                 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
   5799                     buffer.printf("keyword \"%s\"", nameof(token));
   5800                 } else {
   5801                     buffer.printf("symbol \"%s\"", nameof(token));
   5802                 }
   5803             } else {
   5804                 buffer.printf("%s", nameof(token));
   5805             }
   5806         }
   5807     }
   5808 
   5809     void printToken(tokenid_t token) {
   5810         String buffer;
   5811         decodeToken(buffer, token, true);
   5812         fprintf(stderr, "%s\n", buffer.getUnwrapped());
   5813     }
   5814 
   5815     bool checkSymbol(tokenid_t token) {
   5816         bool result = token >= TOK_SYMBOL;
   5817         if (!result) {
   5818             String temp;
   5819             decodeToken(temp, token, true);
   5820             error("Expected symbol. Got %s", temp.getUnwrapped());
   5821         }
   5822         return result;
   5823     }
   5824 
   5825     tokenid_t acceptSymbol() {
   5826         tokenid_t result = 0;
   5827         if (tok >= TOK_SYMBOL) {
   5828             result = tok;
   5829             next();
   5830         }
   5831         return result;
   5832     }
   5833 
   5834     void globalDeclarations() {
   5835         mpCurrentSymbolStack = &mGlobals;
   5836         while (tok != EOF) {
   5837             Type* pBaseType = expectPrimitiveType(true);
   5838             if (!pBaseType) {
   5839                 break;
   5840             }
   5841             Type* pDecl = expectDeclaration(pBaseType);
   5842             if (!pDecl) {
   5843                 break;
   5844             }
   5845             if (!pDecl->id) {
   5846                 skip(';');
   5847                 continue;
   5848             }
   5849 
   5850             if (checkUndeclaredStruct(pDecl)) {
   5851                 skip(';');
   5852                 continue;
   5853             }
   5854             if (! isDefined(pDecl->id)) {
   5855                 addGlobalSymbol(pDecl);
   5856             }
   5857             VariableInfo* name = VI(pDecl->id);
   5858             if (name && name->pAddress) {
   5859                 error("Already defined global %s", nameof(pDecl->id));
   5860             }
   5861             if (pDecl->tag < TY_FUNC) {
   5862                 // it's a variable declaration
   5863                 for(;;) {
   5864                     if (pDecl->storageClass == SC_TYPEDEF) {
   5865                         // Do not allocate storage.
   5866                     } else {
   5867                         if (name && !name->pAddress) {
   5868                             name->pAddress = (int*) allocGlobalSpace(
   5869                                                        pGen->alignmentOf(name->pType),
   5870                                                        pGen->sizeOf(name->pType));
   5871                         }
   5872                         if (accept('=')) {
   5873                             if (tok == TOK_NUM) {
   5874                                 if (name) {
   5875                                     * (int*) name->pAddress = tokc;
   5876                                 }
   5877                                 next();
   5878                             } else {
   5879                                 error("Expected an integer constant");
   5880                             }
   5881                         }
   5882                     }
   5883                     if (!accept(',')) {
   5884                         break;
   5885                     }
   5886                     pDecl = expectDeclaration(pBaseType);
   5887                     if (!pDecl) {
   5888                         break;
   5889                     }
   5890                     if (! isDefined(pDecl->id)) {
   5891                         addGlobalSymbol(pDecl);
   5892                     }
   5893                     name = VI(pDecl->id);
   5894                 }
   5895                 skip(';');
   5896             } else {
   5897                 // Function declaration
   5898                 if (accept(';')) {
   5899                     // forward declaration.
   5900                 } else if (tok != '{') {
   5901                     error("expected '{'");
   5902                 } else {
   5903                     mpCurrentArena = &mLocalArena;
   5904                     mpCurrentSymbolStack = &mLocals;
   5905                     if (name) {
   5906                         /* patch forward references */
   5907                         pGen->resolveForward((int) name->pForward);
   5908                         /* put function address */
   5909                         name->pAddress = (void*) pCodeBuf->getPC();
   5910                     }
   5911                     // Calculate stack offsets for parameters
   5912                     mLocals.pushLevel();
   5913                     intptr_t a = 8;
   5914                     int argCount = 0;
   5915                     for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
   5916                         Type* pArg = pP->pHead;
   5917                         if (pArg->id) {
   5918                             addLocalSymbol(pArg);
   5919                         }
   5920                         /* read param name and compute offset */
   5921                         Type* pPassingType = passingType(pArg);
   5922                         size_t alignment = pGen->alignmentOf(pPassingType);
   5923                         a = (a + alignment - 1) & ~ (alignment-1);
   5924                         if (pArg->id) {
   5925                             VI(pArg->id)->pAddress = (void*) a;
   5926                         }
   5927                         a = a + pGen->sizeOf(pPassingType);
   5928                         argCount++;
   5929                     }
   5930                     rsym = loc = 0;
   5931                     pReturnType = pDecl->pHead;
   5932                     a = pGen->functionEntry(pDecl);
   5933                     block(0, 0, true);
   5934                     pGen->gsym(rsym);
   5935                     pGen->functionExit(pDecl, a, loc);
   5936                     mLocals.popLevel();
   5937                     mpCurrentArena = &mGlobalArena;
   5938                     mpCurrentSymbolStack = &mGlobals;
   5939                 }
   5940             }
   5941         }
   5942     }
   5943 
   5944     Type* passingType(Type* pType) {
   5945         switch (pType->tag) {
   5946         case TY_CHAR:
   5947         case TY_SHORT:
   5948             return mkpInt;
   5949         default:
   5950             return pType;
   5951         }
   5952     }
   5953 
   5954     char* allocGlobalSpace(size_t alignment, size_t bytes) {
   5955         size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
   5956         size_t end = base + bytes;
   5957         if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
   5958             error("Global space exhausted");
   5959             assert(false);
   5960             return NULL;
   5961         }
   5962         char* result = (char*) base;
   5963         glo = (char*) end;
   5964         return result;
   5965     }
   5966 
   5967     void cleanup() {
   5968         if (pGlobalBase != 0) {
   5969             free(pGlobalBase);
   5970             pGlobalBase = 0;
   5971         }
   5972         if (pGen) {
   5973             delete pGen;
   5974             pGen = 0;
   5975         }
   5976         if (pCodeBuf) {
   5977             delete pCodeBuf;
   5978             pCodeBuf = 0;
   5979         }
   5980         if (file) {
   5981             delete file;
   5982             file = 0;
   5983         }
   5984     }
   5985 
   5986     // One-time initialization, when class is constructed.
   5987     void init() {
   5988         mpSymbolLookupFn = 0;
   5989         mpSymbolLookupContext = 0;
   5990     }
   5991 
   5992     void clear() {
   5993         tok = 0;
   5994         tokc = 0;
   5995         tokl = 0;
   5996         ch = 0;
   5997         rsym = 0;
   5998         loc = 0;
   5999         glo = 0;
   6000         macroLevel = -1;
   6001         file = 0;
   6002         pGlobalBase = 0;
   6003         pCodeBuf = 0;
   6004         pGen = 0;
   6005         mPragmaStringCount = 0;
   6006         mCompileResult = 0;
   6007         mLineNumber = 1;
   6008         mbBumpLine = false;
   6009         mbSuppressMacroExpansion = false;
   6010     }
   6011 
   6012     void setArchitecture(const char* architecture) {
   6013         delete pGen;
   6014         pGen = 0;
   6015 
   6016         delete pCodeBuf;
   6017         pCodeBuf = new CodeBuf();
   6018 
   6019         if (architecture != NULL) {
   6020 #ifdef PROVIDE_ARM_CODEGEN
   6021             if (! pGen && strcmp(architecture, "arm") == 0) {
   6022                 pGen = new ARMCodeGenerator();
   6023                 pCodeBuf = new ARMCodeBuf(pCodeBuf);
   6024             }
   6025 #endif
   6026 #ifdef PROVIDE_X86_CODEGEN
   6027             if (! pGen && strcmp(architecture, "x86") == 0) {
   6028                 pGen = new X86CodeGenerator();
   6029             }
   6030 #endif
   6031             if (!pGen ) {
   6032                 error("Unknown architecture %s\n", architecture);
   6033             }
   6034         }
   6035 
   6036         if (pGen == NULL) {
   6037 #if defined(DEFAULT_ARM_CODEGEN)
   6038             pGen = new ARMCodeGenerator();
   6039             pCodeBuf = new ARMCodeBuf(pCodeBuf);
   6040 #elif defined(DEFAULT_X86_CODEGEN)
   6041             pGen = new X86CodeGenerator();
   6042 #endif
   6043         }
   6044         if (pGen == NULL) {
   6045             error("No code generator defined.");
   6046         } else {
   6047             pGen->setErrorSink(this);
   6048             pGen->setTypes(mkpInt);
   6049         }
   6050     }
   6051 
   6052 public:
   6053     struct args {
   6054         args() {
   6055             architecture = 0;
   6056         }
   6057         const char* architecture;
   6058     };
   6059 
   6060     Compiler() {
   6061         init();
   6062         clear();
   6063     }
   6064 
   6065     ~Compiler() {
   6066         cleanup();
   6067     }
   6068 
   6069     void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
   6070         mpSymbolLookupFn = pFn;
   6071         mpSymbolLookupContext = pContext;
   6072     }
   6073 
   6074     int compile(const char* text, size_t textLength) {
   6075         int result;
   6076 
   6077         mpCurrentArena = &mGlobalArena;
   6078         createPrimitiveTypes();
   6079         cleanup();
   6080         clear();
   6081         mTokenTable.setArena(&mGlobalArena);
   6082         mGlobals.setArena(&mGlobalArena);
   6083         mGlobals.setTokenTable(&mTokenTable);
   6084         mLocals.setArena(&mLocalArena);
   6085         mLocals.setTokenTable(&mTokenTable);
   6086 
   6087         internKeywords();
   6088         setArchitecture(NULL);
   6089         if (!pGen) {
   6090             return -1;
   6091         }
   6092 #ifdef PROVIDE_TRACE_CODEGEN
   6093             pGen = new TraceCodeGenerator(pGen);
   6094 #endif
   6095         pGen->setErrorSink(this);
   6096 
   6097         if (pCodeBuf) {
   6098             pCodeBuf->init(ALLOC_SIZE);
   6099         }
   6100         pGen->init(pCodeBuf);
   6101         file = new TextInputStream(text, textLength);
   6102         pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
   6103         glo = pGlobalBase;
   6104         inp();
   6105         next();
   6106         globalDeclarations();
   6107         checkForUndefinedForwardReferences();
   6108         result = pGen->finishCompile();
   6109         if (result == 0) {
   6110             if (mErrorBuf.len()) {
   6111                 result = -2;
   6112             }
   6113         }
   6114         mCompileResult = result;
   6115         return result;
   6116     }
   6117 
   6118     void createPrimitiveTypes() {
   6119         mkpInt = createType(TY_INT, NULL, NULL);
   6120         mkpShort = createType(TY_SHORT, NULL, NULL);
   6121         mkpChar = createType(TY_CHAR, NULL, NULL);
   6122         mkpVoid = createType(TY_VOID, NULL, NULL);
   6123         mkpFloat = createType(TY_FLOAT, NULL, NULL);
   6124         mkpDouble = createType(TY_DOUBLE, NULL, NULL);
   6125         mkpIntFn =  createType(TY_FUNC, mkpInt, NULL);
   6126         mkpIntPtr = createPtrType(mkpInt);
   6127         mkpCharPtr = createPtrType(mkpChar);
   6128         mkpFloatPtr = createPtrType(mkpFloat);
   6129         mkpDoublePtr = createPtrType(mkpDouble);
   6130         mkpPtrIntFn = createPtrType(mkpIntFn);
   6131     }
   6132 
   6133     void checkForUndefinedForwardReferences() {
   6134         mGlobals.forEach(static_ufrcFn, this);
   6135     }
   6136 
   6137     static bool static_ufrcFn(VariableInfo* value, void* context) {
   6138         Compiler* pCompiler = (Compiler*) context;
   6139         return pCompiler->undefinedForwardReferenceCheck(value);
   6140     }
   6141 
   6142     bool undefinedForwardReferenceCheck(VariableInfo* value) {
   6143         if (!value->pAddress && value->pForward) {
   6144             error("Undefined forward reference: %s",
   6145                   mTokenTable[value->tok].pText);
   6146         }
   6147         return true;
   6148     }
   6149 
   6150     /* Look through the symbol table to find a symbol.
   6151      * If found, return its value.
   6152      */
   6153     void* lookup(const char* name) {
   6154         if (mCompileResult == 0) {
   6155             tokenid_t tok = mTokenTable.intern(name, strlen(name));
   6156             VariableInfo* pVariableInfo = VI(tok);
   6157             if (pVariableInfo) {
   6158                 return pVariableInfo->pAddress;
   6159             }
   6160         }
   6161         return NULL;
   6162     }
   6163 
   6164     void getPragmas(ACCsizei* actualStringCount,
   6165                     ACCsizei maxStringCount, ACCchar** strings) {
   6166         int stringCount = mPragmaStringCount;
   6167         if (actualStringCount) {
   6168             *actualStringCount = stringCount;
   6169         }
   6170         if (stringCount > maxStringCount) {
   6171             stringCount = maxStringCount;
   6172         }
   6173         if (strings) {
   6174             char* pPragmas = mPragmas.getUnwrapped();
   6175             while (stringCount-- > 0) {
   6176                 *strings++ = pPragmas;
   6177                 pPragmas += strlen(pPragmas) + 1;
   6178             }
   6179         }
   6180     }
   6181 
   6182     void getProgramBinary(ACCvoid** base, ACCsizei* length) {
   6183         *base = pCodeBuf->getBase();
   6184         *length = (ACCsizei) pCodeBuf->getSize();
   6185     }
   6186 
   6187     char* getErrorMessage() {
   6188         return mErrorBuf.getUnwrapped();
   6189     }
   6190 };
   6191 
   6192 const char* Compiler::operatorChars =
   6193     "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
   6194 
   6195 const char Compiler::operatorLevel[] =
   6196     {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
   6197             5, 5, /* ==, != */
   6198             9, 10, /* &&, || */
   6199             6, 7, 8, /* & ^ | */
   6200             2, 2 /* ~ ! */
   6201             };
   6202 
   6203 #ifdef PROVIDE_X86_CODEGEN
   6204 const int Compiler::X86CodeGenerator::operatorHelper[] = {
   6205         0x1,     // ++
   6206         0xff,    // --
   6207         0xc1af0f, // *
   6208         0xf9f79991, // /
   6209         0xf9f79991, // % (With manual assist to swap results)
   6210         0xc801, // +
   6211         0xd8f7c829, // -
   6212         0xe0d391, // <<
   6213         0xf8d391, // >>
   6214         0xe, // <=
   6215         0xd, // >=
   6216         0xc, // <
   6217         0xf, // >
   6218         0x4, // ==
   6219         0x5, // !=
   6220         0x0, // &&
   6221         0x1, // ||
   6222         0xc821, // &
   6223         0xc831, // ^
   6224         0xc809, // |
   6225         0xd0f7, // ~
   6226         0x4     // !
   6227 };
   6228 #endif
   6229 
   6230 struct ACCscript {
   6231     ACCscript() {
   6232         text = 0;
   6233         textLength = 0;
   6234         accError = ACC_NO_ERROR;
   6235     }
   6236 
   6237     ~ACCscript() {
   6238         delete text;
   6239     }
   6240 
   6241     void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
   6242         compiler.registerSymbolCallback(pFn, pContext);
   6243     }
   6244 
   6245     void setError(ACCenum error) {
   6246         if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
   6247             accError = error;
   6248         }
   6249     }
   6250 
   6251     ACCenum getError() {
   6252         ACCenum result = accError;
   6253         accError = ACC_NO_ERROR;
   6254         return result;
   6255     }
   6256 
   6257     Compiler compiler;
   6258     char* text;
   6259     int textLength;
   6260     ACCenum accError;
   6261 };
   6262 
   6263 
   6264 extern "C"
   6265 ACCscript* accCreateScript() {
   6266     return new ACCscript();
   6267 }
   6268 
   6269 extern "C"
   6270 ACCenum accGetError( ACCscript* script ) {
   6271     return script->getError();
   6272 }
   6273 
   6274 extern "C"
   6275 void accDeleteScript(ACCscript* script) {
   6276     delete script;
   6277 }
   6278 
   6279 extern "C"
   6280 void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
   6281                                ACCvoid* pContext) {
   6282     script->registerSymbolCallback(pFn, pContext);
   6283 }
   6284 
   6285 extern "C"
   6286 void accScriptSource(ACCscript* script,
   6287     ACCsizei count,
   6288     const ACCchar ** string,
   6289     const ACCint * length) {
   6290     int totalLength = 0;
   6291     for(int i = 0; i < count; i++) {
   6292         int len = -1;
   6293         const ACCchar* s = string[i];
   6294         if (length) {
   6295             len = length[i];
   6296         }
   6297         if (len < 0) {
   6298             len = strlen(s);
   6299         }
   6300         totalLength += len;
   6301     }
   6302     delete script->text;
   6303     char* text = new char[totalLength + 1];
   6304     script->text = text;
   6305     script->textLength = totalLength;
   6306     char* dest = text;
   6307     for(int i = 0; i < count; i++) {
   6308         int len = -1;
   6309         const ACCchar* s = string[i];
   6310         if (length) {
   6311             len = length[i];
   6312         }
   6313         if (len < 0) {
   6314             len = strlen(s);
   6315         }
   6316         memcpy(dest, s, len);
   6317         dest += len;
   6318     }
   6319     text[totalLength] = '\0';
   6320 
   6321 #ifdef DEBUG_SAVE_INPUT_TO_FILE
   6322     LOGD("Saving input to file...");
   6323     int counter;
   6324     char path[PATH_MAX];
   6325     for (counter = 0; counter < 4096; counter++) {
   6326         sprintf(path, DEBUG_DUMP_PATTERN, counter);
   6327         if(access(path, F_OK) != 0) {
   6328             break;
   6329         }
   6330     }
   6331     if (counter < 4096) {
   6332         LOGD("Saving input to file %s", path);
   6333         FILE* fd = fopen(path, "w");
   6334         if (fd) {
   6335             fwrite(text, totalLength, 1, fd);
   6336             fclose(fd);
   6337             LOGD("Saved input to file %s", path);
   6338         } else {
   6339             LOGD("Could not save. errno: %d", errno);
   6340         }
   6341     }
   6342 #endif
   6343 }
   6344 
   6345 extern "C"
   6346 void accCompileScript(ACCscript* script) {
   6347     int result = script->compiler.compile(script->text, script->textLength);
   6348     if (result) {
   6349         script->setError(ACC_INVALID_OPERATION);
   6350     }
   6351 }
   6352 
   6353 extern "C"
   6354 void accGetScriptiv(ACCscript* script,
   6355     ACCenum pname,
   6356     ACCint * params) {
   6357     switch (pname) {
   6358         case ACC_INFO_LOG_LENGTH:
   6359             *params = 0;
   6360             break;
   6361     }
   6362 }
   6363 
   6364 extern "C"
   6365 void accGetScriptInfoLog(ACCscript* script,
   6366     ACCsizei maxLength,
   6367     ACCsizei * length,
   6368     ACCchar * infoLog) {
   6369     char* message = script->compiler.getErrorMessage();
   6370     int messageLength = strlen(message) + 1;
   6371     if (length) {
   6372         *length = messageLength;
   6373     }
   6374     if (infoLog && maxLength > 0) {
   6375         int trimmedLength = maxLength < messageLength ?
   6376                 maxLength : messageLength;
   6377         memcpy(infoLog, message, trimmedLength);
   6378         infoLog[trimmedLength] = 0;
   6379     }
   6380 }
   6381 
   6382 extern "C"
   6383 void accGetScriptLabel(ACCscript* script, const ACCchar * name,
   6384                        ACCvoid ** address) {
   6385     void* value = script->compiler.lookup(name);
   6386     if (value) {
   6387         *address = value;
   6388     } else {
   6389         script->setError(ACC_INVALID_VALUE);
   6390     }
   6391 }
   6392 
   6393 extern "C"
   6394 void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
   6395                    ACCsizei maxStringCount, ACCchar** strings){
   6396     script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
   6397 }
   6398 
   6399 extern "C"
   6400 void accGetProgramBinary(ACCscript* script,
   6401     ACCvoid** base, ACCsizei* length) {
   6402     script->compiler.getProgramBinary(base, length);
   6403 }
   6404 
   6405 
   6406 } // namespace acc
   6407 
   6408