blob: b8ff29d52d04b0a951df6daed73c2d0689b23d8a [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 {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001551 if (r0Tag == TY_DOUBLE) {
1552 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001553#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001554 o4(0xEEFD7BC7); // ftosizd s15, d7
1555 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001556#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001557 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001558#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001559 } else {
1560 if(destTag == TY_FLOAT) {
1561#ifdef ARM_USE_VFP
1562 o4(0xEEF77BC7); // fcvtsd s15, d7
1563#else
1564 callRuntime((void*) runtime_double_to_float);
1565#endif
1566 } else {
1567 incompatibleTypes(pR0Type, pType);
1568 }
1569 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001570 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001571 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001572 }
1573 }
Jack Palevich8df46192009-07-07 14:48:51 -07001574 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001575 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001576 }
1577
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001578 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001579 return o4(0xE24DDF00); // Placeholder
1580 }
1581
Jack Palevich8148c5b2009-07-16 18:24:47 -07001582 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001583 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001584 Type* pR0Type = getR0Type();
1585 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001586#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001587 switch(r0ct) {
1588 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001589 if (l < 0 || l > 4096-4) {
1590 error("l out of range for stack offset: 0x%08x", l);
1591 }
1592 o4(0xE58D0000 | l); // str r0, [sp, #l]
1593 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001594 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001595 if (l < 0 || l > 1020 || (l & 3)) {
1596 error("l out of range for stack offset: 0x%08x", l);
1597 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001598 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001599 return 4;
1600 case TY_DOUBLE: {
1601 // Align to 8 byte boundary
1602 int l2 = (l + 7) & ~7;
1603 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1604 error("l out of range for stack offset: 0x%08x", l);
1605 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001606 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001607 return (l2 - l) + 8;
1608 }
1609 default:
1610 assert(false);
1611 return 0;
1612 }
1613#else
1614 switch(r0ct) {
1615 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001616 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001617 if (l < 0 || l > 4096-4) {
1618 error("l out of range for stack offset: 0x%08x", l);
1619 }
1620 o4(0xE58D0000 + l); // str r0, [sp, #l]
1621 return 4;
1622 case TY_DOUBLE: {
1623 // Align to 8 byte boundary
1624 int l2 = (l + 7) & ~7;
1625 if (l2 < 0 || l2 > 4096-8) {
1626 error("l out of range for stack offset: 0x%08x", l);
1627 }
1628 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1629 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1630 return (l2 - l) + 8;
1631 }
1632 default:
1633 assert(false);
1634 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001635 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001636#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001637 }
1638
Jack Palevichb7718b92009-07-09 22:00:24 -07001639 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001640 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001641 // Have to calculate register arg count from actual stack size,
1642 // in order to properly handle ... functions.
1643 int regArgCount = l >> 2;
1644 if (regArgCount > 4) {
1645 regArgCount = 4;
1646 }
1647 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001648 argumentStackUse -= regArgCount * 4;
1649 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1650 }
1651 mStackUse += argumentStackUse;
1652
1653 // Align stack.
1654 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1655 * STACK_ALIGNMENT);
1656 mStackAlignmentAdjustment = 0;
1657 if (missalignment > 0) {
1658 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1659 }
1660 l += mStackAlignmentAdjustment;
1661
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001662 if (l < 0 || l > 0x3FC) {
1663 error("L out of range for stack adjustment: 0x%08x", l);
1664 }
1665 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001666 mStackUse += mStackAlignmentAdjustment;
1667 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1668 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001669 }
1670
Jack Palevich8df46192009-07-07 14:48:51 -07001671 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001672 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001673 // Forward calls are always short (local)
1674 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001675 }
1676
Jack Palevich8df46192009-07-07 14:48:51 -07001677 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001678 assert(pFunc->tag == TY_FUNC);
1679 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001680 int argCount = l >> 2;
1681 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001682 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001683 if (adjustedL < 0 || adjustedL > 4096-4) {
1684 error("l out of range for stack offset: 0x%08x", l);
1685 }
1686 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1687 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001688 Type* pReturnType = pFunc->pHead;
1689 setR0Type(pReturnType);
1690#ifdef ARM_USE_VFP
1691 switch(pReturnType->tag) {
1692 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001693 o4(0xEE070A90); // fmsr s15, r0
1694 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001695 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001696 o4(0xEC410B17); // fmdrr d7, r0, r1
1697 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001698 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001699 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001700 }
1701#endif
Jack Palevich22305132009-05-13 10:58:45 -07001702 }
1703
Jack Palevichb7718b92009-07-09 22:00:24 -07001704 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001705 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001706 // Have to calculate register arg count from actual stack size,
1707 // in order to properly handle ... functions.
1708 int regArgCount = l >> 2;
1709 if (regArgCount > 4) {
1710 regArgCount = 4;
1711 }
1712 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001713 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1714 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001715 if (stackUse) {
1716 if (stackUse < 0 || stackUse > 255) {
1717 error("L out of range for stack adjustment: 0x%08x", l);
1718 }
1719 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001720 mStackUse -= stackUse * 4;
1721 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001722 }
Jack Palevich22305132009-05-13 10:58:45 -07001723 }
1724
Jack Palevicha6535612009-05-13 16:24:17 -07001725 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001726 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001727 }
1728
1729 /* output a symbol and patch all calls to it */
1730 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001731 int n;
1732 int base = getBase();
1733 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001734 while (t) {
1735 int data = * (int*) t;
1736 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1737 if (decodedOffset == 0) {
1738 n = 0;
1739 } else {
1740 n = base + decodedOffset; /* next value */
1741 }
1742 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1743 | encodeRelAddress(pc - t - 8);
1744 t = n;
1745 }
1746 }
1747
Jack Palevich9f51a262009-07-29 16:22:26 -07001748 /* output a symbol and patch all calls to it */
1749 virtual void resolveForward(int t) {
1750 if (t) {
1751 int pc = getPC();
1752 *(int *) t = pc;
1753 }
1754 }
1755
Jack Palevich1cdef202009-05-22 12:06:27 -07001756 virtual int finishCompile() {
1757#if defined(__arm__)
1758 const long base = long(getBase());
1759 const long curr = long(getPC());
1760 int err = cacheflush(base, curr, 0);
1761 return err;
1762#else
1763 return 0;
1764#endif
1765 }
1766
Jack Palevicha6535612009-05-13 16:24:17 -07001767 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001768#ifdef ENABLE_ARM_DISASSEMBLY
1769 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001770 disasm_interface_t di;
1771 di.di_readword = disassemble_readword;
1772 di.di_printaddr = disassemble_printaddr;
1773 di.di_printf = disassemble_printf;
1774
1775 int base = getBase();
1776 int pc = getPC();
1777 for(int i = base; i < pc; i += 4) {
1778 fprintf(out, "%08x: %08x ", i, *(int*) i);
1779 ::disasm(&di, i, 0);
1780 }
Jack Palevich09555c72009-05-27 12:25:55 -07001781#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001782 return 0;
1783 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001784
Jack Palevich9eed7a22009-07-06 17:24:34 -07001785 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001786 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001787 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001788 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001789 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001790 case TY_CHAR:
1791 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001792 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07001793 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001794 case TY_DOUBLE:
1795 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001796 case TY_ARRAY:
1797 return alignmentOf(pType->pHead);
1798 case TY_STRUCT:
1799 return pType->pHead->alignment & 0x7fffffff;
1800 case TY_FUNC:
1801 error("alignment of func not supported");
1802 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001803 default:
1804 return 4;
1805 }
1806 }
1807
1808 /**
1809 * Array element alignment (in bytes) for this type of data.
1810 */
1811 virtual size_t sizeOf(Type* pType){
1812 switch(pType->tag) {
1813 case TY_INT:
1814 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001815 case TY_SHORT:
1816 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001817 case TY_CHAR:
1818 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001819 case TY_FLOAT:
1820 return 4;
1821 case TY_DOUBLE:
1822 return 8;
1823 case TY_POINTER:
1824 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001825 case TY_ARRAY:
1826 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07001827 case TY_STRUCT:
1828 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07001829 default:
1830 error("Unsupported type %d", pType->tag);
1831 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001832 }
1833 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001834
Jack Palevich22305132009-05-13 10:58:45 -07001835 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001836 static FILE* disasmOut;
1837
1838 static u_int
1839 disassemble_readword(u_int address)
1840 {
1841 return(*((u_int *)address));
1842 }
1843
1844 static void
1845 disassemble_printaddr(u_int address)
1846 {
1847 fprintf(disasmOut, "0x%08x", address);
1848 }
1849
1850 static void
1851 disassemble_printf(const char *fmt, ...) {
1852 va_list ap;
1853 va_start(ap, fmt);
1854 vfprintf(disasmOut, fmt, ap);
1855 va_end(ap);
1856 }
1857
1858 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1859
1860 /** Encode a relative address that might also be
1861 * a label.
1862 */
1863 int encodeAddress(int value) {
1864 int base = getBase();
1865 if (value >= base && value <= getPC() ) {
1866 // This is a label, encode it relative to the base.
1867 value = value - base;
1868 }
1869 return encodeRelAddress(value);
1870 }
1871
1872 int encodeRelAddress(int value) {
1873 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1874 }
Jack Palevich22305132009-05-13 10:58:45 -07001875
Jack Palevichb7718b92009-07-09 22:00:24 -07001876 int calcRegArgCount(Type* pDecl) {
1877 int reg = 0;
1878 Type* pArgs = pDecl->pTail;
1879 while (pArgs && reg < 4) {
1880 Type* pArg = pArgs->pHead;
1881 if ( pArg->tag == TY_DOUBLE) {
1882 int evenReg = (reg + 1) & ~1;
1883 if (evenReg >= 4) {
1884 break;
1885 }
1886 reg = evenReg + 2;
1887 } else {
1888 reg++;
1889 }
1890 pArgs = pArgs->pTail;
1891 }
1892 return reg;
1893 }
1894
Jack Palevich58c30ee2009-07-17 16:35:23 -07001895 void setupIntPtrArgs() {
1896 o4(0xE8BD0002); // ldmfd sp!,{r1}
1897 mStackUse -= 4;
1898 popType();
1899 }
1900
Jack Palevich30321cb2009-08-20 15:34:23 -07001901 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001902 * Make sure both R0 and TOS are floats. (Could be ints)
1903 * We know that at least one of R0 and TOS is already a float
1904 */
1905 void setupFloatArgs() {
1906 Type* pR0Type = getR0Type();
1907 Type* pTOSType = getTOSType();
1908 TypeTag tagR0 = collapseType(pR0Type->tag);
1909 TypeTag tagTOS = collapseType(pTOSType->tag);
1910 if (tagR0 != TY_FLOAT) {
1911 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001912#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001913 o4(0xEE070A90); // fmsr s15, r0
1914 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001915#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001916 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001917#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001918 }
1919 if (tagTOS != TY_FLOAT) {
1920 assert(tagTOS == TY_INT);
1921 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001922#ifdef ARM_USE_VFP
1923 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07001924 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07001925#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001926 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1927 o4(0xE59D0004); // ldr r0, [sp, #4]
1928 callRuntime((void*) runtime_int_to_float);
1929 o4(0xE1A01000); // mov r1, r0
1930 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1931 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001932#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001933 } else {
1934 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001935#ifdef ARM_USE_VFP
1936 o4(0xECBD7A01); // fldmfds sp!, {s14}
1937
1938#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001939 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001940#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001941 }
1942 mStackUse -= 4;
1943 popType();
1944 }
1945
Jack Palevich30321cb2009-08-20 15:34:23 -07001946 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001947 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1948 * We know that at least one of R0 and TOS are already a double.
1949 */
1950
1951 void setupDoubleArgs() {
1952 Type* pR0Type = getR0Type();
1953 Type* pTOSType = getTOSType();
1954 TypeTag tagR0 = collapseType(pR0Type->tag);
1955 TypeTag tagTOS = collapseType(pTOSType->tag);
1956 if (tagR0 != TY_DOUBLE) {
1957 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001958#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001959 o4(0xEE070A90); // fmsr s15, r0
1960 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001961
1962#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001963 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001964#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001965 } else {
1966 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001967#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001968 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001969#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001970 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001971#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001972 }
1973 }
1974 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001975#ifdef ARM_USE_VFP
1976 if (tagTOS == TY_INT) {
1977 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001978 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001979 } else {
1980 assert(tagTOS == TY_FLOAT);
1981 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001982 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001983 }
1984#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001985 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1986 o4(0xE59D0008); // ldr r0, [sp, #8]
1987 if (tagTOS == TY_INT) {
1988 callRuntime((void*) runtime_int_to_double);
1989 } else {
1990 assert(tagTOS == TY_FLOAT);
1991 callRuntime((void*) runtime_float_to_double);
1992 }
1993 o4(0xE1A02000); // mov r2, r0
1994 o4(0xE1A03001); // mov r3, r1
1995 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1996 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001997#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001998 mStackUse -= 4;
1999 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002000#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002001 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002002#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002003 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002004#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002005 mStackUse -= 8;
2006 }
2007 popType();
2008 }
2009
Jack Palevicha8f427f2009-07-13 18:40:08 -07002010 void liReg(int t, int reg) {
2011 assert(reg >= 0 && reg < 16);
2012 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002013 size_t encodedImmediate;
2014 if (encode12BitImmediate(t, &encodedImmediate)) {
2015 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2016 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002017 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002018 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002019 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002020 o4(0xE51F0000 | rN); // ldr rN, .L3
2021 o4(0xEA000000); // b .L99
2022 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002023 // .L99:
2024 }
2025 }
2026
Jack Palevich9221bcc2009-08-26 16:15:07 -07002027 bool encode12BitImmediate(size_t immediate, size_t* pResult) {
2028 for(size_t i = 0; i < 16; i++) {
2029 size_t rotate = i * 2;
2030 size_t mask = rotateRight(0xff, rotate);
2031 if ((immediate | mask) == mask) {
2032 size_t bits8 = rotateLeft(immediate, rotate);
2033 assert(bits8 <= 0xff);
2034 *pResult = (i << 8) | bits8;
2035 return true;
2036 }
2037 }
2038 return false;
2039 }
2040
Jack Palevichc408bbf2009-09-08 12:07:32 -07002041 void incompatibleTypes(Type* pR0Type, Type* pType) {
2042 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2043 }
2044
Jack Palevich9221bcc2009-08-26 16:15:07 -07002045 size_t rotateRight(size_t n, size_t rotate) {
2046 return (n >> rotate) | (n << (32 - rotate));
2047 }
2048
2049 size_t rotateLeft(size_t n, size_t rotate) {
2050 return (n << rotate) | (n >> (32 - rotate));
2051 }
2052
Jack Palevichb7718b92009-07-09 22:00:24 -07002053 void callRuntime(void* fn) {
2054 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002055 o4(0xEA000000); // b .L99
2056 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002057 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002058 }
2059
Jack Palevichb7718b92009-07-09 22:00:24 -07002060 // Integer math:
2061
2062 static int runtime_DIV(int b, int a) {
2063 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002064 }
2065
Jack Palevichb7718b92009-07-09 22:00:24 -07002066 static int runtime_MOD(int b, int a) {
2067 return a % b;
2068 }
2069
Jack Palevich9221bcc2009-08-26 16:15:07 -07002070 static void runtime_structCopy(void* src, size_t size, void* dest) {
2071 memcpy(dest, src, size);
2072 }
2073
Jack Palevich30321cb2009-08-20 15:34:23 -07002074#ifndef ARM_USE_VFP
2075
Jack Palevichb7718b92009-07-09 22:00:24 -07002076 // Comparison to zero
2077
2078 static int runtime_is_non_zero_f(float a) {
2079 return a != 0;
2080 }
2081
2082 static int runtime_is_non_zero_d(double a) {
2083 return a != 0;
2084 }
2085
2086 // Comparison to zero
2087
2088 static int runtime_is_zero_f(float a) {
2089 return a == 0;
2090 }
2091
2092 static int runtime_is_zero_d(double a) {
2093 return a == 0;
2094 }
2095
2096 // Type conversion
2097
2098 static int runtime_float_to_int(float a) {
2099 return (int) a;
2100 }
2101
2102 static double runtime_float_to_double(float a) {
2103 return (double) a;
2104 }
2105
2106 static int runtime_double_to_int(double a) {
2107 return (int) a;
2108 }
2109
2110 static float runtime_double_to_float(double a) {
2111 return (float) a;
2112 }
2113
2114 static float runtime_int_to_float(int a) {
2115 return (float) a;
2116 }
2117
2118 static double runtime_int_to_double(int a) {
2119 return (double) a;
2120 }
2121
2122 // Comparisons float
2123
2124 static int runtime_cmp_eq_ff(float b, float a) {
2125 return a == b;
2126 }
2127
2128 static int runtime_cmp_ne_ff(float b, float a) {
2129 return a != b;
2130 }
2131
2132 static int runtime_cmp_lt_ff(float b, float a) {
2133 return a < b;
2134 }
2135
2136 static int runtime_cmp_le_ff(float b, float a) {
2137 return a <= b;
2138 }
2139
2140 static int runtime_cmp_ge_ff(float b, float a) {
2141 return a >= b;
2142 }
2143
2144 static int runtime_cmp_gt_ff(float b, float a) {
2145 return a > b;
2146 }
2147
2148 // Comparisons double
2149
2150 static int runtime_cmp_eq_dd(double b, double a) {
2151 return a == b;
2152 }
2153
2154 static int runtime_cmp_ne_dd(double b, double a) {
2155 return a != b;
2156 }
2157
2158 static int runtime_cmp_lt_dd(double b, double a) {
2159 return a < b;
2160 }
2161
2162 static int runtime_cmp_le_dd(double b, double a) {
2163 return a <= b;
2164 }
2165
2166 static int runtime_cmp_ge_dd(double b, double a) {
2167 return a >= b;
2168 }
2169
2170 static int runtime_cmp_gt_dd(double b, double a) {
2171 return a > b;
2172 }
2173
2174 // Math float
2175
2176 static float runtime_op_add_ff(float b, float a) {
2177 return a + b;
2178 }
2179
2180 static float runtime_op_sub_ff(float b, float a) {
2181 return a - b;
2182 }
2183
2184 static float runtime_op_mul_ff(float b, float a) {
2185 return a * b;
2186 }
2187
2188 static float runtime_op_div_ff(float b, float a) {
2189 return a / b;
2190 }
2191
2192 static float runtime_op_neg_f(float a) {
2193 return -a;
2194 }
2195
2196 // Math double
2197
2198 static double runtime_op_add_dd(double b, double a) {
2199 return a + b;
2200 }
2201
2202 static double runtime_op_sub_dd(double b, double a) {
2203 return a - b;
2204 }
2205
2206 static double runtime_op_mul_dd(double b, double a) {
2207 return a * b;
2208 }
2209
2210 static double runtime_op_div_dd(double b, double a) {
2211 return a / b;
2212 }
2213
2214 static double runtime_op_neg_d(double a) {
2215 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002216 }
-b master422972c2009-06-17 19:13:52 -07002217
Jack Palevich30321cb2009-08-20 15:34:23 -07002218#endif
2219
-b master422972c2009-06-17 19:13:52 -07002220 static const int STACK_ALIGNMENT = 8;
2221 int mStackUse;
2222 // This variable holds the amount we adjusted the stack in the most
2223 // recent endFunctionCallArguments call. It's examined by the
2224 // following adjustStackAfterCall call.
2225 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002226 };
2227
Jack Palevich09555c72009-05-27 12:25:55 -07002228#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002229
2230#ifdef PROVIDE_X86_CODEGEN
2231
Jack Palevich21a15a22009-05-11 14:49:29 -07002232 class X86CodeGenerator : public CodeGenerator {
2233 public:
2234 X86CodeGenerator() {}
2235 virtual ~X86CodeGenerator() {}
2236
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002237 /* returns address to patch with local variable size
2238 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002239 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002240 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2241 return oad(0xec81, 0); /* sub $xxx, %esp */
2242 }
2243
Jack Palevichb7718b92009-07-09 22:00:24 -07002244 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002245 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002246 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002247 }
2248
Jack Palevich21a15a22009-05-11 14:49:29 -07002249 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002250 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002251 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002252 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002253 }
2254
Jack Palevich1a539db2009-07-08 13:04:41 -07002255 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002256 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002257 switch (pType->tag) {
2258 case TY_FLOAT:
2259 oad(0x05D9, address); // flds
2260 break;
2261 case TY_DOUBLE:
2262 oad(0x05DD, address); // fldl
2263 break;
2264 default:
2265 assert(false);
2266 break;
2267 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002268 }
2269
Jack Palevich9221bcc2009-08-26 16:15:07 -07002270 virtual void addStructOffsetR0(int offset, Type* pType) {
2271 if (offset) {
2272 oad(0x05, offset); // addl offset, %eax
2273 }
2274 setR0Type(pType, ET_LVALUE);
2275 }
2276
Jack Palevich22305132009-05-13 10:58:45 -07002277 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002278 return psym(0xe9, t);
2279 }
2280
2281 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002282 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002283 Type* pR0Type = getR0Type();
2284 TypeTag tagR0 = pR0Type->tag;
2285 bool isFloatR0 = isFloatTag(tagR0);
2286 if (isFloatR0) {
2287 o(0xeed9); // fldz
2288 o(0xe9da); // fucompp
2289 o(0xe0df); // fnstsw %ax
2290 o(0x9e); // sahf
2291 } else {
2292 o(0xc085); // test %eax, %eax
2293 }
2294 // Use two output statements to generate one instruction.
2295 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002296 return psym(0x84 + l, t);
2297 }
2298
Jack Palevich58c30ee2009-07-17 16:35:23 -07002299 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002300 Type* pR0Type = getR0Type();
2301 Type* pTOSType = getTOSType();
2302 TypeTag tagR0 = pR0Type->tag;
2303 TypeTag tagTOS = pTOSType->tag;
2304 bool isFloatR0 = isFloatTag(tagR0);
2305 bool isFloatTOS = isFloatTag(tagTOS);
2306 if (!isFloatR0 && !isFloatTOS) {
2307 int t = decodeOp(op);
2308 o(0x59); /* pop %ecx */
2309 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002310 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002311 o(0x0f); /* setxx %al */
2312 o(t + 0x90);
2313 o(0xc0);
2314 popType();
2315 } else {
2316 setupFloatOperands();
2317 switch (op) {
2318 case OP_EQUALS:
2319 o(0xe9da); // fucompp
2320 o(0xe0df); // fnstsw %ax
2321 o(0x9e); // sahf
2322 o(0xc0940f); // sete %al
2323 o(0xc29b0f); // setnp %dl
2324 o(0xd021); // andl %edx, %eax
2325 break;
2326 case OP_NOT_EQUALS:
2327 o(0xe9da); // fucompp
2328 o(0xe0df); // fnstsw %ax
2329 o(0x9e); // sahf
2330 o(0xc0950f); // setne %al
2331 o(0xc29a0f); // setp %dl
2332 o(0xd009); // orl %edx, %eax
2333 break;
2334 case OP_GREATER_EQUAL:
2335 o(0xe9da); // fucompp
2336 o(0xe0df); // fnstsw %ax
2337 o(0x05c4f6); // testb $5, %ah
2338 o(0xc0940f); // sete %al
2339 break;
2340 case OP_LESS:
2341 o(0xc9d9); // fxch %st(1)
2342 o(0xe9da); // fucompp
2343 o(0xe0df); // fnstsw %ax
2344 o(0x9e); // sahf
2345 o(0xc0970f); // seta %al
2346 break;
2347 case OP_LESS_EQUAL:
2348 o(0xc9d9); // fxch %st(1)
2349 o(0xe9da); // fucompp
2350 o(0xe0df); // fnstsw %ax
2351 o(0x9e); // sahf
2352 o(0xc0930f); // setea %al
2353 break;
2354 case OP_GREATER:
2355 o(0xe9da); // fucompp
2356 o(0xe0df); // fnstsw %ax
2357 o(0x45c4f6); // testb $69, %ah
2358 o(0xc0940f); // sete %al
2359 break;
2360 default:
2361 error("Unknown comparison op");
2362 }
2363 o(0xc0b60f); // movzbl %al, %eax
2364 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002365 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002366 }
2367
Jack Palevich546b2242009-05-13 15:10:04 -07002368 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002369 Type* pR0Type = getR0Type();
2370 Type* pTOSType = getTOSType();
2371 TypeTag tagR0 = pR0Type->tag;
2372 TypeTag tagTOS = pTOSType->tag;
2373 bool isFloatR0 = isFloatTag(tagR0);
2374 bool isFloatTOS = isFloatTag(tagTOS);
2375 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002376 bool isPtrR0 = isPointerTag(tagR0);
2377 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002378 if (isPtrR0 || isPtrTOS) {
2379 if (isPtrR0 && isPtrTOS) {
2380 if (op != OP_MINUS) {
2381 error("Unsupported pointer-pointer operation %d.", op);
2382 }
2383 if (! typeEqual(pR0Type, pTOSType)) {
2384 error("Incompatible pointer types for subtraction.");
2385 }
2386 o(0x59); /* pop %ecx */
2387 o(decodeOp(op));
2388 popType();
2389 setR0Type(mkpInt);
2390 int size = sizeOf(pR0Type->pHead);
2391 if (size != 1) {
2392 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002393 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002394 // TODO: Optimize for power-of-two.
2395 genOp(OP_DIV);
2396 }
2397 } else {
2398 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2399 error("Unsupported pointer-scalar operation %d", op);
2400 }
Jack Palevichb6154502009-08-04 14:56:09 -07002401 Type* pPtrType = getPointerArithmeticResultType(
2402 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002403 o(0x59); /* pop %ecx */
2404 int size = sizeOf(pPtrType->pHead);
2405 if (size != 1) {
2406 // TODO: Optimize for power-of-two.
2407 if (isPtrR0) {
2408 oad(0xC969, size); // imull $size, %ecx
2409 } else {
2410 oad(0xC069, size); // mul $size, %eax
2411 }
2412 }
2413 o(decodeOp(op));
2414 popType();
2415 setR0Type(pPtrType);
2416 }
2417 } else {
2418 o(0x59); /* pop %ecx */
2419 o(decodeOp(op));
2420 if (op == OP_MOD)
2421 o(0x92); /* xchg %edx, %eax */
2422 popType();
2423 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002424 } else {
2425 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2426 setupFloatOperands();
2427 // Both float. x87 R0 == left hand, x87 R1 == right hand
2428 switch (op) {
2429 case OP_MUL:
2430 o(0xc9de); // fmulp
2431 break;
2432 case OP_DIV:
2433 o(0xf1de); // fdivp
2434 break;
2435 case OP_PLUS:
2436 o(0xc1de); // faddp
2437 break;
2438 case OP_MINUS:
2439 o(0xe1de); // fsubp
2440 break;
2441 default:
2442 error("Unsupported binary floating operation.");
2443 break;
2444 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002445 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002446 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002447 }
2448
Jack Palevich58c30ee2009-07-17 16:35:23 -07002449 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002450 if (op != OP_LOGICAL_NOT) {
2451 error("Unknown unary cmp %d", op);
2452 } else {
2453 Type* pR0Type = getR0Type();
2454 TypeTag tag = collapseType(pR0Type->tag);
2455 switch(tag) {
2456 case TY_INT: {
2457 oad(0xb9, 0); /* movl $0, %ecx */
2458 int t = decodeOp(op);
2459 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002460 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002461 o(0x0f); /* setxx %al */
2462 o(t + 0x90);
2463 o(0xc0);
2464 }
2465 break;
2466 case TY_FLOAT:
2467 case TY_DOUBLE:
2468 o(0xeed9); // fldz
2469 o(0xe9da); // fucompp
2470 o(0xe0df); // fnstsw %ax
2471 o(0x9e); // sahf
2472 o(0xc0950f); // setne %al
2473 o(0xc29a0f); // setp %dl
2474 o(0xd009); // orl %edx, %eax
2475 o(0xc0b60f); // movzbl %al, %eax
2476 o(0x01f083); // xorl $1, %eax
2477 break;
2478 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002479 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002480 break;
2481 }
2482 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002483 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002484 }
2485
2486 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002487 Type* pR0Type = getR0Type();
2488 TypeTag tag = collapseType(pR0Type->tag);
2489 switch(tag) {
2490 case TY_INT:
2491 oad(0xb9, 0); /* movl $0, %ecx */
2492 o(decodeOp(op));
2493 break;
2494 case TY_FLOAT:
2495 case TY_DOUBLE:
2496 switch (op) {
2497 case OP_MINUS:
2498 o(0xe0d9); // fchs
2499 break;
2500 case OP_BIT_NOT:
2501 error("Can't apply '~' operator to a float or double.");
2502 break;
2503 default:
2504 error("Unknown unary op %d\n", op);
2505 break;
2506 }
2507 break;
2508 default:
2509 error("genUnaryOp unsupported type");
2510 break;
2511 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002512 }
2513
Jack Palevich1cdef202009-05-22 12:06:27 -07002514 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002515 Type* pR0Type = getR0Type();
2516 TypeTag r0ct = collapseType(pR0Type->tag);
2517 switch(r0ct) {
2518 case TY_INT:
2519 o(0x50); /* push %eax */
2520 break;
2521 case TY_FLOAT:
2522 o(0x50); /* push %eax */
2523 o(0x241cd9); // fstps 0(%esp)
2524 break;
2525 case TY_DOUBLE:
2526 o(0x50); /* push %eax */
2527 o(0x50); /* push %eax */
2528 o(0x241cdd); // fstpl 0(%esp)
2529 break;
2530 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002531 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002532 break;
2533 }
Jack Palevich8df46192009-07-07 14:48:51 -07002534 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002535 }
2536
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002537 virtual void over() {
2538 // We know it's only used for int-ptr ops (++/--)
2539
2540 Type* pR0Type = getR0Type();
2541 TypeTag r0ct = collapseType(pR0Type->tag);
2542
2543 Type* pTOSType = getTOSType();
2544 TypeTag tosct = collapseType(pTOSType->tag);
2545
2546 assert (r0ct == TY_INT && tosct == TY_INT);
2547
2548 o(0x59); /* pop %ecx */
2549 o(0x50); /* push %eax */
2550 o(0x51); /* push %ecx */
2551
2552 overType();
2553 }
2554
Jack Palevich58c30ee2009-07-17 16:35:23 -07002555 virtual void popR0() {
2556 Type* pR0Type = getR0Type();
2557 TypeTag r0ct = collapseType(pR0Type->tag);
2558 switch(r0ct) {
2559 case TY_INT:
2560 o(0x58); /* popl %eax */
2561 break;
2562 case TY_FLOAT:
2563 o(0x2404d9); // flds (%esp)
2564 o(0x58); /* popl %eax */
2565 break;
2566 case TY_DOUBLE:
2567 o(0x2404dd); // fldl (%esp)
2568 o(0x58); /* popl %eax */
2569 o(0x58); /* popl %eax */
2570 break;
2571 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002572 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002573 break;
2574 }
2575 popType();
2576 }
2577
2578 virtual void storeR0ToTOS() {
2579 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002580 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002581 Type* pTargetType = pPointerType->pHead;
2582 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002583 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002584 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002585 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002586 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002587 case TY_INT:
2588 o(0x0189); /* movl %eax/%al, (%ecx) */
2589 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002590 case TY_SHORT:
2591 o(0x018966); /* movw %ax, (%ecx) */
2592 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002593 case TY_CHAR:
2594 o(0x0188); /* movl %eax/%al, (%ecx) */
2595 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002596 case TY_FLOAT:
2597 o(0x19d9); /* fstps (%ecx) */
2598 break;
2599 case TY_DOUBLE:
2600 o(0x19dd); /* fstpl (%ecx) */
2601 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002602 case TY_STRUCT:
2603 {
2604 // TODO: use alignment information to use movsw/movsl instead of movsb
2605 int size = sizeOf(pTargetType);
2606 if (size > 0) {
2607 o(0x9c); // pushf
2608 o(0x57); // pushl %edi
2609 o(0x56); // pushl %esi
2610 o(0xcf89); // movl %ecx, %edi
2611 o(0xc689); // movl %eax, %esi
2612 oad(0xb9, size); // mov #size, %ecx
2613 o(0xfc); // cld
2614 o(0xf3); // rep
2615 o(0xa4); // movsb
2616 o(0x5e); // popl %esi
2617 o(0x5f); // popl %edi
2618 o(0x9d); // popf
2619 }
2620 }
2621 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002622 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002623 error("storeR0ToTOS: unsupported type %d",
2624 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002625 break;
2626 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002627 }
2628
Jack Palevich58c30ee2009-07-17 16:35:23 -07002629 virtual void loadR0FromR0() {
2630 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002631 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002632 Type* pNewType = pPointerType->pHead;
2633 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002634 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002635 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002636 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002637 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002638 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002639 case TY_SHORT:
2640 o(0xbf0f); /* movswl (%eax), %eax */
2641 ob(0);
2642 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002643 case TY_CHAR:
2644 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002645 ob(0); /* add zero in code */
2646 break;
2647 case TY_FLOAT:
2648 o2(0x00d9); // flds (%eax)
2649 break;
2650 case TY_DOUBLE:
2651 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002652 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002653 case TY_ARRAY:
2654 pNewType = pNewType->pTail;
2655 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002656 case TY_STRUCT:
2657 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002658 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002659 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002660 break;
2661 }
Jack Palevich80e49722009-08-04 15:39:49 -07002662 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002663 }
2664
Jack Palevichb5e33312009-07-30 19:06:34 -07002665 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002666 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002667 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002668 }
2669
Jack Palevich9f51a262009-07-29 16:22:26 -07002670 virtual int leaForward(int ea, Type* pPointerType) {
2671 oad(0xb8, ea); /* mov $xx, %eax */
2672 setR0Type(pPointerType);
2673 return getPC() - 4;
2674 }
2675
Jack Palevichb6154502009-08-04 14:56:09 -07002676 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002677 Type* pR0Type = getR0Type();
2678 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002679 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002680 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002681 return;
2682 }
Jack Palevichb6154502009-08-04 14:56:09 -07002683 if (isPointerType(pType) && isPointerType(pR0Type)) {
2684 Type* pA = pR0Type;
2685 Type* pB = pType;
2686 // Array decays to pointer
2687 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2688 pA = pA->pTail;
2689 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002690 if (! (typeEqual(pA, pB)
2691 || pB->pHead->tag == TY_VOID
2692 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2693 )) {
2694 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002695 }
Jack Palevichb6154502009-08-04 14:56:09 -07002696 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002697 // do nothing special
2698 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2699 // do nothing special, both held in same register on x87.
2700 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002701 TypeTag r0Tag = collapseType(pR0Type->tag);
2702 TypeTag destTag = collapseType(pType->tag);
2703 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2704 // Convert R0 from int to float
2705 o(0x50); // push %eax
2706 o(0x2404DB); // fildl 0(%esp)
2707 o(0x58); // pop %eax
2708 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2709 // Convert R0 from float to int. Complicated because
2710 // need to save and restore the rounding mode.
2711 o(0x50); // push %eax
2712 o(0x50); // push %eax
2713 o(0x02247cD9); // fnstcw 2(%esp)
2714 o(0x2444b70f); // movzwl 2(%esp), %eax
2715 o(0x02);
2716 o(0x0cb4); // movb $12, %ah
2717 o(0x24048966); // movw %ax, 0(%esp)
2718 o(0x242cd9); // fldcw 0(%esp)
2719 o(0x04245cdb); // fistpl 4(%esp)
2720 o(0x02246cd9); // fldcw 2(%esp)
2721 o(0x58); // pop %eax
2722 o(0x58); // pop %eax
2723 } else {
2724 error("Incompatible types old: %d new: %d",
2725 pR0Type->tag, pType->tag);
2726 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002727 }
2728 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002729 }
2730
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002731 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002732 return oad(0xec81, 0); /* sub $xxx, %esp */
2733 }
2734
Jack Palevich8148c5b2009-07-16 18:24:47 -07002735 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2736 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002737 Type* pR0Type = getR0Type();
2738 TypeTag r0ct = collapseType(pR0Type->tag);
2739 switch(r0ct) {
2740 case TY_INT:
2741 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2742 return 4;
2743 case TY_FLOAT:
2744 oad(0x249CD9, l); /* fstps xxx(%esp) */
2745 return 4;
2746 case TY_DOUBLE:
2747 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2748 return 8;
2749 default:
2750 assert(false);
2751 return 0;
2752 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002753 }
2754
Jack Palevichb7718b92009-07-09 22:00:24 -07002755 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002756 * (int*) a = l;
2757 }
2758
Jack Palevich8df46192009-07-07 14:48:51 -07002759 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002760 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002761 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002762 return psym(0xe8, symbol); /* call xxx */
2763 }
2764
Jack Palevich8df46192009-07-07 14:48:51 -07002765 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002766 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002767 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002768 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002769 oad(0x2494ff, l); /* call *xxx(%esp) */
2770 }
2771
Jack Palevichb7718b92009-07-09 22:00:24 -07002772 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002773 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002774 if (isIndirect) {
2775 l += 4;
2776 }
-b master422972c2009-06-17 19:13:52 -07002777 if (l > 0) {
2778 oad(0xc481, l); /* add $xxx, %esp */
2779 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002780 }
2781
Jack Palevicha6535612009-05-13 16:24:17 -07002782 virtual int jumpOffset() {
2783 return 5;
2784 }
2785
2786 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002787 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002788 }
2789
Jack Paleviche7b59062009-05-19 17:12:17 -07002790 /* output a symbol and patch all calls to it */
2791 virtual void gsym(int t) {
2792 int n;
2793 int pc = getPC();
2794 while (t) {
2795 n = *(int *) t; /* next value */
2796 *(int *) t = pc - t - 4;
2797 t = n;
2798 }
2799 }
2800
Jack Palevich9f51a262009-07-29 16:22:26 -07002801 /* output a symbol and patch all calls to it, using absolute address */
2802 virtual void resolveForward(int t) {
2803 int n;
2804 int pc = getPC();
2805 while (t) {
2806 n = *(int *) t; /* next value */
2807 *(int *) t = pc;
2808 t = n;
2809 }
2810 }
2811
Jack Palevich1cdef202009-05-22 12:06:27 -07002812 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002813 size_t pagesize = 4096;
2814 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2815 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2816 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2817 if (err) {
2818 error("mprotect() failed: %d", errno);
2819 }
2820 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002821 }
2822
Jack Palevich9eed7a22009-07-06 17:24:34 -07002823 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002824 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002825 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002826 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002827 switch (pType->tag) {
2828 case TY_CHAR:
2829 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002830 case TY_SHORT:
2831 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002832 case TY_ARRAY:
2833 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002834 case TY_STRUCT:
2835 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07002836 case TY_FUNC:
2837 error("alignment of func not supported");
2838 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002839 default:
2840 return 4;
2841 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002842 }
2843
2844 /**
2845 * Array element alignment (in bytes) for this type of data.
2846 */
2847 virtual size_t sizeOf(Type* pType){
2848 switch(pType->tag) {
2849 case TY_INT:
2850 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002851 case TY_SHORT:
2852 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002853 case TY_CHAR:
2854 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002855 case TY_FLOAT:
2856 return 4;
2857 case TY_DOUBLE:
2858 return 8;
2859 case TY_POINTER:
2860 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002861 case TY_ARRAY:
2862 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002863 case TY_STRUCT:
2864 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002865 default:
2866 error("Unsupported type %d", pType->tag);
2867 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002868 }
2869 }
2870
Jack Palevich21a15a22009-05-11 14:49:29 -07002871 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002872
2873 /** Output 1 to 4 bytes.
2874 *
2875 */
2876 void o(int n) {
2877 /* cannot use unsigned, so we must do a hack */
2878 while (n && n != -1) {
2879 ob(n & 0xff);
2880 n = n >> 8;
2881 }
2882 }
2883
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002884 /* Output exactly 2 bytes
2885 */
2886 void o2(int n) {
2887 ob(n & 0xff);
2888 ob(0xff & (n >> 8));
2889 }
2890
Jack Paleviche7b59062009-05-19 17:12:17 -07002891 /* psym is used to put an instruction with a data field which is a
2892 reference to a symbol. It is in fact the same as oad ! */
2893 int psym(int n, int t) {
2894 return oad(n, t);
2895 }
2896
2897 /* instruction + address */
2898 int oad(int n, int t) {
2899 o(n);
2900 int result = getPC();
2901 o4(t);
2902 return result;
2903 }
2904
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002905 static const int operatorHelper[];
2906
2907 int decodeOp(int op) {
2908 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002909 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002910 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002911 }
2912 return operatorHelper[op];
2913 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002914
Jack Palevich546b2242009-05-13 15:10:04 -07002915 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002916 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002917 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002918 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002919
2920 void setupFloatOperands() {
2921 Type* pR0Type = getR0Type();
2922 Type* pTOSType = getTOSType();
2923 TypeTag tagR0 = pR0Type->tag;
2924 TypeTag tagTOS = pTOSType->tag;
2925 bool isFloatR0 = isFloatTag(tagR0);
2926 bool isFloatTOS = isFloatTag(tagTOS);
2927 if (! isFloatR0) {
2928 // Convert R0 from int to float
2929 o(0x50); // push %eax
2930 o(0x2404DB); // fildl 0(%esp)
2931 o(0x58); // pop %eax
2932 }
2933 if (! isFloatTOS){
2934 o(0x2404DB); // fildl 0(%esp);
2935 o(0x58); // pop %eax
2936 } else {
2937 if (tagTOS == TY_FLOAT) {
2938 o(0x2404d9); // flds (%esp)
2939 o(0x58); // pop %eax
2940 } else {
2941 o(0x2404dd); // fldl (%esp)
2942 o(0x58); // pop %eax
2943 o(0x58); // pop %eax
2944 }
2945 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002946 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002947 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002948 };
2949
Jack Paleviche7b59062009-05-19 17:12:17 -07002950#endif // PROVIDE_X86_CODEGEN
2951
Jack Palevichb67b18f2009-06-11 21:12:23 -07002952#ifdef PROVIDE_TRACE_CODEGEN
2953 class TraceCodeGenerator : public CodeGenerator {
2954 private:
2955 CodeGenerator* mpBase;
2956
2957 public:
2958 TraceCodeGenerator(CodeGenerator* pBase) {
2959 mpBase = pBase;
2960 }
2961
2962 virtual ~TraceCodeGenerator() {
2963 delete mpBase;
2964 }
2965
2966 virtual void init(CodeBuf* pCodeBuf) {
2967 mpBase->init(pCodeBuf);
2968 }
2969
2970 void setErrorSink(ErrorSink* pErrorSink) {
2971 mpBase->setErrorSink(pErrorSink);
2972 }
2973
2974 /* returns address to patch with local variable size
2975 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002976 virtual int functionEntry(Type* pDecl) {
2977 int result = mpBase->functionEntry(pDecl);
2978 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002979 return result;
2980 }
2981
Jack Palevichb7718b92009-07-09 22:00:24 -07002982 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2983 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2984 localVariableAddress, localVariableSize);
2985 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002986 }
2987
2988 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002989 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002990 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002991 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002992 }
2993
Jack Palevich1a539db2009-07-08 13:04:41 -07002994 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002995 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002996 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002997 }
2998
Jack Palevich9221bcc2009-08-26 16:15:07 -07002999 virtual void addStructOffsetR0(int offset, Type* pType) {
3000 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3001 mpBase->addStructOffsetR0(offset, pType);
3002 }
3003
Jack Palevichb67b18f2009-06-11 21:12:23 -07003004 virtual int gjmp(int t) {
3005 int result = mpBase->gjmp(t);
3006 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3007 return result;
3008 }
3009
3010 /* l = 0: je, l == 1: jne */
3011 virtual int gtst(bool l, int t) {
3012 int result = mpBase->gtst(l, t);
3013 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3014 return result;
3015 }
3016
Jack Palevich58c30ee2009-07-17 16:35:23 -07003017 virtual void gcmp(int op) {
3018 fprintf(stderr, "gcmp(%d)\n", op);
3019 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003020 }
3021
3022 virtual void genOp(int op) {
3023 fprintf(stderr, "genOp(%d)\n", op);
3024 mpBase->genOp(op);
3025 }
3026
Jack Palevich9eed7a22009-07-06 17:24:34 -07003027
Jack Palevich58c30ee2009-07-17 16:35:23 -07003028 virtual void gUnaryCmp(int op) {
3029 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3030 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003031 }
3032
3033 virtual void genUnaryOp(int op) {
3034 fprintf(stderr, "genUnaryOp(%d)\n", op);
3035 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003036 }
3037
3038 virtual void pushR0() {
3039 fprintf(stderr, "pushR0()\n");
3040 mpBase->pushR0();
3041 }
3042
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003043 virtual void over() {
3044 fprintf(stderr, "over()\n");
3045 mpBase->over();
3046 }
3047
Jack Palevich58c30ee2009-07-17 16:35:23 -07003048 virtual void popR0() {
3049 fprintf(stderr, "popR0()\n");
3050 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003051 }
3052
Jack Palevich58c30ee2009-07-17 16:35:23 -07003053 virtual void storeR0ToTOS() {
3054 fprintf(stderr, "storeR0ToTOS()\n");
3055 mpBase->storeR0ToTOS();
3056 }
3057
3058 virtual void loadR0FromR0() {
3059 fprintf(stderr, "loadR0FromR0()\n");
3060 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003061 }
3062
Jack Palevichb5e33312009-07-30 19:06:34 -07003063 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3064 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3065 pPointerType->pHead->tag, et);
3066 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003067 }
3068
Jack Palevich9f51a262009-07-29 16:22:26 -07003069 virtual int leaForward(int ea, Type* pPointerType) {
3070 fprintf(stderr, "leaForward(%d)\n", ea);
3071 return mpBase->leaForward(ea, pPointerType);
3072 }
3073
Jack Palevich30321cb2009-08-20 15:34:23 -07003074 virtual void convertR0Imp(Type* pType, bool isCast){
3075 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3076 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003077 }
3078
3079 virtual int beginFunctionCallArguments() {
3080 int result = mpBase->beginFunctionCallArguments();
3081 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3082 return result;
3083 }
3084
Jack Palevich8148c5b2009-07-16 18:24:47 -07003085 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3086 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3087 pArgType->tag);
3088 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003089 }
3090
Jack Palevichb7718b92009-07-09 22:00:24 -07003091 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003092 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003093 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003094 }
3095
Jack Palevich8df46192009-07-07 14:48:51 -07003096 virtual int callForward(int symbol, Type* pFunc) {
3097 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003098 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3099 return result;
3100 }
3101
Jack Palevich8df46192009-07-07 14:48:51 -07003102 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003103 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3104 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003105 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003106 }
3107
Jack Palevichb7718b92009-07-09 22:00:24 -07003108 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3109 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3110 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003111 }
3112
3113 virtual int jumpOffset() {
3114 return mpBase->jumpOffset();
3115 }
3116
3117 virtual int disassemble(FILE* out) {
3118 return mpBase->disassemble(out);
3119 }
3120
3121 /* output a symbol and patch all calls to it */
3122 virtual void gsym(int t) {
3123 fprintf(stderr, "gsym(%d)\n", t);
3124 mpBase->gsym(t);
3125 }
3126
Jack Palevich9f51a262009-07-29 16:22:26 -07003127 virtual void resolveForward(int t) {
3128 mpBase->resolveForward(t);
3129 }
3130
Jack Palevichb67b18f2009-06-11 21:12:23 -07003131 virtual int finishCompile() {
3132 int result = mpBase->finishCompile();
3133 fprintf(stderr, "finishCompile() = %d\n", result);
3134 return result;
3135 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003136
3137 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003138 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003139 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003140 virtual size_t alignmentOf(Type* pType){
3141 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003142 }
3143
3144 /**
3145 * Array element alignment (in bytes) for this type of data.
3146 */
3147 virtual size_t sizeOf(Type* pType){
3148 return mpBase->sizeOf(pType);
3149 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003150
3151 virtual Type* getR0Type() {
3152 return mpBase->getR0Type();
3153 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003154
3155 virtual ExpressionType getR0ExpressionType() {
3156 return mpBase->getR0ExpressionType();
3157 }
3158
3159 virtual void setR0ExpressionType(ExpressionType et) {
3160 mpBase->setR0ExpressionType(et);
3161 }
3162
3163 virtual size_t getExpressionStackDepth() {
3164 return mpBase->getExpressionStackDepth();
3165 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003166
3167 virtual void forceR0RVal() {
3168 return mpBase->forceR0RVal();
3169 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003170 };
3171
3172#endif // PROVIDE_TRACE_CODEGEN
3173
Jack Palevich569f1352009-06-29 14:29:08 -07003174 class Arena {
3175 public:
3176 // Used to record a given allocation amount.
3177 // Used:
3178 // Mark mark = arena.mark();
3179 // ... lots of arena.allocate()
3180 // arena.free(mark);
3181
3182 struct Mark {
3183 size_t chunk;
3184 size_t offset;
3185 };
3186
3187 Arena() {
3188 mCurrentChunk = 0;
3189 Chunk start(CHUNK_SIZE);
3190 mData.push_back(start);
3191 }
3192
3193 ~Arena() {
3194 for(size_t i = 0; i < mData.size(); i++) {
3195 mData[i].free();
3196 }
3197 }
3198
3199 // Alloc using the standard alignment size safe for any variable
3200 void* alloc(size_t size) {
3201 return alloc(size, 8);
3202 }
3203
3204 Mark mark(){
3205 Mark result;
3206 result.chunk = mCurrentChunk;
3207 result.offset = mData[mCurrentChunk].mOffset;
3208 return result;
3209 }
3210
3211 void freeToMark(const Mark& mark) {
3212 mCurrentChunk = mark.chunk;
3213 mData[mCurrentChunk].mOffset = mark.offset;
3214 }
3215
3216 private:
3217 // Allocate memory aligned to a given size
3218 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3219 // Memory is not zero filled.
3220
3221 void* alloc(size_t size, size_t alignment) {
3222 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3223 if (mCurrentChunk + 1 < mData.size()) {
3224 mCurrentChunk++;
3225 } else {
3226 size_t allocSize = CHUNK_SIZE;
3227 if (allocSize < size + alignment - 1) {
3228 allocSize = size + alignment - 1;
3229 }
3230 Chunk chunk(allocSize);
3231 mData.push_back(chunk);
3232 mCurrentChunk++;
3233 }
3234 }
3235 return mData[mCurrentChunk].allocate(size, alignment);
3236 }
3237
3238 static const size_t CHUNK_SIZE = 128*1024;
3239 // Note: this class does not deallocate its
3240 // memory when it's destroyed. It depends upon
3241 // its parent to deallocate the memory.
3242 struct Chunk {
3243 Chunk() {
3244 mpData = 0;
3245 mSize = 0;
3246 mOffset = 0;
3247 }
3248
3249 Chunk(size_t size) {
3250 mSize = size;
3251 mpData = (char*) malloc(size);
3252 mOffset = 0;
3253 }
3254
3255 ~Chunk() {
3256 // Doesn't deallocate memory.
3257 }
3258
3259 void* allocate(size_t size, size_t alignment) {
3260 size_t alignedOffset = aligned(mOffset, alignment);
3261 void* result = mpData + alignedOffset;
3262 mOffset = alignedOffset + size;
3263 return result;
3264 }
3265
3266 void free() {
3267 if (mpData) {
3268 ::free(mpData);
3269 mpData = 0;
3270 }
3271 }
3272
3273 size_t remainingCapacity(size_t alignment) {
3274 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3275 }
3276
3277 // Assume alignment is a power of two
3278 inline size_t aligned(size_t v, size_t alignment) {
3279 size_t mask = alignment-1;
3280 return (v + mask) & ~mask;
3281 }
3282
3283 char* mpData;
3284 size_t mSize;
3285 size_t mOffset;
3286 };
3287
3288 size_t mCurrentChunk;
3289
3290 Vector<Chunk> mData;
3291 };
3292
Jack Palevich569f1352009-06-29 14:29:08 -07003293 struct VariableInfo;
3294
3295 struct Token {
3296 int hash;
3297 size_t length;
3298 char* pText;
3299 tokenid_t id;
3300
3301 // Current values for the token
3302 char* mpMacroDefinition;
3303 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003304 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003305 };
3306
3307 class TokenTable {
3308 public:
3309 // Don't use 0..0xff, allows characters and operators to be tokens too.
3310
3311 static const int TOKEN_BASE = 0x100;
3312 TokenTable() {
3313 mpMap = hashmapCreate(128, hashFn, equalsFn);
3314 }
3315
3316 ~TokenTable() {
3317 hashmapFree(mpMap);
3318 }
3319
3320 void setArena(Arena* pArena) {
3321 mpArena = pArena;
3322 }
3323
3324 // Returns a token for a given string of characters.
3325 tokenid_t intern(const char* pText, size_t length) {
3326 Token probe;
3327 int hash = hashmapHash((void*) pText, length);
3328 {
3329 Token probe;
3330 probe.hash = hash;
3331 probe.length = length;
3332 probe.pText = (char*) pText;
3333 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3334 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003335 return pValue->id;
3336 }
3337 }
3338
3339 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3340 memset(pToken, 0, sizeof(*pToken));
3341 pToken->hash = hash;
3342 pToken->length = length;
3343 pToken->pText = (char*) mpArena->alloc(length + 1);
3344 memcpy(pToken->pText, pText, length);
3345 pToken->pText[length] = 0;
3346 pToken->id = mTokens.size() + TOKEN_BASE;
3347 mTokens.push_back(pToken);
3348 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003349 return pToken->id;
3350 }
3351
3352 // Return the Token for a given tokenid.
3353 Token& operator[](tokenid_t id) {
3354 return *mTokens[id - TOKEN_BASE];
3355 }
3356
3357 inline size_t size() {
3358 return mTokens.size();
3359 }
3360
3361 private:
3362
3363 static int hashFn(void* pKey) {
3364 Token* pToken = (Token*) pKey;
3365 return pToken->hash;
3366 }
3367
3368 static bool equalsFn(void* keyA, void* keyB) {
3369 Token* pTokenA = (Token*) keyA;
3370 Token* pTokenB = (Token*) keyB;
3371 // Don't need to compare hash values, they should always be equal
3372 return pTokenA->length == pTokenB->length
3373 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3374 }
3375
3376 Hashmap* mpMap;
3377 Vector<Token*> mTokens;
3378 Arena* mpArena;
3379 };
3380
Jack Palevich1cdef202009-05-22 12:06:27 -07003381 class InputStream {
3382 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003383 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003384 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003385 };
3386
3387 class TextInputStream : public InputStream {
3388 public:
3389 TextInputStream(const char* text, size_t textLength)
3390 : pText(text), mTextLength(textLength), mPosition(0) {
3391 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003392
Jack Palevichdc456462009-07-16 16:50:56 -07003393 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003394 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3395 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003396
Jack Palevichdc456462009-07-16 16:50:56 -07003397 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003398 const char* pText;
3399 size_t mTextLength;
3400 size_t mPosition;
3401 };
3402
Jack Palevicheedf9d22009-06-04 16:23:40 -07003403 class String {
3404 public:
3405 String() {
3406 mpBase = 0;
3407 mUsed = 0;
3408 mSize = 0;
3409 }
3410
Jack Palevich303d8ff2009-06-11 19:06:24 -07003411 String(const char* item, int len, bool adopt) {
3412 if (len < 0) {
3413 len = strlen(item);
3414 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003415 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003416 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003417 mUsed = len;
3418 mSize = len + 1;
3419 } else {
3420 mpBase = 0;
3421 mUsed = 0;
3422 mSize = 0;
3423 appendBytes(item, len);
3424 }
3425 }
3426
Jack Palevich303d8ff2009-06-11 19:06:24 -07003427 String(const String& other) {
3428 mpBase = 0;
3429 mUsed = 0;
3430 mSize = 0;
3431 appendBytes(other.getUnwrapped(), other.len());
3432 }
3433
Jack Palevicheedf9d22009-06-04 16:23:40 -07003434 ~String() {
3435 if (mpBase) {
3436 free(mpBase);
3437 }
3438 }
3439
Jack Palevicha6baa232009-06-12 11:25:59 -07003440 String& operator=(const String& other) {
3441 clear();
3442 appendBytes(other.getUnwrapped(), other.len());
3443 return *this;
3444 }
3445
Jack Palevich303d8ff2009-06-11 19:06:24 -07003446 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003447 return mpBase;
3448 }
3449
Jack Palevich303d8ff2009-06-11 19:06:24 -07003450 void clear() {
3451 mUsed = 0;
3452 if (mSize > 0) {
3453 mpBase[0] = 0;
3454 }
3455 }
3456
Jack Palevicheedf9d22009-06-04 16:23:40 -07003457 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003458 appendBytes(s, strlen(s));
3459 }
3460
3461 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003462 memcpy(ensure(n), s, n + 1);
3463 }
3464
3465 void append(char c) {
3466 * ensure(1) = c;
3467 }
3468
Jack Palevich86351982009-06-30 18:09:56 -07003469 void append(String& other) {
3470 appendBytes(other.getUnwrapped(), other.len());
3471 }
3472
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003473 char* orphan() {
3474 char* result = mpBase;
3475 mpBase = 0;
3476 mUsed = 0;
3477 mSize = 0;
3478 return result;
3479 }
3480
Jack Palevicheedf9d22009-06-04 16:23:40 -07003481 void printf(const char* fmt,...) {
3482 va_list ap;
3483 va_start(ap, fmt);
3484 vprintf(fmt, ap);
3485 va_end(ap);
3486 }
3487
3488 void vprintf(const char* fmt, va_list ap) {
3489 char* temp;
3490 int numChars = vasprintf(&temp, fmt, ap);
3491 memcpy(ensure(numChars), temp, numChars+1);
3492 free(temp);
3493 }
3494
Jack Palevich303d8ff2009-06-11 19:06:24 -07003495 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003496 return mUsed;
3497 }
3498
3499 private:
3500 char* ensure(int n) {
3501 size_t newUsed = mUsed + n;
3502 if (newUsed > mSize) {
3503 size_t newSize = mSize * 2 + 10;
3504 if (newSize < newUsed) {
3505 newSize = newUsed;
3506 }
3507 mpBase = (char*) realloc(mpBase, newSize + 1);
3508 mSize = newSize;
3509 }
3510 mpBase[newUsed] = '\0';
3511 char* result = mpBase + mUsed;
3512 mUsed = newUsed;
3513 return result;
3514 }
3515
3516 char* mpBase;
3517 size_t mUsed;
3518 size_t mSize;
3519 };
3520
Jack Palevich569f1352009-06-29 14:29:08 -07003521 void internKeywords() {
3522 // Note: order has to match TOK_ constants
3523 static const char* keywords[] = {
3524 "int",
3525 "char",
3526 "void",
3527 "if",
3528 "else",
3529 "while",
3530 "break",
3531 "return",
3532 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003533 "auto",
3534 "case",
3535 "const",
3536 "continue",
3537 "default",
3538 "do",
3539 "double",
3540 "enum",
3541 "extern",
3542 "float",
3543 "goto",
3544 "long",
3545 "register",
3546 "short",
3547 "signed",
3548 "sizeof",
3549 "static",
3550 "struct",
3551 "switch",
3552 "typedef",
3553 "union",
3554 "unsigned",
3555 "volatile",
3556 "_Bool",
3557 "_Complex",
3558 "_Imaginary",
3559 "inline",
3560 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003561
3562 // predefined tokens that can also be symbols start here:
3563 "pragma",
3564 "define",
3565 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003566 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003567
Jack Palevich569f1352009-06-29 14:29:08 -07003568 for(int i = 0; keywords[i]; i++) {
3569 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003570 }
Jack Palevich569f1352009-06-29 14:29:08 -07003571 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003572
Jack Palevich36d94142009-06-08 15:55:32 -07003573 struct InputState {
3574 InputStream* pStream;
3575 int oldCh;
3576 };
3577
Jack Palevich2db168f2009-06-11 14:29:47 -07003578 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003579 void* pAddress;
3580 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003581 tokenid_t tok;
3582 size_t level;
3583 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003584 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003585 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003586 };
3587
Jack Palevich303d8ff2009-06-11 19:06:24 -07003588 class SymbolStack {
3589 public:
3590 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003591 mpArena = 0;
3592 mpTokenTable = 0;
3593 }
3594
3595 void setArena(Arena* pArena) {
3596 mpArena = pArena;
3597 }
3598
3599 void setTokenTable(TokenTable* pTokenTable) {
3600 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003601 }
3602
3603 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003604 Mark mark;
3605 mark.mArenaMark = mpArena->mark();
3606 mark.mSymbolHead = mStack.size();
3607 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003608 }
3609
3610 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003611 // Undo any shadowing that was done:
3612 Mark mark = mLevelStack.back();
3613 mLevelStack.pop_back();
3614 while (mStack.size() > mark.mSymbolHead) {
3615 VariableInfo* pV = mStack.back();
3616 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003617 if (pV->isStructTag) {
3618 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3619 } else {
3620 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3621 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003622 }
Jack Palevich569f1352009-06-29 14:29:08 -07003623 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003624 }
3625
Jack Palevich569f1352009-06-29 14:29:08 -07003626 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3627 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3628 return pV && pV->level == level();
3629 }
3630
Jack Palevich9221bcc2009-08-26 16:15:07 -07003631 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3632 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3633 return pV && pV->level == level();
3634 }
3635
Jack Palevich569f1352009-06-29 14:29:08 -07003636 VariableInfo* add(tokenid_t tok) {
3637 Token& token = (*mpTokenTable)[tok];
3638 VariableInfo* pOldV = token.mpVariableInfo;
3639 VariableInfo* pNewV =
3640 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3641 memset(pNewV, 0, sizeof(VariableInfo));
3642 pNewV->tok = tok;
3643 pNewV->level = level();
3644 pNewV->pOldDefinition = pOldV;
3645 token.mpVariableInfo = pNewV;
3646 mStack.push_back(pNewV);
3647 return pNewV;
3648 }
3649
Jack Palevich9221bcc2009-08-26 16:15:07 -07003650 VariableInfo* addStructTag(tokenid_t tok) {
3651 Token& token = (*mpTokenTable)[tok];
3652 VariableInfo* pOldS = token.mpStructInfo;
3653 VariableInfo* pNewS =
3654 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3655 memset(pNewS, 0, sizeof(VariableInfo));
3656 pNewS->tok = tok;
3657 pNewS->level = level();
3658 pNewS->isStructTag = true;
3659 pNewS->pOldDefinition = pOldS;
3660 token.mpStructInfo = pNewS;
3661 mStack.push_back(pNewS);
3662 return pNewS;
3663 }
3664
Jack Palevich86351982009-06-30 18:09:56 -07003665 VariableInfo* add(Type* pType) {
3666 VariableInfo* pVI = add(pType->id);
3667 pVI->pType = pType;
3668 return pVI;
3669 }
3670
Jack Palevich569f1352009-06-29 14:29:08 -07003671 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3672 for (size_t i = 0; i < mStack.size(); i++) {
3673 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003674 break;
3675 }
3676 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003677 }
3678
Jack Palevich303d8ff2009-06-11 19:06:24 -07003679 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003680 inline size_t level() {
3681 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003682 }
3683
Jack Palevich569f1352009-06-29 14:29:08 -07003684 struct Mark {
3685 Arena::Mark mArenaMark;
3686 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003687 };
3688
Jack Palevich569f1352009-06-29 14:29:08 -07003689 Arena* mpArena;
3690 TokenTable* mpTokenTable;
3691 Vector<VariableInfo*> mStack;
3692 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003693 };
Jack Palevich36d94142009-06-08 15:55:32 -07003694
3695 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003696 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003697 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003698 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003699 int tokl; // token operator level
3700 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003701 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003702 intptr_t loc; // local variable index
3703 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003704 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003705 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003706 char* dptr; // Macro state: Points to macro text during macro playback.
3707 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003708 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003709 ACCSymbolLookupFn mpSymbolLookupFn;
3710 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003711
3712 // Arena for the duration of the compile
3713 Arena mGlobalArena;
3714 // Arena for data that's only needed when compiling a single function
3715 Arena mLocalArena;
3716
Jack Palevich2ff5c222009-07-23 15:11:22 -07003717 Arena* mpCurrentArena;
3718
Jack Palevich569f1352009-06-29 14:29:08 -07003719 TokenTable mTokenTable;
3720 SymbolStack mGlobals;
3721 SymbolStack mLocals;
3722
Jack Palevich9221bcc2009-08-26 16:15:07 -07003723 SymbolStack* mpCurrentSymbolStack;
3724
Jack Palevich40600de2009-07-01 15:32:35 -07003725 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003726 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003727 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003728 Type* mkpChar; // char
3729 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003730 Type* mkpFloat;
3731 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003732 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003733 Type* mkpIntPtr;
3734 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003735 Type* mkpFloatPtr;
3736 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003737 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003738
Jack Palevich36d94142009-06-08 15:55:32 -07003739 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003740 int mLineNumber;
3741 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003742
3743 CodeBuf codeBuf;
3744 CodeGenerator* pGen;
3745
Jack Palevicheedf9d22009-06-04 16:23:40 -07003746 String mErrorBuf;
3747
Jack Palevicheedf9d22009-06-04 16:23:40 -07003748 String mPragmas;
3749 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003750 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003751
Jack Palevich21a15a22009-05-11 14:49:29 -07003752 static const int ALLOC_SIZE = 99999;
3753
Jack Palevich303d8ff2009-06-11 19:06:24 -07003754 static const int TOK_DUMMY = 1;
3755 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003756 static const int TOK_NUM_FLOAT = 3;
3757 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003758 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003759 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003760
3761 // 3..255 are character and/or operators
3762
Jack Palevich2db168f2009-06-11 14:29:47 -07003763 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003764 // Order has to match string list in "internKeywords".
3765 enum {
3766 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3767 TOK_INT = TOK_KEYWORD,
3768 TOK_CHAR,
3769 TOK_VOID,
3770 TOK_IF,
3771 TOK_ELSE,
3772 TOK_WHILE,
3773 TOK_BREAK,
3774 TOK_RETURN,
3775 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003776 TOK_AUTO,
3777 TOK_CASE,
3778 TOK_CONST,
3779 TOK_CONTINUE,
3780 TOK_DEFAULT,
3781 TOK_DO,
3782 TOK_DOUBLE,
3783 TOK_ENUM,
3784 TOK_EXTERN,
3785 TOK_FLOAT,
3786 TOK_GOTO,
3787 TOK_LONG,
3788 TOK_REGISTER,
3789 TOK_SHORT,
3790 TOK_SIGNED,
3791 TOK_SIZEOF,
3792 TOK_STATIC,
3793 TOK_STRUCT,
3794 TOK_SWITCH,
3795 TOK_TYPEDEF,
3796 TOK_UNION,
3797 TOK_UNSIGNED,
3798 TOK_VOLATILE,
3799 TOK__BOOL,
3800 TOK__COMPLEX,
3801 TOK__IMAGINARY,
3802 TOK_INLINE,
3803 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003804
3805 // Symbols start after keywords
3806
3807 TOK_SYMBOL,
3808 TOK_PRAGMA = TOK_SYMBOL,
3809 TOK_DEFINE,
3810 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003811 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003812
3813 static const int LOCAL = 0x200;
3814
3815 static const int SYM_FORWARD = 0;
3816 static const int SYM_DEFINE = 1;
3817
3818 /* tokens in string heap */
3819 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003820
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003821 static const int OP_INCREMENT = 0;
3822 static const int OP_DECREMENT = 1;
3823 static const int OP_MUL = 2;
3824 static const int OP_DIV = 3;
3825 static const int OP_MOD = 4;
3826 static const int OP_PLUS = 5;
3827 static const int OP_MINUS = 6;
3828 static const int OP_SHIFT_LEFT = 7;
3829 static const int OP_SHIFT_RIGHT = 8;
3830 static const int OP_LESS_EQUAL = 9;
3831 static const int OP_GREATER_EQUAL = 10;
3832 static const int OP_LESS = 11;
3833 static const int OP_GREATER = 12;
3834 static const int OP_EQUALS = 13;
3835 static const int OP_NOT_EQUALS = 14;
3836 static const int OP_LOGICAL_AND = 15;
3837 static const int OP_LOGICAL_OR = 16;
3838 static const int OP_BIT_AND = 17;
3839 static const int OP_BIT_XOR = 18;
3840 static const int OP_BIT_OR = 19;
3841 static const int OP_BIT_NOT = 20;
3842 static const int OP_LOGICAL_NOT = 21;
3843 static const int OP_COUNT = 22;
3844
3845 /* Operators are searched from front, the two-character operators appear
3846 * before the single-character operators with the same first character.
3847 * @ is used to pad out single-character operators.
3848 */
3849 static const char* operatorChars;
3850 static const char operatorLevel[];
3851
Jack Palevich569f1352009-06-29 14:29:08 -07003852 /* Called when we detect an internal problem. Does nothing in production.
3853 *
3854 */
3855 void internalError() {
3856 * (char*) 0 = 0;
3857 }
3858
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003859 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003860 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07003861 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003862 internalError();
3863 }
Jack Palevich86351982009-06-30 18:09:56 -07003864 }
3865
Jack Palevich40600de2009-07-01 15:32:35 -07003866 bool isSymbol(tokenid_t t) {
3867 return t >= TOK_SYMBOL &&
3868 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3869 }
3870
3871 bool isSymbolOrKeyword(tokenid_t t) {
3872 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003873 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003874 }
3875
Jack Palevich86351982009-06-30 18:09:56 -07003876 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003877 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003878 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3879 if (pV && pV->tok != t) {
3880 internalError();
3881 }
3882 return pV;
3883 }
3884
3885 inline bool isDefined(tokenid_t t) {
3886 return t >= TOK_SYMBOL && VI(t) != 0;
3887 }
3888
Jack Palevich40600de2009-07-01 15:32:35 -07003889 const char* nameof(tokenid_t t) {
3890 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003891 return mTokenTable[t].pText;
3892 }
3893
Jack Palevich21a15a22009-05-11 14:49:29 -07003894 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003895 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003896 }
3897
3898 void inp() {
3899 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003900 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003901 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003902 dptr = 0;
3903 ch = dch;
3904 }
Jack Palevichdc456462009-07-16 16:50:56 -07003905 } else {
3906 if (mbBumpLine) {
3907 mLineNumber++;
3908 mbBumpLine = false;
3909 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003910 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003911 if (ch == '\n') {
3912 mbBumpLine = true;
3913 }
3914 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003915#if 0
3916 printf("ch='%c' 0x%x\n", ch, ch);
3917#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003918 }
3919
3920 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003921 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003922 }
3923
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003924 int decodeHex(int c) {
3925 if (isdigit(c)) {
3926 c -= '0';
3927 } else if (c <= 'F') {
3928 c = c - 'A' + 10;
3929 } else {
3930 c =c - 'a' + 10;
3931 }
3932 return c;
3933 }
3934
Jack Palevichb4758ff2009-06-12 12:49:14 -07003935 /* read a character constant, advances ch to after end of constant */
3936 int getq() {
3937 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003938 if (ch == '\\') {
3939 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003940 if (isoctal(ch)) {
3941 // 1 to 3 octal characters.
3942 val = 0;
3943 for(int i = 0; i < 3; i++) {
3944 if (isoctal(ch)) {
3945 val = (val << 3) + ch - '0';
3946 inp();
3947 }
3948 }
3949 return val;
3950 } else if (ch == 'x' || ch == 'X') {
3951 // N hex chars
3952 inp();
3953 if (! isxdigit(ch)) {
3954 error("'x' character escape requires at least one digit.");
3955 } else {
3956 val = 0;
3957 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003958 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003959 inp();
3960 }
3961 }
3962 } else {
3963 int val = ch;
3964 switch (ch) {
3965 case 'a':
3966 val = '\a';
3967 break;
3968 case 'b':
3969 val = '\b';
3970 break;
3971 case 'f':
3972 val = '\f';
3973 break;
3974 case 'n':
3975 val = '\n';
3976 break;
3977 case 'r':
3978 val = '\r';
3979 break;
3980 case 't':
3981 val = '\t';
3982 break;
3983 case 'v':
3984 val = '\v';
3985 break;
3986 case '\\':
3987 val = '\\';
3988 break;
3989 case '\'':
3990 val = '\'';
3991 break;
3992 case '"':
3993 val = '"';
3994 break;
3995 case '?':
3996 val = '?';
3997 break;
3998 default:
3999 error("Undefined character escape %c", ch);
4000 break;
4001 }
4002 inp();
4003 return val;
4004 }
4005 } else {
4006 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004007 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004008 return val;
4009 }
4010
4011 static bool isoctal(int ch) {
4012 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004013 }
4014
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004015 bool acceptCh(int c) {
4016 bool result = c == ch;
4017 if (result) {
4018 pdef(ch);
4019 inp();
4020 }
4021 return result;
4022 }
4023
4024 bool acceptDigitsCh() {
4025 bool result = false;
4026 while (isdigit(ch)) {
4027 result = true;
4028 pdef(ch);
4029 inp();
4030 }
4031 return result;
4032 }
4033
4034 void parseFloat() {
4035 tok = TOK_NUM_DOUBLE;
4036 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004037 if(mTokenString.len() == 0) {
4038 mTokenString.append('0');
4039 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004040 acceptCh('.');
4041 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004042 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004043 acceptCh('-') || acceptCh('+');
4044 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004045 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004046 if (ch == 'f' || ch == 'F') {
4047 tok = TOK_NUM_FLOAT;
4048 inp();
4049 } else if (ch == 'l' || ch == 'L') {
4050 inp();
4051 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004052 }
4053 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004054 char* pEnd = pText + strlen(pText);
4055 char* pEndPtr = 0;
4056 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004057 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004058 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004059 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004060 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004061 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004062 if (errno || pEndPtr != pEnd) {
4063 error("Can't parse constant: %s", pText);
4064 }
4065 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004066 }
4067
Jack Palevich21a15a22009-05-11 14:49:29 -07004068 void next() {
4069 int l, a;
4070
Jack Palevich546b2242009-05-13 15:10:04 -07004071 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004072 if (ch == '#') {
4073 inp();
4074 next();
4075 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004076 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004077 } else if (tok == TOK_PRAGMA) {
4078 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004079 } else if (tok == TOK_LINE) {
4080 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004081 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004082 error("Unsupported preprocessor directive \"%s\"",
4083 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004084 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004085 }
4086 inp();
4087 }
4088 tokl = 0;
4089 tok = ch;
4090 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004091 if (isdigit(ch) || ch == '.') {
4092 // Start of a numeric constant. Could be integer, float, or
4093 // double, won't know until we look further.
4094 mTokenString.clear();
4095 pdef(ch);
4096 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004097 if (tok == '.' && !isdigit(ch)) {
4098 goto done;
4099 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004100 int base = 10;
4101 if (tok == '0') {
4102 if (ch == 'x' || ch == 'X') {
4103 base = 16;
4104 tok = TOK_NUM;
4105 tokc = 0;
4106 inp();
4107 while ( isxdigit(ch) ) {
4108 tokc = (tokc << 4) + decodeHex(ch);
4109 inp();
4110 }
4111 } else if (isoctal(ch)){
4112 base = 8;
4113 tok = TOK_NUM;
4114 tokc = 0;
4115 while ( isoctal(ch) ) {
4116 tokc = (tokc << 3) + (ch - '0');
4117 inp();
4118 }
4119 }
4120 } else if (isdigit(tok)){
4121 acceptDigitsCh();
4122 }
4123 if (base == 10) {
4124 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4125 parseFloat();
4126 } else {
4127 // It's an integer constant
4128 char* pText = mTokenString.getUnwrapped();
4129 char* pEnd = pText + strlen(pText);
4130 char* pEndPtr = 0;
4131 errno = 0;
4132 tokc = strtol(pText, &pEndPtr, base);
4133 if (errno || pEndPtr != pEnd) {
4134 error("Can't parse constant: %s %d %d", pText, base, errno);
4135 }
4136 tok = TOK_NUM;
4137 }
4138 }
4139 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004140 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004141 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004142 pdef(ch);
4143 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004144 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004145 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004146 if (! mbSuppressMacroExpansion) {
4147 // Is this a macro?
4148 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4149 if (pMacroDefinition) {
4150 // Yes, it is a macro
4151 dptr = pMacroDefinition;
4152 dch = ch;
4153 inp();
4154 next();
4155 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004156 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004157 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004158 inp();
4159 if (tok == '\'') {
4160 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004161 tokc = getq();
4162 if (ch != '\'') {
4163 error("Expected a ' character, got %c", ch);
4164 } else {
4165 inp();
4166 }
Jack Palevich546b2242009-05-13 15:10:04 -07004167 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004168 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004169 while (ch && ch != EOF) {
4170 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004171 inp();
4172 inp();
4173 if (ch == '/')
4174 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004175 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004176 if (ch == EOF) {
4177 error("End of file inside comment.");
4178 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004179 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004180 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004181 } else if ((tok == '/') & (ch == '/')) {
4182 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004183 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004184 inp();
4185 }
4186 inp();
4187 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004188 } else if ((tok == '-') & (ch == '>')) {
4189 inp();
4190 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004191 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004192 const char* t = operatorChars;
4193 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004194 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004195 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004196 tokl = operatorLevel[opIndex];
4197 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004198 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004199#if 0
4200 printf("%c%c -> tokl=%d tokc=0x%x\n",
4201 l, a, tokl, tokc);
4202#endif
4203 if (a == ch) {
4204 inp();
4205 tok = TOK_DUMMY; /* dummy token for double tokens */
4206 }
Jack Palevich0c017742009-07-31 12:00:39 -07004207 /* check for op=, valid for * / % + - << >> & ^ | */
4208 if (ch == '=' &&
4209 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004210 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004211 inp();
4212 tok = TOK_OP_ASSIGNMENT;
4213 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004214 break;
4215 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004216 opIndex++;
4217 }
4218 if (l == 0) {
4219 tokl = 0;
4220 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004221 }
4222 }
4223 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004224
4225 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004226#if 0
4227 {
Jack Palevich569f1352009-06-29 14:29:08 -07004228 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004229 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004230 fprintf(stderr, "%s\n", buf.getUnwrapped());
4231 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004232#endif
4233 }
4234
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004235 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004236 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004237 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004238 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004239 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004240 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004241 if (ch == '(') {
4242 delete pName;
4243 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004244 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004245 }
4246 while (isspace(ch)) {
4247 inp();
4248 }
Jack Palevich569f1352009-06-29 14:29:08 -07004249 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004250 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004251 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004252 // Check for '//' comments.
4253 if (appendToValue && ch == '/') {
4254 inp();
4255 if (ch == '/') {
4256 appendToValue = false;
4257 } else {
4258 value.append('/');
4259 }
4260 }
4261 if (appendToValue && ch != EOF) {
4262 value.append(ch);
4263 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004264 inp();
4265 }
Jack Palevich569f1352009-06-29 14:29:08 -07004266 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4267 memcpy(pDefn, value.getUnwrapped(), value.len());
4268 pDefn[value.len()] = 0;
4269 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004270 }
4271
Jack Palevicheedf9d22009-06-04 16:23:40 -07004272 void doPragma() {
4273 // # pragma name(val)
4274 int state = 0;
4275 while(ch != EOF && ch != '\n' && state < 10) {
4276 switch(state) {
4277 case 0:
4278 if (isspace(ch)) {
4279 inp();
4280 } else {
4281 state++;
4282 }
4283 break;
4284 case 1:
4285 if (isalnum(ch)) {
4286 mPragmas.append(ch);
4287 inp();
4288 } else if (ch == '(') {
4289 mPragmas.append(0);
4290 inp();
4291 state++;
4292 } else {
4293 state = 11;
4294 }
4295 break;
4296 case 2:
4297 if (isalnum(ch)) {
4298 mPragmas.append(ch);
4299 inp();
4300 } else if (ch == ')') {
4301 mPragmas.append(0);
4302 inp();
4303 state = 10;
4304 } else {
4305 state = 11;
4306 }
4307 break;
4308 }
4309 }
4310 if(state != 10) {
4311 error("Unexpected pragma syntax");
4312 }
4313 mPragmaStringCount += 2;
4314 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004315
Jack Palevichdc456462009-07-16 16:50:56 -07004316 void doLine() {
4317 // # line number { "filename "}
4318 next();
4319 if (tok != TOK_NUM) {
4320 error("Expected a line-number");
4321 } else {
4322 mLineNumber = tokc-1; // The end-of-line will increment it.
4323 }
4324 while(ch != EOF && ch != '\n') {
4325 inp();
4326 }
4327 }
4328
Jack Palevichac0e95e2009-05-29 13:53:44 -07004329 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004330 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004331 mErrorBuf.vprintf(fmt, ap);
4332 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004333 }
4334
Jack Palevich8b0624c2009-05-20 12:12:06 -07004335 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004336 if (tok != c) {
4337 error("'%c' expected", c);
4338 }
4339 next();
4340 }
4341
Jack Palevich86351982009-06-30 18:09:56 -07004342 bool accept(intptr_t c) {
4343 if (tok == c) {
4344 next();
4345 return true;
4346 }
4347 return false;
4348 }
4349
Jack Palevich40600de2009-07-01 15:32:35 -07004350 bool acceptStringLiteral() {
4351 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004352 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004353 // This while loop merges multiple adjacent string constants.
4354 while (tok == '"') {
4355 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004356 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004357 }
4358 if (ch != '"') {
4359 error("Unterminated string constant.");
4360 }
4361 inp();
4362 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004363 }
Jack Palevich40600de2009-07-01 15:32:35 -07004364 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004365 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004366 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004367 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004368
4369 return true;
4370 }
4371 return false;
4372 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004373
Jack Palevichb1544ca2009-07-16 15:09:20 -07004374 void linkGlobal(tokenid_t t, bool isFunction) {
4375 VariableInfo* pVI = VI(t);
4376 void* n = NULL;
4377 if (mpSymbolLookupFn) {
4378 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4379 }
4380 if (pVI->pType == NULL) {
4381 if (isFunction) {
4382 pVI->pType = mkpIntFn;
4383 } else {
4384 pVI->pType = mkpInt;
4385 }
4386 }
4387 pVI->pAddress = n;
4388 }
4389
Jack Palevich29daf572009-07-30 19:38:55 -07004390 void unaryOrAssignment() {
4391 unary();
4392 if (accept('=')) {
4393 checkLVal();
4394 pGen->pushR0();
4395 expr();
4396 pGen->forceR0RVal();
4397 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004398 } else if (tok == TOK_OP_ASSIGNMENT) {
4399 int t = tokc;
4400 next();
4401 checkLVal();
4402 pGen->pushR0();
4403 pGen->forceR0RVal();
4404 pGen->pushR0();
4405 expr();
4406 pGen->forceR0RVal();
4407 pGen->genOp(t);
4408 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004409 }
4410 }
4411
Jack Palevich40600de2009-07-01 15:32:35 -07004412 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004413 */
Jack Palevich29daf572009-07-30 19:38:55 -07004414 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004415 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004416 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004417 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004418 if (acceptStringLiteral()) {
4419 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004420 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004421 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004422 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004423 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004424 t = tok;
4425 next();
4426 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004427 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004428 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004429 // Align to 4-byte boundary
4430 glo = (char*) (((intptr_t) glo + 3) & -4);
4431 * (float*) glo = (float) ad;
4432 pGen->loadFloat((int) glo, mkpFloat);
4433 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004434 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004435 // Align to 8-byte boundary
4436 glo = (char*) (((intptr_t) glo + 7) & -8);
4437 * (double*) glo = ad;
4438 pGen->loadFloat((int) glo, mkpDouble);
4439 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004440 } else if (c == 2) {
4441 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004442 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004443 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004444 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004445 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004446 else if (t == '+') {
4447 // ignore unary plus.
4448 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004449 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004450 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004451 } else if (c == 11) {
4452 // pre increment / pre decrement
4453 unary();
4454 doIncDec(a == OP_INCREMENT, 0);
4455 }
4456 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004457 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004458 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004459 if (pCast) {
4460 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004461 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004462 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004463 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004464 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004465 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004466 skip(')');
4467 }
4468 } else if (t == '*') {
4469 /* This is a pointer dereference.
4470 */
Jack Palevich29daf572009-07-30 19:38:55 -07004471 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004472 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004473 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004474 unary();
4475 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004476 } else if (t == EOF ) {
4477 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004478 } else if (t == ';') {
4479 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004480 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004481 // Don't have to do anything special here, the error
4482 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004483 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004484 if (!isDefined(t)) {
4485 mGlobals.add(t);
4486 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004487 }
Jack Palevich8df46192009-07-07 14:48:51 -07004488 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004489 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004490 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004491 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004492 linkGlobal(t, tok == '(');
4493 n = (intptr_t) pVI->pAddress;
4494 if (!n && tok != '(') {
4495 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004496 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004497 }
Jack Palevich29daf572009-07-30 19:38:55 -07004498 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004499 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004500 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004501 linkGlobal(t, false);
4502 n = (intptr_t) pVI->pAddress;
4503 if (!n) {
4504 error("Undeclared variable %s\n", nameof(t));
4505 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004506 }
Jack Palevich5b659092009-07-31 14:55:07 -07004507 }
4508 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004509 Type* pVal;
4510 ExpressionType et;
4511 if (pVI->pType->tag == TY_ARRAY) {
4512 pVal = pVI->pType;
4513 et = ET_RVALUE;
4514 } else {
4515 pVal = createPtrType(pVI->pType);
4516 et = ET_LVALUE;
4517 }
Jack Palevich5b659092009-07-31 14:55:07 -07004518 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004519 int tag = pVal->pHead->tag;
4520 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004521 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004522 }
Jack Palevich5b659092009-07-31 14:55:07 -07004523 pGen->leaR0(n, pVal, et);
4524 } else {
4525 pVI->pForward = (void*) pGen->leaForward(
4526 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004527 }
4528 }
4529 }
4530
Jack Palevich5b659092009-07-31 14:55:07 -07004531 /* Now handle postfix operators */
4532 for(;;) {
4533 if (tokl == 11) {
4534 // post inc / post dec
4535 doIncDec(tokc == OP_INCREMENT, true);
4536 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004537 } else if (accept('[')) {
4538 // Array reference
4539 pGen->forceR0RVal();
4540 pGen->pushR0();
4541 commaExpr();
4542 pGen->forceR0RVal();
4543 pGen->genOp(OP_PLUS);
4544 doPointer();
4545 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004546 } else if (accept('.')) {
4547 // struct element
4548 pGen->forceR0RVal();
4549 Type* pStruct = pGen->getR0Type();
4550 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004551 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004552 } else {
4553 error("expected a struct value to the left of '.'");
4554 }
4555 } else if (accept(TOK_OP_ARROW)) {
4556 pGen->forceR0RVal();
4557 Type* pPtr = pGen->getR0Type();
4558 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4559 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004560 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004561 } else {
4562 error("Expected a pointer to a struct to the left of '->'");
4563 }
Jack Palevich5b659092009-07-31 14:55:07 -07004564 } else if (accept('(')) {
4565 /* function call */
4566 Type* pDecl = NULL;
4567 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004568 Type* pFn = pGen->getR0Type();
4569 assert(pFn->tag == TY_POINTER);
4570 assert(pFn->pHead->tag == TY_FUNC);
4571 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004572 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004573 Type* pArgList = pDecl->pTail;
4574 bool varArgs = pArgList == NULL;
4575 /* push args and invert order */
4576 a = pGen->beginFunctionCallArguments();
4577 int l = 0;
4578 int argCount = 0;
4579 while (tok != ')' && tok != EOF) {
4580 if (! varArgs && !pArgList) {
4581 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004582 }
Jack Palevich5b659092009-07-31 14:55:07 -07004583 expr();
4584 pGen->forceR0RVal();
4585 Type* pTargetType;
4586 if (pArgList) {
4587 pTargetType = pArgList->pHead;
4588 pArgList = pArgList->pTail;
4589 } else {
4590 // This is a ... function, just pass arguments in their
4591 // natural type.
4592 pTargetType = pGen->getR0Type();
4593 if (pTargetType->tag == TY_FLOAT) {
4594 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004595 } else if (pTargetType->tag == TY_ARRAY) {
4596 // Pass arrays by pointer.
4597 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004598 }
4599 }
4600 if (pTargetType->tag == TY_VOID) {
4601 error("Can't pass void value for argument %d",
4602 argCount + 1);
4603 } else {
4604 l += pGen->storeR0ToArg(l, pTargetType);
4605 }
4606 if (accept(',')) {
4607 // fine
4608 } else if ( tok != ')') {
4609 error("Expected ',' or ')'");
4610 }
4611 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004612 }
Jack Palevich5b659092009-07-31 14:55:07 -07004613 if (! varArgs && pArgList) {
4614 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004615 }
Jack Palevich5b659092009-07-31 14:55:07 -07004616 pGen->endFunctionCallArguments(pDecl, a, l);
4617 skip(')');
4618 pGen->callIndirect(l, pDecl);
4619 pGen->adjustStackAfterCall(pDecl, l, true);
4620 } else {
4621 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004622 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004623 }
4624 }
4625
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004626 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004627 Type* pStructElement = lookupStructMember(pStruct, tok);
4628 if (pStructElement) {
4629 next();
4630 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4631 } else {
4632 String buf;
4633 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004634 error("Expected a struct member to the right of '%s', got %s",
4635 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004636 }
4637 }
4638
Jack Palevichaaac9282009-07-31 14:34:34 -07004639 void doIncDec(int isInc, int isPost) {
4640 // R0 already has the lval
4641 checkLVal();
4642 int lit = isInc ? 1 : -1;
4643 pGen->pushR0();
4644 pGen->loadR0FromR0();
4645 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004646 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4647 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004648 error("++/-- illegal for this type. %d", tag);
4649 }
4650 if (isPost) {
4651 pGen->over();
4652 pGen->pushR0();
4653 pGen->li(lit);
4654 pGen->genOp(OP_PLUS);
4655 pGen->storeR0ToTOS();
4656 pGen->popR0();
4657 } else {
4658 pGen->pushR0();
4659 pGen->li(lit);
4660 pGen->genOp(OP_PLUS);
4661 pGen->over();
4662 pGen->storeR0ToTOS();
4663 pGen->popR0();
4664 }
4665 }
4666
Jack Palevich47cbea92009-07-31 15:25:53 -07004667 void doPointer() {
4668 pGen->forceR0RVal();
4669 Type* pR0Type = pGen->getR0Type();
4670 if (pR0Type->tag != TY_POINTER) {
4671 error("Expected a pointer type.");
4672 } else {
4673 if (pR0Type->pHead->tag != TY_FUNC) {
4674 pGen->setR0ExpressionType(ET_LVALUE);
4675 }
4676 }
4677 }
4678
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004679 void doAddressOf() {
4680 Type* pR0 = pGen->getR0Type();
4681 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4682 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4683 error("Expected an lvalue");
4684 }
4685 Type* pR0Type = pGen->getR0Type();
4686 pGen->setR0ExpressionType(ET_RVALUE);
4687 }
4688
Jack Palevich40600de2009-07-01 15:32:35 -07004689 /* Recursive descent parser for binary operations.
4690 */
4691 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004692 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004693 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004694 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004695 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004696 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004697 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004698 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004699 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004700 t = tokc;
4701 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004702 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004703 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004704 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004705 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004706 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004707 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004708 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004709 // Check for syntax error.
4710 if (pGen->getR0Type() == NULL) {
4711 // We failed to parse a right-hand argument.
4712 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004713 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004714 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004715 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004716 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004717 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004718 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004719 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004720 }
4721 }
4722 }
4723 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004724 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004725 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004726 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004727 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004728 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004729 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004730 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004731 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004732 }
4733 }
4734 }
4735
Jack Palevich43aaee32009-07-31 14:01:37 -07004736 void commaExpr() {
4737 for(;;) {
4738 expr();
4739 if (!accept(',')) {
4740 break;
4741 }
4742 }
4743 }
4744
Jack Palevich21a15a22009-05-11 14:49:29 -07004745 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004746 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004747 }
4748
4749 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004750 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004751 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004752 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004753 }
4754
Jack Palevicha6baa232009-06-12 11:25:59 -07004755 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004756 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004757
Jack Palevich95727a02009-07-06 12:07:15 -07004758 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004759 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004760 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004761 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004762 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004763 next();
4764 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004765 a = test_expr();
4766 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004767 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004768 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004769 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004770 n = pGen->gjmp(0); /* jmp */
4771 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004772 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004773 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004774 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004775 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004776 }
Jack Palevich546b2242009-05-13 15:10:04 -07004777 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004778 t = tok;
4779 next();
4780 skip('(');
4781 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004782 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004783 a = test_expr();
4784 } else {
4785 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004786 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004787 skip(';');
4788 n = codeBuf.getPC();
4789 a = 0;
4790 if (tok != ';')
4791 a = test_expr();
4792 skip(';');
4793 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004794 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004795 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004796 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004797 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004798 n = t + 4;
4799 }
4800 }
4801 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004802 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004803 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004804 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004805 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004806 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004807 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004808 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004809 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004810 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004811 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004812 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004813 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004814 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004815 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004816 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004817 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004818 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004819 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004820 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004821 if (pReturnType->tag == TY_VOID) {
4822 error("Must not return a value from a void function");
4823 } else {
4824 pGen->convertR0(pReturnType);
4825 }
4826 } else {
4827 if (pReturnType->tag != TY_VOID) {
4828 error("Must specify a value here");
4829 }
Jack Palevich8df46192009-07-07 14:48:51 -07004830 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004831 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004832 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004833 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004834 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004835 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004836 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004837 }
4838 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004839
Jack Palevicha8f427f2009-07-13 18:40:08 -07004840 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004841 if (a == b) {
4842 return true;
4843 }
4844 if (a == NULL || b == NULL) {
4845 return false;
4846 }
4847 TypeTag at = a->tag;
4848 if (at != b->tag) {
4849 return false;
4850 }
4851 if (at == TY_POINTER) {
4852 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004853 } else if (at == TY_ARRAY) {
4854 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004855 } else if (at == TY_FUNC || at == TY_PARAM) {
4856 return typeEqual(a->pHead, b->pHead)
4857 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004858 } else if (at == TY_STRUCT) {
4859 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004860 }
4861 return true;
4862 }
4863
Jack Palevich2ff5c222009-07-23 15:11:22 -07004864 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004865 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004866 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004867 memset(pType, 0, sizeof(*pType));
4868 pType->tag = tag;
4869 pType->pHead = pHead;
4870 pType->pTail = pTail;
4871 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004872 }
4873
Jack Palevich2ff5c222009-07-23 15:11:22 -07004874 Type* createPtrType(Type* pType) {
4875 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004876 }
4877
4878 /**
4879 * Try to print a type in declaration order
4880 */
Jack Palevich86351982009-06-30 18:09:56 -07004881 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004882 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004883 if (pType == NULL) {
4884 buffer.appendCStr("null");
4885 return;
4886 }
Jack Palevich3f226492009-07-02 14:46:19 -07004887 decodeTypeImp(buffer, pType);
4888 }
4889
4890 void decodeTypeImp(String& buffer, Type* pType) {
4891 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004892 decodeId(buffer, pType->id);
4893 decodeTypeImpPostfix(buffer, pType);
4894 }
Jack Palevich3f226492009-07-02 14:46:19 -07004895
Jack Palevich9221bcc2009-08-26 16:15:07 -07004896 void decodeId(String& buffer, tokenid_t id) {
4897 if (id) {
4898 String temp;
4899 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004900 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004901 }
Jack Palevich3f226492009-07-02 14:46:19 -07004902 }
4903
4904 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4905 TypeTag tag = pType->tag;
4906
Jack Palevich9221bcc2009-08-26 16:15:07 -07004907 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004908 switch (tag) {
4909 case TY_INT:
4910 buffer.appendCStr("int");
4911 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004912 case TY_SHORT:
4913 buffer.appendCStr("short");
4914 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004915 case TY_CHAR:
4916 buffer.appendCStr("char");
4917 break;
4918 case TY_VOID:
4919 buffer.appendCStr("void");
4920 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004921 case TY_FLOAT:
4922 buffer.appendCStr("float");
4923 break;
4924 case TY_DOUBLE:
4925 buffer.appendCStr("double");
4926 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004927 case TY_STRUCT:
4928 {
4929 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4930 buffer.appendCStr(isStruct ? "struct" : "union");
4931 if (pType->pHead && pType->pHead->structTag) {
4932 buffer.append(' ');
4933 decodeId(buffer, pType->pHead->structTag);
4934 }
4935 }
4936 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004937 default:
4938 break;
4939 }
Jack Palevich86351982009-06-30 18:09:56 -07004940 buffer.append(' ');
4941 }
Jack Palevich3f226492009-07-02 14:46:19 -07004942
4943 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004944 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004945 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004946 case TY_SHORT:
4947 break;
Jack Palevich86351982009-06-30 18:09:56 -07004948 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004949 break;
4950 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004951 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004952 case TY_FLOAT:
4953 break;
4954 case TY_DOUBLE:
4955 break;
Jack Palevich86351982009-06-30 18:09:56 -07004956 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004957 decodeTypeImpPrefix(buffer, pType->pHead);
4958 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4959 buffer.append('(');
4960 }
4961 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004962 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004963 case TY_ARRAY:
4964 decodeTypeImpPrefix(buffer, pType->pHead);
4965 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004966 case TY_STRUCT:
4967 break;
Jack Palevich86351982009-06-30 18:09:56 -07004968 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004969 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004970 break;
4971 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004972 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004973 break;
4974 default:
4975 String temp;
4976 temp.printf("Unknown tag %d", pType->tag);
4977 buffer.append(temp);
4978 break;
4979 }
Jack Palevich3f226492009-07-02 14:46:19 -07004980 }
4981
4982 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4983 TypeTag tag = pType->tag;
4984
4985 switch(tag) {
4986 case TY_POINTER:
4987 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4988 buffer.append(')');
4989 }
4990 decodeTypeImpPostfix(buffer, pType->pHead);
4991 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004992 case TY_ARRAY:
4993 {
4994 String temp;
4995 temp.printf("[%d]", pType->length);
4996 buffer.append(temp);
4997 }
4998 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004999 case TY_STRUCT:
5000 if (pType->pHead->length >= 0) {
5001 buffer.appendCStr(" {");
5002 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5003 decodeTypeImp(buffer, pArg->pHead);
5004 buffer.appendCStr(";");
5005 }
5006 buffer.append('}');
5007 }
5008 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005009 case TY_FUNC:
5010 buffer.append('(');
5011 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5012 decodeTypeImp(buffer, pArg);
5013 if (pArg->pTail) {
5014 buffer.appendCStr(", ");
5015 }
5016 }
5017 buffer.append(')');
5018 break;
5019 default:
5020 break;
Jack Palevich86351982009-06-30 18:09:56 -07005021 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005022 }
5023
Jack Palevich86351982009-06-30 18:09:56 -07005024 void printType(Type* pType) {
5025 String buffer;
5026 decodeType(buffer, pType);
5027 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005028 }
5029
Jack Palevich2ff5c222009-07-23 15:11:22 -07005030 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005031 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005032 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005033 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005034 } else if (tok == TOK_SHORT) {
5035 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005036 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005037 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005038 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005039 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005040 } else if (tok == TOK_FLOAT) {
5041 pType = mkpFloat;
5042 } else if (tok == TOK_DOUBLE) {
5043 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005044 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5045 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005046 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005047 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005048 }
5049 next();
Jack Palevich86351982009-06-30 18:09:56 -07005050 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005051 }
5052
Jack Palevich9221bcc2009-08-26 16:15:07 -07005053 Type* acceptStruct() {
5054 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5055 bool isStruct = tok == TOK_STRUCT;
5056 next();
5057 tokenid_t structTag = acceptSymbol();
5058 bool isDeclaration = accept('{');
5059 bool fail = false;
5060
5061 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5062 if (structTag) {
5063 Token* pToken = &mTokenTable[structTag];
5064 VariableInfo* pStructInfo = pToken->mpStructInfo;
5065 bool needToDeclare = !pStructInfo;
5066 if (pStructInfo) {
5067 if (isDeclaration) {
5068 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5069 if (pStructInfo->pType->pHead->length == -1) {
5070 // we're filling in a forward declaration.
5071 needToDeclare = false;
5072 } else {
5073 error("A struct with the same name is already defined at this level.");
5074 fail = true;
5075 }
5076 } else {
5077 needToDeclare = true;
5078 }
5079 }
5080 if (!fail) {
5081 assert(pStructInfo->isStructTag);
5082 pStructType->pHead = pStructInfo->pType;
5083 pStructType->pTail = pStructType->pHead->pTail;
5084 }
5085 }
5086
5087 if (needToDeclare) {
5088 // This is a new struct name
5089 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5090 pStructType = createType(TY_STRUCT, NULL, NULL);
5091 pStructType->structTag = structTag;
5092 pStructType->pHead = pStructType;
5093 if (! isDeclaration) {
5094 // A forward declaration
5095 pStructType->length = -1;
5096 }
5097 pToken->mpStructInfo->pType = pStructType;
5098 }
5099 } else {
5100 // An anonymous struct
5101 pStructType->pHead = pStructType;
5102 }
5103
5104 if (isDeclaration) {
5105 size_t offset = 0;
5106 size_t structSize = 0;
5107 size_t structAlignment = 0;
5108 Type** pParamHolder = & pStructType->pHead->pTail;
5109 while (tok != '}' && tok != EOF) {
5110 Type* pPrimitiveType = expectPrimitiveType();
5111 if (pPrimitiveType) {
5112 while (tok != ';' && tok != EOF) {
5113 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5114 if (!pItem) {
5115 break;
5116 }
5117 if (lookupStructMember(pStructType, pItem->id)) {
5118 String buf;
5119 decodeToken(buf, pItem->id, false);
5120 error("Duplicate struct member %s", buf.getUnwrapped());
5121 }
5122 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5123 size_t alignment = pGen->alignmentOf(pItem);
5124 if (alignment > structAlignment) {
5125 structAlignment = alignment;
5126 }
5127 size_t alignmentMask = alignment - 1;
5128 offset = (offset + alignmentMask) & ~alignmentMask;
5129 pStructElement->length = offset;
5130 size_t size = pGen->sizeOf(pItem);
5131 if (isStruct) {
5132 offset += size;
5133 structSize = offset;
5134 } else {
5135 if (size >= structSize) {
5136 structSize = size;
5137 }
5138 }
5139 *pParamHolder = pStructElement;
5140 pParamHolder = &pStructElement->pTail;
5141 accept(',');
5142 }
5143 skip(';');
5144 } else {
5145 // Some sort of syntax error, skip token and keep trying
5146 next();
5147 }
5148 }
5149 if (!fail) {
5150 pStructType->pHead->length = structSize;
5151 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5152 }
5153 skip('}');
5154 }
5155 if (fail) {
5156 pStructType = NULL;
5157 }
5158 return pStructType;
5159 }
5160
5161 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5162 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5163 if (pStructElement->pHead->id == memberId) {
5164 return pStructElement;
5165 }
5166 }
5167 return NULL;
5168 }
5169
Jack Palevich2ff5c222009-07-23 15:11:22 -07005170 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005171 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005172 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005173 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005174 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005175 if (declName) {
5176 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005177 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005178 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005179 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005180 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005181 } else if (nameRequired) {
5182 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005183 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005184#if 0
5185 fprintf(stderr, "Parsed a declaration: ");
5186 printType(pType);
5187#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005188 if (reportFailure) {
5189 return NULL;
5190 }
Jack Palevich86351982009-06-30 18:09:56 -07005191 return pType;
5192 }
5193
Jack Palevich2ff5c222009-07-23 15:11:22 -07005194 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005195 bool nameRequired = pBaseType->tag != TY_STRUCT;
5196 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005197 if (! pType) {
5198 error("Expected a declaration");
5199 }
5200 return pType;
5201 }
5202
Jack Palevich3f226492009-07-02 14:46:19 -07005203 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005204 Type* acceptCastTypeDeclaration() {
5205 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005206 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005207 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005208 }
Jack Palevich86351982009-06-30 18:09:56 -07005209 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005210 }
5211
Jack Palevich2ff5c222009-07-23 15:11:22 -07005212 Type* expectCastTypeDeclaration() {
5213 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005214 if (! pType) {
5215 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005216 }
Jack Palevich3f226492009-07-02 14:46:19 -07005217 return pType;
5218 }
5219
5220 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005221 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005222 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005223 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005224 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005225 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005226 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005227 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005228 return pType;
5229 }
5230
5231 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005232 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005233 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005234 // direct-dcl :
5235 // name
5236 // (dcl)
5237 // direct-dcl()
5238 // direct-dcl[]
5239 Type* pNewHead = NULL;
5240 if (accept('(')) {
5241 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005242 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005243 skip(')');
5244 } else if ((declName = acceptSymbol()) != 0) {
5245 if (nameAllowed == false && declName) {
5246 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005247 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005248 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005249 } else if (nameRequired && ! declName) {
5250 String temp;
5251 decodeToken(temp, tok, true);
5252 error("Expected name. Got %s", temp.getUnwrapped());
5253 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005254 }
Jack Palevichb6154502009-08-04 14:56:09 -07005255 for(;;) {
5256 if (accept('(')) {
5257 // Function declaration
5258 Type* pTail = acceptArgs(nameAllowed);
5259 pType = createType(TY_FUNC, pType, pTail);
5260 skip(')');
5261 } if (accept('[')) {
5262 if (tok != ']') {
5263 if (tok != TOK_NUM || tokc <= 0) {
5264 error("Expected positive integer constant");
5265 } else {
5266 Type* pDecayType = createPtrType(pType);
5267 pType = createType(TY_ARRAY, pType, pDecayType);
5268 pType->length = tokc;
5269 }
5270 next();
5271 }
5272 skip(']');
5273 } else {
5274 break;
5275 }
Jack Palevich86351982009-06-30 18:09:56 -07005276 }
Jack Palevich3f226492009-07-02 14:46:19 -07005277
5278 if (pNewHead) {
5279 Type* pA = pNewHead;
5280 while (pA->pHead) {
5281 pA = pA->pHead;
5282 }
5283 pA->pHead = pType;
5284 pType = pNewHead;
5285 }
Jack Palevich86351982009-06-30 18:09:56 -07005286 return pType;
5287 }
5288
Jack Palevich2ff5c222009-07-23 15:11:22 -07005289 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005290 Type* pHead = NULL;
5291 Type* pTail = NULL;
5292 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005293 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005294 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005295 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005296 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005297 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005298 if (!pHead) {
5299 pHead = pParam;
5300 pTail = pParam;
5301 } else {
5302 pTail->pTail = pParam;
5303 pTail = pParam;
5304 }
5305 }
5306 }
5307 if (! accept(',')) {
5308 break;
5309 }
5310 }
5311 return pHead;
5312 }
5313
Jack Palevich2ff5c222009-07-23 15:11:22 -07005314 Type* expectPrimitiveType() {
5315 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005316 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005317 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005318 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005319 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005320 }
Jack Palevich86351982009-06-30 18:09:56 -07005321 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005322 }
5323
Jack Palevichb5e33312009-07-30 19:06:34 -07005324 void checkLVal() {
5325 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005326 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005327 }
5328 }
5329
Jack Palevich86351982009-06-30 18:09:56 -07005330 void addGlobalSymbol(Type* pDecl) {
5331 tokenid_t t = pDecl->id;
5332 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005333 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005334 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005335 }
Jack Palevich86351982009-06-30 18:09:56 -07005336 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005337 }
5338
Jack Palevich86351982009-06-30 18:09:56 -07005339 void reportDuplicate(tokenid_t t) {
5340 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005341 }
5342
Jack Palevich86351982009-06-30 18:09:56 -07005343 void addLocalSymbol(Type* pDecl) {
5344 tokenid_t t = pDecl->id;
5345 if (mLocals.isDefinedAtCurrentLevel(t)) {
5346 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005347 }
Jack Palevich86351982009-06-30 18:09:56 -07005348 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005349 }
5350
Jack Palevich61de31f2009-09-08 11:06:40 -07005351 bool checkUndeclaredStruct(Type* pBaseType) {
5352 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5353 String temp;
5354 decodeToken(temp, pBaseType->structTag, false);
5355 error("Undeclared struct %s", temp.getUnwrapped());
5356 return true;
5357 }
5358 return false;
5359 }
5360
Jack Palevich95727a02009-07-06 12:07:15 -07005361 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005362 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005363
Jack Palevich95727a02009-07-06 12:07:15 -07005364 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005365 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005366 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005367 if (!pDecl) {
5368 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005369 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005370 if (!pDecl->id) {
5371 break;
5372 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005373 if (checkUndeclaredStruct(pDecl)) {
5374 break;
5375 }
Jack Palevich86351982009-06-30 18:09:56 -07005376 int variableAddress = 0;
5377 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005378 size_t alignment = pGen->alignmentOf(pDecl);
5379 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005380 size_t alignmentMask = ~ (alignment - 1);
5381 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005382 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005383 loc = (loc + alignment - 1) & alignmentMask;
5384 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5385 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005386 variableAddress = -loc;
5387 VI(pDecl->id)->pAddress = (void*) variableAddress;
5388 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005389 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005390 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005391 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005392 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005393 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005394 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005395 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005396 if (tok == ',')
5397 next();
5398 }
5399 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005400 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005401 }
5402 }
5403
Jack Palevichf1728be2009-06-12 13:53:51 -07005404 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005405 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005406 }
5407
Jack Palevich37c54bd2009-07-14 18:35:36 -07005408 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005409 if (token == EOF ) {
5410 buffer.printf("EOF");
5411 } else if (token == TOK_NUM) {
5412 buffer.printf("numeric constant");
5413 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005414 if (token < 32) {
5415 buffer.printf("'\\x%02x'", token);
5416 } else {
5417 buffer.printf("'%c'", token);
5418 }
Jack Palevich569f1352009-06-29 14:29:08 -07005419 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005420 if (quote) {
5421 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5422 buffer.printf("keyword \"%s\"", nameof(token));
5423 } else {
5424 buffer.printf("symbol \"%s\"", nameof(token));
5425 }
5426 } else {
5427 buffer.printf("%s", nameof(token));
5428 }
Jack Palevich569f1352009-06-29 14:29:08 -07005429 }
5430 }
5431
Jack Palevich9221bcc2009-08-26 16:15:07 -07005432 void printToken(tokenid_t token) {
5433 String buffer;
5434 decodeToken(buffer, token, true);
5435 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5436 }
5437
Jack Palevich40600de2009-07-01 15:32:35 -07005438 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005439 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005440 if (!result) {
5441 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005442 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005443 error("Expected symbol. Got %s", temp.getUnwrapped());
5444 }
5445 return result;
5446 }
5447
Jack Palevich86351982009-06-30 18:09:56 -07005448 tokenid_t acceptSymbol() {
5449 tokenid_t result = 0;
5450 if (tok >= TOK_SYMBOL) {
5451 result = tok;
5452 next();
Jack Palevich86351982009-06-30 18:09:56 -07005453 }
5454 return result;
5455 }
5456
Jack Palevichb7c81e92009-06-04 19:56:13 -07005457 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005458 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005459 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005460 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005461 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005462 break;
5463 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005464 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005465 if (!pDecl) {
5466 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005467 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005468 if (!pDecl->id) {
5469 skip(';');
5470 continue;
5471 }
5472
Jack Palevich61de31f2009-09-08 11:06:40 -07005473 if (checkUndeclaredStruct(pDecl)) {
5474 skip(';');
5475 continue;
5476 }
5477
Jack Palevich86351982009-06-30 18:09:56 -07005478 if (! isDefined(pDecl->id)) {
5479 addGlobalSymbol(pDecl);
5480 }
5481 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005482 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005483 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005484 }
Jack Palevich86351982009-06-30 18:09:56 -07005485 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005486 // it's a variable declaration
5487 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005488 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005489 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005490 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005491 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005492 }
Jack Palevich86351982009-06-30 18:09:56 -07005493 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005494 if (tok == TOK_NUM) {
5495 if (name) {
5496 * (int*) name->pAddress = tokc;
5497 }
5498 next();
5499 } else {
5500 error("Expected an integer constant");
5501 }
5502 }
Jack Palevich86351982009-06-30 18:09:56 -07005503 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005504 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005505 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005506 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005507 if (!pDecl) {
5508 break;
5509 }
5510 if (! isDefined(pDecl->id)) {
5511 addGlobalSymbol(pDecl);
5512 }
5513 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005514 }
5515 skip(';');
5516 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005517 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005518 if (accept(';')) {
5519 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005520 } else if (tok != '{') {
5521 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005522 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005523 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005524 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005525 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005526 /* patch forward references */
5527 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005528 /* put function address */
5529 name->pAddress = (void*) codeBuf.getPC();
5530 }
5531 // Calculate stack offsets for parameters
5532 mLocals.pushLevel();
5533 intptr_t a = 8;
5534 int argCount = 0;
5535 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5536 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005537 if (pArg->id) {
5538 addLocalSymbol(pArg);
5539 }
Jack Palevich95727a02009-07-06 12:07:15 -07005540 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005541 Type* pPassingType = passingType(pArg);
5542 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005543 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005544 if (pArg->id) {
5545 VI(pArg->id)->pAddress = (void*) a;
5546 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005547 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005548 argCount++;
5549 }
5550 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005551 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005552 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005553 block(0, true);
5554 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005555 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005556 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005557 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005558 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005559 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005560 }
5561 }
5562 }
5563
Jack Palevich9221bcc2009-08-26 16:15:07 -07005564 Type* passingType(Type* pType) {
5565 switch (pType->tag) {
5566 case TY_CHAR:
5567 case TY_SHORT:
5568 return mkpInt;
5569 default:
5570 return pType;
5571 }
5572 }
5573
Jack Palevich9cbd2262009-07-08 16:48:41 -07005574 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5575 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5576 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005577 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005578 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005579 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005580 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005581 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005582 char* result = (char*) base;
5583 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005584 return result;
5585 }
5586
Jack Palevich21a15a22009-05-11 14:49:29 -07005587 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005588 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005589 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005590 pGlobalBase = 0;
5591 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005592 if (pGen) {
5593 delete pGen;
5594 pGen = 0;
5595 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005596 if (file) {
5597 delete file;
5598 file = 0;
5599 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005600 }
5601
Jack Palevich8c246a92009-07-14 21:14:10 -07005602 // One-time initialization, when class is constructed.
5603 void init() {
5604 mpSymbolLookupFn = 0;
5605 mpSymbolLookupContext = 0;
5606 }
5607
Jack Palevich21a15a22009-05-11 14:49:29 -07005608 void clear() {
5609 tok = 0;
5610 tokc = 0;
5611 tokl = 0;
5612 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005613 rsym = 0;
5614 loc = 0;
5615 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005616 dptr = 0;
5617 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005618 file = 0;
5619 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005620 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005621 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005622 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005623 mLineNumber = 1;
5624 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005625 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005626 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005627
Jack Palevich22305132009-05-13 10:58:45 -07005628 void setArchitecture(const char* architecture) {
5629 delete pGen;
5630 pGen = 0;
5631
5632 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005633#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005634 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005635 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005636 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005637#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005638#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005639 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005640 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005641 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005642#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005643 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005644 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005645 }
5646 }
5647
5648 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005649#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005650 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005651#elif defined(DEFAULT_X86_CODEGEN)
5652 pGen = new X86CodeGenerator();
5653#endif
5654 }
5655 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005656 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005657 } else {
5658 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005659 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005660 }
5661 }
5662
Jack Palevich77ae76e2009-05-10 19:59:24 -07005663public:
Jack Palevich22305132009-05-13 10:58:45 -07005664 struct args {
5665 args() {
5666 architecture = 0;
5667 }
5668 const char* architecture;
5669 };
5670
Jack Paleviche7b59062009-05-19 17:12:17 -07005671 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005672 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005673 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005674 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005675
Jack Paleviche7b59062009-05-19 17:12:17 -07005676 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005677 cleanup();
5678 }
5679
Jack Palevich8c246a92009-07-14 21:14:10 -07005680 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5681 mpSymbolLookupFn = pFn;
5682 mpSymbolLookupContext = pContext;
5683 }
5684
Jack Palevich1cdef202009-05-22 12:06:27 -07005685 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005686 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005687
Jack Palevich2ff5c222009-07-23 15:11:22 -07005688 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005689 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005690 cleanup();
5691 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005692 mTokenTable.setArena(&mGlobalArena);
5693 mGlobals.setArena(&mGlobalArena);
5694 mGlobals.setTokenTable(&mTokenTable);
5695 mLocals.setArena(&mLocalArena);
5696 mLocals.setTokenTable(&mTokenTable);
5697
5698 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005699 codeBuf.init(ALLOC_SIZE);
5700 setArchitecture(NULL);
5701 if (!pGen) {
5702 return -1;
5703 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005704#ifdef PROVIDE_TRACE_CODEGEN
5705 pGen = new TraceCodeGenerator(pGen);
5706#endif
5707 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005708 pGen->init(&codeBuf);
5709 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005710 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5711 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005712 inp();
5713 next();
5714 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005715 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005716 result = pGen->finishCompile();
5717 if (result == 0) {
5718 if (mErrorBuf.len()) {
5719 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005720 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005721 }
Jack Palevichce105a92009-07-16 14:30:33 -07005722 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005723 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005724 }
5725
Jack Palevich86351982009-06-30 18:09:56 -07005726 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005727 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005728 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005729 mkpChar = createType(TY_CHAR, NULL, NULL);
5730 mkpVoid = createType(TY_VOID, NULL, NULL);
5731 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5732 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5733 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5734 mkpIntPtr = createPtrType(mkpInt);
5735 mkpCharPtr = createPtrType(mkpChar);
5736 mkpFloatPtr = createPtrType(mkpFloat);
5737 mkpDoublePtr = createPtrType(mkpDouble);
5738 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005739 }
5740
Jack Palevicha6baa232009-06-12 11:25:59 -07005741 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005742 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005743 }
5744
Jack Palevich569f1352009-06-29 14:29:08 -07005745 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005746 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005747 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005748 }
5749
Jack Palevich569f1352009-06-29 14:29:08 -07005750 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005751 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005752 error("Undefined forward reference: %s",
5753 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005754 }
5755 return true;
5756 }
5757
Jack Palevich21a15a22009-05-11 14:49:29 -07005758 int dump(FILE* out) {
5759 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5760 return 0;
5761 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005762
Jack Palevicha6535612009-05-13 16:24:17 -07005763 int disassemble(FILE* out) {
5764 return pGen->disassemble(out);
5765 }
5766
Jack Palevich1cdef202009-05-22 12:06:27 -07005767 /* Look through the symbol table to find a symbol.
5768 * If found, return its value.
5769 */
5770 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005771 if (mCompileResult == 0) {
5772 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5773 VariableInfo* pVariableInfo = VI(tok);
5774 if (pVariableInfo) {
5775 return pVariableInfo->pAddress;
5776 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005777 }
5778 return NULL;
5779 }
5780
Jack Palevicheedf9d22009-06-04 16:23:40 -07005781 void getPragmas(ACCsizei* actualStringCount,
5782 ACCsizei maxStringCount, ACCchar** strings) {
5783 int stringCount = mPragmaStringCount;
5784 if (actualStringCount) {
5785 *actualStringCount = stringCount;
5786 }
5787 if (stringCount > maxStringCount) {
5788 stringCount = maxStringCount;
5789 }
5790 if (strings) {
5791 char* pPragmas = mPragmas.getUnwrapped();
5792 while (stringCount-- > 0) {
5793 *strings++ = pPragmas;
5794 pPragmas += strlen(pPragmas) + 1;
5795 }
5796 }
5797 }
5798
Jack Palevichac0e95e2009-05-29 13:53:44 -07005799 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005800 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005801 }
5802
Jack Palevich77ae76e2009-05-10 19:59:24 -07005803};
5804
Jack Paleviche7b59062009-05-19 17:12:17 -07005805const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005806 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5807
Jack Paleviche7b59062009-05-19 17:12:17 -07005808const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005809 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5810 5, 5, /* ==, != */
5811 9, 10, /* &&, || */
5812 6, 7, 8, /* & ^ | */
5813 2, 2 /* ~ ! */
5814 };
5815
Jack Palevich8b0624c2009-05-20 12:12:06 -07005816#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005817FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005818#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005819
Jack Palevich8b0624c2009-05-20 12:12:06 -07005820#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005821const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005822 0x1, // ++
5823 0xff, // --
5824 0xc1af0f, // *
5825 0xf9f79991, // /
5826 0xf9f79991, // % (With manual assist to swap results)
5827 0xc801, // +
5828 0xd8f7c829, // -
5829 0xe0d391, // <<
5830 0xf8d391, // >>
5831 0xe, // <=
5832 0xd, // >=
5833 0xc, // <
5834 0xf, // >
5835 0x4, // ==
5836 0x5, // !=
5837 0x0, // &&
5838 0x1, // ||
5839 0xc821, // &
5840 0xc831, // ^
5841 0xc809, // |
5842 0xd0f7, // ~
5843 0x4 // !
5844};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005845#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005846
Jack Palevich1cdef202009-05-22 12:06:27 -07005847struct ACCscript {
5848 ACCscript() {
5849 text = 0;
5850 textLength = 0;
5851 accError = ACC_NO_ERROR;
5852 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005853
Jack Palevich1cdef202009-05-22 12:06:27 -07005854 ~ACCscript() {
5855 delete text;
5856 }
Jack Palevich546b2242009-05-13 15:10:04 -07005857
Jack Palevich8c246a92009-07-14 21:14:10 -07005858 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5859 compiler.registerSymbolCallback(pFn, pContext);
5860 }
5861
Jack Palevich1cdef202009-05-22 12:06:27 -07005862 void setError(ACCenum error) {
5863 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5864 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005865 }
5866 }
5867
Jack Palevich1cdef202009-05-22 12:06:27 -07005868 ACCenum getError() {
5869 ACCenum result = accError;
5870 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005871 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005872 }
5873
Jack Palevich1cdef202009-05-22 12:06:27 -07005874 Compiler compiler;
5875 char* text;
5876 int textLength;
5877 ACCenum accError;
5878};
5879
5880
5881extern "C"
5882ACCscript* accCreateScript() {
5883 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005884}
Jack Palevich1cdef202009-05-22 12:06:27 -07005885
5886extern "C"
5887ACCenum accGetError( ACCscript* script ) {
5888 return script->getError();
5889}
5890
5891extern "C"
5892void accDeleteScript(ACCscript* script) {
5893 delete script;
5894}
5895
5896extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005897void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5898 ACCvoid* pContext) {
5899 script->registerSymbolCallback(pFn, pContext);
5900}
5901
5902extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005903void accScriptSource(ACCscript* script,
5904 ACCsizei count,
5905 const ACCchar ** string,
5906 const ACCint * length) {
5907 int totalLength = 0;
5908 for(int i = 0; i < count; i++) {
5909 int len = -1;
5910 const ACCchar* s = string[i];
5911 if (length) {
5912 len = length[i];
5913 }
5914 if (len < 0) {
5915 len = strlen(s);
5916 }
5917 totalLength += len;
5918 }
5919 delete script->text;
5920 char* text = new char[totalLength + 1];
5921 script->text = text;
5922 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005923 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005924 for(int i = 0; i < count; i++) {
5925 int len = -1;
5926 const ACCchar* s = string[i];
5927 if (length) {
5928 len = length[i];
5929 }
5930 if (len < 0) {
5931 len = strlen(s);
5932 }
Jack Palevich09555c72009-05-27 12:25:55 -07005933 memcpy(dest, s, len);
5934 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005935 }
5936 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07005937
5938#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07005939 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07005940 int counter;
5941 char path[PATH_MAX];
5942 for (counter = 0; counter < 4096; counter++) {
5943 sprintf(path, DEBUG_DUMP_PATTERN, counter);
5944 if(access(path, F_OK) != 0) {
5945 break;
5946 }
5947 }
5948 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07005949 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07005950 FILE* fd = fopen(path, "w");
5951 if (fd) {
5952 fwrite(text, totalLength, 1, fd);
5953 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07005954 LOGD("Saved input to file %s", path);
5955 } else {
5956 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07005957 }
5958 }
5959#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07005960}
5961
5962extern "C"
5963void accCompileScript(ACCscript* script) {
5964 int result = script->compiler.compile(script->text, script->textLength);
5965 if (result) {
5966 script->setError(ACC_INVALID_OPERATION);
5967 }
5968}
5969
5970extern "C"
5971void accGetScriptiv(ACCscript* script,
5972 ACCenum pname,
5973 ACCint * params) {
5974 switch (pname) {
5975 case ACC_INFO_LOG_LENGTH:
5976 *params = 0;
5977 break;
5978 }
5979}
5980
5981extern "C"
5982void accGetScriptInfoLog(ACCscript* script,
5983 ACCsizei maxLength,
5984 ACCsizei * length,
5985 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005986 char* message = script->compiler.getErrorMessage();
5987 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005988 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005989 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005990 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005991 if (infoLog && maxLength > 0) {
5992 int trimmedLength = maxLength < messageLength ?
5993 maxLength : messageLength;
5994 memcpy(infoLog, message, trimmedLength);
5995 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005996 }
5997}
5998
5999extern "C"
6000void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6001 ACCvoid ** address) {
6002 void* value = script->compiler.lookup(name);
6003 if (value) {
6004 *address = value;
6005 } else {
6006 script->setError(ACC_INVALID_VALUE);
6007 }
6008}
6009
Jack Palevicheedf9d22009-06-04 16:23:40 -07006010extern "C"
6011void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6012 ACCsizei maxStringCount, ACCchar** strings){
6013 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6014}
6015
-b master422972c2009-06-17 19:13:52 -07006016extern "C"
6017void accDisassemble(ACCscript* script) {
6018 script->compiler.disassemble(stderr);
6019}
6020
Jack Palevicheedf9d22009-06-04 16:23:40 -07006021
Jack Palevich1cdef202009-05-22 12:06:27 -07006022} // namespace acc
6023