blob: d3544667dd4d84c58e44f21973cd4d38c86038d5 [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 Paleviche7b59062009-05-19 17:12:17 -070042#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070043#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070044#endif
Jack Palevicha6535612009-05-13 16:24:17 -070045
Jack Palevich30321cb2009-08-20 15:34:23 -070046#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
47#define ARM_USE_VFP
48#endif
49
Jack Palevich1cdef202009-05-22 12:06:27 -070050#include <acc/acc.h>
51
Jack Palevich09555c72009-05-27 12:25:55 -070052#define LOG_API(...) do {} while(0)
53// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070054
-b master422972c2009-06-17 19:13:52 -070055#define LOG_STACK(...) do {} while(0)
56// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
57
Jack Palevich9f51a262009-07-29 16:22:26 -070058#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070059// #define PROVIDE_TRACE_CODEGEN
60
Jack Palevich61de31f2009-09-08 11:06:40 -070061// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
62// #define DEBUG_SAVE_INPUT_TO_FILE
63
Jack Palevich9116bc42009-09-08 11:46:42 -070064#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070065#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070066#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070067#else
68#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
69#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070070#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070071
Jack Palevich7f5b1a22009-08-17 16:54:56 -070072#define assert(b) assertImpl(b, __LINE__)
73
Jack Palevichbbf8ab52009-05-11 11:54:30 -070074namespace acc {
75
Jack Palevich8df46192009-07-07 14:48:51 -070076// Subset of STL vector.
77template<class E> class Vector {
78 public:
79 Vector() {
80 mpBase = 0;
81 mUsed = 0;
82 mSize = 0;
83 }
84
85 ~Vector() {
86 if (mpBase) {
87 for(size_t i = 0; i < mUsed; i++) {
88 mpBase[mUsed].~E();
89 }
90 free(mpBase);
91 }
92 }
93
94 inline E& operator[](size_t i) {
95 return mpBase[i];
96 }
97
98 inline E& front() {
99 return mpBase[0];
100 }
101
102 inline E& back() {
103 return mpBase[mUsed - 1];
104 }
105
106 void pop_back() {
107 mUsed -= 1;
108 mpBase[mUsed].~E();
109 }
110
111 void push_back(const E& item) {
112 * ensure(1) = item;
113 }
114
115 size_t size() {
116 return mUsed;
117 }
118
119private:
120 E* ensure(int n) {
121 size_t newUsed = mUsed + n;
122 if (newUsed > mSize) {
123 size_t newSize = mSize * 2 + 10;
124 if (newSize < newUsed) {
125 newSize = newUsed;
126 }
127 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
128 mSize = newSize;
129 }
130 E* result = mpBase + mUsed;
131 mUsed = newUsed;
132 return result;
133 }
134
135 E* mpBase;
136 size_t mUsed;
137 size_t mSize;
138};
139
Jack Palevichac0e95e2009-05-29 13:53:44 -0700140class ErrorSink {
141public:
142 void error(const char *fmt, ...) {
143 va_list ap;
144 va_start(ap, fmt);
145 verror(fmt, ap);
146 va_end(ap);
147 }
148
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700149 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700150 virtual void verror(const char* fmt, va_list ap) = 0;
151};
152
153class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700154 typedef int tokenid_t;
155 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700156 TY_INT, // 0
157 TY_CHAR, // 1
158 TY_SHORT, // 2
159 TY_VOID, // 3
160 TY_FLOAT, // 4
161 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700162 TY_POINTER, // 6
163 TY_ARRAY, // 7
164 TY_STRUCT, // 8
165 TY_FUNC, // 9
166 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700167 };
168
169 struct Type {
170 TypeTag tag;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700171 tokenid_t id; // For function arguments, global vars, local vars, struct elements
172 tokenid_t structTag; // For structs the name of the struct
173 int length; // length of array, offset of struct element. -1 means struct is forward defined
174 int alignment; // for structs only
175 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700176 Type* pTail;
177 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700178
Jack Palevichba929a42009-07-17 10:20:32 -0700179 enum ExpressionType {
180 ET_RVALUE,
181 ET_LVALUE
182 };
183
184 struct ExpressionValue {
185 ExpressionValue() {
186 et = ET_RVALUE;
187 pType = NULL;
188 }
189 ExpressionType et;
190 Type* pType;
191 };
192
Jack Palevich21a15a22009-05-11 14:49:29 -0700193 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700194 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700195 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700196 ErrorSink* mErrorSink;
197 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700198 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700199
Jack Palevich21a15a22009-05-11 14:49:29 -0700200 void release() {
201 if (pProgramBase != 0) {
202 free(pProgramBase);
203 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700204 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700205 }
206
Jack Palevich0a280a02009-06-11 10:53:51 -0700207 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700208 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700209 bool overflow = newSize > mSize;
210 if (overflow && !mOverflowed) {
211 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700212 if (mErrorSink) {
213 mErrorSink->error("Code too large: %d bytes", newSize);
214 }
215 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700216 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700217 }
218
Jack Palevich21a15a22009-05-11 14:49:29 -0700219 public:
220 CodeBuf() {
221 pProgramBase = 0;
222 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700223 mErrorSink = 0;
224 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700225 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700226 }
227
228 ~CodeBuf() {
229 release();
230 }
231
232 void init(int size) {
233 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700234 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700235 pProgramBase = (char*) calloc(1, size);
236 ind = pProgramBase;
237 }
238
Jack Palevichac0e95e2009-05-29 13:53:44 -0700239 void setErrorSink(ErrorSink* pErrorSink) {
240 mErrorSink = pErrorSink;
241 }
242
Jack Palevich546b2242009-05-13 15:10:04 -0700243 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700244 if(check(4)) {
245 return 0;
246 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700247 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700248 * (int*) ind = n;
249 ind += 4;
250 return result;
251 }
252
Jack Palevich21a15a22009-05-11 14:49:29 -0700253 /*
254 * Output a byte. Handles all values, 0..ff.
255 */
256 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700257 if(check(1)) {
258 return;
259 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 *ind++ = n;
261 }
262
Jack Palevich21a15a22009-05-11 14:49:29 -0700263 inline void* getBase() {
264 return (void*) pProgramBase;
265 }
266
Jack Palevich8b0624c2009-05-20 12:12:06 -0700267 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700268 return ind - pProgramBase;
269 }
270
Jack Palevich8b0624c2009-05-20 12:12:06 -0700271 intptr_t getPC() {
272 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700273 }
274 };
275
Jack Palevich1cdef202009-05-22 12:06:27 -0700276 /**
277 * A code generator creates an in-memory program, generating the code on
278 * the fly. There is one code generator implementation for each supported
279 * architecture.
280 *
281 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700282 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700283 * FP - a frame pointer for accessing function arguments and local
284 * variables.
285 * SP - a stack pointer for storing intermediate results while evaluating
286 * expressions. The stack pointer grows downwards.
287 *
288 * The function calling convention is that all arguments are placed on the
289 * stack such that the first argument has the lowest address.
290 * After the call, the result is in R0. The caller is responsible for
291 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700292 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700293 * FP and SP registers are saved.
294 */
295
Jack Palevich21a15a22009-05-11 14:49:29 -0700296 class CodeGenerator {
297 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700298 CodeGenerator() {
299 mErrorSink = 0;
300 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700301 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700302 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700303 virtual ~CodeGenerator() {}
304
Jack Palevich22305132009-05-13 10:58:45 -0700305 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700306 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700307 pCodeBuf->setErrorSink(mErrorSink);
308 }
309
Jack Palevichb67b18f2009-06-11 21:12:23 -0700310 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700311 mErrorSink = pErrorSink;
312 if (pCodeBuf) {
313 pCodeBuf->setErrorSink(mErrorSink);
314 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700315 }
316
Jack Palevich58c30ee2009-07-17 16:35:23 -0700317 /* Give the code generator some utility types so it can
318 * use its own types as needed for the results of some
319 * operations like gcmp.
320 */
321
Jack Palevicha8f427f2009-07-13 18:40:08 -0700322 void setTypes(Type* pInt) {
323 mkpInt = pInt;
324 }
325
Jack Palevich1cdef202009-05-22 12:06:27 -0700326 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700327 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 * Save the old value of the FP.
329 * Set the new value of the FP.
330 * Convert from the native platform calling convention to
331 * our stack-based calling convention. This may require
332 * pushing arguments from registers to the stack.
333 * Allocate "N" bytes of stack space. N isn't known yet, so
334 * just emit the instructions for adjusting the stack, and return
335 * the address to patch up. The patching will be done in
336 * functionExit().
337 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700338 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700339 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700340
Jack Palevich1cdef202009-05-22 12:06:27 -0700341 /* Emit a function epilog.
342 * Restore the old SP and FP register values.
343 * Return to the calling function.
344 * argCount - the number of arguments to the function.
345 * localVariableAddress - returned from functionEntry()
346 * localVariableSize - the size in bytes of the local variables.
347 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700348 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700350
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700352 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700353
Jack Palevich1a539db2009-07-08 13:04:41 -0700354 /* Load floating point value from global address. */
355 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700356
Jack Palevich9221bcc2009-08-26 16:15:07 -0700357 /* Add the struct offset in bytes to R0, change the type to pType */
358 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
359
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 /* Jump to a target, and return the address of the word that
361 * holds the target data, in case it needs to be fixed up later.
362 */
Jack Palevich22305132009-05-13 10:58:45 -0700363 virtual int gjmp(int t) = 0;
364
Jack Palevich1cdef202009-05-22 12:06:27 -0700365 /* Test R0 and jump to a target if the test succeeds.
366 * l = 0: je, l == 1: jne
367 * Return the address of the word that holds the targed data, in
368 * case it needs to be fixed up later.
369 */
Jack Palevich22305132009-05-13 10:58:45 -0700370 virtual int gtst(bool l, int t) = 0;
371
Jack Palevich9eed7a22009-07-06 17:24:34 -0700372 /* Compare TOS against R0, and store the boolean result in R0.
373 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700374 * op specifies the comparison.
375 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700376 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700377
Jack Palevich9eed7a22009-07-06 17:24:34 -0700378 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700379 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700380 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700381 */
Jack Palevich546b2242009-05-13 15:10:04 -0700382 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700383
Jack Palevich9eed7a22009-07-06 17:24:34 -0700384 /* Compare 0 against R0, and store the boolean result in R0.
385 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700387 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700388
389 /* Perform the arithmetic op specified by op. 0 is the
390 * left argument, R0 is the right argument.
391 */
392 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700393
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700394 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700395 */
396 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700397
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700398 /* Turn R0, TOS into R0 TOS R0 */
399
400 virtual void over() = 0;
401
402 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700403 */
404 virtual void popR0() = 0;
405
Jack Palevich9eed7a22009-07-06 17:24:34 -0700406 /* Store R0 to the address stored in TOS.
407 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700408 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700409 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700410
Jack Palevich1cdef202009-05-22 12:06:27 -0700411 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700412 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700413 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700414
Jack Palevich1cdef202009-05-22 12:06:27 -0700415 /* Load the absolute address of a variable to R0.
416 * If ea <= LOCAL, then this is a local variable, or an
417 * argument, addressed relative to FP.
418 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700419 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700420 * et is ET_RVALUE for things like string constants, ET_LVALUE for
421 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700422 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700423 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700424
Jack Palevich9f51a262009-07-29 16:22:26 -0700425 /* Load the pc-relative address of a forward-referenced variable to R0.
426 * Return the address of the 4-byte constant so that it can be filled
427 * in later.
428 */
429 virtual int leaForward(int ea, Type* pPointerType) = 0;
430
Jack Palevich8df46192009-07-07 14:48:51 -0700431 /**
432 * Convert R0 to the given type.
433 */
Jack Palevichb6154502009-08-04 14:56:09 -0700434
435 void convertR0(Type* pType) {
436 convertR0Imp(pType, false);
437 }
438
439 void castR0(Type* pType) {
440 convertR0Imp(pType, true);
441 }
442
443 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700444
Jack Palevich1cdef202009-05-22 12:06:27 -0700445 /* Emit code to adjust the stack for a function call. Return the
446 * label for the address of the instruction that adjusts the
447 * stack size. This will be passed as argument "a" to
448 * endFunctionCallArguments.
449 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700450 virtual int beginFunctionCallArguments() = 0;
451
Jack Palevich1cdef202009-05-22 12:06:27 -0700452 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700453 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700454 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700455 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700456
Jack Palevich1cdef202009-05-22 12:06:27 -0700457 /* Patch the function call preamble.
458 * a is the address returned from beginFunctionCallArguments
459 * l is the number of bytes the arguments took on the stack.
460 * Typically you would also emit code to convert the argument
461 * list into whatever the native function calling convention is.
462 * On ARM for example you would pop the first 5 arguments into
463 * R0..R4
464 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700465 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700466
Jack Palevich1cdef202009-05-22 12:06:27 -0700467 /* Emit a call to an unknown function. The argument "symbol" needs to
468 * be stored in the location where the address should go. It forms
469 * a chain. The address will be patched later.
470 * Return the address of the word that has to be patched.
471 */
Jack Palevich8df46192009-07-07 14:48:51 -0700472 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700473
Jack Palevich1cdef202009-05-22 12:06:27 -0700474 /* Call a function pointer. L is the number of bytes the arguments
475 * take on the stack. The address of the function is stored at
476 * location SP + l.
477 */
Jack Palevich8df46192009-07-07 14:48:51 -0700478 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700479
Jack Palevich1cdef202009-05-22 12:06:27 -0700480 /* Adjust SP after returning from a function call. l is the
481 * number of bytes of arguments stored on the stack. isIndirect
482 * is true if this was an indirect call. (In which case the
483 * address of the function is stored at location SP + l.)
484 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700485 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700486
Jack Palevich1cdef202009-05-22 12:06:27 -0700487 /* Print a disassembly of the assembled code to out. Return
488 * non-zero if there is an error.
489 */
Jack Palevicha6535612009-05-13 16:24:17 -0700490 virtual int disassemble(FILE* out) = 0;
491
Jack Palevich1cdef202009-05-22 12:06:27 -0700492 /* Generate a symbol at the current PC. t is the head of a
493 * linked list of addresses to patch.
494 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700495 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700496
Jack Palevich9f51a262009-07-29 16:22:26 -0700497 /* Resolve a forward reference function at the current PC.
498 * t is the head of a
499 * linked list of addresses to patch.
500 * (Like gsym, but using absolute address, not PC relative address.)
501 */
502 virtual void resolveForward(int t) = 0;
503
Jack Palevich1cdef202009-05-22 12:06:27 -0700504 /*
505 * Do any cleanup work required at the end of a compile.
506 * For example, an instruction cache might need to be
507 * invalidated.
508 * Return non-zero if there is an error.
509 */
510 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700511
Jack Palevicha6535612009-05-13 16:24:17 -0700512 /**
513 * Adjust relative branches by this amount.
514 */
515 virtual int jumpOffset() = 0;
516
Jack Palevich9eed7a22009-07-06 17:24:34 -0700517 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700518 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700519 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700520 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700521
522 /**
523 * Array element alignment (in bytes) for this type of data.
524 */
525 virtual size_t sizeOf(Type* type) = 0;
526
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700527 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700528 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700529 }
530
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700531 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700532 return mExpressionStack.back().et;
533 }
534
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700535 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700536 mExpressionStack.back().et = et;
537 }
538
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700539 virtual size_t getExpressionStackDepth() {
540 return mExpressionStack.size();
541 }
542
Jack Palevichb5e33312009-07-30 19:06:34 -0700543 virtual void forceR0RVal() {
544 if (getR0ExpressionType() == ET_LVALUE) {
545 loadR0FromR0();
546 }
547 }
548
Jack Palevich21a15a22009-05-11 14:49:29 -0700549 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700550 /*
551 * Output a byte. Handles all values, 0..ff.
552 */
553 void ob(int n) {
554 pCodeBuf->ob(n);
555 }
556
Jack Palevich8b0624c2009-05-20 12:12:06 -0700557 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700558 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700559 }
560
Jack Palevich8b0624c2009-05-20 12:12:06 -0700561 intptr_t getBase() {
562 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700563 }
564
Jack Palevich8b0624c2009-05-20 12:12:06 -0700565 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700566 return pCodeBuf->getPC();
567 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700568
569 intptr_t getSize() {
570 return pCodeBuf->getSize();
571 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700572
573 void error(const char* fmt,...) {
574 va_list ap;
575 va_start(ap, fmt);
576 mErrorSink->verror(fmt, ap);
577 va_end(ap);
578 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700579
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700580 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700581 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700582 error("code generator assertion failed at line %s:%d.", __FILE__, line);
583 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700584 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700585 }
586 }
Jack Palevich8df46192009-07-07 14:48:51 -0700587
588 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700589 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700590 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700591 mExpressionStack.back().et = ET_RVALUE;
592 }
593
594 void setR0Type(Type* pType, ExpressionType et) {
595 assert(pType != NULL);
596 mExpressionStack.back().pType = pType;
597 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700598 }
599
Jack Palevich8df46192009-07-07 14:48:51 -0700600 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700601 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700602 }
603
604 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700605 if (mExpressionStack.size()) {
606 mExpressionStack.push_back(mExpressionStack.back());
607 } else {
608 mExpressionStack.push_back(ExpressionValue());
609 }
610
Jack Palevich8df46192009-07-07 14:48:51 -0700611 }
612
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700613 void overType() {
614 size_t size = mExpressionStack.size();
615 if (size >= 2) {
616 mExpressionStack.push_back(mExpressionStack.back());
617 mExpressionStack[size-1] = mExpressionStack[size-2];
618 mExpressionStack[size-2] = mExpressionStack[size];
619 }
620 }
621
Jack Palevich8df46192009-07-07 14:48:51 -0700622 void popType() {
623 mExpressionStack.pop_back();
624 }
625
626 bool bitsSame(Type* pA, Type* pB) {
627 return collapseType(pA->tag) == collapseType(pB->tag);
628 }
629
630 TypeTag collapseType(TypeTag tag) {
631 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700632 TY_INT,
633 TY_INT,
634 TY_INT,
635 TY_VOID,
636 TY_FLOAT,
637 TY_DOUBLE,
638 TY_INT,
639 TY_INT,
640 TY_VOID,
641 TY_VOID,
642 TY_VOID
643 };
Jack Palevich8df46192009-07-07 14:48:51 -0700644 return collapsedTag[tag];
645 }
646
Jack Palevich1a539db2009-07-08 13:04:41 -0700647 TypeTag collapseTypeR0() {
648 return collapseType(getR0Type()->tag);
649 }
650
Jack Palevichb6154502009-08-04 14:56:09 -0700651 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700652 return isFloatTag(pType->tag);
653 }
654
Jack Palevichb6154502009-08-04 14:56:09 -0700655 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700656 return tag == TY_FLOAT || tag == TY_DOUBLE;
657 }
658
Jack Palevichb6154502009-08-04 14:56:09 -0700659 static bool isPointerType(Type* pType) {
660 return isPointerTag(pType->tag);
661 }
662
663 static bool isPointerTag(TypeTag tag) {
664 return tag == TY_POINTER || tag == TY_ARRAY;
665 }
666
667 Type* getPointerArithmeticResultType(Type* a, Type* b) {
668 TypeTag aTag = a->tag;
669 TypeTag bTag = b->tag;
670 if (aTag == TY_POINTER) {
671 return a;
672 }
673 if (bTag == TY_POINTER) {
674 return b;
675 }
676 if (aTag == TY_ARRAY) {
677 return a->pTail;
678 }
679 if (bTag == TY_ARRAY) {
680 return b->pTail;
681 }
682 return NULL;
683 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700684 Type* mkpInt;
685
Jack Palevich21a15a22009-05-11 14:49:29 -0700686 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700687 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700688 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700689 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700690 };
691
Jack Paleviche7b59062009-05-19 17:12:17 -0700692#ifdef PROVIDE_ARM_CODEGEN
693
Jack Palevich22305132009-05-13 10:58:45 -0700694 class ARMCodeGenerator : public CodeGenerator {
695 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700696 ARMCodeGenerator() {
697#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700698 LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700699#else
Jack Palevichc0f25332009-08-25 12:23:43 -0700700 LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700701#endif
702 }
-b master422972c2009-06-17 19:13:52 -0700703
Jack Palevich22305132009-05-13 10:58:45 -0700704 virtual ~ARMCodeGenerator() {}
705
706 /* returns address to patch with local variable size
707 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700708 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700709 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700710 // sp -> arg4 arg5 ...
711 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700712 int regArgCount = calcRegArgCount(pDecl);
713 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700714 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700715 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700716 }
717 // sp -> arg0 arg1 ...
718 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700719 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700720 // sp, fp -> oldfp, retadr, arg0 arg1 ....
721 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700722 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700723 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700724 // We don't know how many local variables we are going to use,
725 // but we will round the allocation up to a multiple of
726 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700727 }
728
Jack Palevichb7718b92009-07-09 22:00:24 -0700729 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700730 // Round local variable size up to a multiple of stack alignment
731 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
732 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700733 // Patch local variable allocation code:
734 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700735 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700736 }
Jack Palevich69796b62009-05-14 15:42:26 -0700737 *(char*) (localVariableAddress) = localVariableSize;
738
Jack Palevich30321cb2009-08-20 15:34:23 -0700739#ifdef ARM_USE_VFP
740 {
Jack Palevichc0f25332009-08-25 12:23:43 -0700741 Type* pReturnType = pDecl->pHead;
742 switch(pReturnType->tag) {
743 case TY_FLOAT:
744 o4(0xEE170A90); // fmrs r0, s15
745 break;
746 case TY_DOUBLE:
747 o4(0xEC510B17); // fmrrd r0, r1, d7
748 break;
749 default:
750 break;
751 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700752 }
753#endif
754
Jack Palevich69796b62009-05-14 15:42:26 -0700755 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
756 o4(0xE1A0E00B); // mov lr, fp
757 o4(0xE59BB000); // ldr fp, [fp]
758 o4(0xE28ED004); // add sp, lr, #4
759 // sp -> retadr, arg0, ...
760 o4(0xE8BD4000); // ldmfd sp!, {lr}
761 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700762
763 // We store the PC into the lr so we can adjust the sp before
764 // returning. We need to pull off the registers we pushed
765 // earlier. We don't need to actually store them anywhere,
766 // just adjust the stack.
767 int regArgCount = calcRegArgCount(pDecl);
768 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700769 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
770 }
771 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700772 }
773
774 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700775 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700776 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700777 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700778 }
779
Jack Palevich1a539db2009-07-08 13:04:41 -0700780 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700781 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700782 // Global, absolute address
783 o4(0xE59F0000); // ldr r0, .L1
784 o4(0xEA000000); // b .L99
785 o4(address); // .L1: .word ea
786 // .L99:
787
788 switch (pType->tag) {
789 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700790#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700791 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700792#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700793 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700794#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700795 break;
796 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700797#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700798 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700799#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700800 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700801#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700802 break;
803 default:
804 assert(false);
805 break;
806 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700807 }
808
Jack Palevich9221bcc2009-08-26 16:15:07 -0700809
810 virtual void addStructOffsetR0(int offset, Type* pType) {
811 if (offset) {
812 size_t immediate = 0;
813 if (encode12BitImmediate(offset, &immediate)) {
814 o4(0xE2800000 | immediate); // add r0, r0, #offset
815 } else {
816 error("structure offset out of range: %d", offset);
817 }
818 }
819 setR0Type(pType, ET_LVALUE);
820 }
821
Jack Palevich22305132009-05-13 10:58:45 -0700822 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700823 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700824 }
825
826 /* l = 0: je, l == 1: jne */
827 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700828 Type* pR0Type = getR0Type();
829 TypeTag tagR0 = pR0Type->tag;
830 switch(tagR0) {
831 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700832#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700833 o4(0xEEF57A40); // fcmpzs s15
834 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700835#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700836 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -0700837 o4(0xE3500000); // cmp r0,#0
838#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700839 break;
840 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700841#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700842 o4(0xEEB57B40); // fcmpzd d7
843 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700844#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700845 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -0700846 o4(0xE3500000); // cmp r0,#0
847#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700848 break;
849 default:
Jack Palevich30321cb2009-08-20 15:34:23 -0700850 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700851 break;
852 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700853 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
854 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700855 }
856
Jack Palevich58c30ee2009-07-17 16:35:23 -0700857 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700858 Type* pR0Type = getR0Type();
859 Type* pTOSType = getTOSType();
860 TypeTag tagR0 = collapseType(pR0Type->tag);
861 TypeTag tagTOS = collapseType(pTOSType->tag);
862 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700863 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700864 o4(0xE1510000); // cmp r1, r1
865 switch(op) {
866 case OP_EQUALS:
867 o4(0x03A00001); // moveq r0,#1
868 o4(0x13A00000); // movne r0,#0
869 break;
870 case OP_NOT_EQUALS:
871 o4(0x03A00000); // moveq r0,#0
872 o4(0x13A00001); // movne r0,#1
873 break;
874 case OP_LESS_EQUAL:
875 o4(0xD3A00001); // movle r0,#1
876 o4(0xC3A00000); // movgt r0,#0
877 break;
878 case OP_GREATER:
879 o4(0xD3A00000); // movle r0,#0
880 o4(0xC3A00001); // movgt r0,#1
881 break;
882 case OP_GREATER_EQUAL:
883 o4(0xA3A00001); // movge r0,#1
884 o4(0xB3A00000); // movlt r0,#0
885 break;
886 case OP_LESS:
887 o4(0xA3A00000); // movge r0,#0
888 o4(0xB3A00001); // movlt r0,#1
889 break;
890 default:
891 error("Unknown comparison op %d", op);
892 break;
893 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700894 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
895 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700896#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700897 o4(0xEEB46BC7); // fcmped d6, d7
898 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700899 switch(op) {
900 case OP_EQUALS:
901 o4(0x03A00001); // moveq r0,#1
902 o4(0x13A00000); // movne r0,#0
903 break;
904 case OP_NOT_EQUALS:
905 o4(0x03A00000); // moveq r0,#0
906 o4(0x13A00001); // movne r0,#1
907 break;
908 case OP_LESS_EQUAL:
909 o4(0xD3A00001); // movle r0,#1
910 o4(0xC3A00000); // movgt r0,#0
911 break;
912 case OP_GREATER:
913 o4(0xD3A00000); // movle r0,#0
914 o4(0xC3A00001); // movgt r0,#1
915 break;
916 case OP_GREATER_EQUAL:
917 o4(0xA3A00001); // movge r0,#1
918 o4(0xB3A00000); // movlt r0,#0
919 break;
920 case OP_LESS:
921 o4(0xA3A00000); // movge r0,#0
922 o4(0xB3A00001); // movlt r0,#1
923 break;
924 default:
925 error("Unknown comparison op %d", op);
926 break;
927 }
928#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700929 switch(op) {
930 case OP_EQUALS:
931 callRuntime((void*) runtime_cmp_eq_dd);
932 break;
933 case OP_NOT_EQUALS:
934 callRuntime((void*) runtime_cmp_ne_dd);
935 break;
936 case OP_LESS_EQUAL:
937 callRuntime((void*) runtime_cmp_le_dd);
938 break;
939 case OP_GREATER:
940 callRuntime((void*) runtime_cmp_gt_dd);
941 break;
942 case OP_GREATER_EQUAL:
943 callRuntime((void*) runtime_cmp_ge_dd);
944 break;
945 case OP_LESS:
946 callRuntime((void*) runtime_cmp_lt_dd);
947 break;
948 default:
949 error("Unknown comparison op %d", op);
950 break;
951 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700952#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700953 } else {
954 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700955#ifdef ARM_USE_VFP
956 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -0700957 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700958 switch(op) {
959 case OP_EQUALS:
960 o4(0x03A00001); // moveq r0,#1
961 o4(0x13A00000); // movne r0,#0
962 break;
963 case OP_NOT_EQUALS:
964 o4(0x03A00000); // moveq r0,#0
965 o4(0x13A00001); // movne r0,#1
966 break;
967 case OP_LESS_EQUAL:
968 o4(0xD3A00001); // movle r0,#1
969 o4(0xC3A00000); // movgt r0,#0
970 break;
971 case OP_GREATER:
972 o4(0xD3A00000); // movle r0,#0
973 o4(0xC3A00001); // movgt r0,#1
974 break;
975 case OP_GREATER_EQUAL:
976 o4(0xA3A00001); // movge r0,#1
977 o4(0xB3A00000); // movlt r0,#0
978 break;
979 case OP_LESS:
980 o4(0xA3A00000); // movge r0,#0
981 o4(0xB3A00001); // movlt r0,#1
982 break;
983 default:
984 error("Unknown comparison op %d", op);
985 break;
986 }
987#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700988 switch(op) {
989 case OP_EQUALS:
990 callRuntime((void*) runtime_cmp_eq_ff);
991 break;
992 case OP_NOT_EQUALS:
993 callRuntime((void*) runtime_cmp_ne_ff);
994 break;
995 case OP_LESS_EQUAL:
996 callRuntime((void*) runtime_cmp_le_ff);
997 break;
998 case OP_GREATER:
999 callRuntime((void*) runtime_cmp_gt_ff);
1000 break;
1001 case OP_GREATER_EQUAL:
1002 callRuntime((void*) runtime_cmp_ge_ff);
1003 break;
1004 case OP_LESS:
1005 callRuntime((void*) runtime_cmp_lt_ff);
1006 break;
1007 default:
1008 error("Unknown comparison op %d", op);
1009 break;
1010 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001011#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001012 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001013 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001014 }
1015
Jack Palevich546b2242009-05-13 15:10:04 -07001016 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001017 Type* pR0Type = getR0Type();
1018 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001019 TypeTag tagR0 = pR0Type->tag;
1020 TypeTag tagTOS = pTOSType->tag;
1021 bool isFloatR0 = isFloatTag(tagR0);
1022 bool isFloatTOS = isFloatTag(tagTOS);
1023 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001024 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001025 bool isPtrR0 = isPointerTag(tagR0);
1026 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001027 if (isPtrR0 || isPtrTOS) {
1028 if (isPtrR0 && isPtrTOS) {
1029 if (op != OP_MINUS) {
1030 error("Unsupported pointer-pointer operation %d.", op);
1031 }
1032 if (! typeEqual(pR0Type, pTOSType)) {
1033 error("Incompatible pointer types for subtraction.");
1034 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001035 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001036 setR0Type(mkpInt);
1037 int size = sizeOf(pR0Type->pHead);
1038 if (size != 1) {
1039 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001040 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001041 // TODO: Optimize for power-of-two.
1042 genOp(OP_DIV);
1043 }
1044 } else {
1045 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1046 error("Unsupported pointer-scalar operation %d", op);
1047 }
Jack Palevichb6154502009-08-04 14:56:09 -07001048 Type* pPtrType = getPointerArithmeticResultType(
1049 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001050 int size = sizeOf(pPtrType->pHead);
1051 if (size != 1) {
1052 // TODO: Optimize for power-of-two.
1053 liReg(size, 2);
1054 if (isPtrR0) {
1055 o4(0x0E0010192); // mul r1,r2,r1
1056 } else {
1057 o4(0x0E0000092); // mul r0,r2,r0
1058 }
1059 }
1060 switch(op) {
1061 case OP_PLUS:
1062 o4(0xE0810000); // add r0,r1,r0
1063 break;
1064 case OP_MINUS:
1065 o4(0xE0410000); // sub r0,r1,r0
1066 break;
1067 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001068 setR0Type(pPtrType);
1069 }
1070 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001071 switch(op) {
1072 case OP_MUL:
1073 o4(0x0E0000091); // mul r0,r1,r0
1074 break;
1075 case OP_DIV:
1076 callRuntime((void*) runtime_DIV);
1077 break;
1078 case OP_MOD:
1079 callRuntime((void*) runtime_MOD);
1080 break;
1081 case OP_PLUS:
1082 o4(0xE0810000); // add r0,r1,r0
1083 break;
1084 case OP_MINUS:
1085 o4(0xE0410000); // sub r0,r1,r0
1086 break;
1087 case OP_SHIFT_LEFT:
1088 o4(0xE1A00011); // lsl r0,r1,r0
1089 break;
1090 case OP_SHIFT_RIGHT:
1091 o4(0xE1A00051); // asr r0,r1,r0
1092 break;
1093 case OP_BIT_AND:
1094 o4(0xE0010000); // and r0,r1,r0
1095 break;
1096 case OP_BIT_XOR:
1097 o4(0xE0210000); // eor r0,r1,r0
1098 break;
1099 case OP_BIT_OR:
1100 o4(0xE1810000); // orr r0,r1,r0
1101 break;
1102 case OP_BIT_NOT:
1103 o4(0xE1E00000); // mvn r0, r0
1104 break;
1105 default:
1106 error("Unimplemented op %d\n", op);
1107 break;
1108 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001109 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001110 } else {
1111 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1112 if (pResultType->tag == TY_DOUBLE) {
1113 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001114
Jack Palevichb7718b92009-07-09 22:00:24 -07001115 switch(op) {
1116 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001117#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001118 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001119#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001120 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001121#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001122 break;
1123 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001124#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001125 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001126#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001127 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001128#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001129 break;
1130 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001131#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001132 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001133#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001134 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001135#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001136 break;
1137 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001138#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001139 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001140#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001141 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001142#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001143 break;
1144 default:
1145 error("Unsupported binary floating operation %d\n", op);
1146 break;
1147 }
1148 } else {
1149 setupFloatArgs();
1150 switch(op) {
1151 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001152#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001153 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001154#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001155 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001156#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001157 break;
1158 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001159#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001160 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001161#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001162 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001163#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001164 break;
1165 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001166#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001167 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001168#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001169 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001170#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001171 break;
1172 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001173#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001174 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001175#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001176 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001177#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001178 break;
1179 default:
1180 error("Unsupported binary floating operation %d\n", op);
1181 break;
1182 }
1183 }
1184 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001185 }
Jack Palevich22305132009-05-13 10:58:45 -07001186 }
1187
Jack Palevich58c30ee2009-07-17 16:35:23 -07001188 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001189 if (op != OP_LOGICAL_NOT) {
1190 error("Unknown unary cmp %d", op);
1191 } else {
1192 Type* pR0Type = getR0Type();
1193 TypeTag tag = collapseType(pR0Type->tag);
1194 switch(tag) {
1195 case TY_INT:
1196 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001197 o4(0xE1510000); // cmp r1, r0
1198 o4(0x03A00001); // moveq r0,#1
1199 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001200 break;
1201 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001202#ifdef ARM_USE_VFP
1203 o4(0xEEF57A40); // fcmpzs s15
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_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001209#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001210 break;
1211 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001212#ifdef ARM_USE_VFP
1213 o4(0xEEB57B40); // fcmpzd d7
1214 o4(0xEEF1FA10); // fmstat
1215 o4(0x03A00001); // moveq r0,#1
1216 o4(0x13A00000); // movne r0,#0
1217#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001218 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001219#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001220 break;
1221 default:
1222 error("gUnaryCmp unsupported type");
1223 break;
1224 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001225 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001226 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001227 }
1228
1229 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001230 Type* pR0Type = getR0Type();
1231 TypeTag tag = collapseType(pR0Type->tag);
1232 switch(tag) {
1233 case TY_INT:
1234 switch(op) {
1235 case OP_MINUS:
1236 o4(0xE3A01000); // mov r1, #0
1237 o4(0xE0410000); // sub r0,r1,r0
1238 break;
1239 case OP_BIT_NOT:
1240 o4(0xE1E00000); // mvn r0, r0
1241 break;
1242 default:
1243 error("Unknown unary op %d\n", op);
1244 break;
1245 }
1246 break;
1247 case TY_FLOAT:
1248 case TY_DOUBLE:
1249 switch (op) {
1250 case OP_MINUS:
1251 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001252#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001253 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001254#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001255 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001256#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001257 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001258#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001259 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001260#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001261 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001262#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001263 }
1264 break;
1265 case OP_BIT_NOT:
1266 error("Can't apply '~' operator to a float or double.");
1267 break;
1268 default:
1269 error("Unknown unary op %d\n", op);
1270 break;
1271 }
1272 break;
1273 default:
1274 error("genUnaryOp unsupported type");
1275 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001276 }
Jack Palevich22305132009-05-13 10:58:45 -07001277 }
1278
Jack Palevich1cdef202009-05-22 12:06:27 -07001279 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001280 Type* pR0Type = getR0Type();
1281 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001282
1283#ifdef ARM_USE_VFP
1284 switch (r0ct ) {
1285 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001286 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001287 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001288 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001289 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001290 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001291 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001292 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001293 default:
1294 o4(0xE92D0001); // stmfd sp!,{r0}
1295 mStackUse += 4;
1296 }
1297#else
1298
Jack Palevichb7718b92009-07-09 22:00:24 -07001299 if (r0ct != TY_DOUBLE) {
1300 o4(0xE92D0001); // stmfd sp!,{r0}
1301 mStackUse += 4;
1302 } else {
1303 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1304 mStackUse += 8;
1305 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001306#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001307 pushType();
-b master422972c2009-06-17 19:13:52 -07001308 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001309 }
1310
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001311 virtual void over() {
1312 // We know it's only used for int-ptr ops (++/--)
1313
1314 Type* pR0Type = getR0Type();
1315 TypeTag r0ct = collapseType(pR0Type->tag);
1316
1317 Type* pTOSType = getTOSType();
1318 TypeTag tosct = collapseType(pTOSType->tag);
1319
1320 assert (r0ct == TY_INT && tosct == TY_INT);
1321
1322 o4(0xE8BD0002); // ldmfd sp!,{r1}
1323 o4(0xE92D0001); // stmfd sp!,{r0}
1324 o4(0xE92D0002); // stmfd sp!,{r1}
1325 overType();
1326 mStackUse += 4;
1327 }
1328
Jack Palevich58c30ee2009-07-17 16:35:23 -07001329 virtual void popR0() {
1330 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001331 TypeTag tosct = collapseType(pTOSType->tag);
1332#ifdef ARM_USE_VFP
1333 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001334 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001335 }
1336#endif
1337 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001338 case TY_INT:
1339 case TY_FLOAT:
1340 o4(0xE8BD0001); // ldmfd sp!,{r0}
1341 mStackUse -= 4;
1342 break;
1343 case TY_DOUBLE:
1344 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1345 mStackUse -= 8;
1346 break;
1347 default:
1348 error("Can't pop this type.");
1349 break;
1350 }
1351 popType();
1352 LOG_STACK("popR0: %d\n", mStackUse);
1353 }
1354
1355 virtual void storeR0ToTOS() {
1356 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001357 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001358 Type* pDestType = pPointerType->pHead;
1359 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001360 o4(0xE8BD0004); // ldmfd sp!,{r2}
1361 popType();
-b master422972c2009-06-17 19:13:52 -07001362 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001363 switch (pDestType->tag) {
1364 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001365 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001366 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001367 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001368 case TY_FLOAT:
1369#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001370 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001371#else
1372 o4(0xE5820000); // str r0, [r2]
1373#endif
1374 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001375 case TY_SHORT:
1376 o4(0xE1C200B0); // strh r0, [r2]
1377 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001378 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001379 o4(0xE5C20000); // strb r0, [r2]
1380 break;
1381 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001382#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001383 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001384#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001385 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001386#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001387 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001388 case TY_STRUCT:
1389 {
1390 int size = sizeOf(pDestType);
1391 if (size > 0) {
1392 liReg(size, 1);
1393 callRuntime((void*) runtime_structCopy);
1394 }
1395 }
1396 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001397 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001398 error("storeR0ToTOS: unimplemented type %d",
1399 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001400 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001401 }
Jack Palevich22305132009-05-13 10:58:45 -07001402 }
1403
Jack Palevich58c30ee2009-07-17 16:35:23 -07001404 virtual void loadR0FromR0() {
1405 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001406 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001407 Type* pNewType = pPointerType->pHead;
1408 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001409 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001410 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001411 case TY_INT:
1412 o4(0xE5900000); // ldr r0, [r0]
1413 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001414 case TY_FLOAT:
1415#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001416 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001417#else
1418 o4(0xE5900000); // ldr r0, [r0]
1419#endif
1420 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001421 case TY_SHORT:
1422 o4(0xE1D000F0); // ldrsh r0, [r0]
1423 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001424 case TY_CHAR:
1425 o4(0xE5D00000); // ldrb r0, [r0]
1426 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001427 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001428#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001429 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001430#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001431 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001432#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001433 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001434 case TY_ARRAY:
1435 pNewType = pNewType->pTail;
1436 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001437 case TY_STRUCT:
1438 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001439 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001440 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001441 break;
1442 }
Jack Palevich80e49722009-08-04 15:39:49 -07001443 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001444 }
1445
Jack Palevichb5e33312009-07-30 19:06:34 -07001446 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001447 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001448 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001449
1450 size_t immediate = 0;
1451 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001452 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001453 inRange = encode12BitImmediate(-ea, &immediate);
1454 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001455 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001456 inRange = encode12BitImmediate(ea, &immediate);
1457 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1458 }
1459 if (! inRange) {
1460 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001461 }
Jack Palevichbd894902009-05-14 19:35:31 -07001462 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001463 // Global, absolute.
1464 o4(0xE59F0000); // ldr r0, .L1
1465 o4(0xEA000000); // b .L99
1466 o4(ea); // .L1: .word 0
1467 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001468 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001469 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001470 }
1471
Jack Palevich9f51a262009-07-29 16:22:26 -07001472 virtual int leaForward(int ea, Type* pPointerType) {
1473 setR0Type(pPointerType);
1474 int result = ea;
1475 int pc = getPC();
1476 int offset = 0;
1477 if (ea) {
1478 offset = (pc - ea - 8) >> 2;
1479 if ((offset & 0xffff) != offset) {
1480 error("function forward reference out of bounds");
1481 }
1482 } else {
1483 offset = 0;
1484 }
1485 o4(0xE59F0000 | offset); // ldr r0, .L1
1486
1487 if (ea == 0) {
1488 o4(0xEA000000); // b .L99
1489 result = o4(ea); // .L1: .word 0
1490 // .L99:
1491 }
1492 return result;
1493 }
1494
Jack Palevichb6154502009-08-04 14:56:09 -07001495 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001496 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001497 if (isPointerType(pType) && isPointerType(pR0Type)) {
1498 Type* pA = pR0Type;
1499 Type* pB = pType;
1500 // Array decays to pointer
1501 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1502 pA = pA->pTail;
1503 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001504 if (! (typeEqual(pA, pB)
1505 || pB->pHead->tag == TY_VOID
1506 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1507 )) {
1508 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001509 }
Jack Palevichb6154502009-08-04 14:56:09 -07001510 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001511 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001512 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001513 TypeTag r0Tag = collapseType(pR0Type->tag);
1514 TypeTag destTag = collapseType(pType->tag);
1515 if (r0Tag == TY_INT) {
1516 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001517#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001518 o4(0xEE070A90); // fmsr s15, r0
1519 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001520
1521#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001522 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001523#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001524 } else {
1525 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001526#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001527 o4(0xEE070A90); // fmsr s15, r0
1528 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001529
1530#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001531 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001532#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001533 }
1534 } else if (r0Tag == TY_FLOAT) {
1535 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001536#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001537 o4(0xEEFD7AE7); // ftosizs s15, s15
1538 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001539#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001540 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001541#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001542 } else {
1543 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001544#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001545 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001546#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001548#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001549 }
1550 } else {
1551 assert (r0Tag == TY_DOUBLE);
1552 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001553#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001554 o4(0xEEFD7BC7); // ftosizd s15, d7
1555 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001556#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001557 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001558#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001559 } else {
1560 assert(destTag == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001561#ifdef ARM_USE_VFP
1562 o4(0xEEF77BC7); // fcvtsd s15, d7
1563#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001564 callRuntime((void*) runtime_double_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001565#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001566 }
1567 }
Jack Palevich8df46192009-07-07 14:48:51 -07001568 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001569 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001570 }
1571
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001572 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001573 return o4(0xE24DDF00); // Placeholder
1574 }
1575
Jack Palevich8148c5b2009-07-16 18:24:47 -07001576 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001577 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001578 Type* pR0Type = getR0Type();
1579 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001580#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001581 switch(r0ct) {
1582 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001583 if (l < 0 || l > 4096-4) {
1584 error("l out of range for stack offset: 0x%08x", l);
1585 }
1586 o4(0xE58D0000 | l); // str r0, [sp, #l]
1587 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001588 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001589 if (l < 0 || l > 1020 || (l & 3)) {
1590 error("l out of range for stack offset: 0x%08x", l);
1591 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001592 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001593 return 4;
1594 case TY_DOUBLE: {
1595 // Align to 8 byte boundary
1596 int l2 = (l + 7) & ~7;
1597 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1598 error("l out of range for stack offset: 0x%08x", l);
1599 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001600 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001601 return (l2 - l) + 8;
1602 }
1603 default:
1604 assert(false);
1605 return 0;
1606 }
1607#else
1608 switch(r0ct) {
1609 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001610 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001611 if (l < 0 || l > 4096-4) {
1612 error("l out of range for stack offset: 0x%08x", l);
1613 }
1614 o4(0xE58D0000 + l); // str r0, [sp, #l]
1615 return 4;
1616 case TY_DOUBLE: {
1617 // Align to 8 byte boundary
1618 int l2 = (l + 7) & ~7;
1619 if (l2 < 0 || l2 > 4096-8) {
1620 error("l out of range for stack offset: 0x%08x", l);
1621 }
1622 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1623 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1624 return (l2 - l) + 8;
1625 }
1626 default:
1627 assert(false);
1628 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001629 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001630#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001631 }
1632
Jack Palevichb7718b92009-07-09 22:00:24 -07001633 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001634 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001635 // Have to calculate register arg count from actual stack size,
1636 // in order to properly handle ... functions.
1637 int regArgCount = l >> 2;
1638 if (regArgCount > 4) {
1639 regArgCount = 4;
1640 }
1641 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001642 argumentStackUse -= regArgCount * 4;
1643 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1644 }
1645 mStackUse += argumentStackUse;
1646
1647 // Align stack.
1648 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1649 * STACK_ALIGNMENT);
1650 mStackAlignmentAdjustment = 0;
1651 if (missalignment > 0) {
1652 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1653 }
1654 l += mStackAlignmentAdjustment;
1655
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001656 if (l < 0 || l > 0x3FC) {
1657 error("L out of range for stack adjustment: 0x%08x", l);
1658 }
1659 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001660 mStackUse += mStackAlignmentAdjustment;
1661 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1662 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001663 }
1664
Jack Palevich8df46192009-07-07 14:48:51 -07001665 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001666 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001667 // Forward calls are always short (local)
1668 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001669 }
1670
Jack Palevich8df46192009-07-07 14:48:51 -07001671 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001672 assert(pFunc->tag == TY_FUNC);
1673 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001674 int argCount = l >> 2;
1675 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001676 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001677 if (adjustedL < 0 || adjustedL > 4096-4) {
1678 error("l out of range for stack offset: 0x%08x", l);
1679 }
1680 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1681 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001682 Type* pReturnType = pFunc->pHead;
1683 setR0Type(pReturnType);
1684#ifdef ARM_USE_VFP
1685 switch(pReturnType->tag) {
1686 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001687 o4(0xEE070A90); // fmsr s15, r0
1688 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001689 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001690 o4(0xEC410B17); // fmdrr d7, r0, r1
1691 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001692 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001693 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001694 }
1695#endif
Jack Palevich22305132009-05-13 10:58:45 -07001696 }
1697
Jack Palevichb7718b92009-07-09 22:00:24 -07001698 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001699 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001700 // Have to calculate register arg count from actual stack size,
1701 // in order to properly handle ... functions.
1702 int regArgCount = l >> 2;
1703 if (regArgCount > 4) {
1704 regArgCount = 4;
1705 }
1706 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001707 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1708 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001709 if (stackUse) {
1710 if (stackUse < 0 || stackUse > 255) {
1711 error("L out of range for stack adjustment: 0x%08x", l);
1712 }
1713 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001714 mStackUse -= stackUse * 4;
1715 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001716 }
Jack Palevich22305132009-05-13 10:58:45 -07001717 }
1718
Jack Palevicha6535612009-05-13 16:24:17 -07001719 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001720 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001721 }
1722
1723 /* output a symbol and patch all calls to it */
1724 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001725 int n;
1726 int base = getBase();
1727 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001728 while (t) {
1729 int data = * (int*) t;
1730 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1731 if (decodedOffset == 0) {
1732 n = 0;
1733 } else {
1734 n = base + decodedOffset; /* next value */
1735 }
1736 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1737 | encodeRelAddress(pc - t - 8);
1738 t = n;
1739 }
1740 }
1741
Jack Palevich9f51a262009-07-29 16:22:26 -07001742 /* output a symbol and patch all calls to it */
1743 virtual void resolveForward(int t) {
1744 if (t) {
1745 int pc = getPC();
1746 *(int *) t = pc;
1747 }
1748 }
1749
Jack Palevich1cdef202009-05-22 12:06:27 -07001750 virtual int finishCompile() {
1751#if defined(__arm__)
1752 const long base = long(getBase());
1753 const long curr = long(getPC());
1754 int err = cacheflush(base, curr, 0);
1755 return err;
1756#else
1757 return 0;
1758#endif
1759 }
1760
Jack Palevicha6535612009-05-13 16:24:17 -07001761 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001762#ifdef ENABLE_ARM_DISASSEMBLY
1763 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001764 disasm_interface_t di;
1765 di.di_readword = disassemble_readword;
1766 di.di_printaddr = disassemble_printaddr;
1767 di.di_printf = disassemble_printf;
1768
1769 int base = getBase();
1770 int pc = getPC();
1771 for(int i = base; i < pc; i += 4) {
1772 fprintf(out, "%08x: %08x ", i, *(int*) i);
1773 ::disasm(&di, i, 0);
1774 }
Jack Palevich09555c72009-05-27 12:25:55 -07001775#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001776 return 0;
1777 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001778
Jack Palevich9eed7a22009-07-06 17:24:34 -07001779 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001780 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001781 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001782 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001783 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001784 case TY_CHAR:
1785 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001786 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07001787 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001788 case TY_DOUBLE:
1789 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001790 case TY_ARRAY:
1791 return alignmentOf(pType->pHead);
1792 case TY_STRUCT:
1793 return pType->pHead->alignment & 0x7fffffff;
1794 case TY_FUNC:
1795 error("alignment of func not supported");
1796 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001797 default:
1798 return 4;
1799 }
1800 }
1801
1802 /**
1803 * Array element alignment (in bytes) for this type of data.
1804 */
1805 virtual size_t sizeOf(Type* pType){
1806 switch(pType->tag) {
1807 case TY_INT:
1808 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001809 case TY_SHORT:
1810 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001811 case TY_CHAR:
1812 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001813 case TY_FLOAT:
1814 return 4;
1815 case TY_DOUBLE:
1816 return 8;
1817 case TY_POINTER:
1818 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001819 case TY_ARRAY:
1820 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07001821 case TY_STRUCT:
1822 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07001823 default:
1824 error("Unsupported type %d", pType->tag);
1825 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001826 }
1827 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001828
Jack Palevich22305132009-05-13 10:58:45 -07001829 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001830 static FILE* disasmOut;
1831
1832 static u_int
1833 disassemble_readword(u_int address)
1834 {
1835 return(*((u_int *)address));
1836 }
1837
1838 static void
1839 disassemble_printaddr(u_int address)
1840 {
1841 fprintf(disasmOut, "0x%08x", address);
1842 }
1843
1844 static void
1845 disassemble_printf(const char *fmt, ...) {
1846 va_list ap;
1847 va_start(ap, fmt);
1848 vfprintf(disasmOut, fmt, ap);
1849 va_end(ap);
1850 }
1851
1852 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1853
1854 /** Encode a relative address that might also be
1855 * a label.
1856 */
1857 int encodeAddress(int value) {
1858 int base = getBase();
1859 if (value >= base && value <= getPC() ) {
1860 // This is a label, encode it relative to the base.
1861 value = value - base;
1862 }
1863 return encodeRelAddress(value);
1864 }
1865
1866 int encodeRelAddress(int value) {
1867 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1868 }
Jack Palevich22305132009-05-13 10:58:45 -07001869
Jack Palevichb7718b92009-07-09 22:00:24 -07001870 int calcRegArgCount(Type* pDecl) {
1871 int reg = 0;
1872 Type* pArgs = pDecl->pTail;
1873 while (pArgs && reg < 4) {
1874 Type* pArg = pArgs->pHead;
1875 if ( pArg->tag == TY_DOUBLE) {
1876 int evenReg = (reg + 1) & ~1;
1877 if (evenReg >= 4) {
1878 break;
1879 }
1880 reg = evenReg + 2;
1881 } else {
1882 reg++;
1883 }
1884 pArgs = pArgs->pTail;
1885 }
1886 return reg;
1887 }
1888
Jack Palevich58c30ee2009-07-17 16:35:23 -07001889 void setupIntPtrArgs() {
1890 o4(0xE8BD0002); // ldmfd sp!,{r1}
1891 mStackUse -= 4;
1892 popType();
1893 }
1894
Jack Palevich30321cb2009-08-20 15:34:23 -07001895 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001896 * Make sure both R0 and TOS are floats. (Could be ints)
1897 * We know that at least one of R0 and TOS is already a float
1898 */
1899 void setupFloatArgs() {
1900 Type* pR0Type = getR0Type();
1901 Type* pTOSType = getTOSType();
1902 TypeTag tagR0 = collapseType(pR0Type->tag);
1903 TypeTag tagTOS = collapseType(pTOSType->tag);
1904 if (tagR0 != TY_FLOAT) {
1905 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001906#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001907 o4(0xEE070A90); // fmsr s15, r0
1908 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001909#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001910 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001911#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001912 }
1913 if (tagTOS != TY_FLOAT) {
1914 assert(tagTOS == TY_INT);
1915 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001916#ifdef ARM_USE_VFP
1917 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07001918 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07001919#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001920 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1921 o4(0xE59D0004); // ldr r0, [sp, #4]
1922 callRuntime((void*) runtime_int_to_float);
1923 o4(0xE1A01000); // mov r1, r0
1924 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1925 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001926#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001927 } else {
1928 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001929#ifdef ARM_USE_VFP
1930 o4(0xECBD7A01); // fldmfds sp!, {s14}
1931
1932#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001933 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001934#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001935 }
1936 mStackUse -= 4;
1937 popType();
1938 }
1939
Jack Palevich30321cb2009-08-20 15:34:23 -07001940 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001941 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1942 * We know that at least one of R0 and TOS are already a double.
1943 */
1944
1945 void setupDoubleArgs() {
1946 Type* pR0Type = getR0Type();
1947 Type* pTOSType = getTOSType();
1948 TypeTag tagR0 = collapseType(pR0Type->tag);
1949 TypeTag tagTOS = collapseType(pTOSType->tag);
1950 if (tagR0 != TY_DOUBLE) {
1951 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001952#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001953 o4(0xEE070A90); // fmsr s15, r0
1954 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001955
1956#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001957 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001958#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001959 } else {
1960 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001961#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001962 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001963#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001964 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001965#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001966 }
1967 }
1968 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001969#ifdef ARM_USE_VFP
1970 if (tagTOS == TY_INT) {
1971 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001972 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001973 } else {
1974 assert(tagTOS == TY_FLOAT);
1975 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001976 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001977 }
1978#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001979 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1980 o4(0xE59D0008); // ldr r0, [sp, #8]
1981 if (tagTOS == TY_INT) {
1982 callRuntime((void*) runtime_int_to_double);
1983 } else {
1984 assert(tagTOS == TY_FLOAT);
1985 callRuntime((void*) runtime_float_to_double);
1986 }
1987 o4(0xE1A02000); // mov r2, r0
1988 o4(0xE1A03001); // mov r3, r1
1989 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1990 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001991#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001992 mStackUse -= 4;
1993 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001994#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001995 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07001996#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001997 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07001998#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001999 mStackUse -= 8;
2000 }
2001 popType();
2002 }
2003
Jack Palevicha8f427f2009-07-13 18:40:08 -07002004 void liReg(int t, int reg) {
2005 assert(reg >= 0 && reg < 16);
2006 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002007 size_t encodedImmediate;
2008 if (encode12BitImmediate(t, &encodedImmediate)) {
2009 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2010 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002011 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002012 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002013 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002014 o4(0xE51F0000 | rN); // ldr rN, .L3
2015 o4(0xEA000000); // b .L99
2016 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002017 // .L99:
2018 }
2019 }
2020
Jack Palevich9221bcc2009-08-26 16:15:07 -07002021 bool encode12BitImmediate(size_t immediate, size_t* pResult) {
2022 for(size_t i = 0; i < 16; i++) {
2023 size_t rotate = i * 2;
2024 size_t mask = rotateRight(0xff, rotate);
2025 if ((immediate | mask) == mask) {
2026 size_t bits8 = rotateLeft(immediate, rotate);
2027 assert(bits8 <= 0xff);
2028 *pResult = (i << 8) | bits8;
2029 return true;
2030 }
2031 }
2032 return false;
2033 }
2034
2035 size_t rotateRight(size_t n, size_t rotate) {
2036 return (n >> rotate) | (n << (32 - rotate));
2037 }
2038
2039 size_t rotateLeft(size_t n, size_t rotate) {
2040 return (n << rotate) | (n >> (32 - rotate));
2041 }
2042
Jack Palevichb7718b92009-07-09 22:00:24 -07002043 void callRuntime(void* fn) {
2044 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002045 o4(0xEA000000); // b .L99
2046 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002047 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002048 }
2049
Jack Palevichb7718b92009-07-09 22:00:24 -07002050 // Integer math:
2051
2052 static int runtime_DIV(int b, int a) {
2053 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002054 }
2055
Jack Palevichb7718b92009-07-09 22:00:24 -07002056 static int runtime_MOD(int b, int a) {
2057 return a % b;
2058 }
2059
Jack Palevich9221bcc2009-08-26 16:15:07 -07002060 static void runtime_structCopy(void* src, size_t size, void* dest) {
2061 memcpy(dest, src, size);
2062 }
2063
Jack Palevich30321cb2009-08-20 15:34:23 -07002064#ifndef ARM_USE_VFP
2065
Jack Palevichb7718b92009-07-09 22:00:24 -07002066 // Comparison to zero
2067
2068 static int runtime_is_non_zero_f(float a) {
2069 return a != 0;
2070 }
2071
2072 static int runtime_is_non_zero_d(double a) {
2073 return a != 0;
2074 }
2075
2076 // Comparison to zero
2077
2078 static int runtime_is_zero_f(float a) {
2079 return a == 0;
2080 }
2081
2082 static int runtime_is_zero_d(double a) {
2083 return a == 0;
2084 }
2085
2086 // Type conversion
2087
2088 static int runtime_float_to_int(float a) {
2089 return (int) a;
2090 }
2091
2092 static double runtime_float_to_double(float a) {
2093 return (double) a;
2094 }
2095
2096 static int runtime_double_to_int(double a) {
2097 return (int) a;
2098 }
2099
2100 static float runtime_double_to_float(double a) {
2101 return (float) a;
2102 }
2103
2104 static float runtime_int_to_float(int a) {
2105 return (float) a;
2106 }
2107
2108 static double runtime_int_to_double(int a) {
2109 return (double) a;
2110 }
2111
2112 // Comparisons float
2113
2114 static int runtime_cmp_eq_ff(float b, float a) {
2115 return a == b;
2116 }
2117
2118 static int runtime_cmp_ne_ff(float b, float a) {
2119 return a != b;
2120 }
2121
2122 static int runtime_cmp_lt_ff(float b, float a) {
2123 return a < b;
2124 }
2125
2126 static int runtime_cmp_le_ff(float b, float a) {
2127 return a <= b;
2128 }
2129
2130 static int runtime_cmp_ge_ff(float b, float a) {
2131 return a >= b;
2132 }
2133
2134 static int runtime_cmp_gt_ff(float b, float a) {
2135 return a > b;
2136 }
2137
2138 // Comparisons double
2139
2140 static int runtime_cmp_eq_dd(double b, double a) {
2141 return a == b;
2142 }
2143
2144 static int runtime_cmp_ne_dd(double b, double a) {
2145 return a != b;
2146 }
2147
2148 static int runtime_cmp_lt_dd(double b, double a) {
2149 return a < b;
2150 }
2151
2152 static int runtime_cmp_le_dd(double b, double a) {
2153 return a <= b;
2154 }
2155
2156 static int runtime_cmp_ge_dd(double b, double a) {
2157 return a >= b;
2158 }
2159
2160 static int runtime_cmp_gt_dd(double b, double a) {
2161 return a > b;
2162 }
2163
2164 // Math float
2165
2166 static float runtime_op_add_ff(float b, float a) {
2167 return a + b;
2168 }
2169
2170 static float runtime_op_sub_ff(float b, float a) {
2171 return a - b;
2172 }
2173
2174 static float runtime_op_mul_ff(float b, float a) {
2175 return a * b;
2176 }
2177
2178 static float runtime_op_div_ff(float b, float a) {
2179 return a / b;
2180 }
2181
2182 static float runtime_op_neg_f(float a) {
2183 return -a;
2184 }
2185
2186 // Math double
2187
2188 static double runtime_op_add_dd(double b, double a) {
2189 return a + b;
2190 }
2191
2192 static double runtime_op_sub_dd(double b, double a) {
2193 return a - b;
2194 }
2195
2196 static double runtime_op_mul_dd(double b, double a) {
2197 return a * b;
2198 }
2199
2200 static double runtime_op_div_dd(double b, double a) {
2201 return a / b;
2202 }
2203
2204 static double runtime_op_neg_d(double a) {
2205 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002206 }
-b master422972c2009-06-17 19:13:52 -07002207
Jack Palevich30321cb2009-08-20 15:34:23 -07002208#endif
2209
-b master422972c2009-06-17 19:13:52 -07002210 static const int STACK_ALIGNMENT = 8;
2211 int mStackUse;
2212 // This variable holds the amount we adjusted the stack in the most
2213 // recent endFunctionCallArguments call. It's examined by the
2214 // following adjustStackAfterCall call.
2215 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002216 };
2217
Jack Palevich09555c72009-05-27 12:25:55 -07002218#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002219
2220#ifdef PROVIDE_X86_CODEGEN
2221
Jack Palevich21a15a22009-05-11 14:49:29 -07002222 class X86CodeGenerator : public CodeGenerator {
2223 public:
2224 X86CodeGenerator() {}
2225 virtual ~X86CodeGenerator() {}
2226
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002227 /* returns address to patch with local variable size
2228 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002229 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002230 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2231 return oad(0xec81, 0); /* sub $xxx, %esp */
2232 }
2233
Jack Palevichb7718b92009-07-09 22:00:24 -07002234 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002235 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002236 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002237 }
2238
Jack Palevich21a15a22009-05-11 14:49:29 -07002239 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002240 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002241 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002242 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002243 }
2244
Jack Palevich1a539db2009-07-08 13:04:41 -07002245 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002246 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002247 switch (pType->tag) {
2248 case TY_FLOAT:
2249 oad(0x05D9, address); // flds
2250 break;
2251 case TY_DOUBLE:
2252 oad(0x05DD, address); // fldl
2253 break;
2254 default:
2255 assert(false);
2256 break;
2257 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002258 }
2259
Jack Palevich9221bcc2009-08-26 16:15:07 -07002260 virtual void addStructOffsetR0(int offset, Type* pType) {
2261 if (offset) {
2262 oad(0x05, offset); // addl offset, %eax
2263 }
2264 setR0Type(pType, ET_LVALUE);
2265 }
2266
Jack Palevich22305132009-05-13 10:58:45 -07002267 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002268 return psym(0xe9, t);
2269 }
2270
2271 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002272 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002273 Type* pR0Type = getR0Type();
2274 TypeTag tagR0 = pR0Type->tag;
2275 bool isFloatR0 = isFloatTag(tagR0);
2276 if (isFloatR0) {
2277 o(0xeed9); // fldz
2278 o(0xe9da); // fucompp
2279 o(0xe0df); // fnstsw %ax
2280 o(0x9e); // sahf
2281 } else {
2282 o(0xc085); // test %eax, %eax
2283 }
2284 // Use two output statements to generate one instruction.
2285 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002286 return psym(0x84 + l, t);
2287 }
2288
Jack Palevich58c30ee2009-07-17 16:35:23 -07002289 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002290 Type* pR0Type = getR0Type();
2291 Type* pTOSType = getTOSType();
2292 TypeTag tagR0 = pR0Type->tag;
2293 TypeTag tagTOS = pTOSType->tag;
2294 bool isFloatR0 = isFloatTag(tagR0);
2295 bool isFloatTOS = isFloatTag(tagTOS);
2296 if (!isFloatR0 && !isFloatTOS) {
2297 int t = decodeOp(op);
2298 o(0x59); /* pop %ecx */
2299 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002300 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002301 o(0x0f); /* setxx %al */
2302 o(t + 0x90);
2303 o(0xc0);
2304 popType();
2305 } else {
2306 setupFloatOperands();
2307 switch (op) {
2308 case OP_EQUALS:
2309 o(0xe9da); // fucompp
2310 o(0xe0df); // fnstsw %ax
2311 o(0x9e); // sahf
2312 o(0xc0940f); // sete %al
2313 o(0xc29b0f); // setnp %dl
2314 o(0xd021); // andl %edx, %eax
2315 break;
2316 case OP_NOT_EQUALS:
2317 o(0xe9da); // fucompp
2318 o(0xe0df); // fnstsw %ax
2319 o(0x9e); // sahf
2320 o(0xc0950f); // setne %al
2321 o(0xc29a0f); // setp %dl
2322 o(0xd009); // orl %edx, %eax
2323 break;
2324 case OP_GREATER_EQUAL:
2325 o(0xe9da); // fucompp
2326 o(0xe0df); // fnstsw %ax
2327 o(0x05c4f6); // testb $5, %ah
2328 o(0xc0940f); // sete %al
2329 break;
2330 case OP_LESS:
2331 o(0xc9d9); // fxch %st(1)
2332 o(0xe9da); // fucompp
2333 o(0xe0df); // fnstsw %ax
2334 o(0x9e); // sahf
2335 o(0xc0970f); // seta %al
2336 break;
2337 case OP_LESS_EQUAL:
2338 o(0xc9d9); // fxch %st(1)
2339 o(0xe9da); // fucompp
2340 o(0xe0df); // fnstsw %ax
2341 o(0x9e); // sahf
2342 o(0xc0930f); // setea %al
2343 break;
2344 case OP_GREATER:
2345 o(0xe9da); // fucompp
2346 o(0xe0df); // fnstsw %ax
2347 o(0x45c4f6); // testb $69, %ah
2348 o(0xc0940f); // sete %al
2349 break;
2350 default:
2351 error("Unknown comparison op");
2352 }
2353 o(0xc0b60f); // movzbl %al, %eax
2354 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002355 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002356 }
2357
Jack Palevich546b2242009-05-13 15:10:04 -07002358 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002359 Type* pR0Type = getR0Type();
2360 Type* pTOSType = getTOSType();
2361 TypeTag tagR0 = pR0Type->tag;
2362 TypeTag tagTOS = pTOSType->tag;
2363 bool isFloatR0 = isFloatTag(tagR0);
2364 bool isFloatTOS = isFloatTag(tagTOS);
2365 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002366 bool isPtrR0 = isPointerTag(tagR0);
2367 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002368 if (isPtrR0 || isPtrTOS) {
2369 if (isPtrR0 && isPtrTOS) {
2370 if (op != OP_MINUS) {
2371 error("Unsupported pointer-pointer operation %d.", op);
2372 }
2373 if (! typeEqual(pR0Type, pTOSType)) {
2374 error("Incompatible pointer types for subtraction.");
2375 }
2376 o(0x59); /* pop %ecx */
2377 o(decodeOp(op));
2378 popType();
2379 setR0Type(mkpInt);
2380 int size = sizeOf(pR0Type->pHead);
2381 if (size != 1) {
2382 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002383 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002384 // TODO: Optimize for power-of-two.
2385 genOp(OP_DIV);
2386 }
2387 } else {
2388 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2389 error("Unsupported pointer-scalar operation %d", op);
2390 }
Jack Palevichb6154502009-08-04 14:56:09 -07002391 Type* pPtrType = getPointerArithmeticResultType(
2392 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002393 o(0x59); /* pop %ecx */
2394 int size = sizeOf(pPtrType->pHead);
2395 if (size != 1) {
2396 // TODO: Optimize for power-of-two.
2397 if (isPtrR0) {
2398 oad(0xC969, size); // imull $size, %ecx
2399 } else {
2400 oad(0xC069, size); // mul $size, %eax
2401 }
2402 }
2403 o(decodeOp(op));
2404 popType();
2405 setR0Type(pPtrType);
2406 }
2407 } else {
2408 o(0x59); /* pop %ecx */
2409 o(decodeOp(op));
2410 if (op == OP_MOD)
2411 o(0x92); /* xchg %edx, %eax */
2412 popType();
2413 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002414 } else {
2415 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2416 setupFloatOperands();
2417 // Both float. x87 R0 == left hand, x87 R1 == right hand
2418 switch (op) {
2419 case OP_MUL:
2420 o(0xc9de); // fmulp
2421 break;
2422 case OP_DIV:
2423 o(0xf1de); // fdivp
2424 break;
2425 case OP_PLUS:
2426 o(0xc1de); // faddp
2427 break;
2428 case OP_MINUS:
2429 o(0xe1de); // fsubp
2430 break;
2431 default:
2432 error("Unsupported binary floating operation.");
2433 break;
2434 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002435 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002436 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002437 }
2438
Jack Palevich58c30ee2009-07-17 16:35:23 -07002439 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002440 if (op != OP_LOGICAL_NOT) {
2441 error("Unknown unary cmp %d", op);
2442 } else {
2443 Type* pR0Type = getR0Type();
2444 TypeTag tag = collapseType(pR0Type->tag);
2445 switch(tag) {
2446 case TY_INT: {
2447 oad(0xb9, 0); /* movl $0, %ecx */
2448 int t = decodeOp(op);
2449 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002450 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002451 o(0x0f); /* setxx %al */
2452 o(t + 0x90);
2453 o(0xc0);
2454 }
2455 break;
2456 case TY_FLOAT:
2457 case TY_DOUBLE:
2458 o(0xeed9); // fldz
2459 o(0xe9da); // fucompp
2460 o(0xe0df); // fnstsw %ax
2461 o(0x9e); // sahf
2462 o(0xc0950f); // setne %al
2463 o(0xc29a0f); // setp %dl
2464 o(0xd009); // orl %edx, %eax
2465 o(0xc0b60f); // movzbl %al, %eax
2466 o(0x01f083); // xorl $1, %eax
2467 break;
2468 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002469 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002470 break;
2471 }
2472 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002473 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002474 }
2475
2476 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002477 Type* pR0Type = getR0Type();
2478 TypeTag tag = collapseType(pR0Type->tag);
2479 switch(tag) {
2480 case TY_INT:
2481 oad(0xb9, 0); /* movl $0, %ecx */
2482 o(decodeOp(op));
2483 break;
2484 case TY_FLOAT:
2485 case TY_DOUBLE:
2486 switch (op) {
2487 case OP_MINUS:
2488 o(0xe0d9); // fchs
2489 break;
2490 case OP_BIT_NOT:
2491 error("Can't apply '~' operator to a float or double.");
2492 break;
2493 default:
2494 error("Unknown unary op %d\n", op);
2495 break;
2496 }
2497 break;
2498 default:
2499 error("genUnaryOp unsupported type");
2500 break;
2501 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002502 }
2503
Jack Palevich1cdef202009-05-22 12:06:27 -07002504 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002505 Type* pR0Type = getR0Type();
2506 TypeTag r0ct = collapseType(pR0Type->tag);
2507 switch(r0ct) {
2508 case TY_INT:
2509 o(0x50); /* push %eax */
2510 break;
2511 case TY_FLOAT:
2512 o(0x50); /* push %eax */
2513 o(0x241cd9); // fstps 0(%esp)
2514 break;
2515 case TY_DOUBLE:
2516 o(0x50); /* push %eax */
2517 o(0x50); /* push %eax */
2518 o(0x241cdd); // fstpl 0(%esp)
2519 break;
2520 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002521 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002522 break;
2523 }
Jack Palevich8df46192009-07-07 14:48:51 -07002524 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002525 }
2526
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002527 virtual void over() {
2528 // We know it's only used for int-ptr ops (++/--)
2529
2530 Type* pR0Type = getR0Type();
2531 TypeTag r0ct = collapseType(pR0Type->tag);
2532
2533 Type* pTOSType = getTOSType();
2534 TypeTag tosct = collapseType(pTOSType->tag);
2535
2536 assert (r0ct == TY_INT && tosct == TY_INT);
2537
2538 o(0x59); /* pop %ecx */
2539 o(0x50); /* push %eax */
2540 o(0x51); /* push %ecx */
2541
2542 overType();
2543 }
2544
Jack Palevich58c30ee2009-07-17 16:35:23 -07002545 virtual void popR0() {
2546 Type* pR0Type = getR0Type();
2547 TypeTag r0ct = collapseType(pR0Type->tag);
2548 switch(r0ct) {
2549 case TY_INT:
2550 o(0x58); /* popl %eax */
2551 break;
2552 case TY_FLOAT:
2553 o(0x2404d9); // flds (%esp)
2554 o(0x58); /* popl %eax */
2555 break;
2556 case TY_DOUBLE:
2557 o(0x2404dd); // fldl (%esp)
2558 o(0x58); /* popl %eax */
2559 o(0x58); /* popl %eax */
2560 break;
2561 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002562 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002563 break;
2564 }
2565 popType();
2566 }
2567
2568 virtual void storeR0ToTOS() {
2569 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002570 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002571 Type* pTargetType = pPointerType->pHead;
2572 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002573 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002574 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002575 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002576 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002577 case TY_INT:
2578 o(0x0189); /* movl %eax/%al, (%ecx) */
2579 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002580 case TY_SHORT:
2581 o(0x018966); /* movw %ax, (%ecx) */
2582 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002583 case TY_CHAR:
2584 o(0x0188); /* movl %eax/%al, (%ecx) */
2585 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002586 case TY_FLOAT:
2587 o(0x19d9); /* fstps (%ecx) */
2588 break;
2589 case TY_DOUBLE:
2590 o(0x19dd); /* fstpl (%ecx) */
2591 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002592 case TY_STRUCT:
2593 {
2594 // TODO: use alignment information to use movsw/movsl instead of movsb
2595 int size = sizeOf(pTargetType);
2596 if (size > 0) {
2597 o(0x9c); // pushf
2598 o(0x57); // pushl %edi
2599 o(0x56); // pushl %esi
2600 o(0xcf89); // movl %ecx, %edi
2601 o(0xc689); // movl %eax, %esi
2602 oad(0xb9, size); // mov #size, %ecx
2603 o(0xfc); // cld
2604 o(0xf3); // rep
2605 o(0xa4); // movsb
2606 o(0x5e); // popl %esi
2607 o(0x5f); // popl %edi
2608 o(0x9d); // popf
2609 }
2610 }
2611 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002612 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002613 error("storeR0ToTOS: unsupported type %d",
2614 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002615 break;
2616 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002617 }
2618
Jack Palevich58c30ee2009-07-17 16:35:23 -07002619 virtual void loadR0FromR0() {
2620 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002621 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002622 Type* pNewType = pPointerType->pHead;
2623 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002624 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002625 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002626 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002627 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002628 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002629 case TY_SHORT:
2630 o(0xbf0f); /* movswl (%eax), %eax */
2631 ob(0);
2632 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002633 case TY_CHAR:
2634 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002635 ob(0); /* add zero in code */
2636 break;
2637 case TY_FLOAT:
2638 o2(0x00d9); // flds (%eax)
2639 break;
2640 case TY_DOUBLE:
2641 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002642 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002643 case TY_ARRAY:
2644 pNewType = pNewType->pTail;
2645 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002646 case TY_STRUCT:
2647 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002648 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002649 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002650 break;
2651 }
Jack Palevich80e49722009-08-04 15:39:49 -07002652 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002653 }
2654
Jack Palevichb5e33312009-07-30 19:06:34 -07002655 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002656 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002657 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002658 }
2659
Jack Palevich9f51a262009-07-29 16:22:26 -07002660 virtual int leaForward(int ea, Type* pPointerType) {
2661 oad(0xb8, ea); /* mov $xx, %eax */
2662 setR0Type(pPointerType);
2663 return getPC() - 4;
2664 }
2665
Jack Palevichb6154502009-08-04 14:56:09 -07002666 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002667 Type* pR0Type = getR0Type();
2668 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002669 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002670 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002671 return;
2672 }
Jack Palevichb6154502009-08-04 14:56:09 -07002673 if (isPointerType(pType) && isPointerType(pR0Type)) {
2674 Type* pA = pR0Type;
2675 Type* pB = pType;
2676 // Array decays to pointer
2677 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2678 pA = pA->pTail;
2679 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002680 if (! (typeEqual(pA, pB)
2681 || pB->pHead->tag == TY_VOID
2682 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2683 )) {
2684 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002685 }
Jack Palevichb6154502009-08-04 14:56:09 -07002686 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002687 // do nothing special
2688 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2689 // do nothing special, both held in same register on x87.
2690 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002691 TypeTag r0Tag = collapseType(pR0Type->tag);
2692 TypeTag destTag = collapseType(pType->tag);
2693 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2694 // Convert R0 from int to float
2695 o(0x50); // push %eax
2696 o(0x2404DB); // fildl 0(%esp)
2697 o(0x58); // pop %eax
2698 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2699 // Convert R0 from float to int. Complicated because
2700 // need to save and restore the rounding mode.
2701 o(0x50); // push %eax
2702 o(0x50); // push %eax
2703 o(0x02247cD9); // fnstcw 2(%esp)
2704 o(0x2444b70f); // movzwl 2(%esp), %eax
2705 o(0x02);
2706 o(0x0cb4); // movb $12, %ah
2707 o(0x24048966); // movw %ax, 0(%esp)
2708 o(0x242cd9); // fldcw 0(%esp)
2709 o(0x04245cdb); // fistpl 4(%esp)
2710 o(0x02246cd9); // fldcw 2(%esp)
2711 o(0x58); // pop %eax
2712 o(0x58); // pop %eax
2713 } else {
2714 error("Incompatible types old: %d new: %d",
2715 pR0Type->tag, pType->tag);
2716 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002717 }
2718 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002719 }
2720
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002721 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002722 return oad(0xec81, 0); /* sub $xxx, %esp */
2723 }
2724
Jack Palevich8148c5b2009-07-16 18:24:47 -07002725 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2726 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002727 Type* pR0Type = getR0Type();
2728 TypeTag r0ct = collapseType(pR0Type->tag);
2729 switch(r0ct) {
2730 case TY_INT:
2731 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2732 return 4;
2733 case TY_FLOAT:
2734 oad(0x249CD9, l); /* fstps xxx(%esp) */
2735 return 4;
2736 case TY_DOUBLE:
2737 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2738 return 8;
2739 default:
2740 assert(false);
2741 return 0;
2742 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002743 }
2744
Jack Palevichb7718b92009-07-09 22:00:24 -07002745 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002746 * (int*) a = l;
2747 }
2748
Jack Palevich8df46192009-07-07 14:48:51 -07002749 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002750 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002751 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002752 return psym(0xe8, symbol); /* call xxx */
2753 }
2754
Jack Palevich8df46192009-07-07 14:48:51 -07002755 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002756 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002757 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002758 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002759 oad(0x2494ff, l); /* call *xxx(%esp) */
2760 }
2761
Jack Palevichb7718b92009-07-09 22:00:24 -07002762 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002763 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002764 if (isIndirect) {
2765 l += 4;
2766 }
-b master422972c2009-06-17 19:13:52 -07002767 if (l > 0) {
2768 oad(0xc481, l); /* add $xxx, %esp */
2769 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002770 }
2771
Jack Palevicha6535612009-05-13 16:24:17 -07002772 virtual int jumpOffset() {
2773 return 5;
2774 }
2775
2776 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002777 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002778 }
2779
Jack Paleviche7b59062009-05-19 17:12:17 -07002780 /* output a symbol and patch all calls to it */
2781 virtual void gsym(int t) {
2782 int n;
2783 int pc = getPC();
2784 while (t) {
2785 n = *(int *) t; /* next value */
2786 *(int *) t = pc - t - 4;
2787 t = n;
2788 }
2789 }
2790
Jack Palevich9f51a262009-07-29 16:22:26 -07002791 /* output a symbol and patch all calls to it, using absolute address */
2792 virtual void resolveForward(int t) {
2793 int n;
2794 int pc = getPC();
2795 while (t) {
2796 n = *(int *) t; /* next value */
2797 *(int *) t = pc;
2798 t = n;
2799 }
2800 }
2801
Jack Palevich1cdef202009-05-22 12:06:27 -07002802 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002803 size_t pagesize = 4096;
2804 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2805 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2806 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2807 if (err) {
2808 error("mprotect() failed: %d", errno);
2809 }
2810 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002811 }
2812
Jack Palevich9eed7a22009-07-06 17:24:34 -07002813 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002814 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002815 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002816 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002817 switch (pType->tag) {
2818 case TY_CHAR:
2819 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002820 case TY_SHORT:
2821 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002822 case TY_ARRAY:
2823 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002824 case TY_STRUCT:
2825 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07002826 case TY_FUNC:
2827 error("alignment of func not supported");
2828 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002829 default:
2830 return 4;
2831 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002832 }
2833
2834 /**
2835 * Array element alignment (in bytes) for this type of data.
2836 */
2837 virtual size_t sizeOf(Type* pType){
2838 switch(pType->tag) {
2839 case TY_INT:
2840 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002841 case TY_SHORT:
2842 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002843 case TY_CHAR:
2844 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002845 case TY_FLOAT:
2846 return 4;
2847 case TY_DOUBLE:
2848 return 8;
2849 case TY_POINTER:
2850 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002851 case TY_ARRAY:
2852 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002853 case TY_STRUCT:
2854 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002855 default:
2856 error("Unsupported type %d", pType->tag);
2857 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002858 }
2859 }
2860
Jack Palevich21a15a22009-05-11 14:49:29 -07002861 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002862
2863 /** Output 1 to 4 bytes.
2864 *
2865 */
2866 void o(int n) {
2867 /* cannot use unsigned, so we must do a hack */
2868 while (n && n != -1) {
2869 ob(n & 0xff);
2870 n = n >> 8;
2871 }
2872 }
2873
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002874 /* Output exactly 2 bytes
2875 */
2876 void o2(int n) {
2877 ob(n & 0xff);
2878 ob(0xff & (n >> 8));
2879 }
2880
Jack Paleviche7b59062009-05-19 17:12:17 -07002881 /* psym is used to put an instruction with a data field which is a
2882 reference to a symbol. It is in fact the same as oad ! */
2883 int psym(int n, int t) {
2884 return oad(n, t);
2885 }
2886
2887 /* instruction + address */
2888 int oad(int n, int t) {
2889 o(n);
2890 int result = getPC();
2891 o4(t);
2892 return result;
2893 }
2894
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002895 static const int operatorHelper[];
2896
2897 int decodeOp(int op) {
2898 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002899 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002900 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002901 }
2902 return operatorHelper[op];
2903 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002904
Jack Palevich546b2242009-05-13 15:10:04 -07002905 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002906 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002907 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002908 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002909
2910 void setupFloatOperands() {
2911 Type* pR0Type = getR0Type();
2912 Type* pTOSType = getTOSType();
2913 TypeTag tagR0 = pR0Type->tag;
2914 TypeTag tagTOS = pTOSType->tag;
2915 bool isFloatR0 = isFloatTag(tagR0);
2916 bool isFloatTOS = isFloatTag(tagTOS);
2917 if (! isFloatR0) {
2918 // Convert R0 from int to float
2919 o(0x50); // push %eax
2920 o(0x2404DB); // fildl 0(%esp)
2921 o(0x58); // pop %eax
2922 }
2923 if (! isFloatTOS){
2924 o(0x2404DB); // fildl 0(%esp);
2925 o(0x58); // pop %eax
2926 } else {
2927 if (tagTOS == TY_FLOAT) {
2928 o(0x2404d9); // flds (%esp)
2929 o(0x58); // pop %eax
2930 } else {
2931 o(0x2404dd); // fldl (%esp)
2932 o(0x58); // pop %eax
2933 o(0x58); // pop %eax
2934 }
2935 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002936 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002937 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002938 };
2939
Jack Paleviche7b59062009-05-19 17:12:17 -07002940#endif // PROVIDE_X86_CODEGEN
2941
Jack Palevichb67b18f2009-06-11 21:12:23 -07002942#ifdef PROVIDE_TRACE_CODEGEN
2943 class TraceCodeGenerator : public CodeGenerator {
2944 private:
2945 CodeGenerator* mpBase;
2946
2947 public:
2948 TraceCodeGenerator(CodeGenerator* pBase) {
2949 mpBase = pBase;
2950 }
2951
2952 virtual ~TraceCodeGenerator() {
2953 delete mpBase;
2954 }
2955
2956 virtual void init(CodeBuf* pCodeBuf) {
2957 mpBase->init(pCodeBuf);
2958 }
2959
2960 void setErrorSink(ErrorSink* pErrorSink) {
2961 mpBase->setErrorSink(pErrorSink);
2962 }
2963
2964 /* returns address to patch with local variable size
2965 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002966 virtual int functionEntry(Type* pDecl) {
2967 int result = mpBase->functionEntry(pDecl);
2968 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002969 return result;
2970 }
2971
Jack Palevichb7718b92009-07-09 22:00:24 -07002972 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2973 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2974 localVariableAddress, localVariableSize);
2975 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002976 }
2977
2978 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002979 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002980 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002981 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002982 }
2983
Jack Palevich1a539db2009-07-08 13:04:41 -07002984 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002985 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002986 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002987 }
2988
Jack Palevich9221bcc2009-08-26 16:15:07 -07002989 virtual void addStructOffsetR0(int offset, Type* pType) {
2990 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
2991 mpBase->addStructOffsetR0(offset, pType);
2992 }
2993
Jack Palevichb67b18f2009-06-11 21:12:23 -07002994 virtual int gjmp(int t) {
2995 int result = mpBase->gjmp(t);
2996 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2997 return result;
2998 }
2999
3000 /* l = 0: je, l == 1: jne */
3001 virtual int gtst(bool l, int t) {
3002 int result = mpBase->gtst(l, t);
3003 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3004 return result;
3005 }
3006
Jack Palevich58c30ee2009-07-17 16:35:23 -07003007 virtual void gcmp(int op) {
3008 fprintf(stderr, "gcmp(%d)\n", op);
3009 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003010 }
3011
3012 virtual void genOp(int op) {
3013 fprintf(stderr, "genOp(%d)\n", op);
3014 mpBase->genOp(op);
3015 }
3016
Jack Palevich9eed7a22009-07-06 17:24:34 -07003017
Jack Palevich58c30ee2009-07-17 16:35:23 -07003018 virtual void gUnaryCmp(int op) {
3019 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3020 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003021 }
3022
3023 virtual void genUnaryOp(int op) {
3024 fprintf(stderr, "genUnaryOp(%d)\n", op);
3025 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003026 }
3027
3028 virtual void pushR0() {
3029 fprintf(stderr, "pushR0()\n");
3030 mpBase->pushR0();
3031 }
3032
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003033 virtual void over() {
3034 fprintf(stderr, "over()\n");
3035 mpBase->over();
3036 }
3037
Jack Palevich58c30ee2009-07-17 16:35:23 -07003038 virtual void popR0() {
3039 fprintf(stderr, "popR0()\n");
3040 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003041 }
3042
Jack Palevich58c30ee2009-07-17 16:35:23 -07003043 virtual void storeR0ToTOS() {
3044 fprintf(stderr, "storeR0ToTOS()\n");
3045 mpBase->storeR0ToTOS();
3046 }
3047
3048 virtual void loadR0FromR0() {
3049 fprintf(stderr, "loadR0FromR0()\n");
3050 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003051 }
3052
Jack Palevichb5e33312009-07-30 19:06:34 -07003053 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3054 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3055 pPointerType->pHead->tag, et);
3056 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003057 }
3058
Jack Palevich9f51a262009-07-29 16:22:26 -07003059 virtual int leaForward(int ea, Type* pPointerType) {
3060 fprintf(stderr, "leaForward(%d)\n", ea);
3061 return mpBase->leaForward(ea, pPointerType);
3062 }
3063
Jack Palevich30321cb2009-08-20 15:34:23 -07003064 virtual void convertR0Imp(Type* pType, bool isCast){
3065 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3066 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003067 }
3068
3069 virtual int beginFunctionCallArguments() {
3070 int result = mpBase->beginFunctionCallArguments();
3071 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3072 return result;
3073 }
3074
Jack Palevich8148c5b2009-07-16 18:24:47 -07003075 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3076 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3077 pArgType->tag);
3078 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003079 }
3080
Jack Palevichb7718b92009-07-09 22:00:24 -07003081 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003082 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003083 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003084 }
3085
Jack Palevich8df46192009-07-07 14:48:51 -07003086 virtual int callForward(int symbol, Type* pFunc) {
3087 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003088 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3089 return result;
3090 }
3091
Jack Palevich8df46192009-07-07 14:48:51 -07003092 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003093 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3094 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003095 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003096 }
3097
Jack Palevichb7718b92009-07-09 22:00:24 -07003098 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3099 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3100 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003101 }
3102
3103 virtual int jumpOffset() {
3104 return mpBase->jumpOffset();
3105 }
3106
3107 virtual int disassemble(FILE* out) {
3108 return mpBase->disassemble(out);
3109 }
3110
3111 /* output a symbol and patch all calls to it */
3112 virtual void gsym(int t) {
3113 fprintf(stderr, "gsym(%d)\n", t);
3114 mpBase->gsym(t);
3115 }
3116
Jack Palevich9f51a262009-07-29 16:22:26 -07003117 virtual void resolveForward(int t) {
3118 mpBase->resolveForward(t);
3119 }
3120
Jack Palevichb67b18f2009-06-11 21:12:23 -07003121 virtual int finishCompile() {
3122 int result = mpBase->finishCompile();
3123 fprintf(stderr, "finishCompile() = %d\n", result);
3124 return result;
3125 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003126
3127 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003128 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003129 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003130 virtual size_t alignmentOf(Type* pType){
3131 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003132 }
3133
3134 /**
3135 * Array element alignment (in bytes) for this type of data.
3136 */
3137 virtual size_t sizeOf(Type* pType){
3138 return mpBase->sizeOf(pType);
3139 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003140
3141 virtual Type* getR0Type() {
3142 return mpBase->getR0Type();
3143 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003144
3145 virtual ExpressionType getR0ExpressionType() {
3146 return mpBase->getR0ExpressionType();
3147 }
3148
3149 virtual void setR0ExpressionType(ExpressionType et) {
3150 mpBase->setR0ExpressionType(et);
3151 }
3152
3153 virtual size_t getExpressionStackDepth() {
3154 return mpBase->getExpressionStackDepth();
3155 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003156
3157 virtual void forceR0RVal() {
3158 return mpBase->forceR0RVal();
3159 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003160 };
3161
3162#endif // PROVIDE_TRACE_CODEGEN
3163
Jack Palevich569f1352009-06-29 14:29:08 -07003164 class Arena {
3165 public:
3166 // Used to record a given allocation amount.
3167 // Used:
3168 // Mark mark = arena.mark();
3169 // ... lots of arena.allocate()
3170 // arena.free(mark);
3171
3172 struct Mark {
3173 size_t chunk;
3174 size_t offset;
3175 };
3176
3177 Arena() {
3178 mCurrentChunk = 0;
3179 Chunk start(CHUNK_SIZE);
3180 mData.push_back(start);
3181 }
3182
3183 ~Arena() {
3184 for(size_t i = 0; i < mData.size(); i++) {
3185 mData[i].free();
3186 }
3187 }
3188
3189 // Alloc using the standard alignment size safe for any variable
3190 void* alloc(size_t size) {
3191 return alloc(size, 8);
3192 }
3193
3194 Mark mark(){
3195 Mark result;
3196 result.chunk = mCurrentChunk;
3197 result.offset = mData[mCurrentChunk].mOffset;
3198 return result;
3199 }
3200
3201 void freeToMark(const Mark& mark) {
3202 mCurrentChunk = mark.chunk;
3203 mData[mCurrentChunk].mOffset = mark.offset;
3204 }
3205
3206 private:
3207 // Allocate memory aligned to a given size
3208 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3209 // Memory is not zero filled.
3210
3211 void* alloc(size_t size, size_t alignment) {
3212 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3213 if (mCurrentChunk + 1 < mData.size()) {
3214 mCurrentChunk++;
3215 } else {
3216 size_t allocSize = CHUNK_SIZE;
3217 if (allocSize < size + alignment - 1) {
3218 allocSize = size + alignment - 1;
3219 }
3220 Chunk chunk(allocSize);
3221 mData.push_back(chunk);
3222 mCurrentChunk++;
3223 }
3224 }
3225 return mData[mCurrentChunk].allocate(size, alignment);
3226 }
3227
3228 static const size_t CHUNK_SIZE = 128*1024;
3229 // Note: this class does not deallocate its
3230 // memory when it's destroyed. It depends upon
3231 // its parent to deallocate the memory.
3232 struct Chunk {
3233 Chunk() {
3234 mpData = 0;
3235 mSize = 0;
3236 mOffset = 0;
3237 }
3238
3239 Chunk(size_t size) {
3240 mSize = size;
3241 mpData = (char*) malloc(size);
3242 mOffset = 0;
3243 }
3244
3245 ~Chunk() {
3246 // Doesn't deallocate memory.
3247 }
3248
3249 void* allocate(size_t size, size_t alignment) {
3250 size_t alignedOffset = aligned(mOffset, alignment);
3251 void* result = mpData + alignedOffset;
3252 mOffset = alignedOffset + size;
3253 return result;
3254 }
3255
3256 void free() {
3257 if (mpData) {
3258 ::free(mpData);
3259 mpData = 0;
3260 }
3261 }
3262
3263 size_t remainingCapacity(size_t alignment) {
3264 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3265 }
3266
3267 // Assume alignment is a power of two
3268 inline size_t aligned(size_t v, size_t alignment) {
3269 size_t mask = alignment-1;
3270 return (v + mask) & ~mask;
3271 }
3272
3273 char* mpData;
3274 size_t mSize;
3275 size_t mOffset;
3276 };
3277
3278 size_t mCurrentChunk;
3279
3280 Vector<Chunk> mData;
3281 };
3282
Jack Palevich569f1352009-06-29 14:29:08 -07003283 struct VariableInfo;
3284
3285 struct Token {
3286 int hash;
3287 size_t length;
3288 char* pText;
3289 tokenid_t id;
3290
3291 // Current values for the token
3292 char* mpMacroDefinition;
3293 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003294 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003295 };
3296
3297 class TokenTable {
3298 public:
3299 // Don't use 0..0xff, allows characters and operators to be tokens too.
3300
3301 static const int TOKEN_BASE = 0x100;
3302 TokenTable() {
3303 mpMap = hashmapCreate(128, hashFn, equalsFn);
3304 }
3305
3306 ~TokenTable() {
3307 hashmapFree(mpMap);
3308 }
3309
3310 void setArena(Arena* pArena) {
3311 mpArena = pArena;
3312 }
3313
3314 // Returns a token for a given string of characters.
3315 tokenid_t intern(const char* pText, size_t length) {
3316 Token probe;
3317 int hash = hashmapHash((void*) pText, length);
3318 {
3319 Token probe;
3320 probe.hash = hash;
3321 probe.length = length;
3322 probe.pText = (char*) pText;
3323 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3324 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003325 return pValue->id;
3326 }
3327 }
3328
3329 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3330 memset(pToken, 0, sizeof(*pToken));
3331 pToken->hash = hash;
3332 pToken->length = length;
3333 pToken->pText = (char*) mpArena->alloc(length + 1);
3334 memcpy(pToken->pText, pText, length);
3335 pToken->pText[length] = 0;
3336 pToken->id = mTokens.size() + TOKEN_BASE;
3337 mTokens.push_back(pToken);
3338 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003339 return pToken->id;
3340 }
3341
3342 // Return the Token for a given tokenid.
3343 Token& operator[](tokenid_t id) {
3344 return *mTokens[id - TOKEN_BASE];
3345 }
3346
3347 inline size_t size() {
3348 return mTokens.size();
3349 }
3350
3351 private:
3352
3353 static int hashFn(void* pKey) {
3354 Token* pToken = (Token*) pKey;
3355 return pToken->hash;
3356 }
3357
3358 static bool equalsFn(void* keyA, void* keyB) {
3359 Token* pTokenA = (Token*) keyA;
3360 Token* pTokenB = (Token*) keyB;
3361 // Don't need to compare hash values, they should always be equal
3362 return pTokenA->length == pTokenB->length
3363 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3364 }
3365
3366 Hashmap* mpMap;
3367 Vector<Token*> mTokens;
3368 Arena* mpArena;
3369 };
3370
Jack Palevich1cdef202009-05-22 12:06:27 -07003371 class InputStream {
3372 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003373 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003374 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003375 };
3376
3377 class TextInputStream : public InputStream {
3378 public:
3379 TextInputStream(const char* text, size_t textLength)
3380 : pText(text), mTextLength(textLength), mPosition(0) {
3381 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003382
Jack Palevichdc456462009-07-16 16:50:56 -07003383 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003384 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3385 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003386
Jack Palevichdc456462009-07-16 16:50:56 -07003387 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003388 const char* pText;
3389 size_t mTextLength;
3390 size_t mPosition;
3391 };
3392
Jack Palevicheedf9d22009-06-04 16:23:40 -07003393 class String {
3394 public:
3395 String() {
3396 mpBase = 0;
3397 mUsed = 0;
3398 mSize = 0;
3399 }
3400
Jack Palevich303d8ff2009-06-11 19:06:24 -07003401 String(const char* item, int len, bool adopt) {
3402 if (len < 0) {
3403 len = strlen(item);
3404 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003405 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003406 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003407 mUsed = len;
3408 mSize = len + 1;
3409 } else {
3410 mpBase = 0;
3411 mUsed = 0;
3412 mSize = 0;
3413 appendBytes(item, len);
3414 }
3415 }
3416
Jack Palevich303d8ff2009-06-11 19:06:24 -07003417 String(const String& other) {
3418 mpBase = 0;
3419 mUsed = 0;
3420 mSize = 0;
3421 appendBytes(other.getUnwrapped(), other.len());
3422 }
3423
Jack Palevicheedf9d22009-06-04 16:23:40 -07003424 ~String() {
3425 if (mpBase) {
3426 free(mpBase);
3427 }
3428 }
3429
Jack Palevicha6baa232009-06-12 11:25:59 -07003430 String& operator=(const String& other) {
3431 clear();
3432 appendBytes(other.getUnwrapped(), other.len());
3433 return *this;
3434 }
3435
Jack Palevich303d8ff2009-06-11 19:06:24 -07003436 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003437 return mpBase;
3438 }
3439
Jack Palevich303d8ff2009-06-11 19:06:24 -07003440 void clear() {
3441 mUsed = 0;
3442 if (mSize > 0) {
3443 mpBase[0] = 0;
3444 }
3445 }
3446
Jack Palevicheedf9d22009-06-04 16:23:40 -07003447 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003448 appendBytes(s, strlen(s));
3449 }
3450
3451 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003452 memcpy(ensure(n), s, n + 1);
3453 }
3454
3455 void append(char c) {
3456 * ensure(1) = c;
3457 }
3458
Jack Palevich86351982009-06-30 18:09:56 -07003459 void append(String& other) {
3460 appendBytes(other.getUnwrapped(), other.len());
3461 }
3462
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003463 char* orphan() {
3464 char* result = mpBase;
3465 mpBase = 0;
3466 mUsed = 0;
3467 mSize = 0;
3468 return result;
3469 }
3470
Jack Palevicheedf9d22009-06-04 16:23:40 -07003471 void printf(const char* fmt,...) {
3472 va_list ap;
3473 va_start(ap, fmt);
3474 vprintf(fmt, ap);
3475 va_end(ap);
3476 }
3477
3478 void vprintf(const char* fmt, va_list ap) {
3479 char* temp;
3480 int numChars = vasprintf(&temp, fmt, ap);
3481 memcpy(ensure(numChars), temp, numChars+1);
3482 free(temp);
3483 }
3484
Jack Palevich303d8ff2009-06-11 19:06:24 -07003485 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003486 return mUsed;
3487 }
3488
3489 private:
3490 char* ensure(int n) {
3491 size_t newUsed = mUsed + n;
3492 if (newUsed > mSize) {
3493 size_t newSize = mSize * 2 + 10;
3494 if (newSize < newUsed) {
3495 newSize = newUsed;
3496 }
3497 mpBase = (char*) realloc(mpBase, newSize + 1);
3498 mSize = newSize;
3499 }
3500 mpBase[newUsed] = '\0';
3501 char* result = mpBase + mUsed;
3502 mUsed = newUsed;
3503 return result;
3504 }
3505
3506 char* mpBase;
3507 size_t mUsed;
3508 size_t mSize;
3509 };
3510
Jack Palevich569f1352009-06-29 14:29:08 -07003511 void internKeywords() {
3512 // Note: order has to match TOK_ constants
3513 static const char* keywords[] = {
3514 "int",
3515 "char",
3516 "void",
3517 "if",
3518 "else",
3519 "while",
3520 "break",
3521 "return",
3522 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003523 "auto",
3524 "case",
3525 "const",
3526 "continue",
3527 "default",
3528 "do",
3529 "double",
3530 "enum",
3531 "extern",
3532 "float",
3533 "goto",
3534 "long",
3535 "register",
3536 "short",
3537 "signed",
3538 "sizeof",
3539 "static",
3540 "struct",
3541 "switch",
3542 "typedef",
3543 "union",
3544 "unsigned",
3545 "volatile",
3546 "_Bool",
3547 "_Complex",
3548 "_Imaginary",
3549 "inline",
3550 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003551
3552 // predefined tokens that can also be symbols start here:
3553 "pragma",
3554 "define",
3555 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003556 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003557
Jack Palevich569f1352009-06-29 14:29:08 -07003558 for(int i = 0; keywords[i]; i++) {
3559 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003560 }
Jack Palevich569f1352009-06-29 14:29:08 -07003561 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003562
Jack Palevich36d94142009-06-08 15:55:32 -07003563 struct InputState {
3564 InputStream* pStream;
3565 int oldCh;
3566 };
3567
Jack Palevich2db168f2009-06-11 14:29:47 -07003568 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003569 void* pAddress;
3570 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003571 tokenid_t tok;
3572 size_t level;
3573 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003574 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003575 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003576 };
3577
Jack Palevich303d8ff2009-06-11 19:06:24 -07003578 class SymbolStack {
3579 public:
3580 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003581 mpArena = 0;
3582 mpTokenTable = 0;
3583 }
3584
3585 void setArena(Arena* pArena) {
3586 mpArena = pArena;
3587 }
3588
3589 void setTokenTable(TokenTable* pTokenTable) {
3590 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003591 }
3592
3593 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003594 Mark mark;
3595 mark.mArenaMark = mpArena->mark();
3596 mark.mSymbolHead = mStack.size();
3597 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003598 }
3599
3600 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003601 // Undo any shadowing that was done:
3602 Mark mark = mLevelStack.back();
3603 mLevelStack.pop_back();
3604 while (mStack.size() > mark.mSymbolHead) {
3605 VariableInfo* pV = mStack.back();
3606 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003607 if (pV->isStructTag) {
3608 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3609 } else {
3610 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3611 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003612 }
Jack Palevich569f1352009-06-29 14:29:08 -07003613 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003614 }
3615
Jack Palevich569f1352009-06-29 14:29:08 -07003616 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3617 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3618 return pV && pV->level == level();
3619 }
3620
Jack Palevich9221bcc2009-08-26 16:15:07 -07003621 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3622 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3623 return pV && pV->level == level();
3624 }
3625
Jack Palevich569f1352009-06-29 14:29:08 -07003626 VariableInfo* add(tokenid_t tok) {
3627 Token& token = (*mpTokenTable)[tok];
3628 VariableInfo* pOldV = token.mpVariableInfo;
3629 VariableInfo* pNewV =
3630 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3631 memset(pNewV, 0, sizeof(VariableInfo));
3632 pNewV->tok = tok;
3633 pNewV->level = level();
3634 pNewV->pOldDefinition = pOldV;
3635 token.mpVariableInfo = pNewV;
3636 mStack.push_back(pNewV);
3637 return pNewV;
3638 }
3639
Jack Palevich9221bcc2009-08-26 16:15:07 -07003640 VariableInfo* addStructTag(tokenid_t tok) {
3641 Token& token = (*mpTokenTable)[tok];
3642 VariableInfo* pOldS = token.mpStructInfo;
3643 VariableInfo* pNewS =
3644 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3645 memset(pNewS, 0, sizeof(VariableInfo));
3646 pNewS->tok = tok;
3647 pNewS->level = level();
3648 pNewS->isStructTag = true;
3649 pNewS->pOldDefinition = pOldS;
3650 token.mpStructInfo = pNewS;
3651 mStack.push_back(pNewS);
3652 return pNewS;
3653 }
3654
Jack Palevich86351982009-06-30 18:09:56 -07003655 VariableInfo* add(Type* pType) {
3656 VariableInfo* pVI = add(pType->id);
3657 pVI->pType = pType;
3658 return pVI;
3659 }
3660
Jack Palevich569f1352009-06-29 14:29:08 -07003661 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3662 for (size_t i = 0; i < mStack.size(); i++) {
3663 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003664 break;
3665 }
3666 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003667 }
3668
Jack Palevich303d8ff2009-06-11 19:06:24 -07003669 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003670 inline size_t level() {
3671 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003672 }
3673
Jack Palevich569f1352009-06-29 14:29:08 -07003674 struct Mark {
3675 Arena::Mark mArenaMark;
3676 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003677 };
3678
Jack Palevich569f1352009-06-29 14:29:08 -07003679 Arena* mpArena;
3680 TokenTable* mpTokenTable;
3681 Vector<VariableInfo*> mStack;
3682 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003683 };
Jack Palevich36d94142009-06-08 15:55:32 -07003684
3685 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003686 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003687 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003688 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003689 int tokl; // token operator level
3690 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003691 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003692 intptr_t loc; // local variable index
3693 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003694 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003695 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003696 char* dptr; // Macro state: Points to macro text during macro playback.
3697 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003698 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003699 ACCSymbolLookupFn mpSymbolLookupFn;
3700 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003701
3702 // Arena for the duration of the compile
3703 Arena mGlobalArena;
3704 // Arena for data that's only needed when compiling a single function
3705 Arena mLocalArena;
3706
Jack Palevich2ff5c222009-07-23 15:11:22 -07003707 Arena* mpCurrentArena;
3708
Jack Palevich569f1352009-06-29 14:29:08 -07003709 TokenTable mTokenTable;
3710 SymbolStack mGlobals;
3711 SymbolStack mLocals;
3712
Jack Palevich9221bcc2009-08-26 16:15:07 -07003713 SymbolStack* mpCurrentSymbolStack;
3714
Jack Palevich40600de2009-07-01 15:32:35 -07003715 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003716 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003717 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003718 Type* mkpChar; // char
3719 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003720 Type* mkpFloat;
3721 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003722 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003723 Type* mkpIntPtr;
3724 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003725 Type* mkpFloatPtr;
3726 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003727 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003728
Jack Palevich36d94142009-06-08 15:55:32 -07003729 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003730 int mLineNumber;
3731 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003732
3733 CodeBuf codeBuf;
3734 CodeGenerator* pGen;
3735
Jack Palevicheedf9d22009-06-04 16:23:40 -07003736 String mErrorBuf;
3737
Jack Palevicheedf9d22009-06-04 16:23:40 -07003738 String mPragmas;
3739 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003740 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003741
Jack Palevich21a15a22009-05-11 14:49:29 -07003742 static const int ALLOC_SIZE = 99999;
3743
Jack Palevich303d8ff2009-06-11 19:06:24 -07003744 static const int TOK_DUMMY = 1;
3745 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003746 static const int TOK_NUM_FLOAT = 3;
3747 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003748 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003749 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003750
3751 // 3..255 are character and/or operators
3752
Jack Palevich2db168f2009-06-11 14:29:47 -07003753 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003754 // Order has to match string list in "internKeywords".
3755 enum {
3756 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3757 TOK_INT = TOK_KEYWORD,
3758 TOK_CHAR,
3759 TOK_VOID,
3760 TOK_IF,
3761 TOK_ELSE,
3762 TOK_WHILE,
3763 TOK_BREAK,
3764 TOK_RETURN,
3765 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003766 TOK_AUTO,
3767 TOK_CASE,
3768 TOK_CONST,
3769 TOK_CONTINUE,
3770 TOK_DEFAULT,
3771 TOK_DO,
3772 TOK_DOUBLE,
3773 TOK_ENUM,
3774 TOK_EXTERN,
3775 TOK_FLOAT,
3776 TOK_GOTO,
3777 TOK_LONG,
3778 TOK_REGISTER,
3779 TOK_SHORT,
3780 TOK_SIGNED,
3781 TOK_SIZEOF,
3782 TOK_STATIC,
3783 TOK_STRUCT,
3784 TOK_SWITCH,
3785 TOK_TYPEDEF,
3786 TOK_UNION,
3787 TOK_UNSIGNED,
3788 TOK_VOLATILE,
3789 TOK__BOOL,
3790 TOK__COMPLEX,
3791 TOK__IMAGINARY,
3792 TOK_INLINE,
3793 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003794
3795 // Symbols start after keywords
3796
3797 TOK_SYMBOL,
3798 TOK_PRAGMA = TOK_SYMBOL,
3799 TOK_DEFINE,
3800 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003801 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003802
3803 static const int LOCAL = 0x200;
3804
3805 static const int SYM_FORWARD = 0;
3806 static const int SYM_DEFINE = 1;
3807
3808 /* tokens in string heap */
3809 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003810
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003811 static const int OP_INCREMENT = 0;
3812 static const int OP_DECREMENT = 1;
3813 static const int OP_MUL = 2;
3814 static const int OP_DIV = 3;
3815 static const int OP_MOD = 4;
3816 static const int OP_PLUS = 5;
3817 static const int OP_MINUS = 6;
3818 static const int OP_SHIFT_LEFT = 7;
3819 static const int OP_SHIFT_RIGHT = 8;
3820 static const int OP_LESS_EQUAL = 9;
3821 static const int OP_GREATER_EQUAL = 10;
3822 static const int OP_LESS = 11;
3823 static const int OP_GREATER = 12;
3824 static const int OP_EQUALS = 13;
3825 static const int OP_NOT_EQUALS = 14;
3826 static const int OP_LOGICAL_AND = 15;
3827 static const int OP_LOGICAL_OR = 16;
3828 static const int OP_BIT_AND = 17;
3829 static const int OP_BIT_XOR = 18;
3830 static const int OP_BIT_OR = 19;
3831 static const int OP_BIT_NOT = 20;
3832 static const int OP_LOGICAL_NOT = 21;
3833 static const int OP_COUNT = 22;
3834
3835 /* Operators are searched from front, the two-character operators appear
3836 * before the single-character operators with the same first character.
3837 * @ is used to pad out single-character operators.
3838 */
3839 static const char* operatorChars;
3840 static const char operatorLevel[];
3841
Jack Palevich569f1352009-06-29 14:29:08 -07003842 /* Called when we detect an internal problem. Does nothing in production.
3843 *
3844 */
3845 void internalError() {
3846 * (char*) 0 = 0;
3847 }
3848
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003849 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003850 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07003851 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003852 internalError();
3853 }
Jack Palevich86351982009-06-30 18:09:56 -07003854 }
3855
Jack Palevich40600de2009-07-01 15:32:35 -07003856 bool isSymbol(tokenid_t t) {
3857 return t >= TOK_SYMBOL &&
3858 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3859 }
3860
3861 bool isSymbolOrKeyword(tokenid_t t) {
3862 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003863 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003864 }
3865
Jack Palevich86351982009-06-30 18:09:56 -07003866 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003867 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003868 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3869 if (pV && pV->tok != t) {
3870 internalError();
3871 }
3872 return pV;
3873 }
3874
3875 inline bool isDefined(tokenid_t t) {
3876 return t >= TOK_SYMBOL && VI(t) != 0;
3877 }
3878
Jack Palevich40600de2009-07-01 15:32:35 -07003879 const char* nameof(tokenid_t t) {
3880 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003881 return mTokenTable[t].pText;
3882 }
3883
Jack Palevich21a15a22009-05-11 14:49:29 -07003884 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003885 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 }
3887
3888 void inp() {
3889 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003890 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003891 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003892 dptr = 0;
3893 ch = dch;
3894 }
Jack Palevichdc456462009-07-16 16:50:56 -07003895 } else {
3896 if (mbBumpLine) {
3897 mLineNumber++;
3898 mbBumpLine = false;
3899 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003900 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003901 if (ch == '\n') {
3902 mbBumpLine = true;
3903 }
3904 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003905#if 0
3906 printf("ch='%c' 0x%x\n", ch, ch);
3907#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003908 }
3909
3910 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003911 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 }
3913
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003914 int decodeHex(int c) {
3915 if (isdigit(c)) {
3916 c -= '0';
3917 } else if (c <= 'F') {
3918 c = c - 'A' + 10;
3919 } else {
3920 c =c - 'a' + 10;
3921 }
3922 return c;
3923 }
3924
Jack Palevichb4758ff2009-06-12 12:49:14 -07003925 /* read a character constant, advances ch to after end of constant */
3926 int getq() {
3927 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003928 if (ch == '\\') {
3929 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003930 if (isoctal(ch)) {
3931 // 1 to 3 octal characters.
3932 val = 0;
3933 for(int i = 0; i < 3; i++) {
3934 if (isoctal(ch)) {
3935 val = (val << 3) + ch - '0';
3936 inp();
3937 }
3938 }
3939 return val;
3940 } else if (ch == 'x' || ch == 'X') {
3941 // N hex chars
3942 inp();
3943 if (! isxdigit(ch)) {
3944 error("'x' character escape requires at least one digit.");
3945 } else {
3946 val = 0;
3947 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003948 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003949 inp();
3950 }
3951 }
3952 } else {
3953 int val = ch;
3954 switch (ch) {
3955 case 'a':
3956 val = '\a';
3957 break;
3958 case 'b':
3959 val = '\b';
3960 break;
3961 case 'f':
3962 val = '\f';
3963 break;
3964 case 'n':
3965 val = '\n';
3966 break;
3967 case 'r':
3968 val = '\r';
3969 break;
3970 case 't':
3971 val = '\t';
3972 break;
3973 case 'v':
3974 val = '\v';
3975 break;
3976 case '\\':
3977 val = '\\';
3978 break;
3979 case '\'':
3980 val = '\'';
3981 break;
3982 case '"':
3983 val = '"';
3984 break;
3985 case '?':
3986 val = '?';
3987 break;
3988 default:
3989 error("Undefined character escape %c", ch);
3990 break;
3991 }
3992 inp();
3993 return val;
3994 }
3995 } else {
3996 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003997 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003998 return val;
3999 }
4000
4001 static bool isoctal(int ch) {
4002 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004003 }
4004
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004005 bool acceptCh(int c) {
4006 bool result = c == ch;
4007 if (result) {
4008 pdef(ch);
4009 inp();
4010 }
4011 return result;
4012 }
4013
4014 bool acceptDigitsCh() {
4015 bool result = false;
4016 while (isdigit(ch)) {
4017 result = true;
4018 pdef(ch);
4019 inp();
4020 }
4021 return result;
4022 }
4023
4024 void parseFloat() {
4025 tok = TOK_NUM_DOUBLE;
4026 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004027 if(mTokenString.len() == 0) {
4028 mTokenString.append('0');
4029 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004030 acceptCh('.');
4031 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004032 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004033 acceptCh('-') || acceptCh('+');
4034 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004035 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004036 if (ch == 'f' || ch == 'F') {
4037 tok = TOK_NUM_FLOAT;
4038 inp();
4039 } else if (ch == 'l' || ch == 'L') {
4040 inp();
4041 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004042 }
4043 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004044 char* pEnd = pText + strlen(pText);
4045 char* pEndPtr = 0;
4046 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004047 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004048 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004049 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004050 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004051 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004052 if (errno || pEndPtr != pEnd) {
4053 error("Can't parse constant: %s", pText);
4054 }
4055 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004056 }
4057
Jack Palevich21a15a22009-05-11 14:49:29 -07004058 void next() {
4059 int l, a;
4060
Jack Palevich546b2242009-05-13 15:10:04 -07004061 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004062 if (ch == '#') {
4063 inp();
4064 next();
4065 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004066 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004067 } else if (tok == TOK_PRAGMA) {
4068 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004069 } else if (tok == TOK_LINE) {
4070 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004071 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004072 error("Unsupported preprocessor directive \"%s\"",
4073 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004074 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 }
4076 inp();
4077 }
4078 tokl = 0;
4079 tok = ch;
4080 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004081 if (isdigit(ch) || ch == '.') {
4082 // Start of a numeric constant. Could be integer, float, or
4083 // double, won't know until we look further.
4084 mTokenString.clear();
4085 pdef(ch);
4086 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004087 if (tok == '.' && !isdigit(ch)) {
4088 goto done;
4089 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004090 int base = 10;
4091 if (tok == '0') {
4092 if (ch == 'x' || ch == 'X') {
4093 base = 16;
4094 tok = TOK_NUM;
4095 tokc = 0;
4096 inp();
4097 while ( isxdigit(ch) ) {
4098 tokc = (tokc << 4) + decodeHex(ch);
4099 inp();
4100 }
4101 } else if (isoctal(ch)){
4102 base = 8;
4103 tok = TOK_NUM;
4104 tokc = 0;
4105 while ( isoctal(ch) ) {
4106 tokc = (tokc << 3) + (ch - '0');
4107 inp();
4108 }
4109 }
4110 } else if (isdigit(tok)){
4111 acceptDigitsCh();
4112 }
4113 if (base == 10) {
4114 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4115 parseFloat();
4116 } else {
4117 // It's an integer constant
4118 char* pText = mTokenString.getUnwrapped();
4119 char* pEnd = pText + strlen(pText);
4120 char* pEndPtr = 0;
4121 errno = 0;
4122 tokc = strtol(pText, &pEndPtr, base);
4123 if (errno || pEndPtr != pEnd) {
4124 error("Can't parse constant: %s %d %d", pText, base, errno);
4125 }
4126 tok = TOK_NUM;
4127 }
4128 }
4129 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004130 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004131 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004132 pdef(ch);
4133 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004134 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004135 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004136 if (! mbSuppressMacroExpansion) {
4137 // Is this a macro?
4138 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4139 if (pMacroDefinition) {
4140 // Yes, it is a macro
4141 dptr = pMacroDefinition;
4142 dch = ch;
4143 inp();
4144 next();
4145 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004146 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004147 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004148 inp();
4149 if (tok == '\'') {
4150 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004151 tokc = getq();
4152 if (ch != '\'') {
4153 error("Expected a ' character, got %c", ch);
4154 } else {
4155 inp();
4156 }
Jack Palevich546b2242009-05-13 15:10:04 -07004157 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004158 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004159 while (ch && ch != EOF) {
4160 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004161 inp();
4162 inp();
4163 if (ch == '/')
4164 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004165 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004166 if (ch == EOF) {
4167 error("End of file inside comment.");
4168 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004169 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004170 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004171 } else if ((tok == '/') & (ch == '/')) {
4172 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004173 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004174 inp();
4175 }
4176 inp();
4177 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004178 } else if ((tok == '-') & (ch == '>')) {
4179 inp();
4180 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004181 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004182 const char* t = operatorChars;
4183 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004184 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004185 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004186 tokl = operatorLevel[opIndex];
4187 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004188 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004189#if 0
4190 printf("%c%c -> tokl=%d tokc=0x%x\n",
4191 l, a, tokl, tokc);
4192#endif
4193 if (a == ch) {
4194 inp();
4195 tok = TOK_DUMMY; /* dummy token for double tokens */
4196 }
Jack Palevich0c017742009-07-31 12:00:39 -07004197 /* check for op=, valid for * / % + - << >> & ^ | */
4198 if (ch == '=' &&
4199 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004200 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004201 inp();
4202 tok = TOK_OP_ASSIGNMENT;
4203 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004204 break;
4205 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004206 opIndex++;
4207 }
4208 if (l == 0) {
4209 tokl = 0;
4210 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004211 }
4212 }
4213 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004214
4215 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004216#if 0
4217 {
Jack Palevich569f1352009-06-29 14:29:08 -07004218 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004219 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004220 fprintf(stderr, "%s\n", buf.getUnwrapped());
4221 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004222#endif
4223 }
4224
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004225 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004226 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004227 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004228 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004229 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004230 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004231 if (ch == '(') {
4232 delete pName;
4233 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004234 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004235 }
4236 while (isspace(ch)) {
4237 inp();
4238 }
Jack Palevich569f1352009-06-29 14:29:08 -07004239 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004240 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004241 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004242 // Check for '//' comments.
4243 if (appendToValue && ch == '/') {
4244 inp();
4245 if (ch == '/') {
4246 appendToValue = false;
4247 } else {
4248 value.append('/');
4249 }
4250 }
4251 if (appendToValue && ch != EOF) {
4252 value.append(ch);
4253 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004254 inp();
4255 }
Jack Palevich569f1352009-06-29 14:29:08 -07004256 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4257 memcpy(pDefn, value.getUnwrapped(), value.len());
4258 pDefn[value.len()] = 0;
4259 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004260 }
4261
Jack Palevicheedf9d22009-06-04 16:23:40 -07004262 void doPragma() {
4263 // # pragma name(val)
4264 int state = 0;
4265 while(ch != EOF && ch != '\n' && state < 10) {
4266 switch(state) {
4267 case 0:
4268 if (isspace(ch)) {
4269 inp();
4270 } else {
4271 state++;
4272 }
4273 break;
4274 case 1:
4275 if (isalnum(ch)) {
4276 mPragmas.append(ch);
4277 inp();
4278 } else if (ch == '(') {
4279 mPragmas.append(0);
4280 inp();
4281 state++;
4282 } else {
4283 state = 11;
4284 }
4285 break;
4286 case 2:
4287 if (isalnum(ch)) {
4288 mPragmas.append(ch);
4289 inp();
4290 } else if (ch == ')') {
4291 mPragmas.append(0);
4292 inp();
4293 state = 10;
4294 } else {
4295 state = 11;
4296 }
4297 break;
4298 }
4299 }
4300 if(state != 10) {
4301 error("Unexpected pragma syntax");
4302 }
4303 mPragmaStringCount += 2;
4304 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004305
Jack Palevichdc456462009-07-16 16:50:56 -07004306 void doLine() {
4307 // # line number { "filename "}
4308 next();
4309 if (tok != TOK_NUM) {
4310 error("Expected a line-number");
4311 } else {
4312 mLineNumber = tokc-1; // The end-of-line will increment it.
4313 }
4314 while(ch != EOF && ch != '\n') {
4315 inp();
4316 }
4317 }
4318
Jack Palevichac0e95e2009-05-29 13:53:44 -07004319 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004320 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004321 mErrorBuf.vprintf(fmt, ap);
4322 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004323 }
4324
Jack Palevich8b0624c2009-05-20 12:12:06 -07004325 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004326 if (tok != c) {
4327 error("'%c' expected", c);
4328 }
4329 next();
4330 }
4331
Jack Palevich86351982009-06-30 18:09:56 -07004332 bool accept(intptr_t c) {
4333 if (tok == c) {
4334 next();
4335 return true;
4336 }
4337 return false;
4338 }
4339
Jack Palevich40600de2009-07-01 15:32:35 -07004340 bool acceptStringLiteral() {
4341 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004342 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004343 // This while loop merges multiple adjacent string constants.
4344 while (tok == '"') {
4345 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004346 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004347 }
4348 if (ch != '"') {
4349 error("Unterminated string constant.");
4350 }
4351 inp();
4352 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004353 }
Jack Palevich40600de2009-07-01 15:32:35 -07004354 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004355 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004356 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004357 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004358
4359 return true;
4360 }
4361 return false;
4362 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004363
Jack Palevichb1544ca2009-07-16 15:09:20 -07004364 void linkGlobal(tokenid_t t, bool isFunction) {
4365 VariableInfo* pVI = VI(t);
4366 void* n = NULL;
4367 if (mpSymbolLookupFn) {
4368 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4369 }
4370 if (pVI->pType == NULL) {
4371 if (isFunction) {
4372 pVI->pType = mkpIntFn;
4373 } else {
4374 pVI->pType = mkpInt;
4375 }
4376 }
4377 pVI->pAddress = n;
4378 }
4379
Jack Palevich29daf572009-07-30 19:38:55 -07004380 void unaryOrAssignment() {
4381 unary();
4382 if (accept('=')) {
4383 checkLVal();
4384 pGen->pushR0();
4385 expr();
4386 pGen->forceR0RVal();
4387 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004388 } else if (tok == TOK_OP_ASSIGNMENT) {
4389 int t = tokc;
4390 next();
4391 checkLVal();
4392 pGen->pushR0();
4393 pGen->forceR0RVal();
4394 pGen->pushR0();
4395 expr();
4396 pGen->forceR0RVal();
4397 pGen->genOp(t);
4398 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004399 }
4400 }
4401
Jack Palevich40600de2009-07-01 15:32:35 -07004402 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004403 */
Jack Palevich29daf572009-07-30 19:38:55 -07004404 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004405 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004406 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004407 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004408 if (acceptStringLiteral()) {
4409 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004410 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004411 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004412 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004413 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004414 t = tok;
4415 next();
4416 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004417 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004418 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004419 // Align to 4-byte boundary
4420 glo = (char*) (((intptr_t) glo + 3) & -4);
4421 * (float*) glo = (float) ad;
4422 pGen->loadFloat((int) glo, mkpFloat);
4423 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004424 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004425 // Align to 8-byte boundary
4426 glo = (char*) (((intptr_t) glo + 7) & -8);
4427 * (double*) glo = ad;
4428 pGen->loadFloat((int) glo, mkpDouble);
4429 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004430 } else if (c == 2) {
4431 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004432 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004433 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004434 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004435 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004436 else if (t == '+') {
4437 // ignore unary plus.
4438 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004439 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004440 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004441 } else if (c == 11) {
4442 // pre increment / pre decrement
4443 unary();
4444 doIncDec(a == OP_INCREMENT, 0);
4445 }
4446 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004447 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004448 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004449 if (pCast) {
4450 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004451 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004452 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004453 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004454 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004455 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004456 skip(')');
4457 }
4458 } else if (t == '*') {
4459 /* This is a pointer dereference.
4460 */
Jack Palevich29daf572009-07-30 19:38:55 -07004461 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004462 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004463 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004464 unary();
4465 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004466 } else if (t == EOF ) {
4467 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004468 } else if (t == ';') {
4469 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004470 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004471 // Don't have to do anything special here, the error
4472 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004473 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004474 if (!isDefined(t)) {
4475 mGlobals.add(t);
4476 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004477 }
Jack Palevich8df46192009-07-07 14:48:51 -07004478 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004479 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004480 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004481 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004482 linkGlobal(t, tok == '(');
4483 n = (intptr_t) pVI->pAddress;
4484 if (!n && tok != '(') {
4485 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004486 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004487 }
Jack Palevich29daf572009-07-30 19:38:55 -07004488 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004489 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004490 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004491 linkGlobal(t, false);
4492 n = (intptr_t) pVI->pAddress;
4493 if (!n) {
4494 error("Undeclared variable %s\n", nameof(t));
4495 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004496 }
Jack Palevich5b659092009-07-31 14:55:07 -07004497 }
4498 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004499 Type* pVal;
4500 ExpressionType et;
4501 if (pVI->pType->tag == TY_ARRAY) {
4502 pVal = pVI->pType;
4503 et = ET_RVALUE;
4504 } else {
4505 pVal = createPtrType(pVI->pType);
4506 et = ET_LVALUE;
4507 }
Jack Palevich5b659092009-07-31 14:55:07 -07004508 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004509 int tag = pVal->pHead->tag;
4510 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004511 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004512 }
Jack Palevich5b659092009-07-31 14:55:07 -07004513 pGen->leaR0(n, pVal, et);
4514 } else {
4515 pVI->pForward = (void*) pGen->leaForward(
4516 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004517 }
4518 }
4519 }
4520
Jack Palevich5b659092009-07-31 14:55:07 -07004521 /* Now handle postfix operators */
4522 for(;;) {
4523 if (tokl == 11) {
4524 // post inc / post dec
4525 doIncDec(tokc == OP_INCREMENT, true);
4526 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004527 } else if (accept('[')) {
4528 // Array reference
4529 pGen->forceR0RVal();
4530 pGen->pushR0();
4531 commaExpr();
4532 pGen->forceR0RVal();
4533 pGen->genOp(OP_PLUS);
4534 doPointer();
4535 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004536 } else if (accept('.')) {
4537 // struct element
4538 pGen->forceR0RVal();
4539 Type* pStruct = pGen->getR0Type();
4540 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004541 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004542 } else {
4543 error("expected a struct value to the left of '.'");
4544 }
4545 } else if (accept(TOK_OP_ARROW)) {
4546 pGen->forceR0RVal();
4547 Type* pPtr = pGen->getR0Type();
4548 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4549 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004550 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004551 } else {
4552 error("Expected a pointer to a struct to the left of '->'");
4553 }
Jack Palevich5b659092009-07-31 14:55:07 -07004554 } else if (accept('(')) {
4555 /* function call */
4556 Type* pDecl = NULL;
4557 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004558 Type* pFn = pGen->getR0Type();
4559 assert(pFn->tag == TY_POINTER);
4560 assert(pFn->pHead->tag == TY_FUNC);
4561 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004562 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004563 Type* pArgList = pDecl->pTail;
4564 bool varArgs = pArgList == NULL;
4565 /* push args and invert order */
4566 a = pGen->beginFunctionCallArguments();
4567 int l = 0;
4568 int argCount = 0;
4569 while (tok != ')' && tok != EOF) {
4570 if (! varArgs && !pArgList) {
4571 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004572 }
Jack Palevich5b659092009-07-31 14:55:07 -07004573 expr();
4574 pGen->forceR0RVal();
4575 Type* pTargetType;
4576 if (pArgList) {
4577 pTargetType = pArgList->pHead;
4578 pArgList = pArgList->pTail;
4579 } else {
4580 // This is a ... function, just pass arguments in their
4581 // natural type.
4582 pTargetType = pGen->getR0Type();
4583 if (pTargetType->tag == TY_FLOAT) {
4584 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004585 } else if (pTargetType->tag == TY_ARRAY) {
4586 // Pass arrays by pointer.
4587 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004588 }
4589 }
4590 if (pTargetType->tag == TY_VOID) {
4591 error("Can't pass void value for argument %d",
4592 argCount + 1);
4593 } else {
4594 l += pGen->storeR0ToArg(l, pTargetType);
4595 }
4596 if (accept(',')) {
4597 // fine
4598 } else if ( tok != ')') {
4599 error("Expected ',' or ')'");
4600 }
4601 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004602 }
Jack Palevich5b659092009-07-31 14:55:07 -07004603 if (! varArgs && pArgList) {
4604 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004605 }
Jack Palevich5b659092009-07-31 14:55:07 -07004606 pGen->endFunctionCallArguments(pDecl, a, l);
4607 skip(')');
4608 pGen->callIndirect(l, pDecl);
4609 pGen->adjustStackAfterCall(pDecl, l, true);
4610 } else {
4611 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004612 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004613 }
4614 }
4615
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004616 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004617 Type* pStructElement = lookupStructMember(pStruct, tok);
4618 if (pStructElement) {
4619 next();
4620 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4621 } else {
4622 String buf;
4623 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004624 error("Expected a struct member to the right of '%s', got %s",
4625 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004626 }
4627 }
4628
Jack Palevichaaac9282009-07-31 14:34:34 -07004629 void doIncDec(int isInc, int isPost) {
4630 // R0 already has the lval
4631 checkLVal();
4632 int lit = isInc ? 1 : -1;
4633 pGen->pushR0();
4634 pGen->loadR0FromR0();
4635 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004636 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4637 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004638 error("++/-- illegal for this type. %d", tag);
4639 }
4640 if (isPost) {
4641 pGen->over();
4642 pGen->pushR0();
4643 pGen->li(lit);
4644 pGen->genOp(OP_PLUS);
4645 pGen->storeR0ToTOS();
4646 pGen->popR0();
4647 } else {
4648 pGen->pushR0();
4649 pGen->li(lit);
4650 pGen->genOp(OP_PLUS);
4651 pGen->over();
4652 pGen->storeR0ToTOS();
4653 pGen->popR0();
4654 }
4655 }
4656
Jack Palevich47cbea92009-07-31 15:25:53 -07004657 void doPointer() {
4658 pGen->forceR0RVal();
4659 Type* pR0Type = pGen->getR0Type();
4660 if (pR0Type->tag != TY_POINTER) {
4661 error("Expected a pointer type.");
4662 } else {
4663 if (pR0Type->pHead->tag != TY_FUNC) {
4664 pGen->setR0ExpressionType(ET_LVALUE);
4665 }
4666 }
4667 }
4668
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004669 void doAddressOf() {
4670 Type* pR0 = pGen->getR0Type();
4671 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4672 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4673 error("Expected an lvalue");
4674 }
4675 Type* pR0Type = pGen->getR0Type();
4676 pGen->setR0ExpressionType(ET_RVALUE);
4677 }
4678
Jack Palevich40600de2009-07-01 15:32:35 -07004679 /* Recursive descent parser for binary operations.
4680 */
4681 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004682 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004683 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004684 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004685 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004686 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004687 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004689 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004690 t = tokc;
4691 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004692 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004693 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004694 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004695 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004696 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004697 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004698 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004699 // Check for syntax error.
4700 if (pGen->getR0Type() == NULL) {
4701 // We failed to parse a right-hand argument.
4702 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004703 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004704 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004705 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004706 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004707 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004709 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004710 }
4711 }
4712 }
4713 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004714 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004715 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004716 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004717 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004718 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004719 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004720 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004721 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004722 }
4723 }
4724 }
4725
Jack Palevich43aaee32009-07-31 14:01:37 -07004726 void commaExpr() {
4727 for(;;) {
4728 expr();
4729 if (!accept(',')) {
4730 break;
4731 }
4732 }
4733 }
4734
Jack Palevich21a15a22009-05-11 14:49:29 -07004735 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004736 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004737 }
4738
4739 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004740 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004741 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004742 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004743 }
4744
Jack Palevicha6baa232009-06-12 11:25:59 -07004745 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004746 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004747
Jack Palevich95727a02009-07-06 12:07:15 -07004748 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004749 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004750 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004751 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004752 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004753 next();
4754 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004755 a = test_expr();
4756 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004757 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004758 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004759 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004760 n = pGen->gjmp(0); /* jmp */
4761 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004762 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004763 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004764 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004765 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004766 }
Jack Palevich546b2242009-05-13 15:10:04 -07004767 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004768 t = tok;
4769 next();
4770 skip('(');
4771 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004772 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004773 a = test_expr();
4774 } else {
4775 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004776 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004777 skip(';');
4778 n = codeBuf.getPC();
4779 a = 0;
4780 if (tok != ';')
4781 a = test_expr();
4782 skip(';');
4783 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004784 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004785 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004786 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004787 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004788 n = t + 4;
4789 }
4790 }
4791 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004792 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004793 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004794 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004795 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004796 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004797 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004798 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004799 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004800 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004801 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004802 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004803 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004804 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004805 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004806 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004807 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004808 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004809 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004810 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004811 if (pReturnType->tag == TY_VOID) {
4812 error("Must not return a value from a void function");
4813 } else {
4814 pGen->convertR0(pReturnType);
4815 }
4816 } else {
4817 if (pReturnType->tag != TY_VOID) {
4818 error("Must specify a value here");
4819 }
Jack Palevich8df46192009-07-07 14:48:51 -07004820 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004821 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004822 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004823 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004824 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004825 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004826 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004827 }
4828 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004829
Jack Palevicha8f427f2009-07-13 18:40:08 -07004830 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004831 if (a == b) {
4832 return true;
4833 }
4834 if (a == NULL || b == NULL) {
4835 return false;
4836 }
4837 TypeTag at = a->tag;
4838 if (at != b->tag) {
4839 return false;
4840 }
4841 if (at == TY_POINTER) {
4842 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004843 } else if (at == TY_ARRAY) {
4844 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004845 } else if (at == TY_FUNC || at == TY_PARAM) {
4846 return typeEqual(a->pHead, b->pHead)
4847 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004848 } else if (at == TY_STRUCT) {
4849 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004850 }
4851 return true;
4852 }
4853
Jack Palevich2ff5c222009-07-23 15:11:22 -07004854 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004855 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004856 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004857 memset(pType, 0, sizeof(*pType));
4858 pType->tag = tag;
4859 pType->pHead = pHead;
4860 pType->pTail = pTail;
4861 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004862 }
4863
Jack Palevich2ff5c222009-07-23 15:11:22 -07004864 Type* createPtrType(Type* pType) {
4865 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004866 }
4867
4868 /**
4869 * Try to print a type in declaration order
4870 */
Jack Palevich86351982009-06-30 18:09:56 -07004871 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004872 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004873 if (pType == NULL) {
4874 buffer.appendCStr("null");
4875 return;
4876 }
Jack Palevich3f226492009-07-02 14:46:19 -07004877 decodeTypeImp(buffer, pType);
4878 }
4879
4880 void decodeTypeImp(String& buffer, Type* pType) {
4881 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004882 decodeId(buffer, pType->id);
4883 decodeTypeImpPostfix(buffer, pType);
4884 }
Jack Palevich3f226492009-07-02 14:46:19 -07004885
Jack Palevich9221bcc2009-08-26 16:15:07 -07004886 void decodeId(String& buffer, tokenid_t id) {
4887 if (id) {
4888 String temp;
4889 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004890 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004891 }
Jack Palevich3f226492009-07-02 14:46:19 -07004892 }
4893
4894 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4895 TypeTag tag = pType->tag;
4896
Jack Palevich9221bcc2009-08-26 16:15:07 -07004897 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004898 switch (tag) {
4899 case TY_INT:
4900 buffer.appendCStr("int");
4901 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004902 case TY_SHORT:
4903 buffer.appendCStr("short");
4904 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004905 case TY_CHAR:
4906 buffer.appendCStr("char");
4907 break;
4908 case TY_VOID:
4909 buffer.appendCStr("void");
4910 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004911 case TY_FLOAT:
4912 buffer.appendCStr("float");
4913 break;
4914 case TY_DOUBLE:
4915 buffer.appendCStr("double");
4916 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004917 case TY_STRUCT:
4918 {
4919 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4920 buffer.appendCStr(isStruct ? "struct" : "union");
4921 if (pType->pHead && pType->pHead->structTag) {
4922 buffer.append(' ');
4923 decodeId(buffer, pType->pHead->structTag);
4924 }
4925 }
4926 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004927 default:
4928 break;
4929 }
Jack Palevich86351982009-06-30 18:09:56 -07004930 buffer.append(' ');
4931 }
Jack Palevich3f226492009-07-02 14:46:19 -07004932
4933 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004934 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004935 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004936 case TY_SHORT:
4937 break;
Jack Palevich86351982009-06-30 18:09:56 -07004938 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004939 break;
4940 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004941 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004942 case TY_FLOAT:
4943 break;
4944 case TY_DOUBLE:
4945 break;
Jack Palevich86351982009-06-30 18:09:56 -07004946 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004947 decodeTypeImpPrefix(buffer, pType->pHead);
4948 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4949 buffer.append('(');
4950 }
4951 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004952 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004953 case TY_ARRAY:
4954 decodeTypeImpPrefix(buffer, pType->pHead);
4955 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004956 case TY_STRUCT:
4957 break;
Jack Palevich86351982009-06-30 18:09:56 -07004958 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004959 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004960 break;
4961 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004962 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004963 break;
4964 default:
4965 String temp;
4966 temp.printf("Unknown tag %d", pType->tag);
4967 buffer.append(temp);
4968 break;
4969 }
Jack Palevich3f226492009-07-02 14:46:19 -07004970 }
4971
4972 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4973 TypeTag tag = pType->tag;
4974
4975 switch(tag) {
4976 case TY_POINTER:
4977 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4978 buffer.append(')');
4979 }
4980 decodeTypeImpPostfix(buffer, pType->pHead);
4981 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004982 case TY_ARRAY:
4983 {
4984 String temp;
4985 temp.printf("[%d]", pType->length);
4986 buffer.append(temp);
4987 }
4988 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004989 case TY_STRUCT:
4990 if (pType->pHead->length >= 0) {
4991 buffer.appendCStr(" {");
4992 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4993 decodeTypeImp(buffer, pArg->pHead);
4994 buffer.appendCStr(";");
4995 }
4996 buffer.append('}');
4997 }
4998 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004999 case TY_FUNC:
5000 buffer.append('(');
5001 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5002 decodeTypeImp(buffer, pArg);
5003 if (pArg->pTail) {
5004 buffer.appendCStr(", ");
5005 }
5006 }
5007 buffer.append(')');
5008 break;
5009 default:
5010 break;
Jack Palevich86351982009-06-30 18:09:56 -07005011 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005012 }
5013
Jack Palevich86351982009-06-30 18:09:56 -07005014 void printType(Type* pType) {
5015 String buffer;
5016 decodeType(buffer, pType);
5017 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005018 }
5019
Jack Palevich2ff5c222009-07-23 15:11:22 -07005020 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005021 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005022 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005023 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005024 } else if (tok == TOK_SHORT) {
5025 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005026 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005027 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005028 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005029 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005030 } else if (tok == TOK_FLOAT) {
5031 pType = mkpFloat;
5032 } else if (tok == TOK_DOUBLE) {
5033 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005034 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5035 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005036 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005037 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005038 }
5039 next();
Jack Palevich86351982009-06-30 18:09:56 -07005040 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005041 }
5042
Jack Palevich9221bcc2009-08-26 16:15:07 -07005043 Type* acceptStruct() {
5044 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5045 bool isStruct = tok == TOK_STRUCT;
5046 next();
5047 tokenid_t structTag = acceptSymbol();
5048 bool isDeclaration = accept('{');
5049 bool fail = false;
5050
5051 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5052 if (structTag) {
5053 Token* pToken = &mTokenTable[structTag];
5054 VariableInfo* pStructInfo = pToken->mpStructInfo;
5055 bool needToDeclare = !pStructInfo;
5056 if (pStructInfo) {
5057 if (isDeclaration) {
5058 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5059 if (pStructInfo->pType->pHead->length == -1) {
5060 // we're filling in a forward declaration.
5061 needToDeclare = false;
5062 } else {
5063 error("A struct with the same name is already defined at this level.");
5064 fail = true;
5065 }
5066 } else {
5067 needToDeclare = true;
5068 }
5069 }
5070 if (!fail) {
5071 assert(pStructInfo->isStructTag);
5072 pStructType->pHead = pStructInfo->pType;
5073 pStructType->pTail = pStructType->pHead->pTail;
5074 }
5075 }
5076
5077 if (needToDeclare) {
5078 // This is a new struct name
5079 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5080 pStructType = createType(TY_STRUCT, NULL, NULL);
5081 pStructType->structTag = structTag;
5082 pStructType->pHead = pStructType;
5083 if (! isDeclaration) {
5084 // A forward declaration
5085 pStructType->length = -1;
5086 }
5087 pToken->mpStructInfo->pType = pStructType;
5088 }
5089 } else {
5090 // An anonymous struct
5091 pStructType->pHead = pStructType;
5092 }
5093
5094 if (isDeclaration) {
5095 size_t offset = 0;
5096 size_t structSize = 0;
5097 size_t structAlignment = 0;
5098 Type** pParamHolder = & pStructType->pHead->pTail;
5099 while (tok != '}' && tok != EOF) {
5100 Type* pPrimitiveType = expectPrimitiveType();
5101 if (pPrimitiveType) {
5102 while (tok != ';' && tok != EOF) {
5103 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5104 if (!pItem) {
5105 break;
5106 }
5107 if (lookupStructMember(pStructType, pItem->id)) {
5108 String buf;
5109 decodeToken(buf, pItem->id, false);
5110 error("Duplicate struct member %s", buf.getUnwrapped());
5111 }
5112 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5113 size_t alignment = pGen->alignmentOf(pItem);
5114 if (alignment > structAlignment) {
5115 structAlignment = alignment;
5116 }
5117 size_t alignmentMask = alignment - 1;
5118 offset = (offset + alignmentMask) & ~alignmentMask;
5119 pStructElement->length = offset;
5120 size_t size = pGen->sizeOf(pItem);
5121 if (isStruct) {
5122 offset += size;
5123 structSize = offset;
5124 } else {
5125 if (size >= structSize) {
5126 structSize = size;
5127 }
5128 }
5129 *pParamHolder = pStructElement;
5130 pParamHolder = &pStructElement->pTail;
5131 accept(',');
5132 }
5133 skip(';');
5134 } else {
5135 // Some sort of syntax error, skip token and keep trying
5136 next();
5137 }
5138 }
5139 if (!fail) {
5140 pStructType->pHead->length = structSize;
5141 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5142 }
5143 skip('}');
5144 }
5145 if (fail) {
5146 pStructType = NULL;
5147 }
5148 return pStructType;
5149 }
5150
5151 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5152 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5153 if (pStructElement->pHead->id == memberId) {
5154 return pStructElement;
5155 }
5156 }
5157 return NULL;
5158 }
5159
Jack Palevich2ff5c222009-07-23 15:11:22 -07005160 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005161 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005162 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005163 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005164 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005165 if (declName) {
5166 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005167 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005168 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005169 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005170 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005171 } else if (nameRequired) {
5172 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005173 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005174#if 0
5175 fprintf(stderr, "Parsed a declaration: ");
5176 printType(pType);
5177#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005178 if (reportFailure) {
5179 return NULL;
5180 }
Jack Palevich86351982009-06-30 18:09:56 -07005181 return pType;
5182 }
5183
Jack Palevich2ff5c222009-07-23 15:11:22 -07005184 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005185 bool nameRequired = pBaseType->tag != TY_STRUCT;
5186 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005187 if (! pType) {
5188 error("Expected a declaration");
5189 }
5190 return pType;
5191 }
5192
Jack Palevich3f226492009-07-02 14:46:19 -07005193 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005194 Type* acceptCastTypeDeclaration() {
5195 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005196 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005197 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005198 }
Jack Palevich86351982009-06-30 18:09:56 -07005199 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005200 }
5201
Jack Palevich2ff5c222009-07-23 15:11:22 -07005202 Type* expectCastTypeDeclaration() {
5203 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005204 if (! pType) {
5205 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005206 }
Jack Palevich3f226492009-07-02 14:46:19 -07005207 return pType;
5208 }
5209
5210 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005211 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005212 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005213 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005214 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005215 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005216 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005217 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005218 return pType;
5219 }
5220
5221 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005222 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005223 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005224 // direct-dcl :
5225 // name
5226 // (dcl)
5227 // direct-dcl()
5228 // direct-dcl[]
5229 Type* pNewHead = NULL;
5230 if (accept('(')) {
5231 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005232 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005233 skip(')');
5234 } else if ((declName = acceptSymbol()) != 0) {
5235 if (nameAllowed == false && declName) {
5236 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005237 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005238 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005239 } else if (nameRequired && ! declName) {
5240 String temp;
5241 decodeToken(temp, tok, true);
5242 error("Expected name. Got %s", temp.getUnwrapped());
5243 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005244 }
Jack Palevichb6154502009-08-04 14:56:09 -07005245 for(;;) {
5246 if (accept('(')) {
5247 // Function declaration
5248 Type* pTail = acceptArgs(nameAllowed);
5249 pType = createType(TY_FUNC, pType, pTail);
5250 skip(')');
5251 } if (accept('[')) {
5252 if (tok != ']') {
5253 if (tok != TOK_NUM || tokc <= 0) {
5254 error("Expected positive integer constant");
5255 } else {
5256 Type* pDecayType = createPtrType(pType);
5257 pType = createType(TY_ARRAY, pType, pDecayType);
5258 pType->length = tokc;
5259 }
5260 next();
5261 }
5262 skip(']');
5263 } else {
5264 break;
5265 }
Jack Palevich86351982009-06-30 18:09:56 -07005266 }
Jack Palevich3f226492009-07-02 14:46:19 -07005267
5268 if (pNewHead) {
5269 Type* pA = pNewHead;
5270 while (pA->pHead) {
5271 pA = pA->pHead;
5272 }
5273 pA->pHead = pType;
5274 pType = pNewHead;
5275 }
Jack Palevich86351982009-06-30 18:09:56 -07005276 return pType;
5277 }
5278
Jack Palevich2ff5c222009-07-23 15:11:22 -07005279 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005280 Type* pHead = NULL;
5281 Type* pTail = NULL;
5282 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005283 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005284 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005285 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005286 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005287 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005288 if (!pHead) {
5289 pHead = pParam;
5290 pTail = pParam;
5291 } else {
5292 pTail->pTail = pParam;
5293 pTail = pParam;
5294 }
5295 }
5296 }
5297 if (! accept(',')) {
5298 break;
5299 }
5300 }
5301 return pHead;
5302 }
5303
Jack Palevich2ff5c222009-07-23 15:11:22 -07005304 Type* expectPrimitiveType() {
5305 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005306 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005307 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005308 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005309 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005310 }
Jack Palevich86351982009-06-30 18:09:56 -07005311 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005312 }
5313
Jack Palevichb5e33312009-07-30 19:06:34 -07005314 void checkLVal() {
5315 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005316 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005317 }
5318 }
5319
Jack Palevich86351982009-06-30 18:09:56 -07005320 void addGlobalSymbol(Type* pDecl) {
5321 tokenid_t t = pDecl->id;
5322 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005323 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005324 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005325 }
Jack Palevich86351982009-06-30 18:09:56 -07005326 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005327 }
5328
Jack Palevich86351982009-06-30 18:09:56 -07005329 void reportDuplicate(tokenid_t t) {
5330 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005331 }
5332
Jack Palevich86351982009-06-30 18:09:56 -07005333 void addLocalSymbol(Type* pDecl) {
5334 tokenid_t t = pDecl->id;
5335 if (mLocals.isDefinedAtCurrentLevel(t)) {
5336 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005337 }
Jack Palevich86351982009-06-30 18:09:56 -07005338 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005339 }
5340
Jack Palevich61de31f2009-09-08 11:06:40 -07005341 bool checkUndeclaredStruct(Type* pBaseType) {
5342 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5343 String temp;
5344 decodeToken(temp, pBaseType->structTag, false);
5345 error("Undeclared struct %s", temp.getUnwrapped());
5346 return true;
5347 }
5348 return false;
5349 }
5350
Jack Palevich95727a02009-07-06 12:07:15 -07005351 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005352 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005353
Jack Palevich95727a02009-07-06 12:07:15 -07005354 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005355 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005356 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005357 if (!pDecl) {
5358 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005359 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005360 if (!pDecl->id) {
5361 break;
5362 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005363 if (checkUndeclaredStruct(pDecl)) {
5364 break;
5365 }
Jack Palevich86351982009-06-30 18:09:56 -07005366 int variableAddress = 0;
5367 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005368 size_t alignment = pGen->alignmentOf(pDecl);
5369 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005370 size_t alignmentMask = ~ (alignment - 1);
5371 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005372 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005373 loc = (loc + alignment - 1) & alignmentMask;
5374 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5375 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005376 variableAddress = -loc;
5377 VI(pDecl->id)->pAddress = (void*) variableAddress;
5378 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005379 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005380 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005381 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005382 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005383 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005384 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005385 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005386 if (tok == ',')
5387 next();
5388 }
5389 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005390 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005391 }
5392 }
5393
Jack Palevichf1728be2009-06-12 13:53:51 -07005394 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005395 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005396 }
5397
Jack Palevich37c54bd2009-07-14 18:35:36 -07005398 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005399 if (token == EOF ) {
5400 buffer.printf("EOF");
5401 } else if (token == TOK_NUM) {
5402 buffer.printf("numeric constant");
5403 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005404 if (token < 32) {
5405 buffer.printf("'\\x%02x'", token);
5406 } else {
5407 buffer.printf("'%c'", token);
5408 }
Jack Palevich569f1352009-06-29 14:29:08 -07005409 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005410 if (quote) {
5411 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5412 buffer.printf("keyword \"%s\"", nameof(token));
5413 } else {
5414 buffer.printf("symbol \"%s\"", nameof(token));
5415 }
5416 } else {
5417 buffer.printf("%s", nameof(token));
5418 }
Jack Palevich569f1352009-06-29 14:29:08 -07005419 }
5420 }
5421
Jack Palevich9221bcc2009-08-26 16:15:07 -07005422 void printToken(tokenid_t token) {
5423 String buffer;
5424 decodeToken(buffer, token, true);
5425 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5426 }
5427
Jack Palevich40600de2009-07-01 15:32:35 -07005428 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005429 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005430 if (!result) {
5431 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005432 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005433 error("Expected symbol. Got %s", temp.getUnwrapped());
5434 }
5435 return result;
5436 }
5437
Jack Palevich86351982009-06-30 18:09:56 -07005438 tokenid_t acceptSymbol() {
5439 tokenid_t result = 0;
5440 if (tok >= TOK_SYMBOL) {
5441 result = tok;
5442 next();
Jack Palevich86351982009-06-30 18:09:56 -07005443 }
5444 return result;
5445 }
5446
Jack Palevichb7c81e92009-06-04 19:56:13 -07005447 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005448 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005449 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005450 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005451 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005452 break;
5453 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005454 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005455 if (!pDecl) {
5456 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005457 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005458 if (!pDecl->id) {
5459 skip(';');
5460 continue;
5461 }
5462
Jack Palevich61de31f2009-09-08 11:06:40 -07005463 if (checkUndeclaredStruct(pDecl)) {
5464 skip(';');
5465 continue;
5466 }
5467
Jack Palevich86351982009-06-30 18:09:56 -07005468 if (! isDefined(pDecl->id)) {
5469 addGlobalSymbol(pDecl);
5470 }
5471 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005472 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005473 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005474 }
Jack Palevich86351982009-06-30 18:09:56 -07005475 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005476 // it's a variable declaration
5477 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005478 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005479 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005480 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005481 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005482 }
Jack Palevich86351982009-06-30 18:09:56 -07005483 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005484 if (tok == TOK_NUM) {
5485 if (name) {
5486 * (int*) name->pAddress = tokc;
5487 }
5488 next();
5489 } else {
5490 error("Expected an integer constant");
5491 }
5492 }
Jack Palevich86351982009-06-30 18:09:56 -07005493 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005494 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005495 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005496 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005497 if (!pDecl) {
5498 break;
5499 }
5500 if (! isDefined(pDecl->id)) {
5501 addGlobalSymbol(pDecl);
5502 }
5503 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005504 }
5505 skip(';');
5506 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005507 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005508 if (accept(';')) {
5509 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005510 } else if (tok != '{') {
5511 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005512 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005513 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005514 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005515 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005516 /* patch forward references */
5517 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005518 /* put function address */
5519 name->pAddress = (void*) codeBuf.getPC();
5520 }
5521 // Calculate stack offsets for parameters
5522 mLocals.pushLevel();
5523 intptr_t a = 8;
5524 int argCount = 0;
5525 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5526 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005527 if (pArg->id) {
5528 addLocalSymbol(pArg);
5529 }
Jack Palevich95727a02009-07-06 12:07:15 -07005530 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005531 Type* pPassingType = passingType(pArg);
5532 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005533 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005534 if (pArg->id) {
5535 VI(pArg->id)->pAddress = (void*) a;
5536 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005537 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005538 argCount++;
5539 }
5540 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005541 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005542 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005543 block(0, true);
5544 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005545 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005546 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005547 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005548 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005549 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005550 }
5551 }
5552 }
5553
Jack Palevich9221bcc2009-08-26 16:15:07 -07005554 Type* passingType(Type* pType) {
5555 switch (pType->tag) {
5556 case TY_CHAR:
5557 case TY_SHORT:
5558 return mkpInt;
5559 default:
5560 return pType;
5561 }
5562 }
5563
Jack Palevich9cbd2262009-07-08 16:48:41 -07005564 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5565 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5566 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005567 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005568 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005569 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005570 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005571 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005572 char* result = (char*) base;
5573 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005574 return result;
5575 }
5576
Jack Palevich21a15a22009-05-11 14:49:29 -07005577 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005578 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005579 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005580 pGlobalBase = 0;
5581 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005582 if (pGen) {
5583 delete pGen;
5584 pGen = 0;
5585 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005586 if (file) {
5587 delete file;
5588 file = 0;
5589 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005590 }
5591
Jack Palevich8c246a92009-07-14 21:14:10 -07005592 // One-time initialization, when class is constructed.
5593 void init() {
5594 mpSymbolLookupFn = 0;
5595 mpSymbolLookupContext = 0;
5596 }
5597
Jack Palevich21a15a22009-05-11 14:49:29 -07005598 void clear() {
5599 tok = 0;
5600 tokc = 0;
5601 tokl = 0;
5602 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005603 rsym = 0;
5604 loc = 0;
5605 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005606 dptr = 0;
5607 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005608 file = 0;
5609 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005610 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005611 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005612 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005613 mLineNumber = 1;
5614 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005615 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005616 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005617
Jack Palevich22305132009-05-13 10:58:45 -07005618 void setArchitecture(const char* architecture) {
5619 delete pGen;
5620 pGen = 0;
5621
5622 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005623#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005624 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005625 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005626 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005627#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005628#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005629 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005630 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005631 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005632#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005633 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005634 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005635 }
5636 }
5637
5638 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005639#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005640 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005641#elif defined(DEFAULT_X86_CODEGEN)
5642 pGen = new X86CodeGenerator();
5643#endif
5644 }
5645 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005646 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005647 } else {
5648 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005649 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005650 }
5651 }
5652
Jack Palevich77ae76e2009-05-10 19:59:24 -07005653public:
Jack Palevich22305132009-05-13 10:58:45 -07005654 struct args {
5655 args() {
5656 architecture = 0;
5657 }
5658 const char* architecture;
5659 };
5660
Jack Paleviche7b59062009-05-19 17:12:17 -07005661 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005662 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005663 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005664 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005665
Jack Paleviche7b59062009-05-19 17:12:17 -07005666 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005667 cleanup();
5668 }
5669
Jack Palevich8c246a92009-07-14 21:14:10 -07005670 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5671 mpSymbolLookupFn = pFn;
5672 mpSymbolLookupContext = pContext;
5673 }
5674
Jack Palevich1cdef202009-05-22 12:06:27 -07005675 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005676 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005677
Jack Palevich2ff5c222009-07-23 15:11:22 -07005678 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005679 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005680 cleanup();
5681 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005682 mTokenTable.setArena(&mGlobalArena);
5683 mGlobals.setArena(&mGlobalArena);
5684 mGlobals.setTokenTable(&mTokenTable);
5685 mLocals.setArena(&mLocalArena);
5686 mLocals.setTokenTable(&mTokenTable);
5687
5688 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005689 codeBuf.init(ALLOC_SIZE);
5690 setArchitecture(NULL);
5691 if (!pGen) {
5692 return -1;
5693 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005694#ifdef PROVIDE_TRACE_CODEGEN
5695 pGen = new TraceCodeGenerator(pGen);
5696#endif
5697 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005698 pGen->init(&codeBuf);
5699 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005700 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5701 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005702 inp();
5703 next();
5704 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005705 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005706 result = pGen->finishCompile();
5707 if (result == 0) {
5708 if (mErrorBuf.len()) {
5709 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005710 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005711 }
Jack Palevichce105a92009-07-16 14:30:33 -07005712 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005713 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005714 }
5715
Jack Palevich86351982009-06-30 18:09:56 -07005716 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005717 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005718 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005719 mkpChar = createType(TY_CHAR, NULL, NULL);
5720 mkpVoid = createType(TY_VOID, NULL, NULL);
5721 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5722 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5723 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5724 mkpIntPtr = createPtrType(mkpInt);
5725 mkpCharPtr = createPtrType(mkpChar);
5726 mkpFloatPtr = createPtrType(mkpFloat);
5727 mkpDoublePtr = createPtrType(mkpDouble);
5728 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005729 }
5730
Jack Palevicha6baa232009-06-12 11:25:59 -07005731 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005732 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005733 }
5734
Jack Palevich569f1352009-06-29 14:29:08 -07005735 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005736 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005737 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005738 }
5739
Jack Palevich569f1352009-06-29 14:29:08 -07005740 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005741 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005742 error("Undefined forward reference: %s",
5743 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005744 }
5745 return true;
5746 }
5747
Jack Palevich21a15a22009-05-11 14:49:29 -07005748 int dump(FILE* out) {
5749 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5750 return 0;
5751 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005752
Jack Palevicha6535612009-05-13 16:24:17 -07005753 int disassemble(FILE* out) {
5754 return pGen->disassemble(out);
5755 }
5756
Jack Palevich1cdef202009-05-22 12:06:27 -07005757 /* Look through the symbol table to find a symbol.
5758 * If found, return its value.
5759 */
5760 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005761 if (mCompileResult == 0) {
5762 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5763 VariableInfo* pVariableInfo = VI(tok);
5764 if (pVariableInfo) {
5765 return pVariableInfo->pAddress;
5766 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005767 }
5768 return NULL;
5769 }
5770
Jack Palevicheedf9d22009-06-04 16:23:40 -07005771 void getPragmas(ACCsizei* actualStringCount,
5772 ACCsizei maxStringCount, ACCchar** strings) {
5773 int stringCount = mPragmaStringCount;
5774 if (actualStringCount) {
5775 *actualStringCount = stringCount;
5776 }
5777 if (stringCount > maxStringCount) {
5778 stringCount = maxStringCount;
5779 }
5780 if (strings) {
5781 char* pPragmas = mPragmas.getUnwrapped();
5782 while (stringCount-- > 0) {
5783 *strings++ = pPragmas;
5784 pPragmas += strlen(pPragmas) + 1;
5785 }
5786 }
5787 }
5788
Jack Palevichac0e95e2009-05-29 13:53:44 -07005789 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005790 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005791 }
5792
Jack Palevich77ae76e2009-05-10 19:59:24 -07005793};
5794
Jack Paleviche7b59062009-05-19 17:12:17 -07005795const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005796 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5797
Jack Paleviche7b59062009-05-19 17:12:17 -07005798const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005799 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5800 5, 5, /* ==, != */
5801 9, 10, /* &&, || */
5802 6, 7, 8, /* & ^ | */
5803 2, 2 /* ~ ! */
5804 };
5805
Jack Palevich8b0624c2009-05-20 12:12:06 -07005806#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005807FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005808#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005809
Jack Palevich8b0624c2009-05-20 12:12:06 -07005810#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005811const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005812 0x1, // ++
5813 0xff, // --
5814 0xc1af0f, // *
5815 0xf9f79991, // /
5816 0xf9f79991, // % (With manual assist to swap results)
5817 0xc801, // +
5818 0xd8f7c829, // -
5819 0xe0d391, // <<
5820 0xf8d391, // >>
5821 0xe, // <=
5822 0xd, // >=
5823 0xc, // <
5824 0xf, // >
5825 0x4, // ==
5826 0x5, // !=
5827 0x0, // &&
5828 0x1, // ||
5829 0xc821, // &
5830 0xc831, // ^
5831 0xc809, // |
5832 0xd0f7, // ~
5833 0x4 // !
5834};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005835#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005836
Jack Palevich1cdef202009-05-22 12:06:27 -07005837struct ACCscript {
5838 ACCscript() {
5839 text = 0;
5840 textLength = 0;
5841 accError = ACC_NO_ERROR;
5842 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005843
Jack Palevich1cdef202009-05-22 12:06:27 -07005844 ~ACCscript() {
5845 delete text;
5846 }
Jack Palevich546b2242009-05-13 15:10:04 -07005847
Jack Palevich8c246a92009-07-14 21:14:10 -07005848 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5849 compiler.registerSymbolCallback(pFn, pContext);
5850 }
5851
Jack Palevich1cdef202009-05-22 12:06:27 -07005852 void setError(ACCenum error) {
5853 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5854 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005855 }
5856 }
5857
Jack Palevich1cdef202009-05-22 12:06:27 -07005858 ACCenum getError() {
5859 ACCenum result = accError;
5860 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005861 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005862 }
5863
Jack Palevich1cdef202009-05-22 12:06:27 -07005864 Compiler compiler;
5865 char* text;
5866 int textLength;
5867 ACCenum accError;
5868};
5869
5870
5871extern "C"
5872ACCscript* accCreateScript() {
5873 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005874}
Jack Palevich1cdef202009-05-22 12:06:27 -07005875
5876extern "C"
5877ACCenum accGetError( ACCscript* script ) {
5878 return script->getError();
5879}
5880
5881extern "C"
5882void accDeleteScript(ACCscript* script) {
5883 delete script;
5884}
5885
5886extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005887void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5888 ACCvoid* pContext) {
5889 script->registerSymbolCallback(pFn, pContext);
5890}
5891
5892extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005893void accScriptSource(ACCscript* script,
5894 ACCsizei count,
5895 const ACCchar ** string,
5896 const ACCint * length) {
5897 int totalLength = 0;
5898 for(int i = 0; i < count; i++) {
5899 int len = -1;
5900 const ACCchar* s = string[i];
5901 if (length) {
5902 len = length[i];
5903 }
5904 if (len < 0) {
5905 len = strlen(s);
5906 }
5907 totalLength += len;
5908 }
5909 delete script->text;
5910 char* text = new char[totalLength + 1];
5911 script->text = text;
5912 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005913 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005914 for(int i = 0; i < count; i++) {
5915 int len = -1;
5916 const ACCchar* s = string[i];
5917 if (length) {
5918 len = length[i];
5919 }
5920 if (len < 0) {
5921 len = strlen(s);
5922 }
Jack Palevich09555c72009-05-27 12:25:55 -07005923 memcpy(dest, s, len);
5924 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005925 }
5926 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07005927
5928#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07005929 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07005930 int counter;
5931 char path[PATH_MAX];
5932 for (counter = 0; counter < 4096; counter++) {
5933 sprintf(path, DEBUG_DUMP_PATTERN, counter);
5934 if(access(path, F_OK) != 0) {
5935 break;
5936 }
5937 }
5938 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07005939 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07005940 FILE* fd = fopen(path, "w");
5941 if (fd) {
5942 fwrite(text, totalLength, 1, fd);
5943 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07005944 LOGD("Saved input to file %s", path);
5945 } else {
5946 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07005947 }
5948 }
5949#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07005950}
5951
5952extern "C"
5953void accCompileScript(ACCscript* script) {
5954 int result = script->compiler.compile(script->text, script->textLength);
5955 if (result) {
5956 script->setError(ACC_INVALID_OPERATION);
5957 }
5958}
5959
5960extern "C"
5961void accGetScriptiv(ACCscript* script,
5962 ACCenum pname,
5963 ACCint * params) {
5964 switch (pname) {
5965 case ACC_INFO_LOG_LENGTH:
5966 *params = 0;
5967 break;
5968 }
5969}
5970
5971extern "C"
5972void accGetScriptInfoLog(ACCscript* script,
5973 ACCsizei maxLength,
5974 ACCsizei * length,
5975 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005976 char* message = script->compiler.getErrorMessage();
5977 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005978 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005979 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005980 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005981 if (infoLog && maxLength > 0) {
5982 int trimmedLength = maxLength < messageLength ?
5983 maxLength : messageLength;
5984 memcpy(infoLog, message, trimmedLength);
5985 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005986 }
5987}
5988
5989extern "C"
5990void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5991 ACCvoid ** address) {
5992 void* value = script->compiler.lookup(name);
5993 if (value) {
5994 *address = value;
5995 } else {
5996 script->setError(ACC_INVALID_VALUE);
5997 }
5998}
5999
Jack Palevicheedf9d22009-06-04 16:23:40 -07006000extern "C"
6001void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6002 ACCsizei maxStringCount, ACCchar** strings){
6003 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6004}
6005
-b master422972c2009-06-17 19:13:52 -07006006extern "C"
6007void accDisassemble(ACCscript* script) {
6008 script->compiler.disassemble(stderr);
6009}
6010
Jack Palevicheedf9d22009-06-04 16:23:40 -07006011
Jack Palevich1cdef202009-05-22 12:06:27 -07006012} // namespace acc
6013