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