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