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