blob: 81d30adb56ac92daffe71884a0806b2b3162d13c [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * 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
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070016#include <limits.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070017#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070018#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070020#include <stdlib.h>
21#include <string.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070022#include <unistd.h>
23
Jack Palevich2d11dfb2009-06-08 14:34:26 -070024#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070025
Jack Palevich8dc662e2009-06-09 22:53:47 +000026#if defined(__i386__)
27#include <sys/mman.h>
28#endif
29
Jack Palevich546b2242009-05-13 15:10:04 -070030
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Palevich30321cb2009-08-20 15:34:23 -070042#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
43#define ARM_USE_VFP
44#endif
45
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050
-b master422972c2009-06-17 19:13:52 -070051#define LOG_STACK(...) do {} while(0)
52// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
53
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevich61de31f2009-09-08 11:06:40 -070056// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
57// #define DEBUG_SAVE_INPUT_TO_FILE
58
Jack Palevich9116bc42009-09-08 11:46:42 -070059#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070060#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070061#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070062#else
63#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
64#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070065#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070066
Jack Palevich7f5b1a22009-08-17 16:54:56 -070067#define assert(b) assertImpl(b, __LINE__)
68
Jack Palevichbbf8ab52009-05-11 11:54:30 -070069namespace acc {
70
Jack Palevich8df46192009-07-07 14:48:51 -070071// Subset of STL vector.
72template<class E> class Vector {
73 public:
74 Vector() {
75 mpBase = 0;
76 mUsed = 0;
77 mSize = 0;
78 }
79
80 ~Vector() {
81 if (mpBase) {
82 for(size_t i = 0; i < mUsed; i++) {
83 mpBase[mUsed].~E();
84 }
85 free(mpBase);
86 }
87 }
88
89 inline E& operator[](size_t i) {
90 return mpBase[i];
91 }
92
93 inline E& front() {
94 return mpBase[0];
95 }
96
97 inline E& back() {
98 return mpBase[mUsed - 1];
99 }
100
101 void pop_back() {
102 mUsed -= 1;
103 mpBase[mUsed].~E();
104 }
105
106 void push_back(const E& item) {
107 * ensure(1) = item;
108 }
109
110 size_t size() {
111 return mUsed;
112 }
113
114private:
115 E* ensure(int n) {
116 size_t newUsed = mUsed + n;
117 if (newUsed > mSize) {
118 size_t newSize = mSize * 2 + 10;
119 if (newSize < newUsed) {
120 newSize = newUsed;
121 }
122 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
123 mSize = newSize;
124 }
125 E* result = mpBase + mUsed;
126 mUsed = newUsed;
127 return result;
128 }
129
130 E* mpBase;
131 size_t mUsed;
132 size_t mSize;
133};
134
Jack Palevichac0e95e2009-05-29 13:53:44 -0700135class ErrorSink {
136public:
137 void error(const char *fmt, ...) {
138 va_list ap;
139 va_start(ap, fmt);
140 verror(fmt, ap);
141 va_end(ap);
142 }
143
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700144 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700145 virtual void verror(const char* fmt, va_list ap) = 0;
146};
147
148class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700149 typedef int tokenid_t;
150 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700151 TY_INT, // 0
152 TY_CHAR, // 1
153 TY_SHORT, // 2
154 TY_VOID, // 3
155 TY_FLOAT, // 4
156 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700157 TY_POINTER, // 6
158 TY_ARRAY, // 7
159 TY_STRUCT, // 8
160 TY_FUNC, // 9
161 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700162 };
163
164 struct Type {
165 TypeTag tag;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700166 tokenid_t id; // For function arguments, global vars, local vars, struct elements
167 tokenid_t structTag; // For structs the name of the struct
168 int length; // length of array, offset of struct element. -1 means struct is forward defined
169 int alignment; // for structs only
170 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700171 Type* pTail;
172 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700173
Jack Palevichba929a42009-07-17 10:20:32 -0700174 enum ExpressionType {
175 ET_RVALUE,
176 ET_LVALUE
177 };
178
179 struct ExpressionValue {
180 ExpressionValue() {
181 et = ET_RVALUE;
182 pType = NULL;
183 }
184 ExpressionType et;
185 Type* pType;
186 };
187
Jack Palevich21a15a22009-05-11 14:49:29 -0700188 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700189 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700191 ErrorSink* mErrorSink;
192 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700193 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700194
Jack Palevich21a15a22009-05-11 14:49:29 -0700195 void release() {
196 if (pProgramBase != 0) {
197 free(pProgramBase);
198 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700199 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700200 }
201
Jack Palevich0a280a02009-06-11 10:53:51 -0700202 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700203 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700204 bool overflow = newSize > mSize;
205 if (overflow && !mOverflowed) {
206 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700207 if (mErrorSink) {
208 mErrorSink->error("Code too large: %d bytes", newSize);
209 }
210 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700211 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700212 }
213
Jack Palevich21a15a22009-05-11 14:49:29 -0700214 public:
215 CodeBuf() {
216 pProgramBase = 0;
217 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700218 mErrorSink = 0;
219 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700220 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700221 }
222
223 ~CodeBuf() {
224 release();
225 }
226
227 void init(int size) {
228 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700229 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700230 pProgramBase = (char*) calloc(1, size);
231 ind = pProgramBase;
232 }
233
Jack Palevichac0e95e2009-05-29 13:53:44 -0700234 void setErrorSink(ErrorSink* pErrorSink) {
235 mErrorSink = pErrorSink;
236 }
237
Jack Palevich546b2242009-05-13 15:10:04 -0700238 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700239 if(check(4)) {
240 return 0;
241 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700242 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700243 * (int*) ind = n;
244 ind += 4;
245 return result;
246 }
247
Jack Palevich21a15a22009-05-11 14:49:29 -0700248 /*
249 * Output a byte. Handles all values, 0..ff.
250 */
251 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700252 if(check(1)) {
253 return;
254 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700255 *ind++ = n;
256 }
257
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 inline void* getBase() {
259 return (void*) pProgramBase;
260 }
261
Jack Palevich8b0624c2009-05-20 12:12:06 -0700262 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700263 return ind - pProgramBase;
264 }
265
Jack Palevich8b0624c2009-05-20 12:12:06 -0700266 intptr_t getPC() {
267 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700268 }
269 };
270
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 /**
272 * A code generator creates an in-memory program, generating the code on
273 * the fly. There is one code generator implementation for each supported
274 * architecture.
275 *
276 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700277 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700278 * FP - a frame pointer for accessing function arguments and local
279 * variables.
280 * SP - a stack pointer for storing intermediate results while evaluating
281 * expressions. The stack pointer grows downwards.
282 *
283 * The function calling convention is that all arguments are placed on the
284 * stack such that the first argument has the lowest address.
285 * After the call, the result is in R0. The caller is responsible for
286 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700287 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700288 * FP and SP registers are saved.
289 */
290
Jack Palevich21a15a22009-05-11 14:49:29 -0700291 class CodeGenerator {
292 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700293 CodeGenerator() {
294 mErrorSink = 0;
295 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700296 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700297 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700298 virtual ~CodeGenerator() {}
299
Jack Palevich22305132009-05-13 10:58:45 -0700300 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700301 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700302 pCodeBuf->setErrorSink(mErrorSink);
303 }
304
Jack Palevichb67b18f2009-06-11 21:12:23 -0700305 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700306 mErrorSink = pErrorSink;
307 if (pCodeBuf) {
308 pCodeBuf->setErrorSink(mErrorSink);
309 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700310 }
311
Jack Palevich58c30ee2009-07-17 16:35:23 -0700312 /* Give the code generator some utility types so it can
313 * use its own types as needed for the results of some
314 * operations like gcmp.
315 */
316
Jack Palevicha8f427f2009-07-13 18:40:08 -0700317 void setTypes(Type* pInt) {
318 mkpInt = pInt;
319 }
320
Jack Palevich1cdef202009-05-22 12:06:27 -0700321 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700322 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 * Save the old value of the FP.
324 * Set the new value of the FP.
325 * Convert from the native platform calling convention to
326 * our stack-based calling convention. This may require
327 * pushing arguments from registers to the stack.
328 * Allocate "N" bytes of stack space. N isn't known yet, so
329 * just emit the instructions for adjusting the stack, and return
330 * the address to patch up. The patching will be done in
331 * functionExit().
332 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700333 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700334 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700335
Jack Palevich1cdef202009-05-22 12:06:27 -0700336 /* Emit a function epilog.
337 * Restore the old SP and FP register values.
338 * Return to the calling function.
339 * argCount - the number of arguments to the function.
340 * localVariableAddress - returned from functionEntry()
341 * localVariableSize - the size in bytes of the local variables.
342 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700343 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700345
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700347 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700348
Jack Palevich1a539db2009-07-08 13:04:41 -0700349 /* Load floating point value from global address. */
350 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700351
Jack Palevich9221bcc2009-08-26 16:15:07 -0700352 /* Add the struct offset in bytes to R0, change the type to pType */
353 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
354
Jack Palevich1cdef202009-05-22 12:06:27 -0700355 /* Jump to a target, and return the address of the word that
356 * holds the target data, in case it needs to be fixed up later.
357 */
Jack Palevich22305132009-05-13 10:58:45 -0700358 virtual int gjmp(int t) = 0;
359
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 /* Test R0 and jump to a target if the test succeeds.
361 * l = 0: je, l == 1: jne
362 * Return the address of the word that holds the targed data, in
363 * case it needs to be fixed up later.
364 */
Jack Palevich22305132009-05-13 10:58:45 -0700365 virtual int gtst(bool l, int t) = 0;
366
Jack Palevich9eed7a22009-07-06 17:24:34 -0700367 /* Compare TOS against R0, and store the boolean result in R0.
368 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 * op specifies the comparison.
370 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700371 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700372
Jack Palevich9eed7a22009-07-06 17:24:34 -0700373 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700374 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700375 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 */
Jack Palevich546b2242009-05-13 15:10:04 -0700377 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700378
Jack Palevich9eed7a22009-07-06 17:24:34 -0700379 /* Compare 0 against R0, and store the boolean result in R0.
380 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700381 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700382 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700383
384 /* Perform the arithmetic op specified by op. 0 is the
385 * left argument, R0 is the right argument.
386 */
387 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700388
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700389 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 */
391 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700392
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700393 /* Turn R0, TOS into R0 TOS R0 */
394
395 virtual void over() = 0;
396
397 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700398 */
399 virtual void popR0() = 0;
400
Jack Palevich9eed7a22009-07-06 17:24:34 -0700401 /* Store R0 to the address stored in TOS.
402 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700403 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700404 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700408 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Load the absolute address of a variable to R0.
411 * If ea <= LOCAL, then this is a local variable, or an
412 * argument, addressed relative to FP.
413 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700414 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700415 * et is ET_RVALUE for things like string constants, ET_LVALUE for
416 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700417 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700418 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich9f51a262009-07-29 16:22:26 -0700420 /* Load the pc-relative address of a forward-referenced variable to R0.
421 * Return the address of the 4-byte constant so that it can be filled
422 * in later.
423 */
424 virtual int leaForward(int ea, Type* pPointerType) = 0;
425
Jack Palevich8df46192009-07-07 14:48:51 -0700426 /**
427 * Convert R0 to the given type.
428 */
Jack Palevichb6154502009-08-04 14:56:09 -0700429
430 void convertR0(Type* pType) {
431 convertR0Imp(pType, false);
432 }
433
434 void castR0(Type* pType) {
435 convertR0Imp(pType, true);
436 }
437
438 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700439
Jack Palevich1cdef202009-05-22 12:06:27 -0700440 /* Emit code to adjust the stack for a function call. Return the
441 * label for the address of the instruction that adjusts the
442 * stack size. This will be passed as argument "a" to
443 * endFunctionCallArguments.
444 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700445 virtual int beginFunctionCallArguments() = 0;
446
Jack Palevich1cdef202009-05-22 12:06:27 -0700447 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700448 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700449 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700450 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700451
Jack Palevich1cdef202009-05-22 12:06:27 -0700452 /* Patch the function call preamble.
453 * a is the address returned from beginFunctionCallArguments
454 * l is the number of bytes the arguments took on the stack.
455 * Typically you would also emit code to convert the argument
456 * list into whatever the native function calling convention is.
457 * On ARM for example you would pop the first 5 arguments into
458 * R0..R4
459 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700460 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700461
Jack Palevich1cdef202009-05-22 12:06:27 -0700462 /* Emit a call to an unknown function. The argument "symbol" needs to
463 * be stored in the location where the address should go. It forms
464 * a chain. The address will be patched later.
465 * Return the address of the word that has to be patched.
466 */
Jack Palevich8df46192009-07-07 14:48:51 -0700467 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700468
Jack Palevich1cdef202009-05-22 12:06:27 -0700469 /* Call a function pointer. L is the number of bytes the arguments
470 * take on the stack. The address of the function is stored at
471 * location SP + l.
472 */
Jack Palevich8df46192009-07-07 14:48:51 -0700473 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700474
Jack Palevich1cdef202009-05-22 12:06:27 -0700475 /* Adjust SP after returning from a function call. l is the
476 * number of bytes of arguments stored on the stack. isIndirect
477 * is true if this was an indirect call. (In which case the
478 * address of the function is stored at location SP + l.)
479 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700480 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700481
Jack Palevich1cdef202009-05-22 12:06:27 -0700482 /* Generate a symbol at the current PC. t is the head of a
483 * linked list of addresses to patch.
484 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700485 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700486
Jack Palevich9f51a262009-07-29 16:22:26 -0700487 /* Resolve a forward reference function at the current PC.
488 * t is the head of a
489 * linked list of addresses to patch.
490 * (Like gsym, but using absolute address, not PC relative address.)
491 */
492 virtual void resolveForward(int t) = 0;
493
Jack Palevich1cdef202009-05-22 12:06:27 -0700494 /*
495 * Do any cleanup work required at the end of a compile.
496 * For example, an instruction cache might need to be
497 * invalidated.
498 * Return non-zero if there is an error.
499 */
500 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700501
Jack Palevicha6535612009-05-13 16:24:17 -0700502 /**
503 * Adjust relative branches by this amount.
504 */
505 virtual int jumpOffset() = 0;
506
Jack Palevich9eed7a22009-07-06 17:24:34 -0700507 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700508 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700509 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700510 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700511
512 /**
513 * Array element alignment (in bytes) for this type of data.
514 */
515 virtual size_t sizeOf(Type* type) = 0;
516
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700517 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700518 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700519 }
520
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700521 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700522 return mExpressionStack.back().et;
523 }
524
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700525 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700526 mExpressionStack.back().et = et;
527 }
528
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700529 virtual size_t getExpressionStackDepth() {
530 return mExpressionStack.size();
531 }
532
Jack Palevichb5e33312009-07-30 19:06:34 -0700533 virtual void forceR0RVal() {
534 if (getR0ExpressionType() == ET_LVALUE) {
535 loadR0FromR0();
536 }
537 }
538
Jack Palevich21a15a22009-05-11 14:49:29 -0700539 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700540 /*
541 * Output a byte. Handles all values, 0..ff.
542 */
543 void ob(int n) {
544 pCodeBuf->ob(n);
545 }
546
Jack Palevich8b0624c2009-05-20 12:12:06 -0700547 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700548 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700549 }
550
Jack Palevich8b0624c2009-05-20 12:12:06 -0700551 intptr_t getBase() {
552 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700553 }
554
Jack Palevich8b0624c2009-05-20 12:12:06 -0700555 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 return pCodeBuf->getPC();
557 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700558
559 intptr_t getSize() {
560 return pCodeBuf->getSize();
561 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700562
563 void error(const char* fmt,...) {
564 va_list ap;
565 va_start(ap, fmt);
566 mErrorSink->verror(fmt, ap);
567 va_end(ap);
568 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700569
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700570 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700571 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700572 error("code generator assertion failed at line %s:%d.", __FILE__, line);
573 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700574 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700575 }
576 }
Jack Palevich8df46192009-07-07 14:48:51 -0700577
578 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700579 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700580 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700581 mExpressionStack.back().et = ET_RVALUE;
582 }
583
584 void setR0Type(Type* pType, ExpressionType et) {
585 assert(pType != NULL);
586 mExpressionStack.back().pType = pType;
587 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700588 }
589
Jack Palevich8df46192009-07-07 14:48:51 -0700590 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700591 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700592 }
593
594 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700595 if (mExpressionStack.size()) {
596 mExpressionStack.push_back(mExpressionStack.back());
597 } else {
598 mExpressionStack.push_back(ExpressionValue());
599 }
600
Jack Palevich8df46192009-07-07 14:48:51 -0700601 }
602
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700603 void overType() {
604 size_t size = mExpressionStack.size();
605 if (size >= 2) {
606 mExpressionStack.push_back(mExpressionStack.back());
607 mExpressionStack[size-1] = mExpressionStack[size-2];
608 mExpressionStack[size-2] = mExpressionStack[size];
609 }
610 }
611
Jack Palevich8df46192009-07-07 14:48:51 -0700612 void popType() {
613 mExpressionStack.pop_back();
614 }
615
616 bool bitsSame(Type* pA, Type* pB) {
617 return collapseType(pA->tag) == collapseType(pB->tag);
618 }
619
620 TypeTag collapseType(TypeTag tag) {
621 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700622 TY_INT,
623 TY_INT,
624 TY_INT,
625 TY_VOID,
626 TY_FLOAT,
627 TY_DOUBLE,
628 TY_INT,
629 TY_INT,
630 TY_VOID,
631 TY_VOID,
632 TY_VOID
633 };
Jack Palevich8df46192009-07-07 14:48:51 -0700634 return collapsedTag[tag];
635 }
636
Jack Palevich1a539db2009-07-08 13:04:41 -0700637 TypeTag collapseTypeR0() {
638 return collapseType(getR0Type()->tag);
639 }
640
Jack Palevichb6154502009-08-04 14:56:09 -0700641 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700642 return isFloatTag(pType->tag);
643 }
644
Jack Palevichb6154502009-08-04 14:56:09 -0700645 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700646 return tag == TY_FLOAT || tag == TY_DOUBLE;
647 }
648
Jack Palevichb6154502009-08-04 14:56:09 -0700649 static bool isPointerType(Type* pType) {
650 return isPointerTag(pType->tag);
651 }
652
653 static bool isPointerTag(TypeTag tag) {
654 return tag == TY_POINTER || tag == TY_ARRAY;
655 }
656
657 Type* getPointerArithmeticResultType(Type* a, Type* b) {
658 TypeTag aTag = a->tag;
659 TypeTag bTag = b->tag;
660 if (aTag == TY_POINTER) {
661 return a;
662 }
663 if (bTag == TY_POINTER) {
664 return b;
665 }
666 if (aTag == TY_ARRAY) {
667 return a->pTail;
668 }
669 if (bTag == TY_ARRAY) {
670 return b->pTail;
671 }
672 return NULL;
673 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700674 Type* mkpInt;
675
Jack Palevich21a15a22009-05-11 14:49:29 -0700676 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700677 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700678 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700679 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700680 };
681
Jack Paleviche7b59062009-05-19 17:12:17 -0700682#ifdef PROVIDE_ARM_CODEGEN
683
Jack Palevich22305132009-05-13 10:58:45 -0700684 class ARMCodeGenerator : public CodeGenerator {
685 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700686 ARMCodeGenerator() {
687#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700688 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700689#else
Jack Palevichd5315572009-09-09 13:19:34 -0700690 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700691#endif
692 }
-b master422972c2009-06-17 19:13:52 -0700693
Jack Palevich22305132009-05-13 10:58:45 -0700694 virtual ~ARMCodeGenerator() {}
695
696 /* returns address to patch with local variable size
697 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700698 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700699 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700700 // sp -> arg4 arg5 ...
701 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700702 int regArgCount = calcRegArgCount(pDecl);
703 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700704 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700705 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700706 }
707 // sp -> arg0 arg1 ...
708 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700709 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700710 // sp, fp -> oldfp, retadr, arg0 arg1 ....
711 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700712 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700713 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700714 // We don't know how many local variables we are going to use,
715 // but we will round the allocation up to a multiple of
716 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700717 }
718
Jack Palevichb7718b92009-07-09 22:00:24 -0700719 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700720 // Round local variable size up to a multiple of stack alignment
721 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
722 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700723 // Patch local variable allocation code:
724 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700725 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700726 }
Jack Palevich69796b62009-05-14 15:42:26 -0700727 *(char*) (localVariableAddress) = localVariableSize;
728
Jack Palevich30321cb2009-08-20 15:34:23 -0700729#ifdef ARM_USE_VFP
730 {
Jack Palevichc0f25332009-08-25 12:23:43 -0700731 Type* pReturnType = pDecl->pHead;
732 switch(pReturnType->tag) {
733 case TY_FLOAT:
734 o4(0xEE170A90); // fmrs r0, s15
735 break;
736 case TY_DOUBLE:
737 o4(0xEC510B17); // fmrrd r0, r1, d7
738 break;
739 default:
740 break;
741 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700742 }
743#endif
744
Jack Palevich69796b62009-05-14 15:42:26 -0700745 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
746 o4(0xE1A0E00B); // mov lr, fp
747 o4(0xE59BB000); // ldr fp, [fp]
748 o4(0xE28ED004); // add sp, lr, #4
749 // sp -> retadr, arg0, ...
750 o4(0xE8BD4000); // ldmfd sp!, {lr}
751 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700752
753 // We store the PC into the lr so we can adjust the sp before
754 // returning. We need to pull off the registers we pushed
755 // earlier. We don't need to actually store them anywhere,
756 // just adjust the stack.
757 int regArgCount = calcRegArgCount(pDecl);
758 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700759 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
760 }
761 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700762 }
763
764 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700765 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700766 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700767 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700768 }
769
Jack Palevich1a539db2009-07-08 13:04:41 -0700770 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700771 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700772 // Global, absolute address
773 o4(0xE59F0000); // ldr r0, .L1
774 o4(0xEA000000); // b .L99
775 o4(address); // .L1: .word ea
776 // .L99:
777
778 switch (pType->tag) {
779 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700780#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700781 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700782#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700783 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700784#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700785 break;
786 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700787#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700788 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700789#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700790 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700791#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700792 break;
793 default:
794 assert(false);
795 break;
796 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700797 }
798
Jack Palevich9221bcc2009-08-26 16:15:07 -0700799
800 virtual void addStructOffsetR0(int offset, Type* pType) {
801 if (offset) {
802 size_t immediate = 0;
803 if (encode12BitImmediate(offset, &immediate)) {
804 o4(0xE2800000 | immediate); // add r0, r0, #offset
805 } else {
806 error("structure offset out of range: %d", offset);
807 }
808 }
809 setR0Type(pType, ET_LVALUE);
810 }
811
Jack Palevich22305132009-05-13 10:58:45 -0700812 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700813 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700814 }
815
816 /* l = 0: je, l == 1: jne */
817 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700818 Type* pR0Type = getR0Type();
819 TypeTag tagR0 = pR0Type->tag;
820 switch(tagR0) {
821 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700822#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700823 o4(0xEEF57A40); // fcmpzs s15
824 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700825#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700826 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -0700827 o4(0xE3500000); // cmp r0,#0
828#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700829 break;
830 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700831#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700832 o4(0xEEB57B40); // fcmpzd d7
833 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700834#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700835 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -0700836 o4(0xE3500000); // cmp r0,#0
837#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700838 break;
839 default:
Jack Palevich30321cb2009-08-20 15:34:23 -0700840 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700841 break;
842 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700843 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
844 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700845 }
846
Jack Palevich58c30ee2009-07-17 16:35:23 -0700847 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700848 Type* pR0Type = getR0Type();
849 Type* pTOSType = getTOSType();
850 TypeTag tagR0 = collapseType(pR0Type->tag);
851 TypeTag tagTOS = collapseType(pTOSType->tag);
852 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700853 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700854 o4(0xE1510000); // cmp r1, r1
855 switch(op) {
856 case OP_EQUALS:
857 o4(0x03A00001); // moveq r0,#1
858 o4(0x13A00000); // movne r0,#0
859 break;
860 case OP_NOT_EQUALS:
861 o4(0x03A00000); // moveq r0,#0
862 o4(0x13A00001); // movne r0,#1
863 break;
864 case OP_LESS_EQUAL:
865 o4(0xD3A00001); // movle r0,#1
866 o4(0xC3A00000); // movgt r0,#0
867 break;
868 case OP_GREATER:
869 o4(0xD3A00000); // movle r0,#0
870 o4(0xC3A00001); // movgt r0,#1
871 break;
872 case OP_GREATER_EQUAL:
873 o4(0xA3A00001); // movge r0,#1
874 o4(0xB3A00000); // movlt r0,#0
875 break;
876 case OP_LESS:
877 o4(0xA3A00000); // movge r0,#0
878 o4(0xB3A00001); // movlt r0,#1
879 break;
880 default:
881 error("Unknown comparison op %d", op);
882 break;
883 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700884 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
885 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700886#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700887 o4(0xEEB46BC7); // fcmped d6, d7
888 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700889 switch(op) {
890 case OP_EQUALS:
891 o4(0x03A00001); // moveq r0,#1
892 o4(0x13A00000); // movne r0,#0
893 break;
894 case OP_NOT_EQUALS:
895 o4(0x03A00000); // moveq r0,#0
896 o4(0x13A00001); // movne r0,#1
897 break;
898 case OP_LESS_EQUAL:
899 o4(0xD3A00001); // movle r0,#1
900 o4(0xC3A00000); // movgt r0,#0
901 break;
902 case OP_GREATER:
903 o4(0xD3A00000); // movle r0,#0
904 o4(0xC3A00001); // movgt r0,#1
905 break;
906 case OP_GREATER_EQUAL:
907 o4(0xA3A00001); // movge r0,#1
908 o4(0xB3A00000); // movlt r0,#0
909 break;
910 case OP_LESS:
911 o4(0xA3A00000); // movge r0,#0
912 o4(0xB3A00001); // movlt r0,#1
913 break;
914 default:
915 error("Unknown comparison op %d", op);
916 break;
917 }
918#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700919 switch(op) {
920 case OP_EQUALS:
921 callRuntime((void*) runtime_cmp_eq_dd);
922 break;
923 case OP_NOT_EQUALS:
924 callRuntime((void*) runtime_cmp_ne_dd);
925 break;
926 case OP_LESS_EQUAL:
927 callRuntime((void*) runtime_cmp_le_dd);
928 break;
929 case OP_GREATER:
930 callRuntime((void*) runtime_cmp_gt_dd);
931 break;
932 case OP_GREATER_EQUAL:
933 callRuntime((void*) runtime_cmp_ge_dd);
934 break;
935 case OP_LESS:
936 callRuntime((void*) runtime_cmp_lt_dd);
937 break;
938 default:
939 error("Unknown comparison op %d", op);
940 break;
941 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700942#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700943 } else {
944 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700945#ifdef ARM_USE_VFP
946 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -0700947 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700948 switch(op) {
949 case OP_EQUALS:
950 o4(0x03A00001); // moveq r0,#1
951 o4(0x13A00000); // movne r0,#0
952 break;
953 case OP_NOT_EQUALS:
954 o4(0x03A00000); // moveq r0,#0
955 o4(0x13A00001); // movne r0,#1
956 break;
957 case OP_LESS_EQUAL:
958 o4(0xD3A00001); // movle r0,#1
959 o4(0xC3A00000); // movgt r0,#0
960 break;
961 case OP_GREATER:
962 o4(0xD3A00000); // movle r0,#0
963 o4(0xC3A00001); // movgt r0,#1
964 break;
965 case OP_GREATER_EQUAL:
966 o4(0xA3A00001); // movge r0,#1
967 o4(0xB3A00000); // movlt r0,#0
968 break;
969 case OP_LESS:
970 o4(0xA3A00000); // movge r0,#0
971 o4(0xB3A00001); // movlt r0,#1
972 break;
973 default:
974 error("Unknown comparison op %d", op);
975 break;
976 }
977#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700978 switch(op) {
979 case OP_EQUALS:
980 callRuntime((void*) runtime_cmp_eq_ff);
981 break;
982 case OP_NOT_EQUALS:
983 callRuntime((void*) runtime_cmp_ne_ff);
984 break;
985 case OP_LESS_EQUAL:
986 callRuntime((void*) runtime_cmp_le_ff);
987 break;
988 case OP_GREATER:
989 callRuntime((void*) runtime_cmp_gt_ff);
990 break;
991 case OP_GREATER_EQUAL:
992 callRuntime((void*) runtime_cmp_ge_ff);
993 break;
994 case OP_LESS:
995 callRuntime((void*) runtime_cmp_lt_ff);
996 break;
997 default:
998 error("Unknown comparison op %d", op);
999 break;
1000 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001001#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001002 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001003 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001004 }
1005
Jack Palevich546b2242009-05-13 15:10:04 -07001006 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001007 Type* pR0Type = getR0Type();
1008 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001009 TypeTag tagR0 = pR0Type->tag;
1010 TypeTag tagTOS = pTOSType->tag;
1011 bool isFloatR0 = isFloatTag(tagR0);
1012 bool isFloatTOS = isFloatTag(tagTOS);
1013 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001014 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001015 bool isPtrR0 = isPointerTag(tagR0);
1016 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001017 if (isPtrR0 || isPtrTOS) {
1018 if (isPtrR0 && isPtrTOS) {
1019 if (op != OP_MINUS) {
1020 error("Unsupported pointer-pointer operation %d.", op);
1021 }
1022 if (! typeEqual(pR0Type, pTOSType)) {
1023 error("Incompatible pointer types for subtraction.");
1024 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001025 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001026 setR0Type(mkpInt);
1027 int size = sizeOf(pR0Type->pHead);
1028 if (size != 1) {
1029 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001030 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001031 // TODO: Optimize for power-of-two.
1032 genOp(OP_DIV);
1033 }
1034 } else {
1035 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1036 error("Unsupported pointer-scalar operation %d", op);
1037 }
Jack Palevichb6154502009-08-04 14:56:09 -07001038 Type* pPtrType = getPointerArithmeticResultType(
1039 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001040 int size = sizeOf(pPtrType->pHead);
1041 if (size != 1) {
1042 // TODO: Optimize for power-of-two.
1043 liReg(size, 2);
1044 if (isPtrR0) {
1045 o4(0x0E0010192); // mul r1,r2,r1
1046 } else {
1047 o4(0x0E0000092); // mul r0,r2,r0
1048 }
1049 }
1050 switch(op) {
1051 case OP_PLUS:
1052 o4(0xE0810000); // add r0,r1,r0
1053 break;
1054 case OP_MINUS:
1055 o4(0xE0410000); // sub r0,r1,r0
1056 break;
1057 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001058 setR0Type(pPtrType);
1059 }
1060 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001061 switch(op) {
1062 case OP_MUL:
1063 o4(0x0E0000091); // mul r0,r1,r0
1064 break;
1065 case OP_DIV:
1066 callRuntime((void*) runtime_DIV);
1067 break;
1068 case OP_MOD:
1069 callRuntime((void*) runtime_MOD);
1070 break;
1071 case OP_PLUS:
1072 o4(0xE0810000); // add r0,r1,r0
1073 break;
1074 case OP_MINUS:
1075 o4(0xE0410000); // sub r0,r1,r0
1076 break;
1077 case OP_SHIFT_LEFT:
1078 o4(0xE1A00011); // lsl r0,r1,r0
1079 break;
1080 case OP_SHIFT_RIGHT:
1081 o4(0xE1A00051); // asr r0,r1,r0
1082 break;
1083 case OP_BIT_AND:
1084 o4(0xE0010000); // and r0,r1,r0
1085 break;
1086 case OP_BIT_XOR:
1087 o4(0xE0210000); // eor r0,r1,r0
1088 break;
1089 case OP_BIT_OR:
1090 o4(0xE1810000); // orr r0,r1,r0
1091 break;
1092 case OP_BIT_NOT:
1093 o4(0xE1E00000); // mvn r0, r0
1094 break;
1095 default:
1096 error("Unimplemented op %d\n", op);
1097 break;
1098 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001099 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001100 } else {
1101 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1102 if (pResultType->tag == TY_DOUBLE) {
1103 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001104
Jack Palevichb7718b92009-07-09 22:00:24 -07001105 switch(op) {
1106 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001107#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001108 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001109#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001110 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001111#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001112 break;
1113 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001114#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001115 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001116#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001117 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001118#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001119 break;
1120 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001121#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001122 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001123#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001124 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001125#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001126 break;
1127 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001128#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001129 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001130#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001131 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001132#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001133 break;
1134 default:
1135 error("Unsupported binary floating operation %d\n", op);
1136 break;
1137 }
1138 } else {
1139 setupFloatArgs();
1140 switch(op) {
1141 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001142#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001143 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001144#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001145 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001146#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001147 break;
1148 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001149#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001150 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001151#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001152 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001153#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001154 break;
1155 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001156#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001157 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001158#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001159 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001160#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001161 break;
1162 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001163#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001164 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001165#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001166 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001167#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001168 break;
1169 default:
1170 error("Unsupported binary floating operation %d\n", op);
1171 break;
1172 }
1173 }
1174 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001175 }
Jack Palevich22305132009-05-13 10:58:45 -07001176 }
1177
Jack Palevich58c30ee2009-07-17 16:35:23 -07001178 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001179 if (op != OP_LOGICAL_NOT) {
1180 error("Unknown unary cmp %d", op);
1181 } else {
1182 Type* pR0Type = getR0Type();
1183 TypeTag tag = collapseType(pR0Type->tag);
1184 switch(tag) {
1185 case TY_INT:
1186 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001187 o4(0xE1510000); // cmp r1, r0
1188 o4(0x03A00001); // moveq r0,#1
1189 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001190 break;
1191 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001192#ifdef ARM_USE_VFP
1193 o4(0xEEF57A40); // fcmpzs s15
1194 o4(0xEEF1FA10); // fmstat
1195 o4(0x03A00001); // moveq r0,#1
1196 o4(0x13A00000); // movne r0,#0
1197#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001198 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001199#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001200 break;
1201 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001202#ifdef ARM_USE_VFP
1203 o4(0xEEB57B40); // fcmpzd d7
1204 o4(0xEEF1FA10); // fmstat
1205 o4(0x03A00001); // moveq r0,#1
1206 o4(0x13A00000); // movne r0,#0
1207#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001208 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001209#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001210 break;
1211 default:
1212 error("gUnaryCmp unsupported type");
1213 break;
1214 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001215 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001216 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001217 }
1218
1219 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001220 Type* pR0Type = getR0Type();
1221 TypeTag tag = collapseType(pR0Type->tag);
1222 switch(tag) {
1223 case TY_INT:
1224 switch(op) {
1225 case OP_MINUS:
1226 o4(0xE3A01000); // mov r1, #0
1227 o4(0xE0410000); // sub r0,r1,r0
1228 break;
1229 case OP_BIT_NOT:
1230 o4(0xE1E00000); // mvn r0, r0
1231 break;
1232 default:
1233 error("Unknown unary op %d\n", op);
1234 break;
1235 }
1236 break;
1237 case TY_FLOAT:
1238 case TY_DOUBLE:
1239 switch (op) {
1240 case OP_MINUS:
1241 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001242#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001243 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001244#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001245 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001246#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001247 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001248#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001249 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001250#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001251 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001252#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001253 }
1254 break;
1255 case OP_BIT_NOT:
1256 error("Can't apply '~' operator to a float or double.");
1257 break;
1258 default:
1259 error("Unknown unary op %d\n", op);
1260 break;
1261 }
1262 break;
1263 default:
1264 error("genUnaryOp unsupported type");
1265 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001266 }
Jack Palevich22305132009-05-13 10:58:45 -07001267 }
1268
Jack Palevich1cdef202009-05-22 12:06:27 -07001269 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001270 Type* pR0Type = getR0Type();
1271 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001272
1273#ifdef ARM_USE_VFP
1274 switch (r0ct ) {
1275 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001276 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001277 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001278 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001279 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001280 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001281 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001282 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001283 default:
1284 o4(0xE92D0001); // stmfd sp!,{r0}
1285 mStackUse += 4;
1286 }
1287#else
1288
Jack Palevichb7718b92009-07-09 22:00:24 -07001289 if (r0ct != TY_DOUBLE) {
1290 o4(0xE92D0001); // stmfd sp!,{r0}
1291 mStackUse += 4;
1292 } else {
1293 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1294 mStackUse += 8;
1295 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001296#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001297 pushType();
-b master422972c2009-06-17 19:13:52 -07001298 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001299 }
1300
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001301 virtual void over() {
1302 // We know it's only used for int-ptr ops (++/--)
1303
1304 Type* pR0Type = getR0Type();
1305 TypeTag r0ct = collapseType(pR0Type->tag);
1306
1307 Type* pTOSType = getTOSType();
1308 TypeTag tosct = collapseType(pTOSType->tag);
1309
1310 assert (r0ct == TY_INT && tosct == TY_INT);
1311
1312 o4(0xE8BD0002); // ldmfd sp!,{r1}
1313 o4(0xE92D0001); // stmfd sp!,{r0}
1314 o4(0xE92D0002); // stmfd sp!,{r1}
1315 overType();
1316 mStackUse += 4;
1317 }
1318
Jack Palevich58c30ee2009-07-17 16:35:23 -07001319 virtual void popR0() {
1320 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001321 TypeTag tosct = collapseType(pTOSType->tag);
1322#ifdef ARM_USE_VFP
1323 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001324 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001325 }
1326#endif
1327 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001328 case TY_INT:
1329 case TY_FLOAT:
1330 o4(0xE8BD0001); // ldmfd sp!,{r0}
1331 mStackUse -= 4;
1332 break;
1333 case TY_DOUBLE:
1334 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1335 mStackUse -= 8;
1336 break;
1337 default:
1338 error("Can't pop this type.");
1339 break;
1340 }
1341 popType();
1342 LOG_STACK("popR0: %d\n", mStackUse);
1343 }
1344
1345 virtual void storeR0ToTOS() {
1346 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001347 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001348 Type* pDestType = pPointerType->pHead;
1349 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001350 o4(0xE8BD0004); // ldmfd sp!,{r2}
1351 popType();
-b master422972c2009-06-17 19:13:52 -07001352 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001353 switch (pDestType->tag) {
1354 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001355 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001356 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001357 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001358 case TY_FLOAT:
1359#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001360 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001361#else
1362 o4(0xE5820000); // str r0, [r2]
1363#endif
1364 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001365 case TY_SHORT:
1366 o4(0xE1C200B0); // strh r0, [r2]
1367 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001368 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001369 o4(0xE5C20000); // strb r0, [r2]
1370 break;
1371 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001372#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001373 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001374#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001375 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001376#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001377 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001378 case TY_STRUCT:
1379 {
1380 int size = sizeOf(pDestType);
1381 if (size > 0) {
1382 liReg(size, 1);
1383 callRuntime((void*) runtime_structCopy);
1384 }
1385 }
1386 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001387 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001388 error("storeR0ToTOS: unimplemented type %d",
1389 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001390 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001391 }
Jack Palevich22305132009-05-13 10:58:45 -07001392 }
1393
Jack Palevich58c30ee2009-07-17 16:35:23 -07001394 virtual void loadR0FromR0() {
1395 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001396 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001397 Type* pNewType = pPointerType->pHead;
1398 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001399 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001400 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001401 case TY_INT:
1402 o4(0xE5900000); // ldr r0, [r0]
1403 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001404 case TY_FLOAT:
1405#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001406 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001407#else
1408 o4(0xE5900000); // ldr r0, [r0]
1409#endif
1410 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001411 case TY_SHORT:
1412 o4(0xE1D000F0); // ldrsh r0, [r0]
1413 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001414 case TY_CHAR:
1415 o4(0xE5D00000); // ldrb r0, [r0]
1416 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001417 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001418#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001419 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001420#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001421 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001422#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001423 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001424 case TY_ARRAY:
1425 pNewType = pNewType->pTail;
1426 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001427 case TY_STRUCT:
1428 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001429 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001430 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001431 break;
1432 }
Jack Palevich80e49722009-08-04 15:39:49 -07001433 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001434 }
1435
Jack Palevichb5e33312009-07-30 19:06:34 -07001436 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001437 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001438 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001439
1440 size_t immediate = 0;
1441 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001442 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001443 inRange = encode12BitImmediate(-ea, &immediate);
1444 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001445 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001446 inRange = encode12BitImmediate(ea, &immediate);
1447 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1448 }
1449 if (! inRange) {
1450 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001451 }
Jack Palevichbd894902009-05-14 19:35:31 -07001452 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001453 // Global, absolute.
1454 o4(0xE59F0000); // ldr r0, .L1
1455 o4(0xEA000000); // b .L99
1456 o4(ea); // .L1: .word 0
1457 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001458 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001459 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001460 }
1461
Jack Palevich9f51a262009-07-29 16:22:26 -07001462 virtual int leaForward(int ea, Type* pPointerType) {
1463 setR0Type(pPointerType);
1464 int result = ea;
1465 int pc = getPC();
1466 int offset = 0;
1467 if (ea) {
1468 offset = (pc - ea - 8) >> 2;
1469 if ((offset & 0xffff) != offset) {
1470 error("function forward reference out of bounds");
1471 }
1472 } else {
1473 offset = 0;
1474 }
1475 o4(0xE59F0000 | offset); // ldr r0, .L1
1476
1477 if (ea == 0) {
1478 o4(0xEA000000); // b .L99
1479 result = o4(ea); // .L1: .word 0
1480 // .L99:
1481 }
1482 return result;
1483 }
1484
Jack Palevichb6154502009-08-04 14:56:09 -07001485 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001486 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001487 if (isPointerType(pType) && isPointerType(pR0Type)) {
1488 Type* pA = pR0Type;
1489 Type* pB = pType;
1490 // Array decays to pointer
1491 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1492 pA = pA->pTail;
1493 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001494 if (! (typeEqual(pA, pB)
1495 || pB->pHead->tag == TY_VOID
1496 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1497 )) {
1498 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001499 }
Jack Palevichb6154502009-08-04 14:56:09 -07001500 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001501 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001502 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001503 TypeTag r0Tag = collapseType(pR0Type->tag);
1504 TypeTag destTag = collapseType(pType->tag);
1505 if (r0Tag == TY_INT) {
1506 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001507#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001508 o4(0xEE070A90); // fmsr s15, r0
1509 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001510
1511#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001512 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001513#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001514 } else {
1515 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001516#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001517 o4(0xEE070A90); // fmsr s15, r0
1518 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001519
1520#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001521 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001522#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001523 }
1524 } else if (r0Tag == TY_FLOAT) {
1525 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001526#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001527 o4(0xEEFD7AE7); // ftosizs s15, s15
1528 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001529#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001530 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001531#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001532 } else {
1533 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001534#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001535 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001536#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001537 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001538#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001539 }
1540 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001541 if (r0Tag == TY_DOUBLE) {
1542 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001543#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001544 o4(0xEEFD7BC7); // ftosizd s15, d7
1545 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001546#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001547 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001548#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001549 } else {
1550 if(destTag == TY_FLOAT) {
1551#ifdef ARM_USE_VFP
1552 o4(0xEEF77BC7); // fcvtsd s15, d7
1553#else
1554 callRuntime((void*) runtime_double_to_float);
1555#endif
1556 } else {
1557 incompatibleTypes(pR0Type, pType);
1558 }
1559 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001560 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001561 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001562 }
1563 }
Jack Palevich8df46192009-07-07 14:48:51 -07001564 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001565 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001566 }
1567
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001568 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001569 return o4(0xE24DDF00); // Placeholder
1570 }
1571
Jack Palevich8148c5b2009-07-16 18:24:47 -07001572 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001573 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001574 Type* pR0Type = getR0Type();
1575 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001576#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001577 switch(r0ct) {
1578 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001579 if (l < 0 || l > 4096-4) {
1580 error("l out of range for stack offset: 0x%08x", l);
1581 }
1582 o4(0xE58D0000 | l); // str r0, [sp, #l]
1583 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001584 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001585 if (l < 0 || l > 1020 || (l & 3)) {
1586 error("l out of range for stack offset: 0x%08x", l);
1587 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001588 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001589 return 4;
1590 case TY_DOUBLE: {
1591 // Align to 8 byte boundary
1592 int l2 = (l + 7) & ~7;
1593 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1594 error("l out of range for stack offset: 0x%08x", l);
1595 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001596 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001597 return (l2 - l) + 8;
1598 }
1599 default:
1600 assert(false);
1601 return 0;
1602 }
1603#else
1604 switch(r0ct) {
1605 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001606 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001607 if (l < 0 || l > 4096-4) {
1608 error("l out of range for stack offset: 0x%08x", l);
1609 }
1610 o4(0xE58D0000 + l); // str r0, [sp, #l]
1611 return 4;
1612 case TY_DOUBLE: {
1613 // Align to 8 byte boundary
1614 int l2 = (l + 7) & ~7;
1615 if (l2 < 0 || l2 > 4096-8) {
1616 error("l out of range for stack offset: 0x%08x", l);
1617 }
1618 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1619 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1620 return (l2 - l) + 8;
1621 }
1622 default:
1623 assert(false);
1624 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001625 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001626#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001627 }
1628
Jack Palevichb7718b92009-07-09 22:00:24 -07001629 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001630 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001631 // Have to calculate register arg count from actual stack size,
1632 // in order to properly handle ... functions.
1633 int regArgCount = l >> 2;
1634 if (regArgCount > 4) {
1635 regArgCount = 4;
1636 }
1637 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001638 argumentStackUse -= regArgCount * 4;
1639 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1640 }
1641 mStackUse += argumentStackUse;
1642
1643 // Align stack.
1644 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1645 * STACK_ALIGNMENT);
1646 mStackAlignmentAdjustment = 0;
1647 if (missalignment > 0) {
1648 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1649 }
1650 l += mStackAlignmentAdjustment;
1651
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001652 if (l < 0 || l > 0x3FC) {
1653 error("L out of range for stack adjustment: 0x%08x", l);
1654 }
1655 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001656 mStackUse += mStackAlignmentAdjustment;
1657 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1658 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001659 }
1660
Jack Palevich8df46192009-07-07 14:48:51 -07001661 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001662 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001663 // Forward calls are always short (local)
1664 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001665 }
1666
Jack Palevich8df46192009-07-07 14:48:51 -07001667 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001668 assert(pFunc->tag == TY_FUNC);
1669 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001670 int argCount = l >> 2;
1671 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001672 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001673 if (adjustedL < 0 || adjustedL > 4096-4) {
1674 error("l out of range for stack offset: 0x%08x", l);
1675 }
1676 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1677 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001678 Type* pReturnType = pFunc->pHead;
1679 setR0Type(pReturnType);
1680#ifdef ARM_USE_VFP
1681 switch(pReturnType->tag) {
1682 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001683 o4(0xEE070A90); // fmsr s15, r0
1684 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001685 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001686 o4(0xEC410B17); // fmdrr d7, r0, r1
1687 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001688 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001689 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001690 }
1691#endif
Jack Palevich22305132009-05-13 10:58:45 -07001692 }
1693
Jack Palevichb7718b92009-07-09 22:00:24 -07001694 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001695 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001696 // Have to calculate register arg count from actual stack size,
1697 // in order to properly handle ... functions.
1698 int regArgCount = l >> 2;
1699 if (regArgCount > 4) {
1700 regArgCount = 4;
1701 }
1702 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001703 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1704 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001705 if (stackUse) {
1706 if (stackUse < 0 || stackUse > 255) {
1707 error("L out of range for stack adjustment: 0x%08x", l);
1708 }
1709 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001710 mStackUse -= stackUse * 4;
1711 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001712 }
Jack Palevich22305132009-05-13 10:58:45 -07001713 }
1714
Jack Palevicha6535612009-05-13 16:24:17 -07001715 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001716 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001717 }
1718
1719 /* output a symbol and patch all calls to it */
1720 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001721 int n;
1722 int base = getBase();
1723 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001724 while (t) {
1725 int data = * (int*) t;
1726 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1727 if (decodedOffset == 0) {
1728 n = 0;
1729 } else {
1730 n = base + decodedOffset; /* next value */
1731 }
1732 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1733 | encodeRelAddress(pc - t - 8);
1734 t = n;
1735 }
1736 }
1737
Jack Palevich9f51a262009-07-29 16:22:26 -07001738 /* output a symbol and patch all calls to it */
1739 virtual void resolveForward(int t) {
1740 if (t) {
1741 int pc = getPC();
1742 *(int *) t = pc;
1743 }
1744 }
1745
Jack Palevich1cdef202009-05-22 12:06:27 -07001746 virtual int finishCompile() {
1747#if defined(__arm__)
1748 const long base = long(getBase());
1749 const long curr = long(getPC());
1750 int err = cacheflush(base, curr, 0);
1751 return err;
1752#else
1753 return 0;
1754#endif
1755 }
1756
Jack Palevich9eed7a22009-07-06 17:24:34 -07001757 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001758 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001759 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001760 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001761 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001762 case TY_CHAR:
1763 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001764 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07001765 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001766 case TY_DOUBLE:
1767 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001768 case TY_ARRAY:
1769 return alignmentOf(pType->pHead);
1770 case TY_STRUCT:
1771 return pType->pHead->alignment & 0x7fffffff;
1772 case TY_FUNC:
1773 error("alignment of func not supported");
1774 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001775 default:
1776 return 4;
1777 }
1778 }
1779
1780 /**
1781 * Array element alignment (in bytes) for this type of data.
1782 */
1783 virtual size_t sizeOf(Type* pType){
1784 switch(pType->tag) {
1785 case TY_INT:
1786 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001787 case TY_SHORT:
1788 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001789 case TY_CHAR:
1790 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001791 case TY_FLOAT:
1792 return 4;
1793 case TY_DOUBLE:
1794 return 8;
1795 case TY_POINTER:
1796 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001797 case TY_ARRAY:
1798 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07001799 case TY_STRUCT:
1800 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07001801 default:
1802 error("Unsupported type %d", pType->tag);
1803 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001804 }
1805 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001806
Jack Palevich22305132009-05-13 10:58:45 -07001807 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001808
1809 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1810
1811 /** Encode a relative address that might also be
1812 * a label.
1813 */
1814 int encodeAddress(int value) {
1815 int base = getBase();
1816 if (value >= base && value <= getPC() ) {
1817 // This is a label, encode it relative to the base.
1818 value = value - base;
1819 }
1820 return encodeRelAddress(value);
1821 }
1822
1823 int encodeRelAddress(int value) {
1824 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1825 }
Jack Palevich22305132009-05-13 10:58:45 -07001826
Jack Palevichb7718b92009-07-09 22:00:24 -07001827 int calcRegArgCount(Type* pDecl) {
1828 int reg = 0;
1829 Type* pArgs = pDecl->pTail;
1830 while (pArgs && reg < 4) {
1831 Type* pArg = pArgs->pHead;
1832 if ( pArg->tag == TY_DOUBLE) {
1833 int evenReg = (reg + 1) & ~1;
1834 if (evenReg >= 4) {
1835 break;
1836 }
1837 reg = evenReg + 2;
1838 } else {
1839 reg++;
1840 }
1841 pArgs = pArgs->pTail;
1842 }
1843 return reg;
1844 }
1845
Jack Palevich58c30ee2009-07-17 16:35:23 -07001846 void setupIntPtrArgs() {
1847 o4(0xE8BD0002); // ldmfd sp!,{r1}
1848 mStackUse -= 4;
1849 popType();
1850 }
1851
Jack Palevich30321cb2009-08-20 15:34:23 -07001852 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001853 * Make sure both R0 and TOS are floats. (Could be ints)
1854 * We know that at least one of R0 and TOS is already a float
1855 */
1856 void setupFloatArgs() {
1857 Type* pR0Type = getR0Type();
1858 Type* pTOSType = getTOSType();
1859 TypeTag tagR0 = collapseType(pR0Type->tag);
1860 TypeTag tagTOS = collapseType(pTOSType->tag);
1861 if (tagR0 != TY_FLOAT) {
1862 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001863#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001864 o4(0xEE070A90); // fmsr s15, r0
1865 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001866#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001867 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001868#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001869 }
1870 if (tagTOS != TY_FLOAT) {
1871 assert(tagTOS == TY_INT);
1872 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001873#ifdef ARM_USE_VFP
1874 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07001875 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07001876#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001877 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1878 o4(0xE59D0004); // ldr r0, [sp, #4]
1879 callRuntime((void*) runtime_int_to_float);
1880 o4(0xE1A01000); // mov r1, r0
1881 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1882 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001883#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001884 } else {
1885 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001886#ifdef ARM_USE_VFP
1887 o4(0xECBD7A01); // fldmfds sp!, {s14}
1888
1889#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001890 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001891#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001892 }
1893 mStackUse -= 4;
1894 popType();
1895 }
1896
Jack Palevich30321cb2009-08-20 15:34:23 -07001897 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001898 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1899 * We know that at least one of R0 and TOS are already a double.
1900 */
1901
1902 void setupDoubleArgs() {
1903 Type* pR0Type = getR0Type();
1904 Type* pTOSType = getTOSType();
1905 TypeTag tagR0 = collapseType(pR0Type->tag);
1906 TypeTag tagTOS = collapseType(pTOSType->tag);
1907 if (tagR0 != TY_DOUBLE) {
1908 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001909#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001910 o4(0xEE070A90); // fmsr s15, r0
1911 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001912
1913#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001914 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001915#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001916 } else {
1917 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001918#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001919 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001920#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001921 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001922#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001923 }
1924 }
1925 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001926#ifdef ARM_USE_VFP
1927 if (tagTOS == TY_INT) {
1928 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001929 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001930 } else {
1931 assert(tagTOS == TY_FLOAT);
1932 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001933 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001934 }
1935#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001936 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1937 o4(0xE59D0008); // ldr r0, [sp, #8]
1938 if (tagTOS == TY_INT) {
1939 callRuntime((void*) runtime_int_to_double);
1940 } else {
1941 assert(tagTOS == TY_FLOAT);
1942 callRuntime((void*) runtime_float_to_double);
1943 }
1944 o4(0xE1A02000); // mov r2, r0
1945 o4(0xE1A03001); // mov r3, r1
1946 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1947 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001948#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001949 mStackUse -= 4;
1950 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001951#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001952 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07001953#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001954 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07001955#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001956 mStackUse -= 8;
1957 }
1958 popType();
1959 }
1960
Jack Palevicha8f427f2009-07-13 18:40:08 -07001961 void liReg(int t, int reg) {
1962 assert(reg >= 0 && reg < 16);
1963 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001964 size_t encodedImmediate;
1965 if (encode12BitImmediate(t, &encodedImmediate)) {
1966 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
1967 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001968 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07001969 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001970 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001971 o4(0xE51F0000 | rN); // ldr rN, .L3
1972 o4(0xEA000000); // b .L99
1973 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001974 // .L99:
1975 }
1976 }
1977
Jack Palevich9221bcc2009-08-26 16:15:07 -07001978 bool encode12BitImmediate(size_t immediate, size_t* pResult) {
1979 for(size_t i = 0; i < 16; i++) {
1980 size_t rotate = i * 2;
1981 size_t mask = rotateRight(0xff, rotate);
1982 if ((immediate | mask) == mask) {
1983 size_t bits8 = rotateLeft(immediate, rotate);
1984 assert(bits8 <= 0xff);
1985 *pResult = (i << 8) | bits8;
1986 return true;
1987 }
1988 }
1989 return false;
1990 }
1991
Jack Palevichc408bbf2009-09-08 12:07:32 -07001992 void incompatibleTypes(Type* pR0Type, Type* pType) {
1993 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
1994 }
1995
Jack Palevich9221bcc2009-08-26 16:15:07 -07001996 size_t rotateRight(size_t n, size_t rotate) {
1997 return (n >> rotate) | (n << (32 - rotate));
1998 }
1999
2000 size_t rotateLeft(size_t n, size_t rotate) {
2001 return (n << rotate) | (n >> (32 - rotate));
2002 }
2003
Jack Palevichb7718b92009-07-09 22:00:24 -07002004 void callRuntime(void* fn) {
2005 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002006 o4(0xEA000000); // b .L99
2007 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002008 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002009 }
2010
Jack Palevichb7718b92009-07-09 22:00:24 -07002011 // Integer math:
2012
2013 static int runtime_DIV(int b, int a) {
2014 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002015 }
2016
Jack Palevichb7718b92009-07-09 22:00:24 -07002017 static int runtime_MOD(int b, int a) {
2018 return a % b;
2019 }
2020
Jack Palevich9221bcc2009-08-26 16:15:07 -07002021 static void runtime_structCopy(void* src, size_t size, void* dest) {
2022 memcpy(dest, src, size);
2023 }
2024
Jack Palevich30321cb2009-08-20 15:34:23 -07002025#ifndef ARM_USE_VFP
2026
Jack Palevichb7718b92009-07-09 22:00:24 -07002027 // Comparison to zero
2028
2029 static int runtime_is_non_zero_f(float a) {
2030 return a != 0;
2031 }
2032
2033 static int runtime_is_non_zero_d(double a) {
2034 return a != 0;
2035 }
2036
2037 // Comparison to zero
2038
2039 static int runtime_is_zero_f(float a) {
2040 return a == 0;
2041 }
2042
2043 static int runtime_is_zero_d(double a) {
2044 return a == 0;
2045 }
2046
2047 // Type conversion
2048
2049 static int runtime_float_to_int(float a) {
2050 return (int) a;
2051 }
2052
2053 static double runtime_float_to_double(float a) {
2054 return (double) a;
2055 }
2056
2057 static int runtime_double_to_int(double a) {
2058 return (int) a;
2059 }
2060
2061 static float runtime_double_to_float(double a) {
2062 return (float) a;
2063 }
2064
2065 static float runtime_int_to_float(int a) {
2066 return (float) a;
2067 }
2068
2069 static double runtime_int_to_double(int a) {
2070 return (double) a;
2071 }
2072
2073 // Comparisons float
2074
2075 static int runtime_cmp_eq_ff(float b, float a) {
2076 return a == b;
2077 }
2078
2079 static int runtime_cmp_ne_ff(float b, float a) {
2080 return a != b;
2081 }
2082
2083 static int runtime_cmp_lt_ff(float b, float a) {
2084 return a < b;
2085 }
2086
2087 static int runtime_cmp_le_ff(float b, float a) {
2088 return a <= b;
2089 }
2090
2091 static int runtime_cmp_ge_ff(float b, float a) {
2092 return a >= b;
2093 }
2094
2095 static int runtime_cmp_gt_ff(float b, float a) {
2096 return a > b;
2097 }
2098
2099 // Comparisons double
2100
2101 static int runtime_cmp_eq_dd(double b, double a) {
2102 return a == b;
2103 }
2104
2105 static int runtime_cmp_ne_dd(double b, double a) {
2106 return a != b;
2107 }
2108
2109 static int runtime_cmp_lt_dd(double b, double a) {
2110 return a < b;
2111 }
2112
2113 static int runtime_cmp_le_dd(double b, double a) {
2114 return a <= b;
2115 }
2116
2117 static int runtime_cmp_ge_dd(double b, double a) {
2118 return a >= b;
2119 }
2120
2121 static int runtime_cmp_gt_dd(double b, double a) {
2122 return a > b;
2123 }
2124
2125 // Math float
2126
2127 static float runtime_op_add_ff(float b, float a) {
2128 return a + b;
2129 }
2130
2131 static float runtime_op_sub_ff(float b, float a) {
2132 return a - b;
2133 }
2134
2135 static float runtime_op_mul_ff(float b, float a) {
2136 return a * b;
2137 }
2138
2139 static float runtime_op_div_ff(float b, float a) {
2140 return a / b;
2141 }
2142
2143 static float runtime_op_neg_f(float a) {
2144 return -a;
2145 }
2146
2147 // Math double
2148
2149 static double runtime_op_add_dd(double b, double a) {
2150 return a + b;
2151 }
2152
2153 static double runtime_op_sub_dd(double b, double a) {
2154 return a - b;
2155 }
2156
2157 static double runtime_op_mul_dd(double b, double a) {
2158 return a * b;
2159 }
2160
2161 static double runtime_op_div_dd(double b, double a) {
2162 return a / b;
2163 }
2164
2165 static double runtime_op_neg_d(double a) {
2166 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002167 }
-b master422972c2009-06-17 19:13:52 -07002168
Jack Palevich30321cb2009-08-20 15:34:23 -07002169#endif
2170
-b master422972c2009-06-17 19:13:52 -07002171 static const int STACK_ALIGNMENT = 8;
2172 int mStackUse;
2173 // This variable holds the amount we adjusted the stack in the most
2174 // recent endFunctionCallArguments call. It's examined by the
2175 // following adjustStackAfterCall call.
2176 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002177 };
2178
Jack Palevich09555c72009-05-27 12:25:55 -07002179#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002180
2181#ifdef PROVIDE_X86_CODEGEN
2182
Jack Palevich21a15a22009-05-11 14:49:29 -07002183 class X86CodeGenerator : public CodeGenerator {
2184 public:
2185 X86CodeGenerator() {}
2186 virtual ~X86CodeGenerator() {}
2187
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002188 /* returns address to patch with local variable size
2189 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002190 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002191 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2192 return oad(0xec81, 0); /* sub $xxx, %esp */
2193 }
2194
Jack Palevichb7718b92009-07-09 22:00:24 -07002195 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002196 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002197 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002198 }
2199
Jack Palevich21a15a22009-05-11 14:49:29 -07002200 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002201 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002202 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002203 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002204 }
2205
Jack Palevich1a539db2009-07-08 13:04:41 -07002206 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002207 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002208 switch (pType->tag) {
2209 case TY_FLOAT:
2210 oad(0x05D9, address); // flds
2211 break;
2212 case TY_DOUBLE:
2213 oad(0x05DD, address); // fldl
2214 break;
2215 default:
2216 assert(false);
2217 break;
2218 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002219 }
2220
Jack Palevich9221bcc2009-08-26 16:15:07 -07002221 virtual void addStructOffsetR0(int offset, Type* pType) {
2222 if (offset) {
2223 oad(0x05, offset); // addl offset, %eax
2224 }
2225 setR0Type(pType, ET_LVALUE);
2226 }
2227
Jack Palevich22305132009-05-13 10:58:45 -07002228 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002229 return psym(0xe9, t);
2230 }
2231
2232 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002233 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002234 Type* pR0Type = getR0Type();
2235 TypeTag tagR0 = pR0Type->tag;
2236 bool isFloatR0 = isFloatTag(tagR0);
2237 if (isFloatR0) {
2238 o(0xeed9); // fldz
2239 o(0xe9da); // fucompp
2240 o(0xe0df); // fnstsw %ax
2241 o(0x9e); // sahf
2242 } else {
2243 o(0xc085); // test %eax, %eax
2244 }
2245 // Use two output statements to generate one instruction.
2246 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002247 return psym(0x84 + l, t);
2248 }
2249
Jack Palevich58c30ee2009-07-17 16:35:23 -07002250 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002251 Type* pR0Type = getR0Type();
2252 Type* pTOSType = getTOSType();
2253 TypeTag tagR0 = pR0Type->tag;
2254 TypeTag tagTOS = pTOSType->tag;
2255 bool isFloatR0 = isFloatTag(tagR0);
2256 bool isFloatTOS = isFloatTag(tagTOS);
2257 if (!isFloatR0 && !isFloatTOS) {
2258 int t = decodeOp(op);
2259 o(0x59); /* pop %ecx */
2260 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002261 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002262 o(0x0f); /* setxx %al */
2263 o(t + 0x90);
2264 o(0xc0);
2265 popType();
2266 } else {
2267 setupFloatOperands();
2268 switch (op) {
2269 case OP_EQUALS:
2270 o(0xe9da); // fucompp
2271 o(0xe0df); // fnstsw %ax
2272 o(0x9e); // sahf
2273 o(0xc0940f); // sete %al
2274 o(0xc29b0f); // setnp %dl
2275 o(0xd021); // andl %edx, %eax
2276 break;
2277 case OP_NOT_EQUALS:
2278 o(0xe9da); // fucompp
2279 o(0xe0df); // fnstsw %ax
2280 o(0x9e); // sahf
2281 o(0xc0950f); // setne %al
2282 o(0xc29a0f); // setp %dl
2283 o(0xd009); // orl %edx, %eax
2284 break;
2285 case OP_GREATER_EQUAL:
2286 o(0xe9da); // fucompp
2287 o(0xe0df); // fnstsw %ax
2288 o(0x05c4f6); // testb $5, %ah
2289 o(0xc0940f); // sete %al
2290 break;
2291 case OP_LESS:
2292 o(0xc9d9); // fxch %st(1)
2293 o(0xe9da); // fucompp
2294 o(0xe0df); // fnstsw %ax
2295 o(0x9e); // sahf
2296 o(0xc0970f); // seta %al
2297 break;
2298 case OP_LESS_EQUAL:
2299 o(0xc9d9); // fxch %st(1)
2300 o(0xe9da); // fucompp
2301 o(0xe0df); // fnstsw %ax
2302 o(0x9e); // sahf
2303 o(0xc0930f); // setea %al
2304 break;
2305 case OP_GREATER:
2306 o(0xe9da); // fucompp
2307 o(0xe0df); // fnstsw %ax
2308 o(0x45c4f6); // testb $69, %ah
2309 o(0xc0940f); // sete %al
2310 break;
2311 default:
2312 error("Unknown comparison op");
2313 }
2314 o(0xc0b60f); // movzbl %al, %eax
2315 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002316 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002317 }
2318
Jack Palevich546b2242009-05-13 15:10:04 -07002319 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002320 Type* pR0Type = getR0Type();
2321 Type* pTOSType = getTOSType();
2322 TypeTag tagR0 = pR0Type->tag;
2323 TypeTag tagTOS = pTOSType->tag;
2324 bool isFloatR0 = isFloatTag(tagR0);
2325 bool isFloatTOS = isFloatTag(tagTOS);
2326 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002327 bool isPtrR0 = isPointerTag(tagR0);
2328 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002329 if (isPtrR0 || isPtrTOS) {
2330 if (isPtrR0 && isPtrTOS) {
2331 if (op != OP_MINUS) {
2332 error("Unsupported pointer-pointer operation %d.", op);
2333 }
2334 if (! typeEqual(pR0Type, pTOSType)) {
2335 error("Incompatible pointer types for subtraction.");
2336 }
2337 o(0x59); /* pop %ecx */
2338 o(decodeOp(op));
2339 popType();
2340 setR0Type(mkpInt);
2341 int size = sizeOf(pR0Type->pHead);
2342 if (size != 1) {
2343 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002344 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002345 // TODO: Optimize for power-of-two.
2346 genOp(OP_DIV);
2347 }
2348 } else {
2349 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2350 error("Unsupported pointer-scalar operation %d", op);
2351 }
Jack Palevichb6154502009-08-04 14:56:09 -07002352 Type* pPtrType = getPointerArithmeticResultType(
2353 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002354 o(0x59); /* pop %ecx */
2355 int size = sizeOf(pPtrType->pHead);
2356 if (size != 1) {
2357 // TODO: Optimize for power-of-two.
2358 if (isPtrR0) {
2359 oad(0xC969, size); // imull $size, %ecx
2360 } else {
2361 oad(0xC069, size); // mul $size, %eax
2362 }
2363 }
2364 o(decodeOp(op));
2365 popType();
2366 setR0Type(pPtrType);
2367 }
2368 } else {
2369 o(0x59); /* pop %ecx */
2370 o(decodeOp(op));
2371 if (op == OP_MOD)
2372 o(0x92); /* xchg %edx, %eax */
2373 popType();
2374 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002375 } else {
2376 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2377 setupFloatOperands();
2378 // Both float. x87 R0 == left hand, x87 R1 == right hand
2379 switch (op) {
2380 case OP_MUL:
2381 o(0xc9de); // fmulp
2382 break;
2383 case OP_DIV:
2384 o(0xf1de); // fdivp
2385 break;
2386 case OP_PLUS:
2387 o(0xc1de); // faddp
2388 break;
2389 case OP_MINUS:
2390 o(0xe1de); // fsubp
2391 break;
2392 default:
2393 error("Unsupported binary floating operation.");
2394 break;
2395 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002396 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002397 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002398 }
2399
Jack Palevich58c30ee2009-07-17 16:35:23 -07002400 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002401 if (op != OP_LOGICAL_NOT) {
2402 error("Unknown unary cmp %d", op);
2403 } else {
2404 Type* pR0Type = getR0Type();
2405 TypeTag tag = collapseType(pR0Type->tag);
2406 switch(tag) {
2407 case TY_INT: {
2408 oad(0xb9, 0); /* movl $0, %ecx */
2409 int t = decodeOp(op);
2410 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002411 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002412 o(0x0f); /* setxx %al */
2413 o(t + 0x90);
2414 o(0xc0);
2415 }
2416 break;
2417 case TY_FLOAT:
2418 case TY_DOUBLE:
2419 o(0xeed9); // fldz
2420 o(0xe9da); // fucompp
2421 o(0xe0df); // fnstsw %ax
2422 o(0x9e); // sahf
2423 o(0xc0950f); // setne %al
2424 o(0xc29a0f); // setp %dl
2425 o(0xd009); // orl %edx, %eax
2426 o(0xc0b60f); // movzbl %al, %eax
2427 o(0x01f083); // xorl $1, %eax
2428 break;
2429 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002430 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002431 break;
2432 }
2433 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002434 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002435 }
2436
2437 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002438 Type* pR0Type = getR0Type();
2439 TypeTag tag = collapseType(pR0Type->tag);
2440 switch(tag) {
2441 case TY_INT:
2442 oad(0xb9, 0); /* movl $0, %ecx */
2443 o(decodeOp(op));
2444 break;
2445 case TY_FLOAT:
2446 case TY_DOUBLE:
2447 switch (op) {
2448 case OP_MINUS:
2449 o(0xe0d9); // fchs
2450 break;
2451 case OP_BIT_NOT:
2452 error("Can't apply '~' operator to a float or double.");
2453 break;
2454 default:
2455 error("Unknown unary op %d\n", op);
2456 break;
2457 }
2458 break;
2459 default:
2460 error("genUnaryOp unsupported type");
2461 break;
2462 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002463 }
2464
Jack Palevich1cdef202009-05-22 12:06:27 -07002465 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002466 Type* pR0Type = getR0Type();
2467 TypeTag r0ct = collapseType(pR0Type->tag);
2468 switch(r0ct) {
2469 case TY_INT:
2470 o(0x50); /* push %eax */
2471 break;
2472 case TY_FLOAT:
2473 o(0x50); /* push %eax */
2474 o(0x241cd9); // fstps 0(%esp)
2475 break;
2476 case TY_DOUBLE:
2477 o(0x50); /* push %eax */
2478 o(0x50); /* push %eax */
2479 o(0x241cdd); // fstpl 0(%esp)
2480 break;
2481 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002482 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002483 break;
2484 }
Jack Palevich8df46192009-07-07 14:48:51 -07002485 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002486 }
2487
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002488 virtual void over() {
2489 // We know it's only used for int-ptr ops (++/--)
2490
2491 Type* pR0Type = getR0Type();
2492 TypeTag r0ct = collapseType(pR0Type->tag);
2493
2494 Type* pTOSType = getTOSType();
2495 TypeTag tosct = collapseType(pTOSType->tag);
2496
2497 assert (r0ct == TY_INT && tosct == TY_INT);
2498
2499 o(0x59); /* pop %ecx */
2500 o(0x50); /* push %eax */
2501 o(0x51); /* push %ecx */
2502
2503 overType();
2504 }
2505
Jack Palevich58c30ee2009-07-17 16:35:23 -07002506 virtual void popR0() {
2507 Type* pR0Type = getR0Type();
2508 TypeTag r0ct = collapseType(pR0Type->tag);
2509 switch(r0ct) {
2510 case TY_INT:
2511 o(0x58); /* popl %eax */
2512 break;
2513 case TY_FLOAT:
2514 o(0x2404d9); // flds (%esp)
2515 o(0x58); /* popl %eax */
2516 break;
2517 case TY_DOUBLE:
2518 o(0x2404dd); // fldl (%esp)
2519 o(0x58); /* popl %eax */
2520 o(0x58); /* popl %eax */
2521 break;
2522 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002523 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002524 break;
2525 }
2526 popType();
2527 }
2528
2529 virtual void storeR0ToTOS() {
2530 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002531 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002532 Type* pTargetType = pPointerType->pHead;
2533 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002534 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002535 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002536 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002537 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002538 case TY_INT:
2539 o(0x0189); /* movl %eax/%al, (%ecx) */
2540 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002541 case TY_SHORT:
2542 o(0x018966); /* movw %ax, (%ecx) */
2543 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002544 case TY_CHAR:
2545 o(0x0188); /* movl %eax/%al, (%ecx) */
2546 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002547 case TY_FLOAT:
2548 o(0x19d9); /* fstps (%ecx) */
2549 break;
2550 case TY_DOUBLE:
2551 o(0x19dd); /* fstpl (%ecx) */
2552 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002553 case TY_STRUCT:
2554 {
2555 // TODO: use alignment information to use movsw/movsl instead of movsb
2556 int size = sizeOf(pTargetType);
2557 if (size > 0) {
2558 o(0x9c); // pushf
2559 o(0x57); // pushl %edi
2560 o(0x56); // pushl %esi
2561 o(0xcf89); // movl %ecx, %edi
2562 o(0xc689); // movl %eax, %esi
2563 oad(0xb9, size); // mov #size, %ecx
2564 o(0xfc); // cld
2565 o(0xf3); // rep
2566 o(0xa4); // movsb
2567 o(0x5e); // popl %esi
2568 o(0x5f); // popl %edi
2569 o(0x9d); // popf
2570 }
2571 }
2572 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002573 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002574 error("storeR0ToTOS: unsupported type %d",
2575 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002576 break;
2577 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002578 }
2579
Jack Palevich58c30ee2009-07-17 16:35:23 -07002580 virtual void loadR0FromR0() {
2581 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002582 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002583 Type* pNewType = pPointerType->pHead;
2584 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002585 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002586 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002587 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002588 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002589 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002590 case TY_SHORT:
2591 o(0xbf0f); /* movswl (%eax), %eax */
2592 ob(0);
2593 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002594 case TY_CHAR:
2595 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002596 ob(0); /* add zero in code */
2597 break;
2598 case TY_FLOAT:
2599 o2(0x00d9); // flds (%eax)
2600 break;
2601 case TY_DOUBLE:
2602 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002603 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002604 case TY_ARRAY:
2605 pNewType = pNewType->pTail;
2606 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002607 case TY_STRUCT:
2608 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002609 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002610 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002611 break;
2612 }
Jack Palevich80e49722009-08-04 15:39:49 -07002613 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002614 }
2615
Jack Palevichb5e33312009-07-30 19:06:34 -07002616 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002617 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002618 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002619 }
2620
Jack Palevich9f51a262009-07-29 16:22:26 -07002621 virtual int leaForward(int ea, Type* pPointerType) {
2622 oad(0xb8, ea); /* mov $xx, %eax */
2623 setR0Type(pPointerType);
2624 return getPC() - 4;
2625 }
2626
Jack Palevichb6154502009-08-04 14:56:09 -07002627 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002628 Type* pR0Type = getR0Type();
2629 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002630 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002631 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002632 return;
2633 }
Jack Palevichb6154502009-08-04 14:56:09 -07002634 if (isPointerType(pType) && isPointerType(pR0Type)) {
2635 Type* pA = pR0Type;
2636 Type* pB = pType;
2637 // Array decays to pointer
2638 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2639 pA = pA->pTail;
2640 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002641 if (! (typeEqual(pA, pB)
2642 || pB->pHead->tag == TY_VOID
2643 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2644 )) {
2645 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002646 }
Jack Palevichb6154502009-08-04 14:56:09 -07002647 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002648 // do nothing special
2649 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2650 // do nothing special, both held in same register on x87.
2651 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002652 TypeTag r0Tag = collapseType(pR0Type->tag);
2653 TypeTag destTag = collapseType(pType->tag);
2654 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2655 // Convert R0 from int to float
2656 o(0x50); // push %eax
2657 o(0x2404DB); // fildl 0(%esp)
2658 o(0x58); // pop %eax
2659 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2660 // Convert R0 from float to int. Complicated because
2661 // need to save and restore the rounding mode.
2662 o(0x50); // push %eax
2663 o(0x50); // push %eax
2664 o(0x02247cD9); // fnstcw 2(%esp)
2665 o(0x2444b70f); // movzwl 2(%esp), %eax
2666 o(0x02);
2667 o(0x0cb4); // movb $12, %ah
2668 o(0x24048966); // movw %ax, 0(%esp)
2669 o(0x242cd9); // fldcw 0(%esp)
2670 o(0x04245cdb); // fistpl 4(%esp)
2671 o(0x02246cd9); // fldcw 2(%esp)
2672 o(0x58); // pop %eax
2673 o(0x58); // pop %eax
2674 } else {
2675 error("Incompatible types old: %d new: %d",
2676 pR0Type->tag, pType->tag);
2677 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002678 }
2679 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002680 }
2681
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002682 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002683 return oad(0xec81, 0); /* sub $xxx, %esp */
2684 }
2685
Jack Palevich8148c5b2009-07-16 18:24:47 -07002686 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2687 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002688 Type* pR0Type = getR0Type();
2689 TypeTag r0ct = collapseType(pR0Type->tag);
2690 switch(r0ct) {
2691 case TY_INT:
2692 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2693 return 4;
2694 case TY_FLOAT:
2695 oad(0x249CD9, l); /* fstps xxx(%esp) */
2696 return 4;
2697 case TY_DOUBLE:
2698 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2699 return 8;
2700 default:
2701 assert(false);
2702 return 0;
2703 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002704 }
2705
Jack Palevichb7718b92009-07-09 22:00:24 -07002706 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002707 * (int*) a = l;
2708 }
2709
Jack Palevich8df46192009-07-07 14:48:51 -07002710 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002711 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002712 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002713 return psym(0xe8, symbol); /* call xxx */
2714 }
2715
Jack Palevich8df46192009-07-07 14:48:51 -07002716 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002717 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002718 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002719 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002720 oad(0x2494ff, l); /* call *xxx(%esp) */
2721 }
2722
Jack Palevichb7718b92009-07-09 22:00:24 -07002723 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002724 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002725 if (isIndirect) {
2726 l += 4;
2727 }
-b master422972c2009-06-17 19:13:52 -07002728 if (l > 0) {
2729 oad(0xc481, l); /* add $xxx, %esp */
2730 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002731 }
2732
Jack Palevicha6535612009-05-13 16:24:17 -07002733 virtual int jumpOffset() {
2734 return 5;
2735 }
2736
Jack Paleviche7b59062009-05-19 17:12:17 -07002737 /* output a symbol and patch all calls to it */
2738 virtual void gsym(int t) {
2739 int n;
2740 int pc = getPC();
2741 while (t) {
2742 n = *(int *) t; /* next value */
2743 *(int *) t = pc - t - 4;
2744 t = n;
2745 }
2746 }
2747
Jack Palevich9f51a262009-07-29 16:22:26 -07002748 /* output a symbol and patch all calls to it, using absolute address */
2749 virtual void resolveForward(int t) {
2750 int n;
2751 int pc = getPC();
2752 while (t) {
2753 n = *(int *) t; /* next value */
2754 *(int *) t = pc;
2755 t = n;
2756 }
2757 }
2758
Jack Palevich1cdef202009-05-22 12:06:27 -07002759 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002760 size_t pagesize = 4096;
2761 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2762 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2763 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2764 if (err) {
2765 error("mprotect() failed: %d", errno);
2766 }
2767 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002768 }
2769
Jack Palevich9eed7a22009-07-06 17:24:34 -07002770 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002771 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002772 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002773 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002774 switch (pType->tag) {
2775 case TY_CHAR:
2776 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002777 case TY_SHORT:
2778 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002779 case TY_ARRAY:
2780 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002781 case TY_STRUCT:
2782 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07002783 case TY_FUNC:
2784 error("alignment of func not supported");
2785 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002786 default:
2787 return 4;
2788 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002789 }
2790
2791 /**
2792 * Array element alignment (in bytes) for this type of data.
2793 */
2794 virtual size_t sizeOf(Type* pType){
2795 switch(pType->tag) {
2796 case TY_INT:
2797 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002798 case TY_SHORT:
2799 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002800 case TY_CHAR:
2801 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002802 case TY_FLOAT:
2803 return 4;
2804 case TY_DOUBLE:
2805 return 8;
2806 case TY_POINTER:
2807 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002808 case TY_ARRAY:
2809 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002810 case TY_STRUCT:
2811 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002812 default:
2813 error("Unsupported type %d", pType->tag);
2814 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002815 }
2816 }
2817
Jack Palevich21a15a22009-05-11 14:49:29 -07002818 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002819
2820 /** Output 1 to 4 bytes.
2821 *
2822 */
2823 void o(int n) {
2824 /* cannot use unsigned, so we must do a hack */
2825 while (n && n != -1) {
2826 ob(n & 0xff);
2827 n = n >> 8;
2828 }
2829 }
2830
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002831 /* Output exactly 2 bytes
2832 */
2833 void o2(int n) {
2834 ob(n & 0xff);
2835 ob(0xff & (n >> 8));
2836 }
2837
Jack Paleviche7b59062009-05-19 17:12:17 -07002838 /* psym is used to put an instruction with a data field which is a
2839 reference to a symbol. It is in fact the same as oad ! */
2840 int psym(int n, int t) {
2841 return oad(n, t);
2842 }
2843
2844 /* instruction + address */
2845 int oad(int n, int t) {
2846 o(n);
2847 int result = getPC();
2848 o4(t);
2849 return result;
2850 }
2851
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002852 static const int operatorHelper[];
2853
2854 int decodeOp(int op) {
2855 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002856 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002857 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002858 }
2859 return operatorHelper[op];
2860 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002861
Jack Palevich546b2242009-05-13 15:10:04 -07002862 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002863 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002864 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002865 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002866
2867 void setupFloatOperands() {
2868 Type* pR0Type = getR0Type();
2869 Type* pTOSType = getTOSType();
2870 TypeTag tagR0 = pR0Type->tag;
2871 TypeTag tagTOS = pTOSType->tag;
2872 bool isFloatR0 = isFloatTag(tagR0);
2873 bool isFloatTOS = isFloatTag(tagTOS);
2874 if (! isFloatR0) {
2875 // Convert R0 from int to float
2876 o(0x50); // push %eax
2877 o(0x2404DB); // fildl 0(%esp)
2878 o(0x58); // pop %eax
2879 }
2880 if (! isFloatTOS){
2881 o(0x2404DB); // fildl 0(%esp);
2882 o(0x58); // pop %eax
2883 } else {
2884 if (tagTOS == TY_FLOAT) {
2885 o(0x2404d9); // flds (%esp)
2886 o(0x58); // pop %eax
2887 } else {
2888 o(0x2404dd); // fldl (%esp)
2889 o(0x58); // pop %eax
2890 o(0x58); // pop %eax
2891 }
2892 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002893 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002894 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002895 };
2896
Jack Paleviche7b59062009-05-19 17:12:17 -07002897#endif // PROVIDE_X86_CODEGEN
2898
Jack Palevichb67b18f2009-06-11 21:12:23 -07002899#ifdef PROVIDE_TRACE_CODEGEN
2900 class TraceCodeGenerator : public CodeGenerator {
2901 private:
2902 CodeGenerator* mpBase;
2903
2904 public:
2905 TraceCodeGenerator(CodeGenerator* pBase) {
2906 mpBase = pBase;
2907 }
2908
2909 virtual ~TraceCodeGenerator() {
2910 delete mpBase;
2911 }
2912
2913 virtual void init(CodeBuf* pCodeBuf) {
2914 mpBase->init(pCodeBuf);
2915 }
2916
2917 void setErrorSink(ErrorSink* pErrorSink) {
2918 mpBase->setErrorSink(pErrorSink);
2919 }
2920
2921 /* returns address to patch with local variable size
2922 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002923 virtual int functionEntry(Type* pDecl) {
2924 int result = mpBase->functionEntry(pDecl);
2925 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002926 return result;
2927 }
2928
Jack Palevichb7718b92009-07-09 22:00:24 -07002929 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2930 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2931 localVariableAddress, localVariableSize);
2932 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002933 }
2934
2935 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002936 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002937 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002938 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002939 }
2940
Jack Palevich1a539db2009-07-08 13:04:41 -07002941 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002942 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002943 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002944 }
2945
Jack Palevich9221bcc2009-08-26 16:15:07 -07002946 virtual void addStructOffsetR0(int offset, Type* pType) {
2947 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
2948 mpBase->addStructOffsetR0(offset, pType);
2949 }
2950
Jack Palevichb67b18f2009-06-11 21:12:23 -07002951 virtual int gjmp(int t) {
2952 int result = mpBase->gjmp(t);
2953 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2954 return result;
2955 }
2956
2957 /* l = 0: je, l == 1: jne */
2958 virtual int gtst(bool l, int t) {
2959 int result = mpBase->gtst(l, t);
2960 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2961 return result;
2962 }
2963
Jack Palevich58c30ee2009-07-17 16:35:23 -07002964 virtual void gcmp(int op) {
2965 fprintf(stderr, "gcmp(%d)\n", op);
2966 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002967 }
2968
2969 virtual void genOp(int op) {
2970 fprintf(stderr, "genOp(%d)\n", op);
2971 mpBase->genOp(op);
2972 }
2973
Jack Palevich9eed7a22009-07-06 17:24:34 -07002974
Jack Palevich58c30ee2009-07-17 16:35:23 -07002975 virtual void gUnaryCmp(int op) {
2976 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2977 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002978 }
2979
2980 virtual void genUnaryOp(int op) {
2981 fprintf(stderr, "genUnaryOp(%d)\n", op);
2982 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002983 }
2984
2985 virtual void pushR0() {
2986 fprintf(stderr, "pushR0()\n");
2987 mpBase->pushR0();
2988 }
2989
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002990 virtual void over() {
2991 fprintf(stderr, "over()\n");
2992 mpBase->over();
2993 }
2994
Jack Palevich58c30ee2009-07-17 16:35:23 -07002995 virtual void popR0() {
2996 fprintf(stderr, "popR0()\n");
2997 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002998 }
2999
Jack Palevich58c30ee2009-07-17 16:35:23 -07003000 virtual void storeR0ToTOS() {
3001 fprintf(stderr, "storeR0ToTOS()\n");
3002 mpBase->storeR0ToTOS();
3003 }
3004
3005 virtual void loadR0FromR0() {
3006 fprintf(stderr, "loadR0FromR0()\n");
3007 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003008 }
3009
Jack Palevichb5e33312009-07-30 19:06:34 -07003010 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3011 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3012 pPointerType->pHead->tag, et);
3013 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003014 }
3015
Jack Palevich9f51a262009-07-29 16:22:26 -07003016 virtual int leaForward(int ea, Type* pPointerType) {
3017 fprintf(stderr, "leaForward(%d)\n", ea);
3018 return mpBase->leaForward(ea, pPointerType);
3019 }
3020
Jack Palevich30321cb2009-08-20 15:34:23 -07003021 virtual void convertR0Imp(Type* pType, bool isCast){
3022 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3023 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003024 }
3025
3026 virtual int beginFunctionCallArguments() {
3027 int result = mpBase->beginFunctionCallArguments();
3028 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3029 return result;
3030 }
3031
Jack Palevich8148c5b2009-07-16 18:24:47 -07003032 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3033 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3034 pArgType->tag);
3035 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003036 }
3037
Jack Palevichb7718b92009-07-09 22:00:24 -07003038 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003039 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003040 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003041 }
3042
Jack Palevich8df46192009-07-07 14:48:51 -07003043 virtual int callForward(int symbol, Type* pFunc) {
3044 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003045 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3046 return result;
3047 }
3048
Jack Palevich8df46192009-07-07 14:48:51 -07003049 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003050 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3051 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003052 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003053 }
3054
Jack Palevichb7718b92009-07-09 22:00:24 -07003055 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3056 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3057 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003058 }
3059
3060 virtual int jumpOffset() {
3061 return mpBase->jumpOffset();
3062 }
3063
Jack Palevichb67b18f2009-06-11 21:12:23 -07003064 /* output a symbol and patch all calls to it */
3065 virtual void gsym(int t) {
3066 fprintf(stderr, "gsym(%d)\n", t);
3067 mpBase->gsym(t);
3068 }
3069
Jack Palevich9f51a262009-07-29 16:22:26 -07003070 virtual void resolveForward(int t) {
3071 mpBase->resolveForward(t);
3072 }
3073
Jack Palevichb67b18f2009-06-11 21:12:23 -07003074 virtual int finishCompile() {
3075 int result = mpBase->finishCompile();
3076 fprintf(stderr, "finishCompile() = %d\n", result);
3077 return result;
3078 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003079
3080 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003081 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003082 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003083 virtual size_t alignmentOf(Type* pType){
3084 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003085 }
3086
3087 /**
3088 * Array element alignment (in bytes) for this type of data.
3089 */
3090 virtual size_t sizeOf(Type* pType){
3091 return mpBase->sizeOf(pType);
3092 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003093
3094 virtual Type* getR0Type() {
3095 return mpBase->getR0Type();
3096 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003097
3098 virtual ExpressionType getR0ExpressionType() {
3099 return mpBase->getR0ExpressionType();
3100 }
3101
3102 virtual void setR0ExpressionType(ExpressionType et) {
3103 mpBase->setR0ExpressionType(et);
3104 }
3105
3106 virtual size_t getExpressionStackDepth() {
3107 return mpBase->getExpressionStackDepth();
3108 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003109
3110 virtual void forceR0RVal() {
3111 return mpBase->forceR0RVal();
3112 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003113 };
3114
3115#endif // PROVIDE_TRACE_CODEGEN
3116
Jack Palevich569f1352009-06-29 14:29:08 -07003117 class Arena {
3118 public:
3119 // Used to record a given allocation amount.
3120 // Used:
3121 // Mark mark = arena.mark();
3122 // ... lots of arena.allocate()
3123 // arena.free(mark);
3124
3125 struct Mark {
3126 size_t chunk;
3127 size_t offset;
3128 };
3129
3130 Arena() {
3131 mCurrentChunk = 0;
3132 Chunk start(CHUNK_SIZE);
3133 mData.push_back(start);
3134 }
3135
3136 ~Arena() {
3137 for(size_t i = 0; i < mData.size(); i++) {
3138 mData[i].free();
3139 }
3140 }
3141
3142 // Alloc using the standard alignment size safe for any variable
3143 void* alloc(size_t size) {
3144 return alloc(size, 8);
3145 }
3146
3147 Mark mark(){
3148 Mark result;
3149 result.chunk = mCurrentChunk;
3150 result.offset = mData[mCurrentChunk].mOffset;
3151 return result;
3152 }
3153
3154 void freeToMark(const Mark& mark) {
3155 mCurrentChunk = mark.chunk;
3156 mData[mCurrentChunk].mOffset = mark.offset;
3157 }
3158
3159 private:
3160 // Allocate memory aligned to a given size
3161 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3162 // Memory is not zero filled.
3163
3164 void* alloc(size_t size, size_t alignment) {
3165 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3166 if (mCurrentChunk + 1 < mData.size()) {
3167 mCurrentChunk++;
3168 } else {
3169 size_t allocSize = CHUNK_SIZE;
3170 if (allocSize < size + alignment - 1) {
3171 allocSize = size + alignment - 1;
3172 }
3173 Chunk chunk(allocSize);
3174 mData.push_back(chunk);
3175 mCurrentChunk++;
3176 }
3177 }
3178 return mData[mCurrentChunk].allocate(size, alignment);
3179 }
3180
3181 static const size_t CHUNK_SIZE = 128*1024;
3182 // Note: this class does not deallocate its
3183 // memory when it's destroyed. It depends upon
3184 // its parent to deallocate the memory.
3185 struct Chunk {
3186 Chunk() {
3187 mpData = 0;
3188 mSize = 0;
3189 mOffset = 0;
3190 }
3191
3192 Chunk(size_t size) {
3193 mSize = size;
3194 mpData = (char*) malloc(size);
3195 mOffset = 0;
3196 }
3197
3198 ~Chunk() {
3199 // Doesn't deallocate memory.
3200 }
3201
3202 void* allocate(size_t size, size_t alignment) {
3203 size_t alignedOffset = aligned(mOffset, alignment);
3204 void* result = mpData + alignedOffset;
3205 mOffset = alignedOffset + size;
3206 return result;
3207 }
3208
3209 void free() {
3210 if (mpData) {
3211 ::free(mpData);
3212 mpData = 0;
3213 }
3214 }
3215
3216 size_t remainingCapacity(size_t alignment) {
3217 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3218 }
3219
3220 // Assume alignment is a power of two
3221 inline size_t aligned(size_t v, size_t alignment) {
3222 size_t mask = alignment-1;
3223 return (v + mask) & ~mask;
3224 }
3225
3226 char* mpData;
3227 size_t mSize;
3228 size_t mOffset;
3229 };
3230
3231 size_t mCurrentChunk;
3232
3233 Vector<Chunk> mData;
3234 };
3235
Jack Palevich569f1352009-06-29 14:29:08 -07003236 struct VariableInfo;
3237
3238 struct Token {
3239 int hash;
3240 size_t length;
3241 char* pText;
3242 tokenid_t id;
3243
3244 // Current values for the token
3245 char* mpMacroDefinition;
3246 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003247 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003248 };
3249
3250 class TokenTable {
3251 public:
3252 // Don't use 0..0xff, allows characters and operators to be tokens too.
3253
3254 static const int TOKEN_BASE = 0x100;
3255 TokenTable() {
3256 mpMap = hashmapCreate(128, hashFn, equalsFn);
3257 }
3258
3259 ~TokenTable() {
3260 hashmapFree(mpMap);
3261 }
3262
3263 void setArena(Arena* pArena) {
3264 mpArena = pArena;
3265 }
3266
3267 // Returns a token for a given string of characters.
3268 tokenid_t intern(const char* pText, size_t length) {
3269 Token probe;
3270 int hash = hashmapHash((void*) pText, length);
3271 {
3272 Token probe;
3273 probe.hash = hash;
3274 probe.length = length;
3275 probe.pText = (char*) pText;
3276 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3277 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003278 return pValue->id;
3279 }
3280 }
3281
3282 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3283 memset(pToken, 0, sizeof(*pToken));
3284 pToken->hash = hash;
3285 pToken->length = length;
3286 pToken->pText = (char*) mpArena->alloc(length + 1);
3287 memcpy(pToken->pText, pText, length);
3288 pToken->pText[length] = 0;
3289 pToken->id = mTokens.size() + TOKEN_BASE;
3290 mTokens.push_back(pToken);
3291 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003292 return pToken->id;
3293 }
3294
3295 // Return the Token for a given tokenid.
3296 Token& operator[](tokenid_t id) {
3297 return *mTokens[id - TOKEN_BASE];
3298 }
3299
3300 inline size_t size() {
3301 return mTokens.size();
3302 }
3303
3304 private:
3305
3306 static int hashFn(void* pKey) {
3307 Token* pToken = (Token*) pKey;
3308 return pToken->hash;
3309 }
3310
3311 static bool equalsFn(void* keyA, void* keyB) {
3312 Token* pTokenA = (Token*) keyA;
3313 Token* pTokenB = (Token*) keyB;
3314 // Don't need to compare hash values, they should always be equal
3315 return pTokenA->length == pTokenB->length
3316 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3317 }
3318
3319 Hashmap* mpMap;
3320 Vector<Token*> mTokens;
3321 Arena* mpArena;
3322 };
3323
Jack Palevich1cdef202009-05-22 12:06:27 -07003324 class InputStream {
3325 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003326 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003327 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003328 };
3329
3330 class TextInputStream : public InputStream {
3331 public:
3332 TextInputStream(const char* text, size_t textLength)
3333 : pText(text), mTextLength(textLength), mPosition(0) {
3334 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003335
Jack Palevichdc456462009-07-16 16:50:56 -07003336 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003337 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3338 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003339
Jack Palevichdc456462009-07-16 16:50:56 -07003340 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003341 const char* pText;
3342 size_t mTextLength;
3343 size_t mPosition;
3344 };
3345
Jack Palevicheedf9d22009-06-04 16:23:40 -07003346 class String {
3347 public:
3348 String() {
3349 mpBase = 0;
3350 mUsed = 0;
3351 mSize = 0;
3352 }
3353
Jack Palevich303d8ff2009-06-11 19:06:24 -07003354 String(const char* item, int len, bool adopt) {
3355 if (len < 0) {
3356 len = strlen(item);
3357 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003358 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003359 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003360 mUsed = len;
3361 mSize = len + 1;
3362 } else {
3363 mpBase = 0;
3364 mUsed = 0;
3365 mSize = 0;
3366 appendBytes(item, len);
3367 }
3368 }
3369
Jack Palevich303d8ff2009-06-11 19:06:24 -07003370 String(const String& other) {
3371 mpBase = 0;
3372 mUsed = 0;
3373 mSize = 0;
3374 appendBytes(other.getUnwrapped(), other.len());
3375 }
3376
Jack Palevicheedf9d22009-06-04 16:23:40 -07003377 ~String() {
3378 if (mpBase) {
3379 free(mpBase);
3380 }
3381 }
3382
Jack Palevicha6baa232009-06-12 11:25:59 -07003383 String& operator=(const String& other) {
3384 clear();
3385 appendBytes(other.getUnwrapped(), other.len());
3386 return *this;
3387 }
3388
Jack Palevich303d8ff2009-06-11 19:06:24 -07003389 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003390 return mpBase;
3391 }
3392
Jack Palevich303d8ff2009-06-11 19:06:24 -07003393 void clear() {
3394 mUsed = 0;
3395 if (mSize > 0) {
3396 mpBase[0] = 0;
3397 }
3398 }
3399
Jack Palevicheedf9d22009-06-04 16:23:40 -07003400 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003401 appendBytes(s, strlen(s));
3402 }
3403
3404 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003405 memcpy(ensure(n), s, n + 1);
3406 }
3407
3408 void append(char c) {
3409 * ensure(1) = c;
3410 }
3411
Jack Palevich86351982009-06-30 18:09:56 -07003412 void append(String& other) {
3413 appendBytes(other.getUnwrapped(), other.len());
3414 }
3415
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003416 char* orphan() {
3417 char* result = mpBase;
3418 mpBase = 0;
3419 mUsed = 0;
3420 mSize = 0;
3421 return result;
3422 }
3423
Jack Palevicheedf9d22009-06-04 16:23:40 -07003424 void printf(const char* fmt,...) {
3425 va_list ap;
3426 va_start(ap, fmt);
3427 vprintf(fmt, ap);
3428 va_end(ap);
3429 }
3430
3431 void vprintf(const char* fmt, va_list ap) {
3432 char* temp;
3433 int numChars = vasprintf(&temp, fmt, ap);
3434 memcpy(ensure(numChars), temp, numChars+1);
3435 free(temp);
3436 }
3437
Jack Palevich303d8ff2009-06-11 19:06:24 -07003438 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003439 return mUsed;
3440 }
3441
3442 private:
3443 char* ensure(int n) {
3444 size_t newUsed = mUsed + n;
3445 if (newUsed > mSize) {
3446 size_t newSize = mSize * 2 + 10;
3447 if (newSize < newUsed) {
3448 newSize = newUsed;
3449 }
3450 mpBase = (char*) realloc(mpBase, newSize + 1);
3451 mSize = newSize;
3452 }
3453 mpBase[newUsed] = '\0';
3454 char* result = mpBase + mUsed;
3455 mUsed = newUsed;
3456 return result;
3457 }
3458
3459 char* mpBase;
3460 size_t mUsed;
3461 size_t mSize;
3462 };
3463
Jack Palevich569f1352009-06-29 14:29:08 -07003464 void internKeywords() {
3465 // Note: order has to match TOK_ constants
3466 static const char* keywords[] = {
3467 "int",
3468 "char",
3469 "void",
3470 "if",
3471 "else",
3472 "while",
3473 "break",
3474 "return",
3475 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003476 "auto",
3477 "case",
3478 "const",
3479 "continue",
3480 "default",
3481 "do",
3482 "double",
3483 "enum",
3484 "extern",
3485 "float",
3486 "goto",
3487 "long",
3488 "register",
3489 "short",
3490 "signed",
3491 "sizeof",
3492 "static",
3493 "struct",
3494 "switch",
3495 "typedef",
3496 "union",
3497 "unsigned",
3498 "volatile",
3499 "_Bool",
3500 "_Complex",
3501 "_Imaginary",
3502 "inline",
3503 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003504
3505 // predefined tokens that can also be symbols start here:
3506 "pragma",
3507 "define",
3508 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003509 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003510
Jack Palevich569f1352009-06-29 14:29:08 -07003511 for(int i = 0; keywords[i]; i++) {
3512 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003513 }
Jack Palevich569f1352009-06-29 14:29:08 -07003514 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003515
Jack Palevich36d94142009-06-08 15:55:32 -07003516 struct InputState {
3517 InputStream* pStream;
3518 int oldCh;
3519 };
3520
Jack Palevich2db168f2009-06-11 14:29:47 -07003521 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003522 void* pAddress;
3523 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003524 tokenid_t tok;
3525 size_t level;
3526 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003527 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003528 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003529 };
3530
Jack Palevich303d8ff2009-06-11 19:06:24 -07003531 class SymbolStack {
3532 public:
3533 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003534 mpArena = 0;
3535 mpTokenTable = 0;
3536 }
3537
3538 void setArena(Arena* pArena) {
3539 mpArena = pArena;
3540 }
3541
3542 void setTokenTable(TokenTable* pTokenTable) {
3543 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003544 }
3545
3546 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003547 Mark mark;
3548 mark.mArenaMark = mpArena->mark();
3549 mark.mSymbolHead = mStack.size();
3550 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003551 }
3552
3553 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003554 // Undo any shadowing that was done:
3555 Mark mark = mLevelStack.back();
3556 mLevelStack.pop_back();
3557 while (mStack.size() > mark.mSymbolHead) {
3558 VariableInfo* pV = mStack.back();
3559 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003560 if (pV->isStructTag) {
3561 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3562 } else {
3563 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3564 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003565 }
Jack Palevich569f1352009-06-29 14:29:08 -07003566 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003567 }
3568
Jack Palevich569f1352009-06-29 14:29:08 -07003569 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3570 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3571 return pV && pV->level == level();
3572 }
3573
Jack Palevich9221bcc2009-08-26 16:15:07 -07003574 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3575 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3576 return pV && pV->level == level();
3577 }
3578
Jack Palevich569f1352009-06-29 14:29:08 -07003579 VariableInfo* add(tokenid_t tok) {
3580 Token& token = (*mpTokenTable)[tok];
3581 VariableInfo* pOldV = token.mpVariableInfo;
3582 VariableInfo* pNewV =
3583 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3584 memset(pNewV, 0, sizeof(VariableInfo));
3585 pNewV->tok = tok;
3586 pNewV->level = level();
3587 pNewV->pOldDefinition = pOldV;
3588 token.mpVariableInfo = pNewV;
3589 mStack.push_back(pNewV);
3590 return pNewV;
3591 }
3592
Jack Palevich9221bcc2009-08-26 16:15:07 -07003593 VariableInfo* addStructTag(tokenid_t tok) {
3594 Token& token = (*mpTokenTable)[tok];
3595 VariableInfo* pOldS = token.mpStructInfo;
3596 VariableInfo* pNewS =
3597 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3598 memset(pNewS, 0, sizeof(VariableInfo));
3599 pNewS->tok = tok;
3600 pNewS->level = level();
3601 pNewS->isStructTag = true;
3602 pNewS->pOldDefinition = pOldS;
3603 token.mpStructInfo = pNewS;
3604 mStack.push_back(pNewS);
3605 return pNewS;
3606 }
3607
Jack Palevich86351982009-06-30 18:09:56 -07003608 VariableInfo* add(Type* pType) {
3609 VariableInfo* pVI = add(pType->id);
3610 pVI->pType = pType;
3611 return pVI;
3612 }
3613
Jack Palevich569f1352009-06-29 14:29:08 -07003614 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3615 for (size_t i = 0; i < mStack.size(); i++) {
3616 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003617 break;
3618 }
3619 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003620 }
3621
Jack Palevich303d8ff2009-06-11 19:06:24 -07003622 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003623 inline size_t level() {
3624 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003625 }
3626
Jack Palevich569f1352009-06-29 14:29:08 -07003627 struct Mark {
3628 Arena::Mark mArenaMark;
3629 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003630 };
3631
Jack Palevich569f1352009-06-29 14:29:08 -07003632 Arena* mpArena;
3633 TokenTable* mpTokenTable;
3634 Vector<VariableInfo*> mStack;
3635 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003636 };
Jack Palevich36d94142009-06-08 15:55:32 -07003637
3638 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003639 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003640 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003641 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003642 int tokl; // token operator level
3643 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003644 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003645 intptr_t loc; // local variable index
3646 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003647 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003648 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003649 char* dptr; // Macro state: Points to macro text during macro playback.
3650 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003651 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003652 ACCSymbolLookupFn mpSymbolLookupFn;
3653 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003654
3655 // Arena for the duration of the compile
3656 Arena mGlobalArena;
3657 // Arena for data that's only needed when compiling a single function
3658 Arena mLocalArena;
3659
Jack Palevich2ff5c222009-07-23 15:11:22 -07003660 Arena* mpCurrentArena;
3661
Jack Palevich569f1352009-06-29 14:29:08 -07003662 TokenTable mTokenTable;
3663 SymbolStack mGlobals;
3664 SymbolStack mLocals;
3665
Jack Palevich9221bcc2009-08-26 16:15:07 -07003666 SymbolStack* mpCurrentSymbolStack;
3667
Jack Palevich40600de2009-07-01 15:32:35 -07003668 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003669 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003670 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003671 Type* mkpChar; // char
3672 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003673 Type* mkpFloat;
3674 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003675 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003676 Type* mkpIntPtr;
3677 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003678 Type* mkpFloatPtr;
3679 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003680 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003681
Jack Palevich36d94142009-06-08 15:55:32 -07003682 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003683 int mLineNumber;
3684 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003685
3686 CodeBuf codeBuf;
3687 CodeGenerator* pGen;
3688
Jack Palevicheedf9d22009-06-04 16:23:40 -07003689 String mErrorBuf;
3690
Jack Palevicheedf9d22009-06-04 16:23:40 -07003691 String mPragmas;
3692 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003693 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003694
Jack Palevich21a15a22009-05-11 14:49:29 -07003695 static const int ALLOC_SIZE = 99999;
3696
Jack Palevich303d8ff2009-06-11 19:06:24 -07003697 static const int TOK_DUMMY = 1;
3698 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003699 static const int TOK_NUM_FLOAT = 3;
3700 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003701 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003702 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003703
3704 // 3..255 are character and/or operators
3705
Jack Palevich2db168f2009-06-11 14:29:47 -07003706 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003707 // Order has to match string list in "internKeywords".
3708 enum {
3709 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3710 TOK_INT = TOK_KEYWORD,
3711 TOK_CHAR,
3712 TOK_VOID,
3713 TOK_IF,
3714 TOK_ELSE,
3715 TOK_WHILE,
3716 TOK_BREAK,
3717 TOK_RETURN,
3718 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003719 TOK_AUTO,
3720 TOK_CASE,
3721 TOK_CONST,
3722 TOK_CONTINUE,
3723 TOK_DEFAULT,
3724 TOK_DO,
3725 TOK_DOUBLE,
3726 TOK_ENUM,
3727 TOK_EXTERN,
3728 TOK_FLOAT,
3729 TOK_GOTO,
3730 TOK_LONG,
3731 TOK_REGISTER,
3732 TOK_SHORT,
3733 TOK_SIGNED,
3734 TOK_SIZEOF,
3735 TOK_STATIC,
3736 TOK_STRUCT,
3737 TOK_SWITCH,
3738 TOK_TYPEDEF,
3739 TOK_UNION,
3740 TOK_UNSIGNED,
3741 TOK_VOLATILE,
3742 TOK__BOOL,
3743 TOK__COMPLEX,
3744 TOK__IMAGINARY,
3745 TOK_INLINE,
3746 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003747
3748 // Symbols start after keywords
3749
3750 TOK_SYMBOL,
3751 TOK_PRAGMA = TOK_SYMBOL,
3752 TOK_DEFINE,
3753 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003754 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003755
3756 static const int LOCAL = 0x200;
3757
3758 static const int SYM_FORWARD = 0;
3759 static const int SYM_DEFINE = 1;
3760
3761 /* tokens in string heap */
3762 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003763
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003764 static const int OP_INCREMENT = 0;
3765 static const int OP_DECREMENT = 1;
3766 static const int OP_MUL = 2;
3767 static const int OP_DIV = 3;
3768 static const int OP_MOD = 4;
3769 static const int OP_PLUS = 5;
3770 static const int OP_MINUS = 6;
3771 static const int OP_SHIFT_LEFT = 7;
3772 static const int OP_SHIFT_RIGHT = 8;
3773 static const int OP_LESS_EQUAL = 9;
3774 static const int OP_GREATER_EQUAL = 10;
3775 static const int OP_LESS = 11;
3776 static const int OP_GREATER = 12;
3777 static const int OP_EQUALS = 13;
3778 static const int OP_NOT_EQUALS = 14;
3779 static const int OP_LOGICAL_AND = 15;
3780 static const int OP_LOGICAL_OR = 16;
3781 static const int OP_BIT_AND = 17;
3782 static const int OP_BIT_XOR = 18;
3783 static const int OP_BIT_OR = 19;
3784 static const int OP_BIT_NOT = 20;
3785 static const int OP_LOGICAL_NOT = 21;
3786 static const int OP_COUNT = 22;
3787
3788 /* Operators are searched from front, the two-character operators appear
3789 * before the single-character operators with the same first character.
3790 * @ is used to pad out single-character operators.
3791 */
3792 static const char* operatorChars;
3793 static const char operatorLevel[];
3794
Jack Palevich569f1352009-06-29 14:29:08 -07003795 /* Called when we detect an internal problem. Does nothing in production.
3796 *
3797 */
3798 void internalError() {
3799 * (char*) 0 = 0;
3800 }
3801
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003802 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003803 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07003804 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003805 internalError();
3806 }
Jack Palevich86351982009-06-30 18:09:56 -07003807 }
3808
Jack Palevich40600de2009-07-01 15:32:35 -07003809 bool isSymbol(tokenid_t t) {
3810 return t >= TOK_SYMBOL &&
3811 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3812 }
3813
3814 bool isSymbolOrKeyword(tokenid_t t) {
3815 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003816 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003817 }
3818
Jack Palevich86351982009-06-30 18:09:56 -07003819 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003820 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003821 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3822 if (pV && pV->tok != t) {
3823 internalError();
3824 }
3825 return pV;
3826 }
3827
3828 inline bool isDefined(tokenid_t t) {
3829 return t >= TOK_SYMBOL && VI(t) != 0;
3830 }
3831
Jack Palevich40600de2009-07-01 15:32:35 -07003832 const char* nameof(tokenid_t t) {
3833 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003834 return mTokenTable[t].pText;
3835 }
3836
Jack Palevich21a15a22009-05-11 14:49:29 -07003837 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003838 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003839 }
3840
3841 void inp() {
3842 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003843 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003844 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003845 dptr = 0;
3846 ch = dch;
3847 }
Jack Palevichdc456462009-07-16 16:50:56 -07003848 } else {
3849 if (mbBumpLine) {
3850 mLineNumber++;
3851 mbBumpLine = false;
3852 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003853 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003854 if (ch == '\n') {
3855 mbBumpLine = true;
3856 }
3857 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003858#if 0
3859 printf("ch='%c' 0x%x\n", ch, ch);
3860#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003861 }
3862
3863 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003864 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003865 }
3866
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003867 int decodeHex(int c) {
3868 if (isdigit(c)) {
3869 c -= '0';
3870 } else if (c <= 'F') {
3871 c = c - 'A' + 10;
3872 } else {
3873 c =c - 'a' + 10;
3874 }
3875 return c;
3876 }
3877
Jack Palevichb4758ff2009-06-12 12:49:14 -07003878 /* read a character constant, advances ch to after end of constant */
3879 int getq() {
3880 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003881 if (ch == '\\') {
3882 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003883 if (isoctal(ch)) {
3884 // 1 to 3 octal characters.
3885 val = 0;
3886 for(int i = 0; i < 3; i++) {
3887 if (isoctal(ch)) {
3888 val = (val << 3) + ch - '0';
3889 inp();
3890 }
3891 }
3892 return val;
3893 } else if (ch == 'x' || ch == 'X') {
3894 // N hex chars
3895 inp();
3896 if (! isxdigit(ch)) {
3897 error("'x' character escape requires at least one digit.");
3898 } else {
3899 val = 0;
3900 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003901 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003902 inp();
3903 }
3904 }
3905 } else {
3906 int val = ch;
3907 switch (ch) {
3908 case 'a':
3909 val = '\a';
3910 break;
3911 case 'b':
3912 val = '\b';
3913 break;
3914 case 'f':
3915 val = '\f';
3916 break;
3917 case 'n':
3918 val = '\n';
3919 break;
3920 case 'r':
3921 val = '\r';
3922 break;
3923 case 't':
3924 val = '\t';
3925 break;
3926 case 'v':
3927 val = '\v';
3928 break;
3929 case '\\':
3930 val = '\\';
3931 break;
3932 case '\'':
3933 val = '\'';
3934 break;
3935 case '"':
3936 val = '"';
3937 break;
3938 case '?':
3939 val = '?';
3940 break;
3941 default:
3942 error("Undefined character escape %c", ch);
3943 break;
3944 }
3945 inp();
3946 return val;
3947 }
3948 } else {
3949 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003950 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003951 return val;
3952 }
3953
3954 static bool isoctal(int ch) {
3955 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003956 }
3957
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003958 bool acceptCh(int c) {
3959 bool result = c == ch;
3960 if (result) {
3961 pdef(ch);
3962 inp();
3963 }
3964 return result;
3965 }
3966
3967 bool acceptDigitsCh() {
3968 bool result = false;
3969 while (isdigit(ch)) {
3970 result = true;
3971 pdef(ch);
3972 inp();
3973 }
3974 return result;
3975 }
3976
3977 void parseFloat() {
3978 tok = TOK_NUM_DOUBLE;
3979 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003980 if(mTokenString.len() == 0) {
3981 mTokenString.append('0');
3982 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003983 acceptCh('.');
3984 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003985 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003986 acceptCh('-') || acceptCh('+');
3987 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003988 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003989 if (ch == 'f' || ch == 'F') {
3990 tok = TOK_NUM_FLOAT;
3991 inp();
3992 } else if (ch == 'l' || ch == 'L') {
3993 inp();
3994 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003995 }
3996 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003997 char* pEnd = pText + strlen(pText);
3998 char* pEndPtr = 0;
3999 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004000 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004001 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004002 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004003 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004004 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004005 if (errno || pEndPtr != pEnd) {
4006 error("Can't parse constant: %s", pText);
4007 }
4008 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004009 }
4010
Jack Palevich21a15a22009-05-11 14:49:29 -07004011 void next() {
4012 int l, a;
4013
Jack Palevich546b2242009-05-13 15:10:04 -07004014 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004015 if (ch == '#') {
4016 inp();
4017 next();
4018 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004019 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004020 } else if (tok == TOK_PRAGMA) {
4021 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004022 } else if (tok == TOK_LINE) {
4023 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004024 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004025 error("Unsupported preprocessor directive \"%s\"",
4026 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004027 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004028 }
4029 inp();
4030 }
4031 tokl = 0;
4032 tok = ch;
4033 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004034 if (isdigit(ch) || ch == '.') {
4035 // Start of a numeric constant. Could be integer, float, or
4036 // double, won't know until we look further.
4037 mTokenString.clear();
4038 pdef(ch);
4039 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004040 if (tok == '.' && !isdigit(ch)) {
4041 goto done;
4042 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004043 int base = 10;
4044 if (tok == '0') {
4045 if (ch == 'x' || ch == 'X') {
4046 base = 16;
4047 tok = TOK_NUM;
4048 tokc = 0;
4049 inp();
4050 while ( isxdigit(ch) ) {
4051 tokc = (tokc << 4) + decodeHex(ch);
4052 inp();
4053 }
4054 } else if (isoctal(ch)){
4055 base = 8;
4056 tok = TOK_NUM;
4057 tokc = 0;
4058 while ( isoctal(ch) ) {
4059 tokc = (tokc << 3) + (ch - '0');
4060 inp();
4061 }
4062 }
4063 } else if (isdigit(tok)){
4064 acceptDigitsCh();
4065 }
4066 if (base == 10) {
4067 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4068 parseFloat();
4069 } else {
4070 // It's an integer constant
4071 char* pText = mTokenString.getUnwrapped();
4072 char* pEnd = pText + strlen(pText);
4073 char* pEndPtr = 0;
4074 errno = 0;
4075 tokc = strtol(pText, &pEndPtr, base);
4076 if (errno || pEndPtr != pEnd) {
4077 error("Can't parse constant: %s %d %d", pText, base, errno);
4078 }
4079 tok = TOK_NUM;
4080 }
4081 }
4082 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004083 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004084 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004085 pdef(ch);
4086 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004087 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004088 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004089 if (! mbSuppressMacroExpansion) {
4090 // Is this a macro?
4091 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4092 if (pMacroDefinition) {
4093 // Yes, it is a macro
4094 dptr = pMacroDefinition;
4095 dch = ch;
4096 inp();
4097 next();
4098 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004099 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004100 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004101 inp();
4102 if (tok == '\'') {
4103 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004104 tokc = getq();
4105 if (ch != '\'') {
4106 error("Expected a ' character, got %c", ch);
4107 } else {
4108 inp();
4109 }
Jack Palevich546b2242009-05-13 15:10:04 -07004110 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004111 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004112 while (ch && ch != EOF) {
4113 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004114 inp();
4115 inp();
4116 if (ch == '/')
4117 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004118 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004119 if (ch == EOF) {
4120 error("End of file inside comment.");
4121 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004122 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004123 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004124 } else if ((tok == '/') & (ch == '/')) {
4125 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004126 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004127 inp();
4128 }
4129 inp();
4130 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004131 } else if ((tok == '-') & (ch == '>')) {
4132 inp();
4133 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004134 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004135 const char* t = operatorChars;
4136 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004137 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004138 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004139 tokl = operatorLevel[opIndex];
4140 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004141 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004142#if 0
4143 printf("%c%c -> tokl=%d tokc=0x%x\n",
4144 l, a, tokl, tokc);
4145#endif
4146 if (a == ch) {
4147 inp();
4148 tok = TOK_DUMMY; /* dummy token for double tokens */
4149 }
Jack Palevich0c017742009-07-31 12:00:39 -07004150 /* check for op=, valid for * / % + - << >> & ^ | */
4151 if (ch == '=' &&
4152 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004153 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004154 inp();
4155 tok = TOK_OP_ASSIGNMENT;
4156 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004157 break;
4158 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004159 opIndex++;
4160 }
4161 if (l == 0) {
4162 tokl = 0;
4163 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004164 }
4165 }
4166 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004167
4168 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004169#if 0
4170 {
Jack Palevich569f1352009-06-29 14:29:08 -07004171 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004172 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004173 fprintf(stderr, "%s\n", buf.getUnwrapped());
4174 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004175#endif
4176 }
4177
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004178 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004179 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004180 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004181 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004182 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004183 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004184 if (ch == '(') {
4185 delete pName;
4186 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004187 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004188 }
4189 while (isspace(ch)) {
4190 inp();
4191 }
Jack Palevich569f1352009-06-29 14:29:08 -07004192 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004193 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004194 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004195 // Check for '//' comments.
4196 if (appendToValue && ch == '/') {
4197 inp();
4198 if (ch == '/') {
4199 appendToValue = false;
4200 } else {
4201 value.append('/');
4202 }
4203 }
4204 if (appendToValue && ch != EOF) {
4205 value.append(ch);
4206 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004207 inp();
4208 }
Jack Palevich569f1352009-06-29 14:29:08 -07004209 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4210 memcpy(pDefn, value.getUnwrapped(), value.len());
4211 pDefn[value.len()] = 0;
4212 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004213 }
4214
Jack Palevicheedf9d22009-06-04 16:23:40 -07004215 void doPragma() {
4216 // # pragma name(val)
4217 int state = 0;
4218 while(ch != EOF && ch != '\n' && state < 10) {
4219 switch(state) {
4220 case 0:
4221 if (isspace(ch)) {
4222 inp();
4223 } else {
4224 state++;
4225 }
4226 break;
4227 case 1:
4228 if (isalnum(ch)) {
4229 mPragmas.append(ch);
4230 inp();
4231 } else if (ch == '(') {
4232 mPragmas.append(0);
4233 inp();
4234 state++;
4235 } else {
4236 state = 11;
4237 }
4238 break;
4239 case 2:
4240 if (isalnum(ch)) {
4241 mPragmas.append(ch);
4242 inp();
4243 } else if (ch == ')') {
4244 mPragmas.append(0);
4245 inp();
4246 state = 10;
4247 } else {
4248 state = 11;
4249 }
4250 break;
4251 }
4252 }
4253 if(state != 10) {
4254 error("Unexpected pragma syntax");
4255 }
4256 mPragmaStringCount += 2;
4257 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004258
Jack Palevichdc456462009-07-16 16:50:56 -07004259 void doLine() {
4260 // # line number { "filename "}
4261 next();
4262 if (tok != TOK_NUM) {
4263 error("Expected a line-number");
4264 } else {
4265 mLineNumber = tokc-1; // The end-of-line will increment it.
4266 }
4267 while(ch != EOF && ch != '\n') {
4268 inp();
4269 }
4270 }
4271
Jack Palevichac0e95e2009-05-29 13:53:44 -07004272 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004273 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004274 mErrorBuf.vprintf(fmt, ap);
4275 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004276 }
4277
Jack Palevich8b0624c2009-05-20 12:12:06 -07004278 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004279 if (tok != c) {
4280 error("'%c' expected", c);
4281 }
4282 next();
4283 }
4284
Jack Palevich86351982009-06-30 18:09:56 -07004285 bool accept(intptr_t c) {
4286 if (tok == c) {
4287 next();
4288 return true;
4289 }
4290 return false;
4291 }
4292
Jack Palevich40600de2009-07-01 15:32:35 -07004293 bool acceptStringLiteral() {
4294 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004295 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004296 // This while loop merges multiple adjacent string constants.
4297 while (tok == '"') {
4298 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004299 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004300 }
4301 if (ch != '"') {
4302 error("Unterminated string constant.");
4303 }
4304 inp();
4305 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004306 }
Jack Palevich40600de2009-07-01 15:32:35 -07004307 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004308 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004309 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004310 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004311
4312 return true;
4313 }
4314 return false;
4315 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004316
Jack Palevichb1544ca2009-07-16 15:09:20 -07004317 void linkGlobal(tokenid_t t, bool isFunction) {
4318 VariableInfo* pVI = VI(t);
4319 void* n = NULL;
4320 if (mpSymbolLookupFn) {
4321 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4322 }
4323 if (pVI->pType == NULL) {
4324 if (isFunction) {
4325 pVI->pType = mkpIntFn;
4326 } else {
4327 pVI->pType = mkpInt;
4328 }
4329 }
4330 pVI->pAddress = n;
4331 }
4332
Jack Palevich29daf572009-07-30 19:38:55 -07004333 void unaryOrAssignment() {
4334 unary();
4335 if (accept('=')) {
4336 checkLVal();
4337 pGen->pushR0();
4338 expr();
4339 pGen->forceR0RVal();
4340 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004341 } else if (tok == TOK_OP_ASSIGNMENT) {
4342 int t = tokc;
4343 next();
4344 checkLVal();
4345 pGen->pushR0();
4346 pGen->forceR0RVal();
4347 pGen->pushR0();
4348 expr();
4349 pGen->forceR0RVal();
4350 pGen->genOp(t);
4351 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004352 }
4353 }
4354
Jack Palevich40600de2009-07-01 15:32:35 -07004355 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004356 */
Jack Palevich29daf572009-07-30 19:38:55 -07004357 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004358 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004359 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004360 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004361 if (acceptStringLiteral()) {
4362 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004363 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004364 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004365 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004366 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004367 t = tok;
4368 next();
4369 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004370 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004371 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004372 // Align to 4-byte boundary
4373 glo = (char*) (((intptr_t) glo + 3) & -4);
4374 * (float*) glo = (float) ad;
4375 pGen->loadFloat((int) glo, mkpFloat);
4376 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004377 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004378 // Align to 8-byte boundary
4379 glo = (char*) (((intptr_t) glo + 7) & -8);
4380 * (double*) glo = ad;
4381 pGen->loadFloat((int) glo, mkpDouble);
4382 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004383 } else if (c == 2) {
4384 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004385 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004386 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004387 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004388 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004389 else if (t == '+') {
4390 // ignore unary plus.
4391 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004392 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004393 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004394 } else if (c == 11) {
4395 // pre increment / pre decrement
4396 unary();
4397 doIncDec(a == OP_INCREMENT, 0);
4398 }
4399 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004400 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004401 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004402 if (pCast) {
4403 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004404 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004405 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004406 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004407 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004408 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004409 skip(')');
4410 }
4411 } else if (t == '*') {
4412 /* This is a pointer dereference.
4413 */
Jack Palevich29daf572009-07-30 19:38:55 -07004414 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004415 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004416 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004417 unary();
4418 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004419 } else if (t == EOF ) {
4420 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004421 } else if (t == ';') {
4422 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004423 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004424 // Don't have to do anything special here, the error
4425 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004426 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004427 if (!isDefined(t)) {
4428 mGlobals.add(t);
4429 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004430 }
Jack Palevich8df46192009-07-07 14:48:51 -07004431 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004432 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004433 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004434 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004435 linkGlobal(t, tok == '(');
4436 n = (intptr_t) pVI->pAddress;
4437 if (!n && tok != '(') {
4438 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004439 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004440 }
Jack Palevich29daf572009-07-30 19:38:55 -07004441 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004442 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004443 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004444 linkGlobal(t, false);
4445 n = (intptr_t) pVI->pAddress;
4446 if (!n) {
4447 error("Undeclared variable %s\n", nameof(t));
4448 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004449 }
Jack Palevich5b659092009-07-31 14:55:07 -07004450 }
4451 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004452 Type* pVal;
4453 ExpressionType et;
4454 if (pVI->pType->tag == TY_ARRAY) {
4455 pVal = pVI->pType;
4456 et = ET_RVALUE;
4457 } else {
4458 pVal = createPtrType(pVI->pType);
4459 et = ET_LVALUE;
4460 }
Jack Palevich5b659092009-07-31 14:55:07 -07004461 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004462 int tag = pVal->pHead->tag;
4463 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004464 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004465 }
Jack Palevich5b659092009-07-31 14:55:07 -07004466 pGen->leaR0(n, pVal, et);
4467 } else {
4468 pVI->pForward = (void*) pGen->leaForward(
4469 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004470 }
4471 }
4472 }
4473
Jack Palevich5b659092009-07-31 14:55:07 -07004474 /* Now handle postfix operators */
4475 for(;;) {
4476 if (tokl == 11) {
4477 // post inc / post dec
4478 doIncDec(tokc == OP_INCREMENT, true);
4479 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004480 } else if (accept('[')) {
4481 // Array reference
4482 pGen->forceR0RVal();
4483 pGen->pushR0();
4484 commaExpr();
4485 pGen->forceR0RVal();
4486 pGen->genOp(OP_PLUS);
4487 doPointer();
4488 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004489 } else if (accept('.')) {
4490 // struct element
4491 pGen->forceR0RVal();
4492 Type* pStruct = pGen->getR0Type();
4493 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004494 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004495 } else {
4496 error("expected a struct value to the left of '.'");
4497 }
4498 } else if (accept(TOK_OP_ARROW)) {
4499 pGen->forceR0RVal();
4500 Type* pPtr = pGen->getR0Type();
4501 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4502 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004503 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004504 } else {
4505 error("Expected a pointer to a struct to the left of '->'");
4506 }
Jack Palevich5b659092009-07-31 14:55:07 -07004507 } else if (accept('(')) {
4508 /* function call */
4509 Type* pDecl = NULL;
4510 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004511 Type* pFn = pGen->getR0Type();
4512 assert(pFn->tag == TY_POINTER);
4513 assert(pFn->pHead->tag == TY_FUNC);
4514 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004515 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004516 Type* pArgList = pDecl->pTail;
4517 bool varArgs = pArgList == NULL;
4518 /* push args and invert order */
4519 a = pGen->beginFunctionCallArguments();
4520 int l = 0;
4521 int argCount = 0;
4522 while (tok != ')' && tok != EOF) {
4523 if (! varArgs && !pArgList) {
4524 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004525 }
Jack Palevich5b659092009-07-31 14:55:07 -07004526 expr();
4527 pGen->forceR0RVal();
4528 Type* pTargetType;
4529 if (pArgList) {
4530 pTargetType = pArgList->pHead;
4531 pArgList = pArgList->pTail;
4532 } else {
4533 // This is a ... function, just pass arguments in their
4534 // natural type.
4535 pTargetType = pGen->getR0Type();
4536 if (pTargetType->tag == TY_FLOAT) {
4537 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004538 } else if (pTargetType->tag == TY_ARRAY) {
4539 // Pass arrays by pointer.
4540 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004541 }
4542 }
4543 if (pTargetType->tag == TY_VOID) {
4544 error("Can't pass void value for argument %d",
4545 argCount + 1);
4546 } else {
4547 l += pGen->storeR0ToArg(l, pTargetType);
4548 }
4549 if (accept(',')) {
4550 // fine
4551 } else if ( tok != ')') {
4552 error("Expected ',' or ')'");
4553 }
4554 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004555 }
Jack Palevich5b659092009-07-31 14:55:07 -07004556 if (! varArgs && pArgList) {
4557 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004558 }
Jack Palevich5b659092009-07-31 14:55:07 -07004559 pGen->endFunctionCallArguments(pDecl, a, l);
4560 skip(')');
4561 pGen->callIndirect(l, pDecl);
4562 pGen->adjustStackAfterCall(pDecl, l, true);
4563 } else {
4564 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004565 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004566 }
4567 }
4568
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004569 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004570 Type* pStructElement = lookupStructMember(pStruct, tok);
4571 if (pStructElement) {
4572 next();
4573 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4574 } else {
4575 String buf;
4576 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004577 error("Expected a struct member to the right of '%s', got %s",
4578 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004579 }
4580 }
4581
Jack Palevichaaac9282009-07-31 14:34:34 -07004582 void doIncDec(int isInc, int isPost) {
4583 // R0 already has the lval
4584 checkLVal();
4585 int lit = isInc ? 1 : -1;
4586 pGen->pushR0();
4587 pGen->loadR0FromR0();
4588 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004589 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4590 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004591 error("++/-- illegal for this type. %d", tag);
4592 }
4593 if (isPost) {
4594 pGen->over();
4595 pGen->pushR0();
4596 pGen->li(lit);
4597 pGen->genOp(OP_PLUS);
4598 pGen->storeR0ToTOS();
4599 pGen->popR0();
4600 } else {
4601 pGen->pushR0();
4602 pGen->li(lit);
4603 pGen->genOp(OP_PLUS);
4604 pGen->over();
4605 pGen->storeR0ToTOS();
4606 pGen->popR0();
4607 }
4608 }
4609
Jack Palevich47cbea92009-07-31 15:25:53 -07004610 void doPointer() {
4611 pGen->forceR0RVal();
4612 Type* pR0Type = pGen->getR0Type();
4613 if (pR0Type->tag != TY_POINTER) {
4614 error("Expected a pointer type.");
4615 } else {
4616 if (pR0Type->pHead->tag != TY_FUNC) {
4617 pGen->setR0ExpressionType(ET_LVALUE);
4618 }
4619 }
4620 }
4621
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004622 void doAddressOf() {
4623 Type* pR0 = pGen->getR0Type();
4624 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4625 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4626 error("Expected an lvalue");
4627 }
4628 Type* pR0Type = pGen->getR0Type();
4629 pGen->setR0ExpressionType(ET_RVALUE);
4630 }
4631
Jack Palevich40600de2009-07-01 15:32:35 -07004632 /* Recursive descent parser for binary operations.
4633 */
4634 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004635 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004636 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004637 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004638 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004639 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004640 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004641 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004642 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004643 t = tokc;
4644 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004645 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004646 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004647 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004648 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004649 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004650 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004651 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004652 // Check for syntax error.
4653 if (pGen->getR0Type() == NULL) {
4654 // We failed to parse a right-hand argument.
4655 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004656 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004657 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004658 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004659 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004660 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004661 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004662 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004663 }
4664 }
4665 }
4666 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004667 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004668 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004669 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004670 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004671 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004672 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004673 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004674 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004675 }
4676 }
4677 }
4678
Jack Palevich43aaee32009-07-31 14:01:37 -07004679 void commaExpr() {
4680 for(;;) {
4681 expr();
4682 if (!accept(',')) {
4683 break;
4684 }
4685 }
4686 }
4687
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004689 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004690 }
4691
4692 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004693 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004694 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004695 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004696 }
4697
Jack Palevicha6baa232009-06-12 11:25:59 -07004698 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004699 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004700
Jack Palevich95727a02009-07-06 12:07:15 -07004701 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004702 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004703 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004704 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004705 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004706 next();
4707 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 a = test_expr();
4709 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004710 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004711 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004712 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004713 n = pGen->gjmp(0); /* jmp */
4714 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004715 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004716 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004717 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004718 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004719 }
Jack Palevich546b2242009-05-13 15:10:04 -07004720 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004721 t = tok;
4722 next();
4723 skip('(');
4724 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004725 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004726 a = test_expr();
4727 } else {
4728 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004729 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004730 skip(';');
4731 n = codeBuf.getPC();
4732 a = 0;
4733 if (tok != ';')
4734 a = test_expr();
4735 skip(';');
4736 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004737 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004738 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004739 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004740 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004741 n = t + 4;
4742 }
4743 }
4744 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004745 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004746 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004747 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004748 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004749 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004750 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004751 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004752 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004753 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004754 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004755 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004756 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004757 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004758 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004759 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004760 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004761 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004762 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004763 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004764 if (pReturnType->tag == TY_VOID) {
4765 error("Must not return a value from a void function");
4766 } else {
4767 pGen->convertR0(pReturnType);
4768 }
4769 } else {
4770 if (pReturnType->tag != TY_VOID) {
4771 error("Must specify a value here");
4772 }
Jack Palevich8df46192009-07-07 14:48:51 -07004773 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004774 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004775 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004776 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004777 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004778 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004779 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004780 }
4781 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004782
Jack Palevicha8f427f2009-07-13 18:40:08 -07004783 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004784 if (a == b) {
4785 return true;
4786 }
4787 if (a == NULL || b == NULL) {
4788 return false;
4789 }
4790 TypeTag at = a->tag;
4791 if (at != b->tag) {
4792 return false;
4793 }
4794 if (at == TY_POINTER) {
4795 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004796 } else if (at == TY_ARRAY) {
4797 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004798 } else if (at == TY_FUNC || at == TY_PARAM) {
4799 return typeEqual(a->pHead, b->pHead)
4800 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004801 } else if (at == TY_STRUCT) {
4802 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004803 }
4804 return true;
4805 }
4806
Jack Palevich2ff5c222009-07-23 15:11:22 -07004807 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004808 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004809 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004810 memset(pType, 0, sizeof(*pType));
4811 pType->tag = tag;
4812 pType->pHead = pHead;
4813 pType->pTail = pTail;
4814 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004815 }
4816
Jack Palevich2ff5c222009-07-23 15:11:22 -07004817 Type* createPtrType(Type* pType) {
4818 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004819 }
4820
4821 /**
4822 * Try to print a type in declaration order
4823 */
Jack Palevich86351982009-06-30 18:09:56 -07004824 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004825 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004826 if (pType == NULL) {
4827 buffer.appendCStr("null");
4828 return;
4829 }
Jack Palevich3f226492009-07-02 14:46:19 -07004830 decodeTypeImp(buffer, pType);
4831 }
4832
4833 void decodeTypeImp(String& buffer, Type* pType) {
4834 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004835 decodeId(buffer, pType->id);
4836 decodeTypeImpPostfix(buffer, pType);
4837 }
Jack Palevich3f226492009-07-02 14:46:19 -07004838
Jack Palevich9221bcc2009-08-26 16:15:07 -07004839 void decodeId(String& buffer, tokenid_t id) {
4840 if (id) {
4841 String temp;
4842 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004843 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004844 }
Jack Palevich3f226492009-07-02 14:46:19 -07004845 }
4846
4847 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4848 TypeTag tag = pType->tag;
4849
Jack Palevich9221bcc2009-08-26 16:15:07 -07004850 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004851 switch (tag) {
4852 case TY_INT:
4853 buffer.appendCStr("int");
4854 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004855 case TY_SHORT:
4856 buffer.appendCStr("short");
4857 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004858 case TY_CHAR:
4859 buffer.appendCStr("char");
4860 break;
4861 case TY_VOID:
4862 buffer.appendCStr("void");
4863 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004864 case TY_FLOAT:
4865 buffer.appendCStr("float");
4866 break;
4867 case TY_DOUBLE:
4868 buffer.appendCStr("double");
4869 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004870 case TY_STRUCT:
4871 {
4872 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4873 buffer.appendCStr(isStruct ? "struct" : "union");
4874 if (pType->pHead && pType->pHead->structTag) {
4875 buffer.append(' ');
4876 decodeId(buffer, pType->pHead->structTag);
4877 }
4878 }
4879 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004880 default:
4881 break;
4882 }
Jack Palevich86351982009-06-30 18:09:56 -07004883 buffer.append(' ');
4884 }
Jack Palevich3f226492009-07-02 14:46:19 -07004885
4886 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004887 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004888 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004889 case TY_SHORT:
4890 break;
Jack Palevich86351982009-06-30 18:09:56 -07004891 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004892 break;
4893 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004894 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004895 case TY_FLOAT:
4896 break;
4897 case TY_DOUBLE:
4898 break;
Jack Palevich86351982009-06-30 18:09:56 -07004899 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004900 decodeTypeImpPrefix(buffer, pType->pHead);
4901 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4902 buffer.append('(');
4903 }
4904 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004905 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004906 case TY_ARRAY:
4907 decodeTypeImpPrefix(buffer, pType->pHead);
4908 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004909 case TY_STRUCT:
4910 break;
Jack Palevich86351982009-06-30 18:09:56 -07004911 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004912 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004913 break;
4914 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004915 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004916 break;
4917 default:
4918 String temp;
4919 temp.printf("Unknown tag %d", pType->tag);
4920 buffer.append(temp);
4921 break;
4922 }
Jack Palevich3f226492009-07-02 14:46:19 -07004923 }
4924
4925 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4926 TypeTag tag = pType->tag;
4927
4928 switch(tag) {
4929 case TY_POINTER:
4930 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4931 buffer.append(')');
4932 }
4933 decodeTypeImpPostfix(buffer, pType->pHead);
4934 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004935 case TY_ARRAY:
4936 {
4937 String temp;
4938 temp.printf("[%d]", pType->length);
4939 buffer.append(temp);
4940 }
4941 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004942 case TY_STRUCT:
4943 if (pType->pHead->length >= 0) {
4944 buffer.appendCStr(" {");
4945 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4946 decodeTypeImp(buffer, pArg->pHead);
4947 buffer.appendCStr(";");
4948 }
4949 buffer.append('}');
4950 }
4951 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004952 case TY_FUNC:
4953 buffer.append('(');
4954 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4955 decodeTypeImp(buffer, pArg);
4956 if (pArg->pTail) {
4957 buffer.appendCStr(", ");
4958 }
4959 }
4960 buffer.append(')');
4961 break;
4962 default:
4963 break;
Jack Palevich86351982009-06-30 18:09:56 -07004964 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004965 }
4966
Jack Palevich86351982009-06-30 18:09:56 -07004967 void printType(Type* pType) {
4968 String buffer;
4969 decodeType(buffer, pType);
4970 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004971 }
4972
Jack Palevich2ff5c222009-07-23 15:11:22 -07004973 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004974 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004975 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004976 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004977 } else if (tok == TOK_SHORT) {
4978 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004979 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004980 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004981 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004982 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004983 } else if (tok == TOK_FLOAT) {
4984 pType = mkpFloat;
4985 } else if (tok == TOK_DOUBLE) {
4986 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004987 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
4988 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004989 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004990 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004991 }
4992 next();
Jack Palevich86351982009-06-30 18:09:56 -07004993 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004994 }
4995
Jack Palevich9221bcc2009-08-26 16:15:07 -07004996 Type* acceptStruct() {
4997 assert(tok == TOK_STRUCT || tok == TOK_UNION);
4998 bool isStruct = tok == TOK_STRUCT;
4999 next();
5000 tokenid_t structTag = acceptSymbol();
5001 bool isDeclaration = accept('{');
5002 bool fail = false;
5003
5004 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5005 if (structTag) {
5006 Token* pToken = &mTokenTable[structTag];
5007 VariableInfo* pStructInfo = pToken->mpStructInfo;
5008 bool needToDeclare = !pStructInfo;
5009 if (pStructInfo) {
5010 if (isDeclaration) {
5011 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5012 if (pStructInfo->pType->pHead->length == -1) {
5013 // we're filling in a forward declaration.
5014 needToDeclare = false;
5015 } else {
5016 error("A struct with the same name is already defined at this level.");
5017 fail = true;
5018 }
5019 } else {
5020 needToDeclare = true;
5021 }
5022 }
5023 if (!fail) {
5024 assert(pStructInfo->isStructTag);
5025 pStructType->pHead = pStructInfo->pType;
5026 pStructType->pTail = pStructType->pHead->pTail;
5027 }
5028 }
5029
5030 if (needToDeclare) {
5031 // This is a new struct name
5032 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5033 pStructType = createType(TY_STRUCT, NULL, NULL);
5034 pStructType->structTag = structTag;
5035 pStructType->pHead = pStructType;
5036 if (! isDeclaration) {
5037 // A forward declaration
5038 pStructType->length = -1;
5039 }
5040 pToken->mpStructInfo->pType = pStructType;
5041 }
5042 } else {
5043 // An anonymous struct
5044 pStructType->pHead = pStructType;
5045 }
5046
5047 if (isDeclaration) {
5048 size_t offset = 0;
5049 size_t structSize = 0;
5050 size_t structAlignment = 0;
5051 Type** pParamHolder = & pStructType->pHead->pTail;
5052 while (tok != '}' && tok != EOF) {
5053 Type* pPrimitiveType = expectPrimitiveType();
5054 if (pPrimitiveType) {
5055 while (tok != ';' && tok != EOF) {
5056 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5057 if (!pItem) {
5058 break;
5059 }
5060 if (lookupStructMember(pStructType, pItem->id)) {
5061 String buf;
5062 decodeToken(buf, pItem->id, false);
5063 error("Duplicate struct member %s", buf.getUnwrapped());
5064 }
5065 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5066 size_t alignment = pGen->alignmentOf(pItem);
5067 if (alignment > structAlignment) {
5068 structAlignment = alignment;
5069 }
5070 size_t alignmentMask = alignment - 1;
5071 offset = (offset + alignmentMask) & ~alignmentMask;
5072 pStructElement->length = offset;
5073 size_t size = pGen->sizeOf(pItem);
5074 if (isStruct) {
5075 offset += size;
5076 structSize = offset;
5077 } else {
5078 if (size >= structSize) {
5079 structSize = size;
5080 }
5081 }
5082 *pParamHolder = pStructElement;
5083 pParamHolder = &pStructElement->pTail;
5084 accept(',');
5085 }
5086 skip(';');
5087 } else {
5088 // Some sort of syntax error, skip token and keep trying
5089 next();
5090 }
5091 }
5092 if (!fail) {
5093 pStructType->pHead->length = structSize;
5094 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5095 }
5096 skip('}');
5097 }
5098 if (fail) {
5099 pStructType = NULL;
5100 }
5101 return pStructType;
5102 }
5103
5104 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5105 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5106 if (pStructElement->pHead->id == memberId) {
5107 return pStructElement;
5108 }
5109 }
5110 return NULL;
5111 }
5112
Jack Palevich2ff5c222009-07-23 15:11:22 -07005113 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005114 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005115 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005116 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005117 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005118 if (declName) {
5119 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005120 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005121 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005122 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005123 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005124 } else if (nameRequired) {
5125 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005126 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005127#if 0
5128 fprintf(stderr, "Parsed a declaration: ");
5129 printType(pType);
5130#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005131 if (reportFailure) {
5132 return NULL;
5133 }
Jack Palevich86351982009-06-30 18:09:56 -07005134 return pType;
5135 }
5136
Jack Palevich2ff5c222009-07-23 15:11:22 -07005137 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005138 bool nameRequired = pBaseType->tag != TY_STRUCT;
5139 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005140 if (! pType) {
5141 error("Expected a declaration");
5142 }
5143 return pType;
5144 }
5145
Jack Palevich3f226492009-07-02 14:46:19 -07005146 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005147 Type* acceptCastTypeDeclaration() {
5148 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005149 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005150 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005151 }
Jack Palevich86351982009-06-30 18:09:56 -07005152 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005153 }
5154
Jack Palevich2ff5c222009-07-23 15:11:22 -07005155 Type* expectCastTypeDeclaration() {
5156 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005157 if (! pType) {
5158 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005159 }
Jack Palevich3f226492009-07-02 14:46:19 -07005160 return pType;
5161 }
5162
5163 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005164 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005165 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005166 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005167 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005168 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005169 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005170 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005171 return pType;
5172 }
5173
5174 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005175 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005176 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005177 // direct-dcl :
5178 // name
5179 // (dcl)
5180 // direct-dcl()
5181 // direct-dcl[]
5182 Type* pNewHead = NULL;
5183 if (accept('(')) {
5184 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005185 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005186 skip(')');
5187 } else if ((declName = acceptSymbol()) != 0) {
5188 if (nameAllowed == false && declName) {
5189 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005190 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005191 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005192 } else if (nameRequired && ! declName) {
5193 String temp;
5194 decodeToken(temp, tok, true);
5195 error("Expected name. Got %s", temp.getUnwrapped());
5196 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005197 }
Jack Palevichb6154502009-08-04 14:56:09 -07005198 for(;;) {
5199 if (accept('(')) {
5200 // Function declaration
5201 Type* pTail = acceptArgs(nameAllowed);
5202 pType = createType(TY_FUNC, pType, pTail);
5203 skip(')');
5204 } if (accept('[')) {
5205 if (tok != ']') {
5206 if (tok != TOK_NUM || tokc <= 0) {
5207 error("Expected positive integer constant");
5208 } else {
5209 Type* pDecayType = createPtrType(pType);
5210 pType = createType(TY_ARRAY, pType, pDecayType);
5211 pType->length = tokc;
5212 }
5213 next();
5214 }
5215 skip(']');
5216 } else {
5217 break;
5218 }
Jack Palevich86351982009-06-30 18:09:56 -07005219 }
Jack Palevich3f226492009-07-02 14:46:19 -07005220
5221 if (pNewHead) {
5222 Type* pA = pNewHead;
5223 while (pA->pHead) {
5224 pA = pA->pHead;
5225 }
5226 pA->pHead = pType;
5227 pType = pNewHead;
5228 }
Jack Palevich86351982009-06-30 18:09:56 -07005229 return pType;
5230 }
5231
Jack Palevich2ff5c222009-07-23 15:11:22 -07005232 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005233 Type* pHead = NULL;
5234 Type* pTail = NULL;
5235 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005236 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005237 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005238 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005239 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005240 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005241 if (!pHead) {
5242 pHead = pParam;
5243 pTail = pParam;
5244 } else {
5245 pTail->pTail = pParam;
5246 pTail = pParam;
5247 }
5248 }
5249 }
5250 if (! accept(',')) {
5251 break;
5252 }
5253 }
5254 return pHead;
5255 }
5256
Jack Palevich2ff5c222009-07-23 15:11:22 -07005257 Type* expectPrimitiveType() {
5258 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005259 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005260 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005261 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005262 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005263 }
Jack Palevich86351982009-06-30 18:09:56 -07005264 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005265 }
5266
Jack Palevichb5e33312009-07-30 19:06:34 -07005267 void checkLVal() {
5268 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005269 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005270 }
5271 }
5272
Jack Palevich86351982009-06-30 18:09:56 -07005273 void addGlobalSymbol(Type* pDecl) {
5274 tokenid_t t = pDecl->id;
5275 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005276 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005277 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005278 }
Jack Palevich86351982009-06-30 18:09:56 -07005279 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005280 }
5281
Jack Palevich86351982009-06-30 18:09:56 -07005282 void reportDuplicate(tokenid_t t) {
5283 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005284 }
5285
Jack Palevich86351982009-06-30 18:09:56 -07005286 void addLocalSymbol(Type* pDecl) {
5287 tokenid_t t = pDecl->id;
5288 if (mLocals.isDefinedAtCurrentLevel(t)) {
5289 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005290 }
Jack Palevich86351982009-06-30 18:09:56 -07005291 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005292 }
5293
Jack Palevich61de31f2009-09-08 11:06:40 -07005294 bool checkUndeclaredStruct(Type* pBaseType) {
5295 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5296 String temp;
5297 decodeToken(temp, pBaseType->structTag, false);
5298 error("Undeclared struct %s", temp.getUnwrapped());
5299 return true;
5300 }
5301 return false;
5302 }
5303
Jack Palevich95727a02009-07-06 12:07:15 -07005304 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005305 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005306
Jack Palevich95727a02009-07-06 12:07:15 -07005307 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005308 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005309 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005310 if (!pDecl) {
5311 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005312 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005313 if (!pDecl->id) {
5314 break;
5315 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005316 if (checkUndeclaredStruct(pDecl)) {
5317 break;
5318 }
Jack Palevich86351982009-06-30 18:09:56 -07005319 int variableAddress = 0;
5320 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005321 size_t alignment = pGen->alignmentOf(pDecl);
5322 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005323 size_t alignmentMask = ~ (alignment - 1);
5324 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005325 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005326 loc = (loc + alignment - 1) & alignmentMask;
5327 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5328 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005329 variableAddress = -loc;
5330 VI(pDecl->id)->pAddress = (void*) variableAddress;
5331 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005332 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005333 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005334 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005335 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005336 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005337 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005338 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005339 if (tok == ',')
5340 next();
5341 }
5342 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005343 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005344 }
5345 }
5346
Jack Palevichf1728be2009-06-12 13:53:51 -07005347 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005348 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005349 }
5350
Jack Palevich37c54bd2009-07-14 18:35:36 -07005351 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005352 if (token == EOF ) {
5353 buffer.printf("EOF");
5354 } else if (token == TOK_NUM) {
5355 buffer.printf("numeric constant");
5356 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005357 if (token < 32) {
5358 buffer.printf("'\\x%02x'", token);
5359 } else {
5360 buffer.printf("'%c'", token);
5361 }
Jack Palevich569f1352009-06-29 14:29:08 -07005362 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005363 if (quote) {
5364 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5365 buffer.printf("keyword \"%s\"", nameof(token));
5366 } else {
5367 buffer.printf("symbol \"%s\"", nameof(token));
5368 }
5369 } else {
5370 buffer.printf("%s", nameof(token));
5371 }
Jack Palevich569f1352009-06-29 14:29:08 -07005372 }
5373 }
5374
Jack Palevich9221bcc2009-08-26 16:15:07 -07005375 void printToken(tokenid_t token) {
5376 String buffer;
5377 decodeToken(buffer, token, true);
5378 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5379 }
5380
Jack Palevich40600de2009-07-01 15:32:35 -07005381 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005382 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005383 if (!result) {
5384 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005385 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005386 error("Expected symbol. Got %s", temp.getUnwrapped());
5387 }
5388 return result;
5389 }
5390
Jack Palevich86351982009-06-30 18:09:56 -07005391 tokenid_t acceptSymbol() {
5392 tokenid_t result = 0;
5393 if (tok >= TOK_SYMBOL) {
5394 result = tok;
5395 next();
Jack Palevich86351982009-06-30 18:09:56 -07005396 }
5397 return result;
5398 }
5399
Jack Palevichb7c81e92009-06-04 19:56:13 -07005400 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005401 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005402 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005403 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005404 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005405 break;
5406 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005407 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005408 if (!pDecl) {
5409 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005410 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005411 if (!pDecl->id) {
5412 skip(';');
5413 continue;
5414 }
5415
Jack Palevich61de31f2009-09-08 11:06:40 -07005416 if (checkUndeclaredStruct(pDecl)) {
5417 skip(';');
5418 continue;
5419 }
5420
Jack Palevich86351982009-06-30 18:09:56 -07005421 if (! isDefined(pDecl->id)) {
5422 addGlobalSymbol(pDecl);
5423 }
5424 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005425 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005426 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005427 }
Jack Palevich86351982009-06-30 18:09:56 -07005428 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005429 // it's a variable declaration
5430 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005431 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005432 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005433 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005434 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005435 }
Jack Palevich86351982009-06-30 18:09:56 -07005436 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005437 if (tok == TOK_NUM) {
5438 if (name) {
5439 * (int*) name->pAddress = tokc;
5440 }
5441 next();
5442 } else {
5443 error("Expected an integer constant");
5444 }
5445 }
Jack Palevich86351982009-06-30 18:09:56 -07005446 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005447 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005448 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005449 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005450 if (!pDecl) {
5451 break;
5452 }
5453 if (! isDefined(pDecl->id)) {
5454 addGlobalSymbol(pDecl);
5455 }
5456 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005457 }
5458 skip(';');
5459 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005460 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005461 if (accept(';')) {
5462 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005463 } else if (tok != '{') {
5464 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005465 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005466 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005467 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005468 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005469 /* patch forward references */
5470 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005471 /* put function address */
5472 name->pAddress = (void*) codeBuf.getPC();
5473 }
5474 // Calculate stack offsets for parameters
5475 mLocals.pushLevel();
5476 intptr_t a = 8;
5477 int argCount = 0;
5478 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5479 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005480 if (pArg->id) {
5481 addLocalSymbol(pArg);
5482 }
Jack Palevich95727a02009-07-06 12:07:15 -07005483 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005484 Type* pPassingType = passingType(pArg);
5485 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005486 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005487 if (pArg->id) {
5488 VI(pArg->id)->pAddress = (void*) a;
5489 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005490 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005491 argCount++;
5492 }
5493 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005494 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005495 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005496 block(0, true);
5497 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005498 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005499 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005500 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005501 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005502 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005503 }
5504 }
5505 }
5506
Jack Palevich9221bcc2009-08-26 16:15:07 -07005507 Type* passingType(Type* pType) {
5508 switch (pType->tag) {
5509 case TY_CHAR:
5510 case TY_SHORT:
5511 return mkpInt;
5512 default:
5513 return pType;
5514 }
5515 }
5516
Jack Palevich9cbd2262009-07-08 16:48:41 -07005517 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5518 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5519 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005520 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005521 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005522 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005523 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005524 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005525 char* result = (char*) base;
5526 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005527 return result;
5528 }
5529
Jack Palevich21a15a22009-05-11 14:49:29 -07005530 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005531 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005532 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005533 pGlobalBase = 0;
5534 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005535 if (pGen) {
5536 delete pGen;
5537 pGen = 0;
5538 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005539 if (file) {
5540 delete file;
5541 file = 0;
5542 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005543 }
5544
Jack Palevich8c246a92009-07-14 21:14:10 -07005545 // One-time initialization, when class is constructed.
5546 void init() {
5547 mpSymbolLookupFn = 0;
5548 mpSymbolLookupContext = 0;
5549 }
5550
Jack Palevich21a15a22009-05-11 14:49:29 -07005551 void clear() {
5552 tok = 0;
5553 tokc = 0;
5554 tokl = 0;
5555 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005556 rsym = 0;
5557 loc = 0;
5558 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005559 dptr = 0;
5560 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005561 file = 0;
5562 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005563 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005564 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005565 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005566 mLineNumber = 1;
5567 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005568 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005569 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005570
Jack Palevich22305132009-05-13 10:58:45 -07005571 void setArchitecture(const char* architecture) {
5572 delete pGen;
5573 pGen = 0;
5574
5575 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005576#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005577 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005578 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005579 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005580#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005581#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005582 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005583 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005584 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005585#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005586 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005587 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005588 }
5589 }
5590
5591 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005592#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005593 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005594#elif defined(DEFAULT_X86_CODEGEN)
5595 pGen = new X86CodeGenerator();
5596#endif
5597 }
5598 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005599 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005600 } else {
5601 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005602 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005603 }
5604 }
5605
Jack Palevich77ae76e2009-05-10 19:59:24 -07005606public:
Jack Palevich22305132009-05-13 10:58:45 -07005607 struct args {
5608 args() {
5609 architecture = 0;
5610 }
5611 const char* architecture;
5612 };
5613
Jack Paleviche7b59062009-05-19 17:12:17 -07005614 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005615 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005616 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005617 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005618
Jack Paleviche7b59062009-05-19 17:12:17 -07005619 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005620 cleanup();
5621 }
5622
Jack Palevich8c246a92009-07-14 21:14:10 -07005623 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5624 mpSymbolLookupFn = pFn;
5625 mpSymbolLookupContext = pContext;
5626 }
5627
Jack Palevich1cdef202009-05-22 12:06:27 -07005628 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005629 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005630
Jack Palevich2ff5c222009-07-23 15:11:22 -07005631 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005632 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005633 cleanup();
5634 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005635 mTokenTable.setArena(&mGlobalArena);
5636 mGlobals.setArena(&mGlobalArena);
5637 mGlobals.setTokenTable(&mTokenTable);
5638 mLocals.setArena(&mLocalArena);
5639 mLocals.setTokenTable(&mTokenTable);
5640
5641 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005642 codeBuf.init(ALLOC_SIZE);
5643 setArchitecture(NULL);
5644 if (!pGen) {
5645 return -1;
5646 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005647#ifdef PROVIDE_TRACE_CODEGEN
5648 pGen = new TraceCodeGenerator(pGen);
5649#endif
5650 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005651 pGen->init(&codeBuf);
5652 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005653 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5654 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005655 inp();
5656 next();
5657 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005658 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005659 result = pGen->finishCompile();
5660 if (result == 0) {
5661 if (mErrorBuf.len()) {
5662 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005663 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005664 }
Jack Palevichce105a92009-07-16 14:30:33 -07005665 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005666 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005667 }
5668
Jack Palevich86351982009-06-30 18:09:56 -07005669 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005670 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005671 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005672 mkpChar = createType(TY_CHAR, NULL, NULL);
5673 mkpVoid = createType(TY_VOID, NULL, NULL);
5674 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5675 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5676 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5677 mkpIntPtr = createPtrType(mkpInt);
5678 mkpCharPtr = createPtrType(mkpChar);
5679 mkpFloatPtr = createPtrType(mkpFloat);
5680 mkpDoublePtr = createPtrType(mkpDouble);
5681 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005682 }
5683
Jack Palevicha6baa232009-06-12 11:25:59 -07005684 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005685 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005686 }
5687
Jack Palevich569f1352009-06-29 14:29:08 -07005688 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005689 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005690 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005691 }
5692
Jack Palevich569f1352009-06-29 14:29:08 -07005693 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005694 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005695 error("Undefined forward reference: %s",
5696 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005697 }
5698 return true;
5699 }
5700
Jack Palevich1cdef202009-05-22 12:06:27 -07005701 /* Look through the symbol table to find a symbol.
5702 * If found, return its value.
5703 */
5704 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005705 if (mCompileResult == 0) {
5706 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5707 VariableInfo* pVariableInfo = VI(tok);
5708 if (pVariableInfo) {
5709 return pVariableInfo->pAddress;
5710 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005711 }
5712 return NULL;
5713 }
5714
Jack Palevicheedf9d22009-06-04 16:23:40 -07005715 void getPragmas(ACCsizei* actualStringCount,
5716 ACCsizei maxStringCount, ACCchar** strings) {
5717 int stringCount = mPragmaStringCount;
5718 if (actualStringCount) {
5719 *actualStringCount = stringCount;
5720 }
5721 if (stringCount > maxStringCount) {
5722 stringCount = maxStringCount;
5723 }
5724 if (strings) {
5725 char* pPragmas = mPragmas.getUnwrapped();
5726 while (stringCount-- > 0) {
5727 *strings++ = pPragmas;
5728 pPragmas += strlen(pPragmas) + 1;
5729 }
5730 }
5731 }
5732
Jack Palevichd5315572009-09-09 13:19:34 -07005733 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
5734 *base = codeBuf.getBase();
5735 *length = (ACCsizei) codeBuf.getSize();
5736 }
5737
Jack Palevichac0e95e2009-05-29 13:53:44 -07005738 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005739 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005740 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005741};
5742
Jack Paleviche7b59062009-05-19 17:12:17 -07005743const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005744 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5745
Jack Paleviche7b59062009-05-19 17:12:17 -07005746const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005747 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5748 5, 5, /* ==, != */
5749 9, 10, /* &&, || */
5750 6, 7, 8, /* & ^ | */
5751 2, 2 /* ~ ! */
5752 };
5753
Jack Palevich8b0624c2009-05-20 12:12:06 -07005754#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005755const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005756 0x1, // ++
5757 0xff, // --
5758 0xc1af0f, // *
5759 0xf9f79991, // /
5760 0xf9f79991, // % (With manual assist to swap results)
5761 0xc801, // +
5762 0xd8f7c829, // -
5763 0xe0d391, // <<
5764 0xf8d391, // >>
5765 0xe, // <=
5766 0xd, // >=
5767 0xc, // <
5768 0xf, // >
5769 0x4, // ==
5770 0x5, // !=
5771 0x0, // &&
5772 0x1, // ||
5773 0xc821, // &
5774 0xc831, // ^
5775 0xc809, // |
5776 0xd0f7, // ~
5777 0x4 // !
5778};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005779#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005780
Jack Palevich1cdef202009-05-22 12:06:27 -07005781struct ACCscript {
5782 ACCscript() {
5783 text = 0;
5784 textLength = 0;
5785 accError = ACC_NO_ERROR;
5786 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005787
Jack Palevich1cdef202009-05-22 12:06:27 -07005788 ~ACCscript() {
5789 delete text;
5790 }
Jack Palevich546b2242009-05-13 15:10:04 -07005791
Jack Palevich8c246a92009-07-14 21:14:10 -07005792 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5793 compiler.registerSymbolCallback(pFn, pContext);
5794 }
5795
Jack Palevich1cdef202009-05-22 12:06:27 -07005796 void setError(ACCenum error) {
5797 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5798 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005799 }
5800 }
5801
Jack Palevich1cdef202009-05-22 12:06:27 -07005802 ACCenum getError() {
5803 ACCenum result = accError;
5804 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005805 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005806 }
5807
Jack Palevich1cdef202009-05-22 12:06:27 -07005808 Compiler compiler;
5809 char* text;
5810 int textLength;
5811 ACCenum accError;
5812};
5813
5814
5815extern "C"
5816ACCscript* accCreateScript() {
5817 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005818}
Jack Palevich1cdef202009-05-22 12:06:27 -07005819
5820extern "C"
5821ACCenum accGetError( ACCscript* script ) {
5822 return script->getError();
5823}
5824
5825extern "C"
5826void accDeleteScript(ACCscript* script) {
5827 delete script;
5828}
5829
5830extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005831void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5832 ACCvoid* pContext) {
5833 script->registerSymbolCallback(pFn, pContext);
5834}
5835
5836extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005837void accScriptSource(ACCscript* script,
5838 ACCsizei count,
5839 const ACCchar ** string,
5840 const ACCint * length) {
5841 int totalLength = 0;
5842 for(int i = 0; i < count; i++) {
5843 int len = -1;
5844 const ACCchar* s = string[i];
5845 if (length) {
5846 len = length[i];
5847 }
5848 if (len < 0) {
5849 len = strlen(s);
5850 }
5851 totalLength += len;
5852 }
5853 delete script->text;
5854 char* text = new char[totalLength + 1];
5855 script->text = text;
5856 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005857 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005858 for(int i = 0; i < count; i++) {
5859 int len = -1;
5860 const ACCchar* s = string[i];
5861 if (length) {
5862 len = length[i];
5863 }
5864 if (len < 0) {
5865 len = strlen(s);
5866 }
Jack Palevich09555c72009-05-27 12:25:55 -07005867 memcpy(dest, s, len);
5868 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005869 }
5870 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07005871
5872#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07005873 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07005874 int counter;
5875 char path[PATH_MAX];
5876 for (counter = 0; counter < 4096; counter++) {
5877 sprintf(path, DEBUG_DUMP_PATTERN, counter);
5878 if(access(path, F_OK) != 0) {
5879 break;
5880 }
5881 }
5882 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07005883 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07005884 FILE* fd = fopen(path, "w");
5885 if (fd) {
5886 fwrite(text, totalLength, 1, fd);
5887 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07005888 LOGD("Saved input to file %s", path);
5889 } else {
5890 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07005891 }
5892 }
5893#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07005894}
5895
5896extern "C"
5897void accCompileScript(ACCscript* script) {
5898 int result = script->compiler.compile(script->text, script->textLength);
5899 if (result) {
5900 script->setError(ACC_INVALID_OPERATION);
5901 }
5902}
5903
5904extern "C"
5905void accGetScriptiv(ACCscript* script,
5906 ACCenum pname,
5907 ACCint * params) {
5908 switch (pname) {
5909 case ACC_INFO_LOG_LENGTH:
5910 *params = 0;
5911 break;
5912 }
5913}
5914
5915extern "C"
5916void accGetScriptInfoLog(ACCscript* script,
5917 ACCsizei maxLength,
5918 ACCsizei * length,
5919 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005920 char* message = script->compiler.getErrorMessage();
5921 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005922 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005923 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005924 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005925 if (infoLog && maxLength > 0) {
5926 int trimmedLength = maxLength < messageLength ?
5927 maxLength : messageLength;
5928 memcpy(infoLog, message, trimmedLength);
5929 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005930 }
5931}
5932
5933extern "C"
5934void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5935 ACCvoid ** address) {
5936 void* value = script->compiler.lookup(name);
5937 if (value) {
5938 *address = value;
5939 } else {
5940 script->setError(ACC_INVALID_VALUE);
5941 }
5942}
5943
Jack Palevicheedf9d22009-06-04 16:23:40 -07005944extern "C"
5945void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5946 ACCsizei maxStringCount, ACCchar** strings){
5947 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5948}
5949
-b master422972c2009-06-17 19:13:52 -07005950extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07005951void accGetProgramBinary(ACCscript* script,
5952 ACCvoid** base, ACCsizei* length) {
5953 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07005954}
5955
Jack Palevicheedf9d22009-06-04 16:23:40 -07005956
Jack Palevich1cdef202009-05-22 12:06:27 -07005957} // namespace acc
5958