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