blob: 0bb0c5efa701f62fcda720c4061fc03f1ecc2626 [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 Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000012#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070014#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070015#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070016#include <stdlib.h>
17#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070018#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich8dc662e2009-06-09 22:53:47 +000020#if defined(__i386__)
21#include <sys/mman.h>
22#endif
23
Jack Palevich546b2242009-05-13 15:10:04 -070024#if defined(__arm__)
25#include <unistd.h>
26#endif
27
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Paleviche7b59062009-05-19 17:12:17 -070039#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070040#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
Jack Palevicha6535612009-05-13 16:24:17 -070042
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
Jack Palevich9f51a262009-07-29 16:22:26 -070051#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070052// #define PROVIDE_TRACE_CODEGEN
53
Jack Palevichbbf8ab52009-05-11 11:54:30 -070054namespace acc {
55
Jack Palevich8df46192009-07-07 14:48:51 -070056// Subset of STL vector.
57template<class E> class Vector {
58 public:
59 Vector() {
60 mpBase = 0;
61 mUsed = 0;
62 mSize = 0;
63 }
64
65 ~Vector() {
66 if (mpBase) {
67 for(size_t i = 0; i < mUsed; i++) {
68 mpBase[mUsed].~E();
69 }
70 free(mpBase);
71 }
72 }
73
74 inline E& operator[](size_t i) {
75 return mpBase[i];
76 }
77
78 inline E& front() {
79 return mpBase[0];
80 }
81
82 inline E& back() {
83 return mpBase[mUsed - 1];
84 }
85
86 void pop_back() {
87 mUsed -= 1;
88 mpBase[mUsed].~E();
89 }
90
91 void push_back(const E& item) {
92 * ensure(1) = item;
93 }
94
95 size_t size() {
96 return mUsed;
97 }
98
99private:
100 E* ensure(int n) {
101 size_t newUsed = mUsed + n;
102 if (newUsed > mSize) {
103 size_t newSize = mSize * 2 + 10;
104 if (newSize < newUsed) {
105 newSize = newUsed;
106 }
107 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
108 mSize = newSize;
109 }
110 E* result = mpBase + mUsed;
111 mUsed = newUsed;
112 return result;
113 }
114
115 E* mpBase;
116 size_t mUsed;
117 size_t mSize;
118};
119
Jack Palevichac0e95e2009-05-29 13:53:44 -0700120class ErrorSink {
121public:
122 void error(const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 verror(fmt, ap);
126 va_end(ap);
127 }
128
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700129 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
136 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
137 TY_POINTER, TY_FUNC, TY_PARAM
138 };
139
140 struct Type {
141 TypeTag tag;
142 tokenid_t id; // For function arguments
143 Type* pHead;
144 Type* pTail;
145 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700146
Jack Palevichba929a42009-07-17 10:20:32 -0700147 enum ExpressionType {
148 ET_RVALUE,
149 ET_LVALUE
150 };
151
152 struct ExpressionValue {
153 ExpressionValue() {
154 et = ET_RVALUE;
155 pType = NULL;
156 }
157 ExpressionType et;
158 Type* pType;
159 };
160
Jack Palevich21a15a22009-05-11 14:49:29 -0700161 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700162 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700163 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700164 ErrorSink* mErrorSink;
165 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700166 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700167
Jack Palevich21a15a22009-05-11 14:49:29 -0700168 void release() {
169 if (pProgramBase != 0) {
170 free(pProgramBase);
171 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700172 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 }
174
Jack Palevich0a280a02009-06-11 10:53:51 -0700175 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700176 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700177 bool overflow = newSize > mSize;
178 if (overflow && !mOverflowed) {
179 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700180 if (mErrorSink) {
181 mErrorSink->error("Code too large: %d bytes", newSize);
182 }
183 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700184 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 }
186
Jack Palevich21a15a22009-05-11 14:49:29 -0700187 public:
188 CodeBuf() {
189 pProgramBase = 0;
190 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700191 mErrorSink = 0;
192 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700193 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
196 ~CodeBuf() {
197 release();
198 }
199
200 void init(int size) {
201 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700202 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700203 pProgramBase = (char*) calloc(1, size);
204 ind = pProgramBase;
205 }
206
Jack Palevichac0e95e2009-05-29 13:53:44 -0700207 void setErrorSink(ErrorSink* pErrorSink) {
208 mErrorSink = pErrorSink;
209 }
210
Jack Palevich546b2242009-05-13 15:10:04 -0700211 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(4)) {
213 return 0;
214 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700215 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700216 * (int*) ind = n;
217 ind += 4;
218 return result;
219 }
220
Jack Palevich21a15a22009-05-11 14:49:29 -0700221 /*
222 * Output a byte. Handles all values, 0..ff.
223 */
224 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700225 if(check(1)) {
226 return;
227 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 *ind++ = n;
229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 inline void* getBase() {
232 return (void*) pProgramBase;
233 }
234
Jack Palevich8b0624c2009-05-20 12:12:06 -0700235 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700236 return ind - pProgramBase;
237 }
238
Jack Palevich8b0624c2009-05-20 12:12:06 -0700239 intptr_t getPC() {
240 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 }
242 };
243
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 /**
245 * A code generator creates an in-memory program, generating the code on
246 * the fly. There is one code generator implementation for each supported
247 * architecture.
248 *
249 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700250 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700251 * FP - a frame pointer for accessing function arguments and local
252 * variables.
253 * SP - a stack pointer for storing intermediate results while evaluating
254 * expressions. The stack pointer grows downwards.
255 *
256 * The function calling convention is that all arguments are placed on the
257 * stack such that the first argument has the lowest address.
258 * After the call, the result is in R0. The caller is responsible for
259 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700260 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 * FP and SP registers are saved.
262 */
263
Jack Palevich21a15a22009-05-11 14:49:29 -0700264 class CodeGenerator {
265 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 CodeGenerator() {
267 mErrorSink = 0;
268 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700269 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700270 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700271 virtual ~CodeGenerator() {}
272
Jack Palevich22305132009-05-13 10:58:45 -0700273 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700275 pCodeBuf->setErrorSink(mErrorSink);
276 }
277
Jack Palevichb67b18f2009-06-11 21:12:23 -0700278 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700279 mErrorSink = pErrorSink;
280 if (pCodeBuf) {
281 pCodeBuf->setErrorSink(mErrorSink);
282 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
284
Jack Palevich58c30ee2009-07-17 16:35:23 -0700285 /* Give the code generator some utility types so it can
286 * use its own types as needed for the results of some
287 * operations like gcmp.
288 */
289
Jack Palevicha8f427f2009-07-13 18:40:08 -0700290 void setTypes(Type* pInt) {
291 mkpInt = pInt;
292 }
293
Jack Palevich1cdef202009-05-22 12:06:27 -0700294 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700295 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700296 * Save the old value of the FP.
297 * Set the new value of the FP.
298 * Convert from the native platform calling convention to
299 * our stack-based calling convention. This may require
300 * pushing arguments from registers to the stack.
301 * Allocate "N" bytes of stack space. N isn't known yet, so
302 * just emit the instructions for adjusting the stack, and return
303 * the address to patch up. The patching will be done in
304 * functionExit().
305 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700306 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700307 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700308
Jack Palevich1cdef202009-05-22 12:06:27 -0700309 /* Emit a function epilog.
310 * Restore the old SP and FP register values.
311 * Return to the calling function.
312 * argCount - the number of arguments to the function.
313 * localVariableAddress - returned from functionEntry()
314 * localVariableSize - the size in bytes of the local variables.
315 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700316 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700318
Jack Palevich1cdef202009-05-22 12:06:27 -0700319 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700320 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700321
Jack Palevich1a539db2009-07-08 13:04:41 -0700322 /* Load floating point value from global address. */
323 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Jump to a target, and return the address of the word that
326 * holds the target data, in case it needs to be fixed up later.
327 */
Jack Palevich22305132009-05-13 10:58:45 -0700328 virtual int gjmp(int t) = 0;
329
Jack Palevich1cdef202009-05-22 12:06:27 -0700330 /* Test R0 and jump to a target if the test succeeds.
331 * l = 0: je, l == 1: jne
332 * Return the address of the word that holds the targed data, in
333 * case it needs to be fixed up later.
334 */
Jack Palevich22305132009-05-13 10:58:45 -0700335 virtual int gtst(bool l, int t) = 0;
336
Jack Palevich9eed7a22009-07-06 17:24:34 -0700337 /* Compare TOS against R0, and store the boolean result in R0.
338 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 * op specifies the comparison.
340 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700341 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700342
Jack Palevich9eed7a22009-07-06 17:24:34 -0700343 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 */
Jack Palevich546b2242009-05-13 15:10:04 -0700347 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700348
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 /* Compare 0 against R0, and store the boolean result in R0.
350 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700352 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353
354 /* Perform the arithmetic op specified by op. 0 is the
355 * left argument, R0 is the right argument.
356 */
357 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700359 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 */
361 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700363 /* Turn R0, TOS into R0 TOS R0 */
364
365 virtual void over() = 0;
366
367 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700368 */
369 virtual void popR0() = 0;
370
Jack Palevich9eed7a22009-07-06 17:24:34 -0700371 /* Store R0 to the address stored in TOS.
372 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700373 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700374 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700378 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 /* Load the absolute address of a variable to R0.
381 * If ea <= LOCAL, then this is a local variable, or an
382 * argument, addressed relative to FP.
383 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700384 *
Jack Palevich1cdef202009-05-22 12:06:27 -0700385 */
Jack Palevich8df46192009-07-07 14:48:51 -0700386 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700387
Jack Palevich9f51a262009-07-29 16:22:26 -0700388 /* Load the pc-relative address of a forward-referenced variable to R0.
389 * Return the address of the 4-byte constant so that it can be filled
390 * in later.
391 */
392 virtual int leaForward(int ea, Type* pPointerType) = 0;
393
Jack Palevich1cdef202009-05-22 12:06:27 -0700394 /* Store R0 to a variable.
395 * If ea <= LOCAL, then this is a local variable, or an
396 * argument, addressed relative to FP.
397 * else it is an absolute global address.
398 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700399 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700400
Jack Palevich8df46192009-07-07 14:48:51 -0700401 /**
402 * Convert R0 to the given type.
403 */
404 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 /* Emit code to adjust the stack for a function call. Return the
407 * label for the address of the instruction that adjusts the
408 * stack size. This will be passed as argument "a" to
409 * endFunctionCallArguments.
410 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700411 virtual int beginFunctionCallArguments() = 0;
412
Jack Palevich1cdef202009-05-22 12:06:27 -0700413 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700414 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700415 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700416 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700417
Jack Palevich1cdef202009-05-22 12:06:27 -0700418 /* Patch the function call preamble.
419 * a is the address returned from beginFunctionCallArguments
420 * l is the number of bytes the arguments took on the stack.
421 * Typically you would also emit code to convert the argument
422 * list into whatever the native function calling convention is.
423 * On ARM for example you would pop the first 5 arguments into
424 * R0..R4
425 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700426 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevich1cdef202009-05-22 12:06:27 -0700428 /* Emit a call to an unknown function. The argument "symbol" needs to
429 * be stored in the location where the address should go. It forms
430 * a chain. The address will be patched later.
431 * Return the address of the word that has to be patched.
432 */
Jack Palevich8df46192009-07-07 14:48:51 -0700433 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700434
Jack Palevich1cdef202009-05-22 12:06:27 -0700435 /* Call a function pointer. L is the number of bytes the arguments
436 * take on the stack. The address of the function is stored at
437 * location SP + l.
438 */
Jack Palevich8df46192009-07-07 14:48:51 -0700439 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Adjust SP after returning from a function call. l is the
442 * number of bytes of arguments stored on the stack. isIndirect
443 * is true if this was an indirect call. (In which case the
444 * address of the function is stored at location SP + l.)
445 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700446 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700447
Jack Palevich1cdef202009-05-22 12:06:27 -0700448 /* Print a disassembly of the assembled code to out. Return
449 * non-zero if there is an error.
450 */
Jack Palevicha6535612009-05-13 16:24:17 -0700451 virtual int disassemble(FILE* out) = 0;
452
Jack Palevich1cdef202009-05-22 12:06:27 -0700453 /* Generate a symbol at the current PC. t is the head of a
454 * linked list of addresses to patch.
455 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700456 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700457
Jack Palevich9f51a262009-07-29 16:22:26 -0700458 /* Resolve a forward reference function at the current PC.
459 * t is the head of a
460 * linked list of addresses to patch.
461 * (Like gsym, but using absolute address, not PC relative address.)
462 */
463 virtual void resolveForward(int t) = 0;
464
Jack Palevich1cdef202009-05-22 12:06:27 -0700465 /*
466 * Do any cleanup work required at the end of a compile.
467 * For example, an instruction cache might need to be
468 * invalidated.
469 * Return non-zero if there is an error.
470 */
471 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700472
Jack Palevicha6535612009-05-13 16:24:17 -0700473 /**
474 * Adjust relative branches by this amount.
475 */
476 virtual int jumpOffset() = 0;
477
Jack Palevich9eed7a22009-07-06 17:24:34 -0700478 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700479 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700480 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700481 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700482
483 /**
484 * Array element alignment (in bytes) for this type of data.
485 */
486 virtual size_t sizeOf(Type* type) = 0;
487
Jack Palevich9cbd2262009-07-08 16:48:41 -0700488 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700489 * Stack alignment of this type of data
490 */
491 virtual size_t stackAlignmentOf(Type* pType) = 0;
492
493 /**
494 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700495 */
496 virtual size_t stackSizeOf(Type* pType) = 0;
497
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700498 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700499 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700500 }
501
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700502 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700503 return mExpressionStack.back().et;
504 }
505
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700506 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700507 mExpressionStack.back().et = et;
508 }
509
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700510 virtual size_t getExpressionStackDepth() {
511 return mExpressionStack.size();
512 }
513
Jack Palevich21a15a22009-05-11 14:49:29 -0700514 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700515 /*
516 * Output a byte. Handles all values, 0..ff.
517 */
518 void ob(int n) {
519 pCodeBuf->ob(n);
520 }
521
Jack Palevich8b0624c2009-05-20 12:12:06 -0700522 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700523 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700524 }
525
Jack Palevich8b0624c2009-05-20 12:12:06 -0700526 intptr_t getBase() {
527 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700528 }
529
Jack Palevich8b0624c2009-05-20 12:12:06 -0700530 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700531 return pCodeBuf->getPC();
532 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700533
534 intptr_t getSize() {
535 return pCodeBuf->getSize();
536 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700537
538 void error(const char* fmt,...) {
539 va_list ap;
540 va_start(ap, fmt);
541 mErrorSink->verror(fmt, ap);
542 va_end(ap);
543 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700544
545 void assert(bool test) {
546 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700547 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700548 error("code generator assertion failed.");
549 }
550 }
Jack Palevich8df46192009-07-07 14:48:51 -0700551
552 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700553 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700554 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700555 }
556
Jack Palevich8df46192009-07-07 14:48:51 -0700557 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700558 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700559 }
560
561 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700562 if (mExpressionStack.size()) {
563 mExpressionStack.push_back(mExpressionStack.back());
564 } else {
565 mExpressionStack.push_back(ExpressionValue());
566 }
567
Jack Palevich8df46192009-07-07 14:48:51 -0700568 }
569
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700570 void overType() {
571 size_t size = mExpressionStack.size();
572 if (size >= 2) {
573 mExpressionStack.push_back(mExpressionStack.back());
574 mExpressionStack[size-1] = mExpressionStack[size-2];
575 mExpressionStack[size-2] = mExpressionStack[size];
576 }
577 }
578
Jack Palevich8df46192009-07-07 14:48:51 -0700579 void popType() {
580 mExpressionStack.pop_back();
581 }
582
583 bool bitsSame(Type* pA, Type* pB) {
584 return collapseType(pA->tag) == collapseType(pB->tag);
585 }
586
587 TypeTag collapseType(TypeTag tag) {
588 static const TypeTag collapsedTag[] = {
589 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
590 TY_VOID, TY_VOID};
591 return collapsedTag[tag];
592 }
593
Jack Palevich1a539db2009-07-08 13:04:41 -0700594 TypeTag collapseTypeR0() {
595 return collapseType(getR0Type()->tag);
596 }
597
598 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700599 return isFloatTag(pType->tag);
600 }
601
602 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700603 return tag == TY_FLOAT || tag == TY_DOUBLE;
604 }
605
Jack Palevicha8f427f2009-07-13 18:40:08 -0700606 Type* mkpInt;
607
Jack Palevich21a15a22009-05-11 14:49:29 -0700608 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700609 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700610 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700611 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700612 };
613
Jack Paleviche7b59062009-05-19 17:12:17 -0700614#ifdef PROVIDE_ARM_CODEGEN
615
Jack Palevich22305132009-05-13 10:58:45 -0700616 class ARMCodeGenerator : public CodeGenerator {
617 public:
618 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700619
Jack Palevich22305132009-05-13 10:58:45 -0700620 virtual ~ARMCodeGenerator() {}
621
622 /* returns address to patch with local variable size
623 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700624 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700625 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700626 // sp -> arg4 arg5 ...
627 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700628 int regArgCount = calcRegArgCount(pDecl);
629 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700630 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700631 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700632 }
633 // sp -> arg0 arg1 ...
634 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700635 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700636 // sp, fp -> oldfp, retadr, arg0 arg1 ....
637 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700638 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700639 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700640 // We don't know how many local variables we are going to use,
641 // but we will round the allocation up to a multiple of
642 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700643 }
644
Jack Palevichb7718b92009-07-09 22:00:24 -0700645 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700646 // Round local variable size up to a multiple of stack alignment
647 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
648 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700649 // Patch local variable allocation code:
650 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700651 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700652 }
Jack Palevich69796b62009-05-14 15:42:26 -0700653 *(char*) (localVariableAddress) = localVariableSize;
654
655 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
656 o4(0xE1A0E00B); // mov lr, fp
657 o4(0xE59BB000); // ldr fp, [fp]
658 o4(0xE28ED004); // add sp, lr, #4
659 // sp -> retadr, arg0, ...
660 o4(0xE8BD4000); // ldmfd sp!, {lr}
661 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700662
663 // We store the PC into the lr so we can adjust the sp before
664 // returning. We need to pull off the registers we pushed
665 // earlier. We don't need to actually store them anywhere,
666 // just adjust the stack.
667 int regArgCount = calcRegArgCount(pDecl);
668 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700669 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
670 }
671 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700672 }
673
674 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700675 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700676 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700677 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700678 }
679
Jack Palevich1a539db2009-07-08 13:04:41 -0700680 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700681 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700682 // Global, absolute address
683 o4(0xE59F0000); // ldr r0, .L1
684 o4(0xEA000000); // b .L99
685 o4(address); // .L1: .word ea
686 // .L99:
687
688 switch (pType->tag) {
689 case TY_FLOAT:
690 o4(0xE5900000); // ldr r0, [r0]
691 break;
692 case TY_DOUBLE:
693 o4(0xE1C000D0); // ldrd r0, [r0]
694 break;
695 default:
696 assert(false);
697 break;
698 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700699 }
700
Jack Palevich22305132009-05-13 10:58:45 -0700701 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700702 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700703 }
704
705 /* l = 0: je, l == 1: jne */
706 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700707 Type* pR0Type = getR0Type();
708 TypeTag tagR0 = pR0Type->tag;
709 switch(tagR0) {
710 case TY_FLOAT:
711 callRuntime((void*) runtime_is_non_zero_f);
712 break;
713 case TY_DOUBLE:
714 callRuntime((void*) runtime_is_non_zero_d);
715 break;
716 default:
717 break;
718 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700719 o4(0xE3500000); // cmp r0,#0
720 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
721 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700722 }
723
Jack Palevich58c30ee2009-07-17 16:35:23 -0700724 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700725 Type* pR0Type = getR0Type();
726 Type* pTOSType = getTOSType();
727 TypeTag tagR0 = collapseType(pR0Type->tag);
728 TypeTag tagTOS = collapseType(pTOSType->tag);
729 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700730 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700731 o4(0xE1510000); // cmp r1, r1
732 switch(op) {
733 case OP_EQUALS:
734 o4(0x03A00001); // moveq r0,#1
735 o4(0x13A00000); // movne r0,#0
736 break;
737 case OP_NOT_EQUALS:
738 o4(0x03A00000); // moveq r0,#0
739 o4(0x13A00001); // movne r0,#1
740 break;
741 case OP_LESS_EQUAL:
742 o4(0xD3A00001); // movle r0,#1
743 o4(0xC3A00000); // movgt r0,#0
744 break;
745 case OP_GREATER:
746 o4(0xD3A00000); // movle r0,#0
747 o4(0xC3A00001); // movgt r0,#1
748 break;
749 case OP_GREATER_EQUAL:
750 o4(0xA3A00001); // movge r0,#1
751 o4(0xB3A00000); // movlt r0,#0
752 break;
753 case OP_LESS:
754 o4(0xA3A00000); // movge r0,#0
755 o4(0xB3A00001); // movlt r0,#1
756 break;
757 default:
758 error("Unknown comparison op %d", op);
759 break;
760 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700761 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
762 setupDoubleArgs();
763 switch(op) {
764 case OP_EQUALS:
765 callRuntime((void*) runtime_cmp_eq_dd);
766 break;
767 case OP_NOT_EQUALS:
768 callRuntime((void*) runtime_cmp_ne_dd);
769 break;
770 case OP_LESS_EQUAL:
771 callRuntime((void*) runtime_cmp_le_dd);
772 break;
773 case OP_GREATER:
774 callRuntime((void*) runtime_cmp_gt_dd);
775 break;
776 case OP_GREATER_EQUAL:
777 callRuntime((void*) runtime_cmp_ge_dd);
778 break;
779 case OP_LESS:
780 callRuntime((void*) runtime_cmp_lt_dd);
781 break;
782 default:
783 error("Unknown comparison op %d", op);
784 break;
785 }
786 } else {
787 setupFloatArgs();
788 switch(op) {
789 case OP_EQUALS:
790 callRuntime((void*) runtime_cmp_eq_ff);
791 break;
792 case OP_NOT_EQUALS:
793 callRuntime((void*) runtime_cmp_ne_ff);
794 break;
795 case OP_LESS_EQUAL:
796 callRuntime((void*) runtime_cmp_le_ff);
797 break;
798 case OP_GREATER:
799 callRuntime((void*) runtime_cmp_gt_ff);
800 break;
801 case OP_GREATER_EQUAL:
802 callRuntime((void*) runtime_cmp_ge_ff);
803 break;
804 case OP_LESS:
805 callRuntime((void*) runtime_cmp_lt_ff);
806 break;
807 default:
808 error("Unknown comparison op %d", op);
809 break;
810 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700811 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700812 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700813 }
814
Jack Palevich546b2242009-05-13 15:10:04 -0700815 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700816 Type* pR0Type = getR0Type();
817 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700818 TypeTag tagR0 = pR0Type->tag;
819 TypeTag tagTOS = pTOSType->tag;
820 bool isFloatR0 = isFloatTag(tagR0);
821 bool isFloatTOS = isFloatTag(tagTOS);
822 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700823 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700824 bool isPtrR0 = tagR0 == TY_POINTER;
825 bool isPtrTOS = tagTOS == TY_POINTER;
826 if (isPtrR0 || isPtrTOS) {
827 if (isPtrR0 && isPtrTOS) {
828 if (op != OP_MINUS) {
829 error("Unsupported pointer-pointer operation %d.", op);
830 }
831 if (! typeEqual(pR0Type, pTOSType)) {
832 error("Incompatible pointer types for subtraction.");
833 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700834 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700835 setR0Type(mkpInt);
836 int size = sizeOf(pR0Type->pHead);
837 if (size != 1) {
838 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700839 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700840 // TODO: Optimize for power-of-two.
841 genOp(OP_DIV);
842 }
843 } else {
844 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
845 error("Unsupported pointer-scalar operation %d", op);
846 }
847 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700848 int size = sizeOf(pPtrType->pHead);
849 if (size != 1) {
850 // TODO: Optimize for power-of-two.
851 liReg(size, 2);
852 if (isPtrR0) {
853 o4(0x0E0010192); // mul r1,r2,r1
854 } else {
855 o4(0x0E0000092); // mul r0,r2,r0
856 }
857 }
858 switch(op) {
859 case OP_PLUS:
860 o4(0xE0810000); // add r0,r1,r0
861 break;
862 case OP_MINUS:
863 o4(0xE0410000); // sub r0,r1,r0
864 break;
865 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700866 setR0Type(pPtrType);
867 }
868 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700869 switch(op) {
870 case OP_MUL:
871 o4(0x0E0000091); // mul r0,r1,r0
872 break;
873 case OP_DIV:
874 callRuntime((void*) runtime_DIV);
875 break;
876 case OP_MOD:
877 callRuntime((void*) runtime_MOD);
878 break;
879 case OP_PLUS:
880 o4(0xE0810000); // add r0,r1,r0
881 break;
882 case OP_MINUS:
883 o4(0xE0410000); // sub r0,r1,r0
884 break;
885 case OP_SHIFT_LEFT:
886 o4(0xE1A00011); // lsl r0,r1,r0
887 break;
888 case OP_SHIFT_RIGHT:
889 o4(0xE1A00051); // asr r0,r1,r0
890 break;
891 case OP_BIT_AND:
892 o4(0xE0010000); // and r0,r1,r0
893 break;
894 case OP_BIT_XOR:
895 o4(0xE0210000); // eor r0,r1,r0
896 break;
897 case OP_BIT_OR:
898 o4(0xE1810000); // orr r0,r1,r0
899 break;
900 case OP_BIT_NOT:
901 o4(0xE1E00000); // mvn r0, r0
902 break;
903 default:
904 error("Unimplemented op %d\n", op);
905 break;
906 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700907 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700908 } else {
909 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
910 if (pResultType->tag == TY_DOUBLE) {
911 setupDoubleArgs();
912 switch(op) {
913 case OP_MUL:
914 callRuntime((void*) runtime_op_mul_dd);
915 break;
916 case OP_DIV:
917 callRuntime((void*) runtime_op_div_dd);
918 break;
919 case OP_PLUS:
920 callRuntime((void*) runtime_op_add_dd);
921 break;
922 case OP_MINUS:
923 callRuntime((void*) runtime_op_sub_dd);
924 break;
925 default:
926 error("Unsupported binary floating operation %d\n", op);
927 break;
928 }
929 } else {
930 setupFloatArgs();
931 switch(op) {
932 case OP_MUL:
933 callRuntime((void*) runtime_op_mul_ff);
934 break;
935 case OP_DIV:
936 callRuntime((void*) runtime_op_div_ff);
937 break;
938 case OP_PLUS:
939 callRuntime((void*) runtime_op_add_ff);
940 break;
941 case OP_MINUS:
942 callRuntime((void*) runtime_op_sub_ff);
943 break;
944 default:
945 error("Unsupported binary floating operation %d\n", op);
946 break;
947 }
948 }
949 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700950 }
Jack Palevich22305132009-05-13 10:58:45 -0700951 }
952
Jack Palevich58c30ee2009-07-17 16:35:23 -0700953 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700954 if (op != OP_LOGICAL_NOT) {
955 error("Unknown unary cmp %d", op);
956 } else {
957 Type* pR0Type = getR0Type();
958 TypeTag tag = collapseType(pR0Type->tag);
959 switch(tag) {
960 case TY_INT:
961 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700962 o4(0xE1510000); // cmp r1, r0
963 o4(0x03A00001); // moveq r0,#1
964 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700965 break;
966 case TY_FLOAT:
967 callRuntime((void*) runtime_is_zero_f);
968 break;
969 case TY_DOUBLE:
970 callRuntime((void*) runtime_is_zero_d);
971 break;
972 default:
973 error("gUnaryCmp unsupported type");
974 break;
975 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700976 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700977 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700978 }
979
980 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700981 Type* pR0Type = getR0Type();
982 TypeTag tag = collapseType(pR0Type->tag);
983 switch(tag) {
984 case TY_INT:
985 switch(op) {
986 case OP_MINUS:
987 o4(0xE3A01000); // mov r1, #0
988 o4(0xE0410000); // sub r0,r1,r0
989 break;
990 case OP_BIT_NOT:
991 o4(0xE1E00000); // mvn r0, r0
992 break;
993 default:
994 error("Unknown unary op %d\n", op);
995 break;
996 }
997 break;
998 case TY_FLOAT:
999 case TY_DOUBLE:
1000 switch (op) {
1001 case OP_MINUS:
1002 if (tag == TY_FLOAT) {
1003 callRuntime((void*) runtime_op_neg_f);
1004 } else {
1005 callRuntime((void*) runtime_op_neg_d);
1006 }
1007 break;
1008 case OP_BIT_NOT:
1009 error("Can't apply '~' operator to a float or double.");
1010 break;
1011 default:
1012 error("Unknown unary op %d\n", op);
1013 break;
1014 }
1015 break;
1016 default:
1017 error("genUnaryOp unsupported type");
1018 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001019 }
Jack Palevich22305132009-05-13 10:58:45 -07001020 }
1021
Jack Palevich1cdef202009-05-22 12:06:27 -07001022 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001023 Type* pR0Type = getR0Type();
1024 TypeTag r0ct = collapseType(pR0Type->tag);
1025 if (r0ct != TY_DOUBLE) {
1026 o4(0xE92D0001); // stmfd sp!,{r0}
1027 mStackUse += 4;
1028 } else {
1029 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1030 mStackUse += 8;
1031 }
Jack Palevich8df46192009-07-07 14:48:51 -07001032 pushType();
-b master422972c2009-06-17 19:13:52 -07001033 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001034 }
1035
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001036 virtual void over() {
1037 // We know it's only used for int-ptr ops (++/--)
1038
1039 Type* pR0Type = getR0Type();
1040 TypeTag r0ct = collapseType(pR0Type->tag);
1041
1042 Type* pTOSType = getTOSType();
1043 TypeTag tosct = collapseType(pTOSType->tag);
1044
1045 assert (r0ct == TY_INT && tosct == TY_INT);
1046
1047 o4(0xE8BD0002); // ldmfd sp!,{r1}
1048 o4(0xE92D0001); // stmfd sp!,{r0}
1049 o4(0xE92D0002); // stmfd sp!,{r1}
1050 overType();
1051 mStackUse += 4;
1052 }
1053
Jack Palevich58c30ee2009-07-17 16:35:23 -07001054 virtual void popR0() {
1055 Type* pTOSType = getTOSType();
1056 switch (collapseType(pTOSType->tag)){
1057 case TY_INT:
1058 case TY_FLOAT:
1059 o4(0xE8BD0001); // ldmfd sp!,{r0}
1060 mStackUse -= 4;
1061 break;
1062 case TY_DOUBLE:
1063 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1064 mStackUse -= 8;
1065 break;
1066 default:
1067 error("Can't pop this type.");
1068 break;
1069 }
1070 popType();
1071 LOG_STACK("popR0: %d\n", mStackUse);
1072 }
1073
1074 virtual void storeR0ToTOS() {
1075 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001076 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001077 o4(0xE8BD0004); // ldmfd sp!,{r2}
1078 popType();
-b master422972c2009-06-17 19:13:52 -07001079 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001080 switch (pPointerType->pHead->tag) {
1081 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001082 case TY_FLOAT:
1083 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001084 break;
1085 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001086 o4(0xE5C20000); // strb r0, [r2]
1087 break;
1088 case TY_DOUBLE:
1089 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001090 break;
1091 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001092 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001093 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001094 }
Jack Palevich22305132009-05-13 10:58:45 -07001095 }
1096
Jack Palevich58c30ee2009-07-17 16:35:23 -07001097 virtual void loadR0FromR0() {
1098 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001099 assert(pPointerType->tag == TY_POINTER);
1100 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001101 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001102 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001103 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001104 o4(0xE5900000); // ldr r0, [r0]
1105 break;
1106 case TY_CHAR:
1107 o4(0xE5D00000); // ldrb r0, [r0]
1108 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001109 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001110 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001111 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001112 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001113 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001114 break;
1115 }
Jack Palevich8df46192009-07-07 14:48:51 -07001116 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001117 }
1118
Jack Palevich8df46192009-07-07 14:48:51 -07001119 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001120 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001121 // Local, fp relative
1122 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1123 error("Offset out of range: %08x", ea);
1124 }
1125 if (ea < 0) {
1126 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1127 } else {
1128 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1129 }
Jack Palevichbd894902009-05-14 19:35:31 -07001130 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001131 // Global, absolute.
1132 o4(0xE59F0000); // ldr r0, .L1
1133 o4(0xEA000000); // b .L99
1134 o4(ea); // .L1: .word 0
1135 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001136 }
Jack Palevich8df46192009-07-07 14:48:51 -07001137 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001138 }
1139
Jack Palevich9f51a262009-07-29 16:22:26 -07001140 virtual int leaForward(int ea, Type* pPointerType) {
1141 setR0Type(pPointerType);
1142 int result = ea;
1143 int pc = getPC();
1144 int offset = 0;
1145 if (ea) {
1146 offset = (pc - ea - 8) >> 2;
1147 if ((offset & 0xffff) != offset) {
1148 error("function forward reference out of bounds");
1149 }
1150 } else {
1151 offset = 0;
1152 }
1153 o4(0xE59F0000 | offset); // ldr r0, .L1
1154
1155 if (ea == 0) {
1156 o4(0xEA000000); // b .L99
1157 result = o4(ea); // .L1: .word 0
1158 // .L99:
1159 }
1160 return result;
1161 }
1162
Jack Palevich9cbd2262009-07-08 16:48:41 -07001163 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001164 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001165 TypeTag tag = pType->tag;
1166 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001167 case TY_CHAR:
1168 if (ea > -LOCAL && ea < LOCAL) {
1169 // Local, fp relative
1170 if (ea < -4095 || ea > 4095) {
1171 error("Offset out of range: %08x", ea);
1172 }
1173 if (ea < 0) {
1174 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1175 } else {
1176 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1177 }
1178 } else{
1179 // Global, absolute
1180 o4(0xE59F1000); // ldr r1, .L1
1181 o4(0xEA000000); // b .L99
1182 o4(ea); // .L1: .word 0
1183 o4(0xE5C10000); // .L99: strb r0, [r1]
1184 }
1185 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001186 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001187 case TY_INT:
1188 case TY_FLOAT:
1189 if (ea > -LOCAL && ea < LOCAL) {
1190 // Local, fp relative
1191 if (ea < -4095 || ea > 4095) {
1192 error("Offset out of range: %08x", ea);
1193 }
1194 if (ea < 0) {
1195 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1196 } else {
1197 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1198 }
1199 } else{
1200 // Global, absolute
1201 o4(0xE59F1000); // ldr r1, .L1
1202 o4(0xEA000000); // b .L99
1203 o4(ea); // .L1: .word 0
1204 o4(0xE5810000); // .L99: str r0, [r1]
1205 }
1206 break;
1207 case TY_DOUBLE:
1208 if ((ea & 0x7) != 0) {
1209 error("double address is not aligned: %d", ea);
1210 }
1211 if (ea > -LOCAL && ea < LOCAL) {
1212 // Local, fp relative
Jack Palevicha7813bd2009-07-29 11:36:04 -07001213 // Global, absolute
1214 o4(0xE59F2000); // ldr r2, .L1
1215 o4(0xEA000000); // b .L99
1216 o4(ea); // .L1: .word 0
1217 o4(0xE18B00F2); // .L99: strd r0, [fp,r2]
Jack Palevichb7718b92009-07-09 22:00:24 -07001218 } else{
1219 // Global, absolute
1220 o4(0xE59F2000); // ldr r2, .L1
1221 o4(0xEA000000); // b .L99
1222 o4(ea); // .L1: .word 0
1223 o4(0xE1C200F0); // .L99: strd r0, [r2]
1224 }
1225 break;
1226 default:
1227 error("Unable to store to type %d", tag);
1228 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001229 }
Jack Palevich22305132009-05-13 10:58:45 -07001230 }
1231
Jack Palevich8df46192009-07-07 14:48:51 -07001232 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001233 Type* pR0Type = getR0Type();
1234 if (bitsSame(pType, pR0Type)) {
1235 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001236 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001237 TypeTag r0Tag = collapseType(pR0Type->tag);
1238 TypeTag destTag = collapseType(pType->tag);
1239 if (r0Tag == TY_INT) {
1240 if (destTag == TY_FLOAT) {
1241 callRuntime((void*) runtime_int_to_float);
1242 } else {
1243 assert(destTag == TY_DOUBLE);
1244 callRuntime((void*) runtime_int_to_double);
1245 }
1246 } else if (r0Tag == TY_FLOAT) {
1247 if (destTag == TY_INT) {
1248 callRuntime((void*) runtime_float_to_int);
1249 } else {
1250 assert(destTag == TY_DOUBLE);
1251 callRuntime((void*) runtime_float_to_double);
1252 }
1253 } else {
1254 assert (r0Tag == TY_DOUBLE);
1255 if (destTag == TY_INT) {
1256 callRuntime((void*) runtime_double_to_int);
1257 } else {
1258 assert(destTag == TY_FLOAT);
1259 callRuntime((void*) runtime_double_to_float);
1260 }
1261 }
Jack Palevich8df46192009-07-07 14:48:51 -07001262 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001263 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001264 }
1265
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001266 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001267 return o4(0xE24DDF00); // Placeholder
1268 }
1269
Jack Palevich8148c5b2009-07-16 18:24:47 -07001270 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001271 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001272 Type* pR0Type = getR0Type();
1273 TypeTag r0ct = collapseType(pR0Type->tag);
1274 switch(r0ct) {
1275 case TY_INT:
1276 case TY_FLOAT:
1277 if (l < 0 || l > 4096-4) {
1278 error("l out of range for stack offset: 0x%08x", l);
1279 }
1280 o4(0xE58D0000 + l); // str r0, [sp, #l]
1281 return 4;
1282 case TY_DOUBLE: {
1283 // Align to 8 byte boundary
1284 int l2 = (l + 7) & ~7;
1285 if (l2 < 0 || l2 > 4096-8) {
1286 error("l out of range for stack offset: 0x%08x", l);
1287 }
1288 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1289 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1290 return (l2 - l) + 8;
1291 }
1292 default:
1293 assert(false);
1294 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001295 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001296 }
1297
Jack Palevichb7718b92009-07-09 22:00:24 -07001298 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001299 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001300 // Have to calculate register arg count from actual stack size,
1301 // in order to properly handle ... functions.
1302 int regArgCount = l >> 2;
1303 if (regArgCount > 4) {
1304 regArgCount = 4;
1305 }
1306 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001307 argumentStackUse -= regArgCount * 4;
1308 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1309 }
1310 mStackUse += argumentStackUse;
1311
1312 // Align stack.
1313 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1314 * STACK_ALIGNMENT);
1315 mStackAlignmentAdjustment = 0;
1316 if (missalignment > 0) {
1317 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1318 }
1319 l += mStackAlignmentAdjustment;
1320
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001321 if (l < 0 || l > 0x3FC) {
1322 error("L out of range for stack adjustment: 0x%08x", l);
1323 }
1324 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001325 mStackUse += mStackAlignmentAdjustment;
1326 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1327 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001328 }
1329
Jack Palevich8df46192009-07-07 14:48:51 -07001330 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001331 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001332 // Forward calls are always short (local)
1333 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001334 }
1335
Jack Palevich8df46192009-07-07 14:48:51 -07001336 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001337 assert(pFunc->tag == TY_FUNC);
1338 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001339 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001340 int argCount = l >> 2;
1341 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001342 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001343 if (adjustedL < 0 || adjustedL > 4096-4) {
1344 error("l out of range for stack offset: 0x%08x", l);
1345 }
1346 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1347 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001348 }
1349
Jack Palevichb7718b92009-07-09 22:00:24 -07001350 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001351 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001352 // Have to calculate register arg count from actual stack size,
1353 // in order to properly handle ... functions.
1354 int regArgCount = l >> 2;
1355 if (regArgCount > 4) {
1356 regArgCount = 4;
1357 }
1358 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001359 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1360 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001361 if (stackUse) {
1362 if (stackUse < 0 || stackUse > 255) {
1363 error("L out of range for stack adjustment: 0x%08x", l);
1364 }
1365 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001366 mStackUse -= stackUse * 4;
1367 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001368 }
Jack Palevich22305132009-05-13 10:58:45 -07001369 }
1370
Jack Palevicha6535612009-05-13 16:24:17 -07001371 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001372 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001373 }
1374
1375 /* output a symbol and patch all calls to it */
1376 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001377 int n;
1378 int base = getBase();
1379 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001380 while (t) {
1381 int data = * (int*) t;
1382 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1383 if (decodedOffset == 0) {
1384 n = 0;
1385 } else {
1386 n = base + decodedOffset; /* next value */
1387 }
1388 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1389 | encodeRelAddress(pc - t - 8);
1390 t = n;
1391 }
1392 }
1393
Jack Palevich9f51a262009-07-29 16:22:26 -07001394 /* output a symbol and patch all calls to it */
1395 virtual void resolveForward(int t) {
1396 if (t) {
1397 int pc = getPC();
1398 *(int *) t = pc;
1399 }
1400 }
1401
Jack Palevich1cdef202009-05-22 12:06:27 -07001402 virtual int finishCompile() {
1403#if defined(__arm__)
1404 const long base = long(getBase());
1405 const long curr = long(getPC());
1406 int err = cacheflush(base, curr, 0);
1407 return err;
1408#else
1409 return 0;
1410#endif
1411 }
1412
Jack Palevicha6535612009-05-13 16:24:17 -07001413 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001414#ifdef ENABLE_ARM_DISASSEMBLY
1415 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001416 disasm_interface_t di;
1417 di.di_readword = disassemble_readword;
1418 di.di_printaddr = disassemble_printaddr;
1419 di.di_printf = disassemble_printf;
1420
1421 int base = getBase();
1422 int pc = getPC();
1423 for(int i = base; i < pc; i += 4) {
1424 fprintf(out, "%08x: %08x ", i, *(int*) i);
1425 ::disasm(&di, i, 0);
1426 }
Jack Palevich09555c72009-05-27 12:25:55 -07001427#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001428 return 0;
1429 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001430
Jack Palevich9eed7a22009-07-06 17:24:34 -07001431 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001432 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001433 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001434 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001435 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001436 case TY_CHAR:
1437 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001438 case TY_DOUBLE:
1439 return 8;
1440 default:
1441 return 4;
1442 }
1443 }
1444
1445 /**
1446 * Array element alignment (in bytes) for this type of data.
1447 */
1448 virtual size_t sizeOf(Type* pType){
1449 switch(pType->tag) {
1450 case TY_INT:
1451 return 4;
1452 case TY_CHAR:
1453 return 1;
1454 default:
1455 return 0;
1456 case TY_FLOAT:
1457 return 4;
1458 case TY_DOUBLE:
1459 return 8;
1460 case TY_POINTER:
1461 return 4;
1462 }
1463 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001464
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001465 virtual size_t stackAlignmentOf(Type* pType) {
1466 switch(pType->tag) {
1467 case TY_DOUBLE:
1468 return 8;
1469 default:
1470 return 4;
1471 }
1472 }
1473
Jack Palevich9cbd2262009-07-08 16:48:41 -07001474 virtual size_t stackSizeOf(Type* pType) {
1475 switch(pType->tag) {
1476 case TY_DOUBLE:
1477 return 8;
1478 default:
1479 return 4;
1480 }
1481 }
1482
Jack Palevich22305132009-05-13 10:58:45 -07001483 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001484 static FILE* disasmOut;
1485
1486 static u_int
1487 disassemble_readword(u_int address)
1488 {
1489 return(*((u_int *)address));
1490 }
1491
1492 static void
1493 disassemble_printaddr(u_int address)
1494 {
1495 fprintf(disasmOut, "0x%08x", address);
1496 }
1497
1498 static void
1499 disassemble_printf(const char *fmt, ...) {
1500 va_list ap;
1501 va_start(ap, fmt);
1502 vfprintf(disasmOut, fmt, ap);
1503 va_end(ap);
1504 }
1505
1506 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1507
1508 /** Encode a relative address that might also be
1509 * a label.
1510 */
1511 int encodeAddress(int value) {
1512 int base = getBase();
1513 if (value >= base && value <= getPC() ) {
1514 // This is a label, encode it relative to the base.
1515 value = value - base;
1516 }
1517 return encodeRelAddress(value);
1518 }
1519
1520 int encodeRelAddress(int value) {
1521 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1522 }
Jack Palevich22305132009-05-13 10:58:45 -07001523
Jack Palevichb7718b92009-07-09 22:00:24 -07001524 int calcRegArgCount(Type* pDecl) {
1525 int reg = 0;
1526 Type* pArgs = pDecl->pTail;
1527 while (pArgs && reg < 4) {
1528 Type* pArg = pArgs->pHead;
1529 if ( pArg->tag == TY_DOUBLE) {
1530 int evenReg = (reg + 1) & ~1;
1531 if (evenReg >= 4) {
1532 break;
1533 }
1534 reg = evenReg + 2;
1535 } else {
1536 reg++;
1537 }
1538 pArgs = pArgs->pTail;
1539 }
1540 return reg;
1541 }
1542
Jack Palevich58c30ee2009-07-17 16:35:23 -07001543 void setupIntPtrArgs() {
1544 o4(0xE8BD0002); // ldmfd sp!,{r1}
1545 mStackUse -= 4;
1546 popType();
1547 }
1548
Jack Palevichb7718b92009-07-09 22:00:24 -07001549 /* Pop TOS to R1
1550 * Make sure both R0 and TOS are floats. (Could be ints)
1551 * We know that at least one of R0 and TOS is already a float
1552 */
1553 void setupFloatArgs() {
1554 Type* pR0Type = getR0Type();
1555 Type* pTOSType = getTOSType();
1556 TypeTag tagR0 = collapseType(pR0Type->tag);
1557 TypeTag tagTOS = collapseType(pTOSType->tag);
1558 if (tagR0 != TY_FLOAT) {
1559 assert(tagR0 == TY_INT);
1560 callRuntime((void*) runtime_int_to_float);
1561 }
1562 if (tagTOS != TY_FLOAT) {
1563 assert(tagTOS == TY_INT);
1564 assert(tagR0 == TY_FLOAT);
1565 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1566 o4(0xE59D0004); // ldr r0, [sp, #4]
1567 callRuntime((void*) runtime_int_to_float);
1568 o4(0xE1A01000); // mov r1, r0
1569 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1570 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1571 } else {
1572 // Pop TOS
1573 o4(0xE8BD0002); // ldmfd sp!,{r1}
1574 }
1575 mStackUse -= 4;
1576 popType();
1577 }
1578
1579 /* Pop TOS into R2..R3
1580 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1581 * We know that at least one of R0 and TOS are already a double.
1582 */
1583
1584 void setupDoubleArgs() {
1585 Type* pR0Type = getR0Type();
1586 Type* pTOSType = getTOSType();
1587 TypeTag tagR0 = collapseType(pR0Type->tag);
1588 TypeTag tagTOS = collapseType(pTOSType->tag);
1589 if (tagR0 != TY_DOUBLE) {
1590 if (tagR0 == TY_INT) {
1591 callRuntime((void*) runtime_int_to_double);
1592 } else {
1593 assert(tagR0 == TY_FLOAT);
1594 callRuntime((void*) runtime_float_to_double);
1595 }
1596 }
1597 if (tagTOS != TY_DOUBLE) {
1598 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1599 o4(0xE59D0008); // ldr r0, [sp, #8]
1600 if (tagTOS == TY_INT) {
1601 callRuntime((void*) runtime_int_to_double);
1602 } else {
1603 assert(tagTOS == TY_FLOAT);
1604 callRuntime((void*) runtime_float_to_double);
1605 }
1606 o4(0xE1A02000); // mov r2, r0
1607 o4(0xE1A03001); // mov r3, r1
1608 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1609 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1610 mStackUse -= 4;
1611 } else {
1612 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1613 mStackUse -= 8;
1614 }
1615 popType();
1616 }
1617
Jack Palevicha8f427f2009-07-13 18:40:08 -07001618 void liReg(int t, int reg) {
1619 assert(reg >= 0 && reg < 16);
1620 int rN = (reg & 0xf) << 12;
1621 if (t >= 0 && t < 255) {
1622 o4((0xE3A00000 + t) | rN); // mov rN, #0
1623 } else if (t >= -256 && t < 0) {
1624 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001625 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001626 } else {
1627 o4(0xE51F0000 | rN); // ldr rN, .L3
1628 o4(0xEA000000); // b .L99
1629 o4(t); // .L3: .word 0
1630 // .L99:
1631 }
1632 }
1633
Jack Palevichb7718b92009-07-09 22:00:24 -07001634 void callRuntime(void* fn) {
1635 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001636 o4(0xEA000000); // b .L99
1637 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001638 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001639 }
1640
Jack Palevichb7718b92009-07-09 22:00:24 -07001641 // Integer math:
1642
1643 static int runtime_DIV(int b, int a) {
1644 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001645 }
1646
Jack Palevichb7718b92009-07-09 22:00:24 -07001647 static int runtime_MOD(int b, int a) {
1648 return a % b;
1649 }
1650
1651 // Comparison to zero
1652
1653 static int runtime_is_non_zero_f(float a) {
1654 return a != 0;
1655 }
1656
1657 static int runtime_is_non_zero_d(double a) {
1658 return a != 0;
1659 }
1660
1661 // Comparison to zero
1662
1663 static int runtime_is_zero_f(float a) {
1664 return a == 0;
1665 }
1666
1667 static int runtime_is_zero_d(double a) {
1668 return a == 0;
1669 }
1670
1671 // Type conversion
1672
1673 static int runtime_float_to_int(float a) {
1674 return (int) a;
1675 }
1676
1677 static double runtime_float_to_double(float a) {
1678 return (double) a;
1679 }
1680
1681 static int runtime_double_to_int(double a) {
1682 return (int) a;
1683 }
1684
1685 static float runtime_double_to_float(double a) {
1686 return (float) a;
1687 }
1688
1689 static float runtime_int_to_float(int a) {
1690 return (float) a;
1691 }
1692
1693 static double runtime_int_to_double(int a) {
1694 return (double) a;
1695 }
1696
1697 // Comparisons float
1698
1699 static int runtime_cmp_eq_ff(float b, float a) {
1700 return a == b;
1701 }
1702
1703 static int runtime_cmp_ne_ff(float b, float a) {
1704 return a != b;
1705 }
1706
1707 static int runtime_cmp_lt_ff(float b, float a) {
1708 return a < b;
1709 }
1710
1711 static int runtime_cmp_le_ff(float b, float a) {
1712 return a <= b;
1713 }
1714
1715 static int runtime_cmp_ge_ff(float b, float a) {
1716 return a >= b;
1717 }
1718
1719 static int runtime_cmp_gt_ff(float b, float a) {
1720 return a > b;
1721 }
1722
1723 // Comparisons double
1724
1725 static int runtime_cmp_eq_dd(double b, double a) {
1726 return a == b;
1727 }
1728
1729 static int runtime_cmp_ne_dd(double b, double a) {
1730 return a != b;
1731 }
1732
1733 static int runtime_cmp_lt_dd(double b, double a) {
1734 return a < b;
1735 }
1736
1737 static int runtime_cmp_le_dd(double b, double a) {
1738 return a <= b;
1739 }
1740
1741 static int runtime_cmp_ge_dd(double b, double a) {
1742 return a >= b;
1743 }
1744
1745 static int runtime_cmp_gt_dd(double b, double a) {
1746 return a > b;
1747 }
1748
1749 // Math float
1750
1751 static float runtime_op_add_ff(float b, float a) {
1752 return a + b;
1753 }
1754
1755 static float runtime_op_sub_ff(float b, float a) {
1756 return a - b;
1757 }
1758
1759 static float runtime_op_mul_ff(float b, float a) {
1760 return a * b;
1761 }
1762
1763 static float runtime_op_div_ff(float b, float a) {
1764 return a / b;
1765 }
1766
1767 static float runtime_op_neg_f(float a) {
1768 return -a;
1769 }
1770
1771 // Math double
1772
1773 static double runtime_op_add_dd(double b, double a) {
1774 return a + b;
1775 }
1776
1777 static double runtime_op_sub_dd(double b, double a) {
1778 return a - b;
1779 }
1780
1781 static double runtime_op_mul_dd(double b, double a) {
1782 return a * b;
1783 }
1784
1785 static double runtime_op_div_dd(double b, double a) {
1786 return a / b;
1787 }
1788
1789 static double runtime_op_neg_d(double a) {
1790 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001791 }
-b master422972c2009-06-17 19:13:52 -07001792
1793 static const int STACK_ALIGNMENT = 8;
1794 int mStackUse;
1795 // This variable holds the amount we adjusted the stack in the most
1796 // recent endFunctionCallArguments call. It's examined by the
1797 // following adjustStackAfterCall call.
1798 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001799 };
1800
Jack Palevich09555c72009-05-27 12:25:55 -07001801#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001802
1803#ifdef PROVIDE_X86_CODEGEN
1804
Jack Palevich21a15a22009-05-11 14:49:29 -07001805 class X86CodeGenerator : public CodeGenerator {
1806 public:
1807 X86CodeGenerator() {}
1808 virtual ~X86CodeGenerator() {}
1809
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001810 /* returns address to patch with local variable size
1811 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001812 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001813 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1814 return oad(0xec81, 0); /* sub $xxx, %esp */
1815 }
1816
Jack Palevichb7718b92009-07-09 22:00:24 -07001817 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001818 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001819 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001820 }
1821
Jack Palevich21a15a22009-05-11 14:49:29 -07001822 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001823 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001824 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001825 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001826 }
1827
Jack Palevich1a539db2009-07-08 13:04:41 -07001828 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001829 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001830 switch (pType->tag) {
1831 case TY_FLOAT:
1832 oad(0x05D9, address); // flds
1833 break;
1834 case TY_DOUBLE:
1835 oad(0x05DD, address); // fldl
1836 break;
1837 default:
1838 assert(false);
1839 break;
1840 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001841 }
1842
Jack Palevich22305132009-05-13 10:58:45 -07001843 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001844 return psym(0xe9, t);
1845 }
1846
1847 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001848 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001849 Type* pR0Type = getR0Type();
1850 TypeTag tagR0 = pR0Type->tag;
1851 bool isFloatR0 = isFloatTag(tagR0);
1852 if (isFloatR0) {
1853 o(0xeed9); // fldz
1854 o(0xe9da); // fucompp
1855 o(0xe0df); // fnstsw %ax
1856 o(0x9e); // sahf
1857 } else {
1858 o(0xc085); // test %eax, %eax
1859 }
1860 // Use two output statements to generate one instruction.
1861 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001862 return psym(0x84 + l, t);
1863 }
1864
Jack Palevich58c30ee2009-07-17 16:35:23 -07001865 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001866 Type* pR0Type = getR0Type();
1867 Type* pTOSType = getTOSType();
1868 TypeTag tagR0 = pR0Type->tag;
1869 TypeTag tagTOS = pTOSType->tag;
1870 bool isFloatR0 = isFloatTag(tagR0);
1871 bool isFloatTOS = isFloatTag(tagTOS);
1872 if (!isFloatR0 && !isFloatTOS) {
1873 int t = decodeOp(op);
1874 o(0x59); /* pop %ecx */
1875 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001876 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001877 o(0x0f); /* setxx %al */
1878 o(t + 0x90);
1879 o(0xc0);
1880 popType();
1881 } else {
1882 setupFloatOperands();
1883 switch (op) {
1884 case OP_EQUALS:
1885 o(0xe9da); // fucompp
1886 o(0xe0df); // fnstsw %ax
1887 o(0x9e); // sahf
1888 o(0xc0940f); // sete %al
1889 o(0xc29b0f); // setnp %dl
1890 o(0xd021); // andl %edx, %eax
1891 break;
1892 case OP_NOT_EQUALS:
1893 o(0xe9da); // fucompp
1894 o(0xe0df); // fnstsw %ax
1895 o(0x9e); // sahf
1896 o(0xc0950f); // setne %al
1897 o(0xc29a0f); // setp %dl
1898 o(0xd009); // orl %edx, %eax
1899 break;
1900 case OP_GREATER_EQUAL:
1901 o(0xe9da); // fucompp
1902 o(0xe0df); // fnstsw %ax
1903 o(0x05c4f6); // testb $5, %ah
1904 o(0xc0940f); // sete %al
1905 break;
1906 case OP_LESS:
1907 o(0xc9d9); // fxch %st(1)
1908 o(0xe9da); // fucompp
1909 o(0xe0df); // fnstsw %ax
1910 o(0x9e); // sahf
1911 o(0xc0970f); // seta %al
1912 break;
1913 case OP_LESS_EQUAL:
1914 o(0xc9d9); // fxch %st(1)
1915 o(0xe9da); // fucompp
1916 o(0xe0df); // fnstsw %ax
1917 o(0x9e); // sahf
1918 o(0xc0930f); // setea %al
1919 break;
1920 case OP_GREATER:
1921 o(0xe9da); // fucompp
1922 o(0xe0df); // fnstsw %ax
1923 o(0x45c4f6); // testb $69, %ah
1924 o(0xc0940f); // sete %al
1925 break;
1926 default:
1927 error("Unknown comparison op");
1928 }
1929 o(0xc0b60f); // movzbl %al, %eax
1930 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001931 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001932 }
1933
Jack Palevich546b2242009-05-13 15:10:04 -07001934 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001935 Type* pR0Type = getR0Type();
1936 Type* pTOSType = getTOSType();
1937 TypeTag tagR0 = pR0Type->tag;
1938 TypeTag tagTOS = pTOSType->tag;
1939 bool isFloatR0 = isFloatTag(tagR0);
1940 bool isFloatTOS = isFloatTag(tagTOS);
1941 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001942 bool isPtrR0 = tagR0 == TY_POINTER;
1943 bool isPtrTOS = tagTOS == TY_POINTER;
1944 if (isPtrR0 || isPtrTOS) {
1945 if (isPtrR0 && isPtrTOS) {
1946 if (op != OP_MINUS) {
1947 error("Unsupported pointer-pointer operation %d.", op);
1948 }
1949 if (! typeEqual(pR0Type, pTOSType)) {
1950 error("Incompatible pointer types for subtraction.");
1951 }
1952 o(0x59); /* pop %ecx */
1953 o(decodeOp(op));
1954 popType();
1955 setR0Type(mkpInt);
1956 int size = sizeOf(pR0Type->pHead);
1957 if (size != 1) {
1958 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001959 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001960 // TODO: Optimize for power-of-two.
1961 genOp(OP_DIV);
1962 }
1963 } else {
1964 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1965 error("Unsupported pointer-scalar operation %d", op);
1966 }
1967 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1968 o(0x59); /* pop %ecx */
1969 int size = sizeOf(pPtrType->pHead);
1970 if (size != 1) {
1971 // TODO: Optimize for power-of-two.
1972 if (isPtrR0) {
1973 oad(0xC969, size); // imull $size, %ecx
1974 } else {
1975 oad(0xC069, size); // mul $size, %eax
1976 }
1977 }
1978 o(decodeOp(op));
1979 popType();
1980 setR0Type(pPtrType);
1981 }
1982 } else {
1983 o(0x59); /* pop %ecx */
1984 o(decodeOp(op));
1985 if (op == OP_MOD)
1986 o(0x92); /* xchg %edx, %eax */
1987 popType();
1988 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001989 } else {
1990 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1991 setupFloatOperands();
1992 // Both float. x87 R0 == left hand, x87 R1 == right hand
1993 switch (op) {
1994 case OP_MUL:
1995 o(0xc9de); // fmulp
1996 break;
1997 case OP_DIV:
1998 o(0xf1de); // fdivp
1999 break;
2000 case OP_PLUS:
2001 o(0xc1de); // faddp
2002 break;
2003 case OP_MINUS:
2004 o(0xe1de); // fsubp
2005 break;
2006 default:
2007 error("Unsupported binary floating operation.");
2008 break;
2009 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002010 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002011 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002012 }
2013
Jack Palevich58c30ee2009-07-17 16:35:23 -07002014 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002015 if (op != OP_LOGICAL_NOT) {
2016 error("Unknown unary cmp %d", op);
2017 } else {
2018 Type* pR0Type = getR0Type();
2019 TypeTag tag = collapseType(pR0Type->tag);
2020 switch(tag) {
2021 case TY_INT: {
2022 oad(0xb9, 0); /* movl $0, %ecx */
2023 int t = decodeOp(op);
2024 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002025 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002026 o(0x0f); /* setxx %al */
2027 o(t + 0x90);
2028 o(0xc0);
2029 }
2030 break;
2031 case TY_FLOAT:
2032 case TY_DOUBLE:
2033 o(0xeed9); // fldz
2034 o(0xe9da); // fucompp
2035 o(0xe0df); // fnstsw %ax
2036 o(0x9e); // sahf
2037 o(0xc0950f); // setne %al
2038 o(0xc29a0f); // setp %dl
2039 o(0xd009); // orl %edx, %eax
2040 o(0xc0b60f); // movzbl %al, %eax
2041 o(0x01f083); // xorl $1, %eax
2042 break;
2043 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002044 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002045 break;
2046 }
2047 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002048 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002049 }
2050
2051 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002052 Type* pR0Type = getR0Type();
2053 TypeTag tag = collapseType(pR0Type->tag);
2054 switch(tag) {
2055 case TY_INT:
2056 oad(0xb9, 0); /* movl $0, %ecx */
2057 o(decodeOp(op));
2058 break;
2059 case TY_FLOAT:
2060 case TY_DOUBLE:
2061 switch (op) {
2062 case OP_MINUS:
2063 o(0xe0d9); // fchs
2064 break;
2065 case OP_BIT_NOT:
2066 error("Can't apply '~' operator to a float or double.");
2067 break;
2068 default:
2069 error("Unknown unary op %d\n", op);
2070 break;
2071 }
2072 break;
2073 default:
2074 error("genUnaryOp unsupported type");
2075 break;
2076 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002077 }
2078
Jack Palevich1cdef202009-05-22 12:06:27 -07002079 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002080 Type* pR0Type = getR0Type();
2081 TypeTag r0ct = collapseType(pR0Type->tag);
2082 switch(r0ct) {
2083 case TY_INT:
2084 o(0x50); /* push %eax */
2085 break;
2086 case TY_FLOAT:
2087 o(0x50); /* push %eax */
2088 o(0x241cd9); // fstps 0(%esp)
2089 break;
2090 case TY_DOUBLE:
2091 o(0x50); /* push %eax */
2092 o(0x50); /* push %eax */
2093 o(0x241cdd); // fstpl 0(%esp)
2094 break;
2095 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002096 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002097 break;
2098 }
Jack Palevich8df46192009-07-07 14:48:51 -07002099 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002100 }
2101
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002102 virtual void over() {
2103 // We know it's only used for int-ptr ops (++/--)
2104
2105 Type* pR0Type = getR0Type();
2106 TypeTag r0ct = collapseType(pR0Type->tag);
2107
2108 Type* pTOSType = getTOSType();
2109 TypeTag tosct = collapseType(pTOSType->tag);
2110
2111 assert (r0ct == TY_INT && tosct == TY_INT);
2112
2113 o(0x59); /* pop %ecx */
2114 o(0x50); /* push %eax */
2115 o(0x51); /* push %ecx */
2116
2117 overType();
2118 }
2119
Jack Palevich58c30ee2009-07-17 16:35:23 -07002120 virtual void popR0() {
2121 Type* pR0Type = getR0Type();
2122 TypeTag r0ct = collapseType(pR0Type->tag);
2123 switch(r0ct) {
2124 case TY_INT:
2125 o(0x58); /* popl %eax */
2126 break;
2127 case TY_FLOAT:
2128 o(0x2404d9); // flds (%esp)
2129 o(0x58); /* popl %eax */
2130 break;
2131 case TY_DOUBLE:
2132 o(0x2404dd); // fldl (%esp)
2133 o(0x58); /* popl %eax */
2134 o(0x58); /* popl %eax */
2135 break;
2136 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002137 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002138 break;
2139 }
2140 popType();
2141 }
2142
2143 virtual void storeR0ToTOS() {
2144 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002145 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002146 Type* pTargetType = pPointerType->pHead;
2147 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002148 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002149 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002150 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002151 case TY_INT:
2152 o(0x0189); /* movl %eax/%al, (%ecx) */
2153 break;
2154 case TY_CHAR:
2155 o(0x0188); /* movl %eax/%al, (%ecx) */
2156 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002157 case TY_FLOAT:
2158 o(0x19d9); /* fstps (%ecx) */
2159 break;
2160 case TY_DOUBLE:
2161 o(0x19dd); /* fstpl (%ecx) */
2162 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002163 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002164 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002165 break;
2166 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002167 }
2168
Jack Palevich58c30ee2009-07-17 16:35:23 -07002169 virtual void loadR0FromR0() {
2170 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002171 assert(pPointerType->tag == TY_POINTER);
2172 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002173 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002174 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002175 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002176 break;
2177 case TY_CHAR:
2178 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002179 ob(0); /* add zero in code */
2180 break;
2181 case TY_FLOAT:
2182 o2(0x00d9); // flds (%eax)
2183 break;
2184 case TY_DOUBLE:
2185 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002186 break;
2187 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002188 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002189 break;
2190 }
Jack Palevich8df46192009-07-07 14:48:51 -07002191 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002192 }
2193
Jack Palevich8df46192009-07-07 14:48:51 -07002194 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002195 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002196 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002197 }
2198
Jack Palevich9f51a262009-07-29 16:22:26 -07002199 virtual int leaForward(int ea, Type* pPointerType) {
2200 oad(0xb8, ea); /* mov $xx, %eax */
2201 setR0Type(pPointerType);
2202 return getPC() - 4;
2203 }
2204
Jack Palevich9cbd2262009-07-08 16:48:41 -07002205 virtual void storeR0(int ea, Type* pType) {
2206 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002207 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002208 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002209 case TY_CHAR:
2210 if (ea < -LOCAL || ea > LOCAL) {
2211 oad(0xa2, ea); // movb %al,ea
2212 } else {
2213 oad(0x8588, ea); // movb %al,ea(%ebp)
2214 }
2215 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002216 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002217 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002218 gmov(6, ea); /* mov %eax, EA */
2219 break;
2220 case TY_FLOAT:
2221 if (ea < -LOCAL || ea > LOCAL) {
2222 oad(0x1dd9, ea); // fstps ea
2223 } else {
2224 oad(0x9dd9, ea); // fstps ea(%ebp)
2225 }
2226 break;
2227 case TY_DOUBLE:
2228 if (ea < -LOCAL || ea > LOCAL) {
2229 oad(0x1ddd, ea); // fstpl ea
2230 } else {
2231 oad(0x9ddd, ea); // fstpl ea(%ebp)
2232 }
2233 break;
2234 default:
2235 error("Unable to store to type %d", tag);
2236 break;
2237 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002238 }
2239
Jack Palevich8df46192009-07-07 14:48:51 -07002240 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002241 Type* pR0Type = getR0Type();
2242 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002243 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002244 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002245 return;
2246 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002247 if (bitsSame(pType, pR0Type)) {
2248 // do nothing special
2249 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2250 // do nothing special, both held in same register on x87.
2251 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002252 TypeTag r0Tag = collapseType(pR0Type->tag);
2253 TypeTag destTag = collapseType(pType->tag);
2254 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2255 // Convert R0 from int to float
2256 o(0x50); // push %eax
2257 o(0x2404DB); // fildl 0(%esp)
2258 o(0x58); // pop %eax
2259 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2260 // Convert R0 from float to int. Complicated because
2261 // need to save and restore the rounding mode.
2262 o(0x50); // push %eax
2263 o(0x50); // push %eax
2264 o(0x02247cD9); // fnstcw 2(%esp)
2265 o(0x2444b70f); // movzwl 2(%esp), %eax
2266 o(0x02);
2267 o(0x0cb4); // movb $12, %ah
2268 o(0x24048966); // movw %ax, 0(%esp)
2269 o(0x242cd9); // fldcw 0(%esp)
2270 o(0x04245cdb); // fistpl 4(%esp)
2271 o(0x02246cd9); // fldcw 2(%esp)
2272 o(0x58); // pop %eax
2273 o(0x58); // pop %eax
2274 } else {
2275 error("Incompatible types old: %d new: %d",
2276 pR0Type->tag, pType->tag);
2277 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002278 }
2279 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002280 }
2281
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002282 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002283 return oad(0xec81, 0); /* sub $xxx, %esp */
2284 }
2285
Jack Palevich8148c5b2009-07-16 18:24:47 -07002286 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2287 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002288 Type* pR0Type = getR0Type();
2289 TypeTag r0ct = collapseType(pR0Type->tag);
2290 switch(r0ct) {
2291 case TY_INT:
2292 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2293 return 4;
2294 case TY_FLOAT:
2295 oad(0x249CD9, l); /* fstps xxx(%esp) */
2296 return 4;
2297 case TY_DOUBLE:
2298 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2299 return 8;
2300 default:
2301 assert(false);
2302 return 0;
2303 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002304 }
2305
Jack Palevichb7718b92009-07-09 22:00:24 -07002306 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002307 * (int*) a = l;
2308 }
2309
Jack Palevich8df46192009-07-07 14:48:51 -07002310 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002311 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002312 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002313 return psym(0xe8, symbol); /* call xxx */
2314 }
2315
Jack Palevich8df46192009-07-07 14:48:51 -07002316 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002317 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002318 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002319 oad(0x2494ff, l); /* call *xxx(%esp) */
2320 }
2321
Jack Palevichb7718b92009-07-09 22:00:24 -07002322 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002323 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002324 if (isIndirect) {
2325 l += 4;
2326 }
-b master422972c2009-06-17 19:13:52 -07002327 if (l > 0) {
2328 oad(0xc481, l); /* add $xxx, %esp */
2329 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002330 }
2331
Jack Palevicha6535612009-05-13 16:24:17 -07002332 virtual int jumpOffset() {
2333 return 5;
2334 }
2335
2336 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002337 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002338 }
2339
Jack Paleviche7b59062009-05-19 17:12:17 -07002340 /* output a symbol and patch all calls to it */
2341 virtual void gsym(int t) {
2342 int n;
2343 int pc = getPC();
2344 while (t) {
2345 n = *(int *) t; /* next value */
2346 *(int *) t = pc - t - 4;
2347 t = n;
2348 }
2349 }
2350
Jack Palevich9f51a262009-07-29 16:22:26 -07002351 /* output a symbol and patch all calls to it, using absolute address */
2352 virtual void resolveForward(int t) {
2353 int n;
2354 int pc = getPC();
2355 while (t) {
2356 n = *(int *) t; /* next value */
2357 *(int *) t = pc;
2358 t = n;
2359 }
2360 }
2361
Jack Palevich1cdef202009-05-22 12:06:27 -07002362 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002363 size_t pagesize = 4096;
2364 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2365 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2366 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2367 if (err) {
2368 error("mprotect() failed: %d", errno);
2369 }
2370 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002371 }
2372
Jack Palevich9eed7a22009-07-06 17:24:34 -07002373 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002374 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002375 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002376 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002377 switch (pType->tag) {
2378 case TY_CHAR:
2379 return 1;
2380 default:
2381 return 4;
2382 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002383 }
2384
2385 /**
2386 * Array element alignment (in bytes) for this type of data.
2387 */
2388 virtual size_t sizeOf(Type* pType){
2389 switch(pType->tag) {
2390 case TY_INT:
2391 return 4;
2392 case TY_CHAR:
2393 return 1;
2394 default:
2395 return 0;
2396 case TY_FLOAT:
2397 return 4;
2398 case TY_DOUBLE:
2399 return 8;
2400 case TY_POINTER:
2401 return 4;
2402 }
2403 }
2404
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002405 virtual size_t stackAlignmentOf(Type* pType){
2406 return 4;
2407 }
2408
Jack Palevich9cbd2262009-07-08 16:48:41 -07002409 virtual size_t stackSizeOf(Type* pType) {
2410 switch(pType->tag) {
2411 case TY_DOUBLE:
2412 return 8;
2413 default:
2414 return 4;
2415 }
2416 }
2417
Jack Palevich21a15a22009-05-11 14:49:29 -07002418 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002419
2420 /** Output 1 to 4 bytes.
2421 *
2422 */
2423 void o(int n) {
2424 /* cannot use unsigned, so we must do a hack */
2425 while (n && n != -1) {
2426 ob(n & 0xff);
2427 n = n >> 8;
2428 }
2429 }
2430
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002431 /* Output exactly 2 bytes
2432 */
2433 void o2(int n) {
2434 ob(n & 0xff);
2435 ob(0xff & (n >> 8));
2436 }
2437
Jack Paleviche7b59062009-05-19 17:12:17 -07002438 /* psym is used to put an instruction with a data field which is a
2439 reference to a symbol. It is in fact the same as oad ! */
2440 int psym(int n, int t) {
2441 return oad(n, t);
2442 }
2443
2444 /* instruction + address */
2445 int oad(int n, int t) {
2446 o(n);
2447 int result = getPC();
2448 o4(t);
2449 return result;
2450 }
2451
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002452 static const int operatorHelper[];
2453
2454 int decodeOp(int op) {
2455 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002456 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002457 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002458 }
2459 return operatorHelper[op];
2460 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002461
Jack Palevich546b2242009-05-13 15:10:04 -07002462 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002463 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002464 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002465 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002466
2467 void setupFloatOperands() {
2468 Type* pR0Type = getR0Type();
2469 Type* pTOSType = getTOSType();
2470 TypeTag tagR0 = pR0Type->tag;
2471 TypeTag tagTOS = pTOSType->tag;
2472 bool isFloatR0 = isFloatTag(tagR0);
2473 bool isFloatTOS = isFloatTag(tagTOS);
2474 if (! isFloatR0) {
2475 // Convert R0 from int to float
2476 o(0x50); // push %eax
2477 o(0x2404DB); // fildl 0(%esp)
2478 o(0x58); // pop %eax
2479 }
2480 if (! isFloatTOS){
2481 o(0x2404DB); // fildl 0(%esp);
2482 o(0x58); // pop %eax
2483 } else {
2484 if (tagTOS == TY_FLOAT) {
2485 o(0x2404d9); // flds (%esp)
2486 o(0x58); // pop %eax
2487 } else {
2488 o(0x2404dd); // fldl (%esp)
2489 o(0x58); // pop %eax
2490 o(0x58); // pop %eax
2491 }
2492 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002493 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002494 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002495 };
2496
Jack Paleviche7b59062009-05-19 17:12:17 -07002497#endif // PROVIDE_X86_CODEGEN
2498
Jack Palevichb67b18f2009-06-11 21:12:23 -07002499#ifdef PROVIDE_TRACE_CODEGEN
2500 class TraceCodeGenerator : public CodeGenerator {
2501 private:
2502 CodeGenerator* mpBase;
2503
2504 public:
2505 TraceCodeGenerator(CodeGenerator* pBase) {
2506 mpBase = pBase;
2507 }
2508
2509 virtual ~TraceCodeGenerator() {
2510 delete mpBase;
2511 }
2512
2513 virtual void init(CodeBuf* pCodeBuf) {
2514 mpBase->init(pCodeBuf);
2515 }
2516
2517 void setErrorSink(ErrorSink* pErrorSink) {
2518 mpBase->setErrorSink(pErrorSink);
2519 }
2520
2521 /* returns address to patch with local variable size
2522 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002523 virtual int functionEntry(Type* pDecl) {
2524 int result = mpBase->functionEntry(pDecl);
2525 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002526 return result;
2527 }
2528
Jack Palevichb7718b92009-07-09 22:00:24 -07002529 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2530 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2531 localVariableAddress, localVariableSize);
2532 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002533 }
2534
2535 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002536 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002537 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002538 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002539 }
2540
Jack Palevich1a539db2009-07-08 13:04:41 -07002541 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002542 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002543 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002544 }
2545
Jack Palevichb67b18f2009-06-11 21:12:23 -07002546 virtual int gjmp(int t) {
2547 int result = mpBase->gjmp(t);
2548 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2549 return result;
2550 }
2551
2552 /* l = 0: je, l == 1: jne */
2553 virtual int gtst(bool l, int t) {
2554 int result = mpBase->gtst(l, t);
2555 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2556 return result;
2557 }
2558
Jack Palevich58c30ee2009-07-17 16:35:23 -07002559 virtual void gcmp(int op) {
2560 fprintf(stderr, "gcmp(%d)\n", op);
2561 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002562 }
2563
2564 virtual void genOp(int op) {
2565 fprintf(stderr, "genOp(%d)\n", op);
2566 mpBase->genOp(op);
2567 }
2568
Jack Palevich9eed7a22009-07-06 17:24:34 -07002569
Jack Palevich58c30ee2009-07-17 16:35:23 -07002570 virtual void gUnaryCmp(int op) {
2571 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2572 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002573 }
2574
2575 virtual void genUnaryOp(int op) {
2576 fprintf(stderr, "genUnaryOp(%d)\n", op);
2577 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002578 }
2579
2580 virtual void pushR0() {
2581 fprintf(stderr, "pushR0()\n");
2582 mpBase->pushR0();
2583 }
2584
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002585 virtual void over() {
2586 fprintf(stderr, "over()\n");
2587 mpBase->over();
2588 }
2589
Jack Palevich58c30ee2009-07-17 16:35:23 -07002590 virtual void popR0() {
2591 fprintf(stderr, "popR0()\n");
2592 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002593 }
2594
Jack Palevich58c30ee2009-07-17 16:35:23 -07002595 virtual void storeR0ToTOS() {
2596 fprintf(stderr, "storeR0ToTOS()\n");
2597 mpBase->storeR0ToTOS();
2598 }
2599
2600 virtual void loadR0FromR0() {
2601 fprintf(stderr, "loadR0FromR0()\n");
2602 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002603 }
2604
Jack Palevich8df46192009-07-07 14:48:51 -07002605 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002606 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002607 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002608 }
2609
Jack Palevich9f51a262009-07-29 16:22:26 -07002610 virtual int leaForward(int ea, Type* pPointerType) {
2611 fprintf(stderr, "leaForward(%d)\n", ea);
2612 return mpBase->leaForward(ea, pPointerType);
2613 }
2614
Jack Palevich9cbd2262009-07-08 16:48:41 -07002615 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002616 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002617 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002618 }
2619
Jack Palevich8df46192009-07-07 14:48:51 -07002620 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002621 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002622 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002623 }
2624
2625 virtual int beginFunctionCallArguments() {
2626 int result = mpBase->beginFunctionCallArguments();
2627 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2628 return result;
2629 }
2630
Jack Palevich8148c5b2009-07-16 18:24:47 -07002631 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2632 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2633 pArgType->tag);
2634 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002635 }
2636
Jack Palevichb7718b92009-07-09 22:00:24 -07002637 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002638 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002639 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002640 }
2641
Jack Palevich8df46192009-07-07 14:48:51 -07002642 virtual int callForward(int symbol, Type* pFunc) {
2643 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002644 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2645 return result;
2646 }
2647
Jack Palevich8df46192009-07-07 14:48:51 -07002648 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002649 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2650 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002651 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002652 }
2653
Jack Palevichb7718b92009-07-09 22:00:24 -07002654 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2655 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2656 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002657 }
2658
2659 virtual int jumpOffset() {
2660 return mpBase->jumpOffset();
2661 }
2662
2663 virtual int disassemble(FILE* out) {
2664 return mpBase->disassemble(out);
2665 }
2666
2667 /* output a symbol and patch all calls to it */
2668 virtual void gsym(int t) {
2669 fprintf(stderr, "gsym(%d)\n", t);
2670 mpBase->gsym(t);
2671 }
2672
Jack Palevich9f51a262009-07-29 16:22:26 -07002673 virtual void resolveForward(int t) {
2674 mpBase->resolveForward(t);
2675 }
2676
Jack Palevichb67b18f2009-06-11 21:12:23 -07002677 virtual int finishCompile() {
2678 int result = mpBase->finishCompile();
2679 fprintf(stderr, "finishCompile() = %d\n", result);
2680 return result;
2681 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002682
2683 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002684 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002685 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002686 virtual size_t alignmentOf(Type* pType){
2687 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002688 }
2689
2690 /**
2691 * Array element alignment (in bytes) for this type of data.
2692 */
2693 virtual size_t sizeOf(Type* pType){
2694 return mpBase->sizeOf(pType);
2695 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002696
Jack Palevich9cbd2262009-07-08 16:48:41 -07002697
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002698 virtual size_t stackAlignmentOf(Type* pType) {
2699 return mpBase->stackAlignmentOf(pType);
2700 }
2701
2702
Jack Palevich9cbd2262009-07-08 16:48:41 -07002703 virtual size_t stackSizeOf(Type* pType) {
2704 return mpBase->stackSizeOf(pType);
2705 }
2706
Jack Palevich1a539db2009-07-08 13:04:41 -07002707 virtual Type* getR0Type() {
2708 return mpBase->getR0Type();
2709 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002710
2711 virtual ExpressionType getR0ExpressionType() {
2712 return mpBase->getR0ExpressionType();
2713 }
2714
2715 virtual void setR0ExpressionType(ExpressionType et) {
2716 mpBase->setR0ExpressionType(et);
2717 }
2718
2719 virtual size_t getExpressionStackDepth() {
2720 return mpBase->getExpressionStackDepth();
2721 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002722 };
2723
2724#endif // PROVIDE_TRACE_CODEGEN
2725
Jack Palevich569f1352009-06-29 14:29:08 -07002726 class Arena {
2727 public:
2728 // Used to record a given allocation amount.
2729 // Used:
2730 // Mark mark = arena.mark();
2731 // ... lots of arena.allocate()
2732 // arena.free(mark);
2733
2734 struct Mark {
2735 size_t chunk;
2736 size_t offset;
2737 };
2738
2739 Arena() {
2740 mCurrentChunk = 0;
2741 Chunk start(CHUNK_SIZE);
2742 mData.push_back(start);
2743 }
2744
2745 ~Arena() {
2746 for(size_t i = 0; i < mData.size(); i++) {
2747 mData[i].free();
2748 }
2749 }
2750
2751 // Alloc using the standard alignment size safe for any variable
2752 void* alloc(size_t size) {
2753 return alloc(size, 8);
2754 }
2755
2756 Mark mark(){
2757 Mark result;
2758 result.chunk = mCurrentChunk;
2759 result.offset = mData[mCurrentChunk].mOffset;
2760 return result;
2761 }
2762
2763 void freeToMark(const Mark& mark) {
2764 mCurrentChunk = mark.chunk;
2765 mData[mCurrentChunk].mOffset = mark.offset;
2766 }
2767
2768 private:
2769 // Allocate memory aligned to a given size
2770 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2771 // Memory is not zero filled.
2772
2773 void* alloc(size_t size, size_t alignment) {
2774 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2775 if (mCurrentChunk + 1 < mData.size()) {
2776 mCurrentChunk++;
2777 } else {
2778 size_t allocSize = CHUNK_SIZE;
2779 if (allocSize < size + alignment - 1) {
2780 allocSize = size + alignment - 1;
2781 }
2782 Chunk chunk(allocSize);
2783 mData.push_back(chunk);
2784 mCurrentChunk++;
2785 }
2786 }
2787 return mData[mCurrentChunk].allocate(size, alignment);
2788 }
2789
2790 static const size_t CHUNK_SIZE = 128*1024;
2791 // Note: this class does not deallocate its
2792 // memory when it's destroyed. It depends upon
2793 // its parent to deallocate the memory.
2794 struct Chunk {
2795 Chunk() {
2796 mpData = 0;
2797 mSize = 0;
2798 mOffset = 0;
2799 }
2800
2801 Chunk(size_t size) {
2802 mSize = size;
2803 mpData = (char*) malloc(size);
2804 mOffset = 0;
2805 }
2806
2807 ~Chunk() {
2808 // Doesn't deallocate memory.
2809 }
2810
2811 void* allocate(size_t size, size_t alignment) {
2812 size_t alignedOffset = aligned(mOffset, alignment);
2813 void* result = mpData + alignedOffset;
2814 mOffset = alignedOffset + size;
2815 return result;
2816 }
2817
2818 void free() {
2819 if (mpData) {
2820 ::free(mpData);
2821 mpData = 0;
2822 }
2823 }
2824
2825 size_t remainingCapacity(size_t alignment) {
2826 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2827 }
2828
2829 // Assume alignment is a power of two
2830 inline size_t aligned(size_t v, size_t alignment) {
2831 size_t mask = alignment-1;
2832 return (v + mask) & ~mask;
2833 }
2834
2835 char* mpData;
2836 size_t mSize;
2837 size_t mOffset;
2838 };
2839
2840 size_t mCurrentChunk;
2841
2842 Vector<Chunk> mData;
2843 };
2844
Jack Palevich569f1352009-06-29 14:29:08 -07002845 struct VariableInfo;
2846
2847 struct Token {
2848 int hash;
2849 size_t length;
2850 char* pText;
2851 tokenid_t id;
2852
2853 // Current values for the token
2854 char* mpMacroDefinition;
2855 VariableInfo* mpVariableInfo;
2856 };
2857
2858 class TokenTable {
2859 public:
2860 // Don't use 0..0xff, allows characters and operators to be tokens too.
2861
2862 static const int TOKEN_BASE = 0x100;
2863 TokenTable() {
2864 mpMap = hashmapCreate(128, hashFn, equalsFn);
2865 }
2866
2867 ~TokenTable() {
2868 hashmapFree(mpMap);
2869 }
2870
2871 void setArena(Arena* pArena) {
2872 mpArena = pArena;
2873 }
2874
2875 // Returns a token for a given string of characters.
2876 tokenid_t intern(const char* pText, size_t length) {
2877 Token probe;
2878 int hash = hashmapHash((void*) pText, length);
2879 {
2880 Token probe;
2881 probe.hash = hash;
2882 probe.length = length;
2883 probe.pText = (char*) pText;
2884 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2885 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002886 return pValue->id;
2887 }
2888 }
2889
2890 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2891 memset(pToken, 0, sizeof(*pToken));
2892 pToken->hash = hash;
2893 pToken->length = length;
2894 pToken->pText = (char*) mpArena->alloc(length + 1);
2895 memcpy(pToken->pText, pText, length);
2896 pToken->pText[length] = 0;
2897 pToken->id = mTokens.size() + TOKEN_BASE;
2898 mTokens.push_back(pToken);
2899 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002900 return pToken->id;
2901 }
2902
2903 // Return the Token for a given tokenid.
2904 Token& operator[](tokenid_t id) {
2905 return *mTokens[id - TOKEN_BASE];
2906 }
2907
2908 inline size_t size() {
2909 return mTokens.size();
2910 }
2911
2912 private:
2913
2914 static int hashFn(void* pKey) {
2915 Token* pToken = (Token*) pKey;
2916 return pToken->hash;
2917 }
2918
2919 static bool equalsFn(void* keyA, void* keyB) {
2920 Token* pTokenA = (Token*) keyA;
2921 Token* pTokenB = (Token*) keyB;
2922 // Don't need to compare hash values, they should always be equal
2923 return pTokenA->length == pTokenB->length
2924 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2925 }
2926
2927 Hashmap* mpMap;
2928 Vector<Token*> mTokens;
2929 Arena* mpArena;
2930 };
2931
Jack Palevich1cdef202009-05-22 12:06:27 -07002932 class InputStream {
2933 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002934 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002935 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002936 };
2937
2938 class TextInputStream : public InputStream {
2939 public:
2940 TextInputStream(const char* text, size_t textLength)
2941 : pText(text), mTextLength(textLength), mPosition(0) {
2942 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002943
Jack Palevichdc456462009-07-16 16:50:56 -07002944 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002945 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2946 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002947
Jack Palevichdc456462009-07-16 16:50:56 -07002948 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002949 const char* pText;
2950 size_t mTextLength;
2951 size_t mPosition;
2952 };
2953
Jack Palevicheedf9d22009-06-04 16:23:40 -07002954 class String {
2955 public:
2956 String() {
2957 mpBase = 0;
2958 mUsed = 0;
2959 mSize = 0;
2960 }
2961
Jack Palevich303d8ff2009-06-11 19:06:24 -07002962 String(const char* item, int len, bool adopt) {
2963 if (len < 0) {
2964 len = strlen(item);
2965 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002966 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002967 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002968 mUsed = len;
2969 mSize = len + 1;
2970 } else {
2971 mpBase = 0;
2972 mUsed = 0;
2973 mSize = 0;
2974 appendBytes(item, len);
2975 }
2976 }
2977
Jack Palevich303d8ff2009-06-11 19:06:24 -07002978 String(const String& other) {
2979 mpBase = 0;
2980 mUsed = 0;
2981 mSize = 0;
2982 appendBytes(other.getUnwrapped(), other.len());
2983 }
2984
Jack Palevicheedf9d22009-06-04 16:23:40 -07002985 ~String() {
2986 if (mpBase) {
2987 free(mpBase);
2988 }
2989 }
2990
Jack Palevicha6baa232009-06-12 11:25:59 -07002991 String& operator=(const String& other) {
2992 clear();
2993 appendBytes(other.getUnwrapped(), other.len());
2994 return *this;
2995 }
2996
Jack Palevich303d8ff2009-06-11 19:06:24 -07002997 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002998 return mpBase;
2999 }
3000
Jack Palevich303d8ff2009-06-11 19:06:24 -07003001 void clear() {
3002 mUsed = 0;
3003 if (mSize > 0) {
3004 mpBase[0] = 0;
3005 }
3006 }
3007
Jack Palevicheedf9d22009-06-04 16:23:40 -07003008 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003009 appendBytes(s, strlen(s));
3010 }
3011
3012 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003013 memcpy(ensure(n), s, n + 1);
3014 }
3015
3016 void append(char c) {
3017 * ensure(1) = c;
3018 }
3019
Jack Palevich86351982009-06-30 18:09:56 -07003020 void append(String& other) {
3021 appendBytes(other.getUnwrapped(), other.len());
3022 }
3023
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003024 char* orphan() {
3025 char* result = mpBase;
3026 mpBase = 0;
3027 mUsed = 0;
3028 mSize = 0;
3029 return result;
3030 }
3031
Jack Palevicheedf9d22009-06-04 16:23:40 -07003032 void printf(const char* fmt,...) {
3033 va_list ap;
3034 va_start(ap, fmt);
3035 vprintf(fmt, ap);
3036 va_end(ap);
3037 }
3038
3039 void vprintf(const char* fmt, va_list ap) {
3040 char* temp;
3041 int numChars = vasprintf(&temp, fmt, ap);
3042 memcpy(ensure(numChars), temp, numChars+1);
3043 free(temp);
3044 }
3045
Jack Palevich303d8ff2009-06-11 19:06:24 -07003046 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003047 return mUsed;
3048 }
3049
3050 private:
3051 char* ensure(int n) {
3052 size_t newUsed = mUsed + n;
3053 if (newUsed > mSize) {
3054 size_t newSize = mSize * 2 + 10;
3055 if (newSize < newUsed) {
3056 newSize = newUsed;
3057 }
3058 mpBase = (char*) realloc(mpBase, newSize + 1);
3059 mSize = newSize;
3060 }
3061 mpBase[newUsed] = '\0';
3062 char* result = mpBase + mUsed;
3063 mUsed = newUsed;
3064 return result;
3065 }
3066
3067 char* mpBase;
3068 size_t mUsed;
3069 size_t mSize;
3070 };
3071
Jack Palevich569f1352009-06-29 14:29:08 -07003072 void internKeywords() {
3073 // Note: order has to match TOK_ constants
3074 static const char* keywords[] = {
3075 "int",
3076 "char",
3077 "void",
3078 "if",
3079 "else",
3080 "while",
3081 "break",
3082 "return",
3083 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003084 "auto",
3085 "case",
3086 "const",
3087 "continue",
3088 "default",
3089 "do",
3090 "double",
3091 "enum",
3092 "extern",
3093 "float",
3094 "goto",
3095 "long",
3096 "register",
3097 "short",
3098 "signed",
3099 "sizeof",
3100 "static",
3101 "struct",
3102 "switch",
3103 "typedef",
3104 "union",
3105 "unsigned",
3106 "volatile",
3107 "_Bool",
3108 "_Complex",
3109 "_Imaginary",
3110 "inline",
3111 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003112
3113 // predefined tokens that can also be symbols start here:
3114 "pragma",
3115 "define",
3116 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003117 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003118
Jack Palevich569f1352009-06-29 14:29:08 -07003119 for(int i = 0; keywords[i]; i++) {
3120 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003121 }
Jack Palevich569f1352009-06-29 14:29:08 -07003122 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003123
Jack Palevich36d94142009-06-08 15:55:32 -07003124 struct InputState {
3125 InputStream* pStream;
3126 int oldCh;
3127 };
3128
Jack Palevich2db168f2009-06-11 14:29:47 -07003129 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003130 void* pAddress;
3131 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003132 tokenid_t tok;
3133 size_t level;
3134 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003135 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003136 };
3137
Jack Palevich303d8ff2009-06-11 19:06:24 -07003138 class SymbolStack {
3139 public:
3140 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003141 mpArena = 0;
3142 mpTokenTable = 0;
3143 }
3144
3145 void setArena(Arena* pArena) {
3146 mpArena = pArena;
3147 }
3148
3149 void setTokenTable(TokenTable* pTokenTable) {
3150 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003151 }
3152
3153 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003154 Mark mark;
3155 mark.mArenaMark = mpArena->mark();
3156 mark.mSymbolHead = mStack.size();
3157 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003158 }
3159
3160 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003161 // Undo any shadowing that was done:
3162 Mark mark = mLevelStack.back();
3163 mLevelStack.pop_back();
3164 while (mStack.size() > mark.mSymbolHead) {
3165 VariableInfo* pV = mStack.back();
3166 mStack.pop_back();
3167 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003168 }
Jack Palevich569f1352009-06-29 14:29:08 -07003169 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003170 }
3171
Jack Palevich569f1352009-06-29 14:29:08 -07003172 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3173 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3174 return pV && pV->level == level();
3175 }
3176
3177 VariableInfo* add(tokenid_t tok) {
3178 Token& token = (*mpTokenTable)[tok];
3179 VariableInfo* pOldV = token.mpVariableInfo;
3180 VariableInfo* pNewV =
3181 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3182 memset(pNewV, 0, sizeof(VariableInfo));
3183 pNewV->tok = tok;
3184 pNewV->level = level();
3185 pNewV->pOldDefinition = pOldV;
3186 token.mpVariableInfo = pNewV;
3187 mStack.push_back(pNewV);
3188 return pNewV;
3189 }
3190
Jack Palevich86351982009-06-30 18:09:56 -07003191 VariableInfo* add(Type* pType) {
3192 VariableInfo* pVI = add(pType->id);
3193 pVI->pType = pType;
3194 return pVI;
3195 }
3196
Jack Palevich569f1352009-06-29 14:29:08 -07003197 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3198 for (size_t i = 0; i < mStack.size(); i++) {
3199 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003200 break;
3201 }
3202 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003203 }
3204
Jack Palevich303d8ff2009-06-11 19:06:24 -07003205 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003206 inline size_t level() {
3207 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003208 }
3209
Jack Palevich569f1352009-06-29 14:29:08 -07003210 struct Mark {
3211 Arena::Mark mArenaMark;
3212 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003213 };
3214
Jack Palevich569f1352009-06-29 14:29:08 -07003215 Arena* mpArena;
3216 TokenTable* mpTokenTable;
3217 Vector<VariableInfo*> mStack;
3218 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003219 };
Jack Palevich36d94142009-06-08 15:55:32 -07003220
3221 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003222 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003223 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003224 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003225 int tokl; // token operator level
3226 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003227 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003228 intptr_t loc; // local variable index
3229 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003230 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003231 char* dptr; // Macro state: Points to macro text during macro playback.
3232 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003233 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003234 ACCSymbolLookupFn mpSymbolLookupFn;
3235 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003236
3237 // Arena for the duration of the compile
3238 Arena mGlobalArena;
3239 // Arena for data that's only needed when compiling a single function
3240 Arena mLocalArena;
3241
Jack Palevich2ff5c222009-07-23 15:11:22 -07003242 Arena* mpCurrentArena;
3243
Jack Palevich569f1352009-06-29 14:29:08 -07003244 TokenTable mTokenTable;
3245 SymbolStack mGlobals;
3246 SymbolStack mLocals;
3247
Jack Palevich40600de2009-07-01 15:32:35 -07003248 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003249 Type* mkpInt; // int
3250 Type* mkpChar; // char
3251 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003252 Type* mkpFloat;
3253 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003254 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003255 Type* mkpIntPtr;
3256 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003257 Type* mkpFloatPtr;
3258 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003259 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003260
Jack Palevich36d94142009-06-08 15:55:32 -07003261 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003262 int mLineNumber;
3263 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003264
3265 CodeBuf codeBuf;
3266 CodeGenerator* pGen;
3267
Jack Palevicheedf9d22009-06-04 16:23:40 -07003268 String mErrorBuf;
3269
Jack Palevicheedf9d22009-06-04 16:23:40 -07003270 String mPragmas;
3271 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003272 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003273
Jack Palevich21a15a22009-05-11 14:49:29 -07003274 static const int ALLOC_SIZE = 99999;
3275
Jack Palevich303d8ff2009-06-11 19:06:24 -07003276 static const int TOK_DUMMY = 1;
3277 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003278 static const int TOK_NUM_FLOAT = 3;
3279 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003280
3281 // 3..255 are character and/or operators
3282
Jack Palevich2db168f2009-06-11 14:29:47 -07003283 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003284 // Order has to match string list in "internKeywords".
3285 enum {
3286 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3287 TOK_INT = TOK_KEYWORD,
3288 TOK_CHAR,
3289 TOK_VOID,
3290 TOK_IF,
3291 TOK_ELSE,
3292 TOK_WHILE,
3293 TOK_BREAK,
3294 TOK_RETURN,
3295 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003296 TOK_AUTO,
3297 TOK_CASE,
3298 TOK_CONST,
3299 TOK_CONTINUE,
3300 TOK_DEFAULT,
3301 TOK_DO,
3302 TOK_DOUBLE,
3303 TOK_ENUM,
3304 TOK_EXTERN,
3305 TOK_FLOAT,
3306 TOK_GOTO,
3307 TOK_LONG,
3308 TOK_REGISTER,
3309 TOK_SHORT,
3310 TOK_SIGNED,
3311 TOK_SIZEOF,
3312 TOK_STATIC,
3313 TOK_STRUCT,
3314 TOK_SWITCH,
3315 TOK_TYPEDEF,
3316 TOK_UNION,
3317 TOK_UNSIGNED,
3318 TOK_VOLATILE,
3319 TOK__BOOL,
3320 TOK__COMPLEX,
3321 TOK__IMAGINARY,
3322 TOK_INLINE,
3323 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003324
3325 // Symbols start after keywords
3326
3327 TOK_SYMBOL,
3328 TOK_PRAGMA = TOK_SYMBOL,
3329 TOK_DEFINE,
3330 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003331 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003332
3333 static const int LOCAL = 0x200;
3334
3335 static const int SYM_FORWARD = 0;
3336 static const int SYM_DEFINE = 1;
3337
3338 /* tokens in string heap */
3339 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003340
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003341 static const int OP_INCREMENT = 0;
3342 static const int OP_DECREMENT = 1;
3343 static const int OP_MUL = 2;
3344 static const int OP_DIV = 3;
3345 static const int OP_MOD = 4;
3346 static const int OP_PLUS = 5;
3347 static const int OP_MINUS = 6;
3348 static const int OP_SHIFT_LEFT = 7;
3349 static const int OP_SHIFT_RIGHT = 8;
3350 static const int OP_LESS_EQUAL = 9;
3351 static const int OP_GREATER_EQUAL = 10;
3352 static const int OP_LESS = 11;
3353 static const int OP_GREATER = 12;
3354 static const int OP_EQUALS = 13;
3355 static const int OP_NOT_EQUALS = 14;
3356 static const int OP_LOGICAL_AND = 15;
3357 static const int OP_LOGICAL_OR = 16;
3358 static const int OP_BIT_AND = 17;
3359 static const int OP_BIT_XOR = 18;
3360 static const int OP_BIT_OR = 19;
3361 static const int OP_BIT_NOT = 20;
3362 static const int OP_LOGICAL_NOT = 21;
3363 static const int OP_COUNT = 22;
3364
3365 /* Operators are searched from front, the two-character operators appear
3366 * before the single-character operators with the same first character.
3367 * @ is used to pad out single-character operators.
3368 */
3369 static const char* operatorChars;
3370 static const char operatorLevel[];
3371
Jack Palevich569f1352009-06-29 14:29:08 -07003372 /* Called when we detect an internal problem. Does nothing in production.
3373 *
3374 */
3375 void internalError() {
3376 * (char*) 0 = 0;
3377 }
3378
Jack Palevich86351982009-06-30 18:09:56 -07003379 void assert(bool isTrue) {
3380 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003381 internalError();
3382 }
Jack Palevich86351982009-06-30 18:09:56 -07003383 }
3384
Jack Palevich40600de2009-07-01 15:32:35 -07003385 bool isSymbol(tokenid_t t) {
3386 return t >= TOK_SYMBOL &&
3387 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3388 }
3389
3390 bool isSymbolOrKeyword(tokenid_t t) {
3391 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003392 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003393 }
3394
Jack Palevich86351982009-06-30 18:09:56 -07003395 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003396 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003397 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3398 if (pV && pV->tok != t) {
3399 internalError();
3400 }
3401 return pV;
3402 }
3403
3404 inline bool isDefined(tokenid_t t) {
3405 return t >= TOK_SYMBOL && VI(t) != 0;
3406 }
3407
Jack Palevich40600de2009-07-01 15:32:35 -07003408 const char* nameof(tokenid_t t) {
3409 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003410 return mTokenTable[t].pText;
3411 }
3412
Jack Palevich21a15a22009-05-11 14:49:29 -07003413 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003414 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003415 }
3416
3417 void inp() {
3418 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003419 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003420 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003421 dptr = 0;
3422 ch = dch;
3423 }
Jack Palevichdc456462009-07-16 16:50:56 -07003424 } else {
3425 if (mbBumpLine) {
3426 mLineNumber++;
3427 mbBumpLine = false;
3428 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003429 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003430 if (ch == '\n') {
3431 mbBumpLine = true;
3432 }
3433 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003434#if 0
3435 printf("ch='%c' 0x%x\n", ch, ch);
3436#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003437 }
3438
3439 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003440 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003441 }
3442
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003443 int decodeHex(int c) {
3444 if (isdigit(c)) {
3445 c -= '0';
3446 } else if (c <= 'F') {
3447 c = c - 'A' + 10;
3448 } else {
3449 c =c - 'a' + 10;
3450 }
3451 return c;
3452 }
3453
Jack Palevichb4758ff2009-06-12 12:49:14 -07003454 /* read a character constant, advances ch to after end of constant */
3455 int getq() {
3456 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003457 if (ch == '\\') {
3458 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003459 if (isoctal(ch)) {
3460 // 1 to 3 octal characters.
3461 val = 0;
3462 for(int i = 0; i < 3; i++) {
3463 if (isoctal(ch)) {
3464 val = (val << 3) + ch - '0';
3465 inp();
3466 }
3467 }
3468 return val;
3469 } else if (ch == 'x' || ch == 'X') {
3470 // N hex chars
3471 inp();
3472 if (! isxdigit(ch)) {
3473 error("'x' character escape requires at least one digit.");
3474 } else {
3475 val = 0;
3476 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003477 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003478 inp();
3479 }
3480 }
3481 } else {
3482 int val = ch;
3483 switch (ch) {
3484 case 'a':
3485 val = '\a';
3486 break;
3487 case 'b':
3488 val = '\b';
3489 break;
3490 case 'f':
3491 val = '\f';
3492 break;
3493 case 'n':
3494 val = '\n';
3495 break;
3496 case 'r':
3497 val = '\r';
3498 break;
3499 case 't':
3500 val = '\t';
3501 break;
3502 case 'v':
3503 val = '\v';
3504 break;
3505 case '\\':
3506 val = '\\';
3507 break;
3508 case '\'':
3509 val = '\'';
3510 break;
3511 case '"':
3512 val = '"';
3513 break;
3514 case '?':
3515 val = '?';
3516 break;
3517 default:
3518 error("Undefined character escape %c", ch);
3519 break;
3520 }
3521 inp();
3522 return val;
3523 }
3524 } else {
3525 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003526 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003527 return val;
3528 }
3529
3530 static bool isoctal(int ch) {
3531 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003532 }
3533
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003534 bool acceptCh(int c) {
3535 bool result = c == ch;
3536 if (result) {
3537 pdef(ch);
3538 inp();
3539 }
3540 return result;
3541 }
3542
3543 bool acceptDigitsCh() {
3544 bool result = false;
3545 while (isdigit(ch)) {
3546 result = true;
3547 pdef(ch);
3548 inp();
3549 }
3550 return result;
3551 }
3552
3553 void parseFloat() {
3554 tok = TOK_NUM_DOUBLE;
3555 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003556 if(mTokenString.len() == 0) {
3557 mTokenString.append('0');
3558 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003559 acceptCh('.');
3560 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003561 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003562 acceptCh('-') || acceptCh('+');
3563 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003564 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003565 if (ch == 'f' || ch == 'F') {
3566 tok = TOK_NUM_FLOAT;
3567 inp();
3568 } else if (ch == 'l' || ch == 'L') {
3569 inp();
3570 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003571 }
3572 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003573 char* pEnd = pText + strlen(pText);
3574 char* pEndPtr = 0;
3575 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003576 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003577 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003578 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003579 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003580 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003581 if (errno || pEndPtr != pEnd) {
3582 error("Can't parse constant: %s", pText);
3583 }
3584 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003585 }
3586
Jack Palevich21a15a22009-05-11 14:49:29 -07003587 void next() {
3588 int l, a;
3589
Jack Palevich546b2242009-05-13 15:10:04 -07003590 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003591 if (ch == '#') {
3592 inp();
3593 next();
3594 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003595 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003596 } else if (tok == TOK_PRAGMA) {
3597 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003598 } else if (tok == TOK_LINE) {
3599 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003600 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003601 error("Unsupported preprocessor directive \"%s\"",
3602 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003603 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003604 }
3605 inp();
3606 }
3607 tokl = 0;
3608 tok = ch;
3609 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003610 if (isdigit(ch) || ch == '.') {
3611 // Start of a numeric constant. Could be integer, float, or
3612 // double, won't know until we look further.
3613 mTokenString.clear();
3614 pdef(ch);
3615 inp();
3616 int base = 10;
3617 if (tok == '0') {
3618 if (ch == 'x' || ch == 'X') {
3619 base = 16;
3620 tok = TOK_NUM;
3621 tokc = 0;
3622 inp();
3623 while ( isxdigit(ch) ) {
3624 tokc = (tokc << 4) + decodeHex(ch);
3625 inp();
3626 }
3627 } else if (isoctal(ch)){
3628 base = 8;
3629 tok = TOK_NUM;
3630 tokc = 0;
3631 while ( isoctal(ch) ) {
3632 tokc = (tokc << 3) + (ch - '0');
3633 inp();
3634 }
3635 }
3636 } else if (isdigit(tok)){
3637 acceptDigitsCh();
3638 }
3639 if (base == 10) {
3640 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3641 parseFloat();
3642 } else {
3643 // It's an integer constant
3644 char* pText = mTokenString.getUnwrapped();
3645 char* pEnd = pText + strlen(pText);
3646 char* pEndPtr = 0;
3647 errno = 0;
3648 tokc = strtol(pText, &pEndPtr, base);
3649 if (errno || pEndPtr != pEnd) {
3650 error("Can't parse constant: %s %d %d", pText, base, errno);
3651 }
3652 tok = TOK_NUM;
3653 }
3654 }
3655 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003656 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003657 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003658 pdef(ch);
3659 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003660 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003661 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3662 // Is this a macro?
3663 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3664 if (pMacroDefinition) {
3665 // Yes, it is a macro
3666 dptr = pMacroDefinition;
3667 dch = ch;
3668 inp();
3669 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003670 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003671 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003672 inp();
3673 if (tok == '\'') {
3674 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003675 tokc = getq();
3676 if (ch != '\'') {
3677 error("Expected a ' character, got %c", ch);
3678 } else {
3679 inp();
3680 }
Jack Palevich546b2242009-05-13 15:10:04 -07003681 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003682 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003683 while (ch && ch != EOF) {
3684 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003685 inp();
3686 inp();
3687 if (ch == '/')
3688 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003689 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003690 if (ch == EOF) {
3691 error("End of file inside comment.");
3692 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003693 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003694 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003695 } else if ((tok == '/') & (ch == '/')) {
3696 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003697 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003698 inp();
3699 }
3700 inp();
3701 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003702 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003703 const char* t = operatorChars;
3704 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003705 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003706 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003707 tokl = operatorLevel[opIndex];
3708 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003709 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003710#if 0
3711 printf("%c%c -> tokl=%d tokc=0x%x\n",
3712 l, a, tokl, tokc);
3713#endif
3714 if (a == ch) {
3715 inp();
3716 tok = TOK_DUMMY; /* dummy token for double tokens */
3717 }
3718 break;
3719 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003720 opIndex++;
3721 }
3722 if (l == 0) {
3723 tokl = 0;
3724 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003725 }
3726 }
3727 }
3728#if 0
3729 {
Jack Palevich569f1352009-06-29 14:29:08 -07003730 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003731 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003732 fprintf(stderr, "%s\n", buf.getUnwrapped());
3733 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003734#endif
3735 }
3736
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003737 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003738 next();
3739 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003740 String* pName = new String();
3741 while (isspace(ch)) {
3742 inp();
3743 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003744 if (ch == '(') {
3745 delete pName;
3746 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003747 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003748 }
3749 while (isspace(ch)) {
3750 inp();
3751 }
Jack Palevich569f1352009-06-29 14:29:08 -07003752 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003753 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003754 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003755 inp();
3756 }
Jack Palevich569f1352009-06-29 14:29:08 -07003757 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3758 memcpy(pDefn, value.getUnwrapped(), value.len());
3759 pDefn[value.len()] = 0;
3760 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003761 }
3762
Jack Palevicheedf9d22009-06-04 16:23:40 -07003763 void doPragma() {
3764 // # pragma name(val)
3765 int state = 0;
3766 while(ch != EOF && ch != '\n' && state < 10) {
3767 switch(state) {
3768 case 0:
3769 if (isspace(ch)) {
3770 inp();
3771 } else {
3772 state++;
3773 }
3774 break;
3775 case 1:
3776 if (isalnum(ch)) {
3777 mPragmas.append(ch);
3778 inp();
3779 } else if (ch == '(') {
3780 mPragmas.append(0);
3781 inp();
3782 state++;
3783 } else {
3784 state = 11;
3785 }
3786 break;
3787 case 2:
3788 if (isalnum(ch)) {
3789 mPragmas.append(ch);
3790 inp();
3791 } else if (ch == ')') {
3792 mPragmas.append(0);
3793 inp();
3794 state = 10;
3795 } else {
3796 state = 11;
3797 }
3798 break;
3799 }
3800 }
3801 if(state != 10) {
3802 error("Unexpected pragma syntax");
3803 }
3804 mPragmaStringCount += 2;
3805 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003806
Jack Palevichdc456462009-07-16 16:50:56 -07003807 void doLine() {
3808 // # line number { "filename "}
3809 next();
3810 if (tok != TOK_NUM) {
3811 error("Expected a line-number");
3812 } else {
3813 mLineNumber = tokc-1; // The end-of-line will increment it.
3814 }
3815 while(ch != EOF && ch != '\n') {
3816 inp();
3817 }
3818 }
3819
Jack Palevichac0e95e2009-05-29 13:53:44 -07003820 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003821 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003822 mErrorBuf.vprintf(fmt, ap);
3823 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003824 }
3825
Jack Palevich8b0624c2009-05-20 12:12:06 -07003826 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003827 if (tok != c) {
3828 error("'%c' expected", c);
3829 }
3830 next();
3831 }
3832
Jack Palevich86351982009-06-30 18:09:56 -07003833 bool accept(intptr_t c) {
3834 if (tok == c) {
3835 next();
3836 return true;
3837 }
3838 return false;
3839 }
3840
Jack Palevich40600de2009-07-01 15:32:35 -07003841 bool acceptStringLiteral() {
3842 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003843 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003844 // This while loop merges multiple adjacent string constants.
3845 while (tok == '"') {
3846 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003847 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003848 }
3849 if (ch != '"') {
3850 error("Unterminated string constant.");
3851 }
3852 inp();
3853 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003854 }
Jack Palevich40600de2009-07-01 15:32:35 -07003855 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003856 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003857 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003858 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003859
3860 return true;
3861 }
3862 return false;
3863 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003864
Jack Palevichb1544ca2009-07-16 15:09:20 -07003865 void linkGlobal(tokenid_t t, bool isFunction) {
3866 VariableInfo* pVI = VI(t);
3867 void* n = NULL;
3868 if (mpSymbolLookupFn) {
3869 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3870 }
3871 if (pVI->pType == NULL) {
3872 if (isFunction) {
3873 pVI->pType = mkpIntFn;
3874 } else {
3875 pVI->pType = mkpInt;
3876 }
3877 }
3878 pVI->pAddress = n;
3879 }
3880
Jack Palevich40600de2009-07-01 15:32:35 -07003881 /* Parse and evaluate a unary expression.
3882 * allowAssignment is true if '=' parsing wanted (quick hack)
3883 */
3884 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003885 tokenid_t t;
3886 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003887 t = 0;
3888 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3889 if (acceptStringLiteral()) {
3890 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003892 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003893 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003894 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003895 t = tok;
3896 next();
3897 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003898 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003899 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003900 // Align to 4-byte boundary
3901 glo = (char*) (((intptr_t) glo + 3) & -4);
3902 * (float*) glo = (float) ad;
3903 pGen->loadFloat((int) glo, mkpFloat);
3904 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003905 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003906 // Align to 8-byte boundary
3907 glo = (char*) (((intptr_t) glo + 7) & -8);
3908 * (double*) glo = ad;
3909 pGen->loadFloat((int) glo, mkpDouble);
3910 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003911 } else if (c == 2) {
3912 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003913 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003914 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003915 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003916 else if (t == '+') {
3917 // ignore unary plus.
3918 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003919 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003920 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003921 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003922 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003923 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003924 if (pCast) {
3925 skip(')');
3926 unary(false);
3927 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003928 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003929 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003930 skip(')');
3931 }
3932 } else if (t == '*') {
3933 /* This is a pointer dereference.
3934 */
3935 unary(false);
3936 Type* pR0Type = pGen->getR0Type();
3937 if (pR0Type->tag != TY_POINTER) {
3938 error("Expected a pointer type.");
3939 } else {
3940 if (pR0Type->pHead->tag == TY_FUNC) {
3941 t = 0;
3942 }
3943 if (accept('=')) {
3944 pGen->pushR0();
3945 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003946 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07003947 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003948 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07003949 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003950 }
Jack Palevich3f226492009-07-02 14:46:19 -07003951 // Else we fall through to the function call below, with
3952 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003953 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003954 VariableInfo* pVI = VI(tok);
Jack Palevich2ff5c222009-07-23 15:11:22 -07003955 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType));
Jack Palevich21a15a22009-05-11 14:49:29 -07003956 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003957 } else if (t == EOF ) {
3958 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003959 } else if (t == ';') {
3960 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003961 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003962 // Don't have to do anything special here, the error
3963 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003964 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003965 if (!isDefined(t)) {
3966 mGlobals.add(t);
3967 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003968 }
Jack Palevich8df46192009-07-07 14:48:51 -07003969 VariableInfo* pVI = VI(t);
3970 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003971 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003972 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003973 linkGlobal(t, tok == '(');
3974 n = (intptr_t) pVI->pAddress;
3975 if (!n && tok != '(') {
3976 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003977 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003978 }
Jack Palevich40600de2009-07-01 15:32:35 -07003979 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003980 /* assignment */
3981 next();
3982 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003983 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003984 } else if (tok != '(') {
3985 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003986 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003987 linkGlobal(t, false);
3988 n = (intptr_t) pVI->pAddress;
3989 if (!n) {
3990 error("Undeclared variable %s\n", nameof(t));
3991 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003992 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07003993 // load a variable
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003995 // post inc / post dec
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003996 pGen->leaR0(n, createPtrType(pVI->pType));
3997
Jack Palevich58c30ee2009-07-17 16:35:23 -07003998 pGen->pushR0();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003999 pGen->loadR0FromR0();
4000 pGen->over();
4001 int lit = 1;
4002 if (tokc == OP_DECREMENT) {
4003 lit = -1;
4004 }
4005 switch (pVI->pType->tag) {
4006 case TY_INT:
4007 case TY_CHAR:
4008 case TY_POINTER:
4009 pGen->pushR0();
4010 pGen->li(lit);
4011 pGen->genOp(OP_PLUS);
4012 break;
4013 default:
4014 error("++/-- illegal for this type.");
4015 break;
4016 }
4017
4018 pGen->storeR0ToTOS();
Jack Palevich58c30ee2009-07-17 16:35:23 -07004019 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07004020 next();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07004021 } else {
Jack Palevicha7813bd2009-07-29 11:36:04 -07004022 pGen->leaR0(n, createPtrType(pVI->pType));
4023 pGen->loadR0FromR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07004024 }
4025 }
4026 }
4027 }
4028
4029 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07004030 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07004031 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07004032 VariableInfo* pVI = NULL;
4033 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevich9f51a262009-07-29 16:22:26 -07004034 Type* pFn = pGen->getR0Type();
4035 assert(pFn->tag == TY_POINTER);
4036 assert(pFn->pHead->tag == TY_FUNC);
4037 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004038 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07004039 } else {
4040 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07004041 pDecl = pVI->pType;
Jack Palevich9f51a262009-07-29 16:22:26 -07004042 Type* pFn = createPtrType(pDecl);
4043 if (n == 0) {
4044 pVI->pForward = (void*) pGen->leaForward(
4045 (int) pVI->pForward, pFn);
4046 } else {
4047 pGen->leaR0(n, pFn);
4048 }
4049 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07004050 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004051 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07004052 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07004053 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004054 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07004055 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004056 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004057 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004058 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004059 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004060 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004061 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004062 Type* pTargetType;
4063 if (pArgList) {
4064 pTargetType = pArgList->pHead;
4065 pArgList = pArgList->pTail;
4066 } else {
Jack Palevich9f51a262009-07-29 16:22:26 -07004067 // This is a ... function, just pass arguments in their
4068 // natural type.
Jack Palevich1a539db2009-07-08 13:04:41 -07004069 pTargetType = pGen->getR0Type();
4070 if (pTargetType->tag == TY_FLOAT) {
4071 pTargetType = mkpDouble;
4072 }
4073 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004074 if (pTargetType->tag == TY_VOID) {
4075 error("Can't pass void value for argument %d",
4076 argCount + 1);
4077 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004078 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004079 }
Jack Palevich95727a02009-07-06 12:07:15 -07004080 if (accept(',')) {
4081 // fine
4082 } else if ( tok != ')') {
4083 error("Expected ',' or ')'");
4084 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004085 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004086 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004087 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004088 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004089 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004090 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004091 skip(')');
Jack Palevich9f51a262009-07-29 16:22:26 -07004092 pGen->callIndirect(l, pDecl);
4093 pGen->adjustStackAfterCall(pDecl, l, true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004094 }
4095 }
4096
Jack Palevich40600de2009-07-01 15:32:35 -07004097 /* Recursive descent parser for binary operations.
4098 */
4099 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004100 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004101 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004102 if (level-- == 1)
4103 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004104 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004105 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004106 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004107 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004108 t = tokc;
4109 next();
4110
Jack Palevich40600de2009-07-01 15:32:35 -07004111 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004112 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004113 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004114 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004115 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004116 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004117 // Check for syntax error.
4118 if (pGen->getR0Type() == NULL) {
4119 // We failed to parse a right-hand argument.
4120 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004121 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004122 }
Jack Palevich40600de2009-07-01 15:32:35 -07004123 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004124 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004125 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004126 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004127 }
4128 }
4129 }
4130 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004131 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004132 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004133 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004134 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004135 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004136 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004137 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004138 }
4139 }
4140 }
4141
4142 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004143 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004144 }
4145
4146 int test_expr() {
4147 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004148 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004149 }
4150
Jack Palevicha6baa232009-06-12 11:25:59 -07004151 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004152 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004153
Jack Palevich95727a02009-07-06 12:07:15 -07004154 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004155 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004156 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004157 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004158 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004159 next();
4160 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004161 a = test_expr();
4162 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004163 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004164 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004165 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004166 n = pGen->gjmp(0); /* jmp */
4167 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004168 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004169 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004170 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004171 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004172 }
Jack Palevich546b2242009-05-13 15:10:04 -07004173 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004174 t = tok;
4175 next();
4176 skip('(');
4177 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004178 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004179 a = test_expr();
4180 } else {
4181 if (tok != ';')
4182 expr();
4183 skip(';');
4184 n = codeBuf.getPC();
4185 a = 0;
4186 if (tok != ';')
4187 a = test_expr();
4188 skip(';');
4189 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004190 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004191 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004192 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004193 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004194 n = t + 4;
4195 }
4196 }
4197 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004198 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004199 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004200 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004201 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004202 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004203 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004204 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004205 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004206 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004207 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004208 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004209 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004210 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004211 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004212 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004213 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004214 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004215 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004216 if (pReturnType->tag == TY_VOID) {
4217 error("Must not return a value from a void function");
4218 } else {
4219 pGen->convertR0(pReturnType);
4220 }
4221 } else {
4222 if (pReturnType->tag != TY_VOID) {
4223 error("Must specify a value here");
4224 }
Jack Palevich8df46192009-07-07 14:48:51 -07004225 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004226 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004227 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004228 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004229 } else if (tok != ';')
4230 expr();
4231 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004232 }
4233 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004234
Jack Palevicha8f427f2009-07-13 18:40:08 -07004235 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004236 if (a == b) {
4237 return true;
4238 }
4239 if (a == NULL || b == NULL) {
4240 return false;
4241 }
4242 TypeTag at = a->tag;
4243 if (at != b->tag) {
4244 return false;
4245 }
4246 if (at == TY_POINTER) {
4247 return typeEqual(a->pHead, b->pHead);
4248 } else if (at == TY_FUNC || at == TY_PARAM) {
4249 return typeEqual(a->pHead, b->pHead)
4250 && typeEqual(a->pTail, b->pTail);
4251 }
4252 return true;
4253 }
4254
Jack Palevich2ff5c222009-07-23 15:11:22 -07004255 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004256 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004257 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004258 memset(pType, 0, sizeof(*pType));
4259 pType->tag = tag;
4260 pType->pHead = pHead;
4261 pType->pTail = pTail;
4262 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004263 }
4264
Jack Palevich2ff5c222009-07-23 15:11:22 -07004265 Type* createPtrType(Type* pType) {
4266 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004267 }
4268
4269 /**
4270 * Try to print a type in declaration order
4271 */
Jack Palevich86351982009-06-30 18:09:56 -07004272 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004273 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004274 if (pType == NULL) {
4275 buffer.appendCStr("null");
4276 return;
4277 }
Jack Palevich3f226492009-07-02 14:46:19 -07004278 decodeTypeImp(buffer, pType);
4279 }
4280
4281 void decodeTypeImp(String& buffer, Type* pType) {
4282 decodeTypeImpPrefix(buffer, pType);
4283
Jack Palevich86351982009-06-30 18:09:56 -07004284 String temp;
4285 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004286 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004287 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004288 }
4289
4290 decodeTypeImpPostfix(buffer, pType);
4291 }
4292
4293 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4294 TypeTag tag = pType->tag;
4295
Jack Palevich37c54bd2009-07-14 18:35:36 -07004296 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004297 switch (tag) {
4298 case TY_INT:
4299 buffer.appendCStr("int");
4300 break;
4301 case TY_CHAR:
4302 buffer.appendCStr("char");
4303 break;
4304 case TY_VOID:
4305 buffer.appendCStr("void");
4306 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004307 case TY_FLOAT:
4308 buffer.appendCStr("float");
4309 break;
4310 case TY_DOUBLE:
4311 buffer.appendCStr("double");
4312 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004313 default:
4314 break;
4315 }
Jack Palevich86351982009-06-30 18:09:56 -07004316 buffer.append(' ');
4317 }
Jack Palevich3f226492009-07-02 14:46:19 -07004318
4319 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004320 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004321 break;
4322 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004323 break;
4324 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004325 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004326 case TY_FLOAT:
4327 break;
4328 case TY_DOUBLE:
4329 break;
Jack Palevich86351982009-06-30 18:09:56 -07004330 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004331 decodeTypeImpPrefix(buffer, pType->pHead);
4332 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4333 buffer.append('(');
4334 }
4335 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004336 break;
4337 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004338 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004339 break;
4340 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004341 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004342 break;
4343 default:
4344 String temp;
4345 temp.printf("Unknown tag %d", pType->tag);
4346 buffer.append(temp);
4347 break;
4348 }
Jack Palevich3f226492009-07-02 14:46:19 -07004349 }
4350
4351 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4352 TypeTag tag = pType->tag;
4353
4354 switch(tag) {
4355 case TY_POINTER:
4356 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4357 buffer.append(')');
4358 }
4359 decodeTypeImpPostfix(buffer, pType->pHead);
4360 break;
4361 case TY_FUNC:
4362 buffer.append('(');
4363 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4364 decodeTypeImp(buffer, pArg);
4365 if (pArg->pTail) {
4366 buffer.appendCStr(", ");
4367 }
4368 }
4369 buffer.append(')');
4370 break;
4371 default:
4372 break;
Jack Palevich86351982009-06-30 18:09:56 -07004373 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004374 }
4375
Jack Palevich86351982009-06-30 18:09:56 -07004376 void printType(Type* pType) {
4377 String buffer;
4378 decodeType(buffer, pType);
4379 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004380 }
4381
Jack Palevich2ff5c222009-07-23 15:11:22 -07004382 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004383 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004384 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004385 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004386 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004387 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004388 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004389 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004390 } else if (tok == TOK_FLOAT) {
4391 pType = mkpFloat;
4392 } else if (tok == TOK_DOUBLE) {
4393 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004394 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004395 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004396 }
4397 next();
Jack Palevich86351982009-06-30 18:09:56 -07004398 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004399 }
4400
Jack Palevich2ff5c222009-07-23 15:11:22 -07004401 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004402 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004403 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004404 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004405 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004406 if (declName) {
4407 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004408 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004409
Jack Palevich86351982009-06-30 18:09:56 -07004410 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004411 }
Jack Palevich3f226492009-07-02 14:46:19 -07004412 // fprintf(stderr, "Parsed a declaration: ");
4413 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004414 if (reportFailure) {
4415 return NULL;
4416 }
Jack Palevich86351982009-06-30 18:09:56 -07004417 return pType;
4418 }
4419
Jack Palevich2ff5c222009-07-23 15:11:22 -07004420 Type* expectDeclaration(Type* pBaseType) {
4421 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004422 if (! pType) {
4423 error("Expected a declaration");
4424 }
4425 return pType;
4426 }
4427
Jack Palevich3f226492009-07-02 14:46:19 -07004428 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004429 Type* acceptCastTypeDeclaration() {
4430 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004431 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004432 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004433 }
Jack Palevich86351982009-06-30 18:09:56 -07004434 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004435 }
4436
Jack Palevich2ff5c222009-07-23 15:11:22 -07004437 Type* expectCastTypeDeclaration() {
4438 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004439 if (! pType) {
4440 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004441 }
Jack Palevich3f226492009-07-02 14:46:19 -07004442 return pType;
4443 }
4444
4445 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004446 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004447 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004448 int ptrCounter = 0;
4449 while (accept('*')) {
4450 ptrCounter++;
4451 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004452 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004453 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004454 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004455 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004456 }
4457 return pType;
4458 }
4459
4460 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004461 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004462 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004463 // direct-dcl :
4464 // name
4465 // (dcl)
4466 // direct-dcl()
4467 // direct-dcl[]
4468 Type* pNewHead = NULL;
4469 if (accept('(')) {
4470 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004471 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004472 skip(')');
4473 } else if ((declName = acceptSymbol()) != 0) {
4474 if (nameAllowed == false && declName) {
4475 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004476 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004477 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004478 } else if (nameRequired && ! declName) {
4479 String temp;
4480 decodeToken(temp, tok, true);
4481 error("Expected name. Got %s", temp.getUnwrapped());
4482 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004483 }
4484 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004485 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004486 Type* pTail = acceptArgs(nameAllowed);
4487 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004488 skip(')');
4489 }
Jack Palevich3f226492009-07-02 14:46:19 -07004490
4491 if (pNewHead) {
4492 Type* pA = pNewHead;
4493 while (pA->pHead) {
4494 pA = pA->pHead;
4495 }
4496 pA->pHead = pType;
4497 pType = pNewHead;
4498 }
Jack Palevich86351982009-06-30 18:09:56 -07004499 return pType;
4500 }
4501
Jack Palevich2ff5c222009-07-23 15:11:22 -07004502 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004503 Type* pHead = NULL;
4504 Type* pTail = NULL;
4505 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004506 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004507 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004508 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004509 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004510 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004511 if (!pHead) {
4512 pHead = pParam;
4513 pTail = pParam;
4514 } else {
4515 pTail->pTail = pParam;
4516 pTail = pParam;
4517 }
4518 }
4519 }
4520 if (! accept(',')) {
4521 break;
4522 }
4523 }
4524 return pHead;
4525 }
4526
Jack Palevich2ff5c222009-07-23 15:11:22 -07004527 Type* expectPrimitiveType() {
4528 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004529 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004530 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004531 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004532 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004533 }
Jack Palevich86351982009-06-30 18:09:56 -07004534 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004535 }
4536
Jack Palevich86351982009-06-30 18:09:56 -07004537 void addGlobalSymbol(Type* pDecl) {
4538 tokenid_t t = pDecl->id;
4539 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004540 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004541 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004542 }
Jack Palevich86351982009-06-30 18:09:56 -07004543 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004544 }
4545
Jack Palevich86351982009-06-30 18:09:56 -07004546 void reportDuplicate(tokenid_t t) {
4547 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004548 }
4549
Jack Palevich86351982009-06-30 18:09:56 -07004550 void addLocalSymbol(Type* pDecl) {
4551 tokenid_t t = pDecl->id;
4552 if (mLocals.isDefinedAtCurrentLevel(t)) {
4553 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004554 }
Jack Palevich86351982009-06-30 18:09:56 -07004555 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004556 }
4557
Jack Palevich95727a02009-07-06 12:07:15 -07004558 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004559 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004560
Jack Palevich95727a02009-07-06 12:07:15 -07004561 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004562 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004563 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004564 if (!pDecl) {
4565 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004566 }
Jack Palevich86351982009-06-30 18:09:56 -07004567 int variableAddress = 0;
4568 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004569 size_t alignment = pGen->stackAlignmentOf(pDecl);
4570 size_t alignmentMask = ~ (alignment - 1);
4571 size_t sizeOf = pGen->sizeOf(pDecl);
4572 loc = (loc + alignment - 1) & alignmentMask;
4573 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4574 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004575 variableAddress = -loc;
4576 VI(pDecl->id)->pAddress = (void*) variableAddress;
4577 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004578 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004579 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004580 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004581 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004582 if (tok == ',')
4583 next();
4584 }
4585 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004586 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004587 }
4588 }
4589
Jack Palevichf1728be2009-06-12 13:53:51 -07004590 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004591 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004592 }
4593
Jack Palevich37c54bd2009-07-14 18:35:36 -07004594 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004595 if (token == EOF ) {
4596 buffer.printf("EOF");
4597 } else if (token == TOK_NUM) {
4598 buffer.printf("numeric constant");
4599 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004600 if (token < 32) {
4601 buffer.printf("'\\x%02x'", token);
4602 } else {
4603 buffer.printf("'%c'", token);
4604 }
Jack Palevich569f1352009-06-29 14:29:08 -07004605 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004606 if (quote) {
4607 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4608 buffer.printf("keyword \"%s\"", nameof(token));
4609 } else {
4610 buffer.printf("symbol \"%s\"", nameof(token));
4611 }
4612 } else {
4613 buffer.printf("%s", nameof(token));
4614 }
Jack Palevich569f1352009-06-29 14:29:08 -07004615 }
4616 }
4617
Jack Palevich40600de2009-07-01 15:32:35 -07004618 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004619 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004620 if (!result) {
4621 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004622 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004623 error("Expected symbol. Got %s", temp.getUnwrapped());
4624 }
4625 return result;
4626 }
4627
Jack Palevich86351982009-06-30 18:09:56 -07004628 tokenid_t acceptSymbol() {
4629 tokenid_t result = 0;
4630 if (tok >= TOK_SYMBOL) {
4631 result = tok;
4632 next();
Jack Palevich86351982009-06-30 18:09:56 -07004633 }
4634 return result;
4635 }
4636
Jack Palevichb7c81e92009-06-04 19:56:13 -07004637 void globalDeclarations() {
4638 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004639 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004640 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004641 break;
4642 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004643 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004644 if (!pDecl) {
4645 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004646 }
Jack Palevich86351982009-06-30 18:09:56 -07004647 if (! isDefined(pDecl->id)) {
4648 addGlobalSymbol(pDecl);
4649 }
4650 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004651 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004652 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004653 }
Jack Palevich86351982009-06-30 18:09:56 -07004654 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004655 // it's a variable declaration
4656 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004657 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004658 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004659 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004660 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004661 }
Jack Palevich86351982009-06-30 18:09:56 -07004662 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004663 if (tok == TOK_NUM) {
4664 if (name) {
4665 * (int*) name->pAddress = tokc;
4666 }
4667 next();
4668 } else {
4669 error("Expected an integer constant");
4670 }
4671 }
Jack Palevich86351982009-06-30 18:09:56 -07004672 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004673 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004674 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004675 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004676 if (!pDecl) {
4677 break;
4678 }
4679 if (! isDefined(pDecl->id)) {
4680 addGlobalSymbol(pDecl);
4681 }
4682 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004683 }
4684 skip(';');
4685 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004686 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004687 if (accept(';')) {
4688 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004689 } else if (tok != '{') {
4690 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004691 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004692 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004693 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004694 /* patch forward references */
4695 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004696 /* put function address */
4697 name->pAddress = (void*) codeBuf.getPC();
4698 }
4699 // Calculate stack offsets for parameters
4700 mLocals.pushLevel();
4701 intptr_t a = 8;
4702 int argCount = 0;
4703 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4704 Type* pArg = pP->pHead;
4705 addLocalSymbol(pArg);
4706 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004707 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004708 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004709 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004710 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004711 argCount++;
4712 }
4713 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004714 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004715 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004716 block(0, true);
4717 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004718 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004719 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004720 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004721 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004722 }
4723 }
4724 }
4725
Jack Palevich9cbd2262009-07-08 16:48:41 -07004726 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4727 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4728 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004729 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004730 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004731 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004732 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004733 char* result = (char*) base;
4734 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004735 return result;
4736 }
4737
Jack Palevich21a15a22009-05-11 14:49:29 -07004738 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004739 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004740 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004741 pGlobalBase = 0;
4742 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004743 if (pGen) {
4744 delete pGen;
4745 pGen = 0;
4746 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004747 if (file) {
4748 delete file;
4749 file = 0;
4750 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004751 }
4752
Jack Palevich8c246a92009-07-14 21:14:10 -07004753 // One-time initialization, when class is constructed.
4754 void init() {
4755 mpSymbolLookupFn = 0;
4756 mpSymbolLookupContext = 0;
4757 }
4758
Jack Palevich21a15a22009-05-11 14:49:29 -07004759 void clear() {
4760 tok = 0;
4761 tokc = 0;
4762 tokl = 0;
4763 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004764 rsym = 0;
4765 loc = 0;
4766 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004767 dptr = 0;
4768 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004769 file = 0;
4770 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004771 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004772 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004773 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004774 mLineNumber = 1;
4775 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004776 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004777
Jack Palevich22305132009-05-13 10:58:45 -07004778 void setArchitecture(const char* architecture) {
4779 delete pGen;
4780 pGen = 0;
4781
4782 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004783#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004784 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004785 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004786 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004787#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004788#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004789 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004790 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004791 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004792#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004793 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004794 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004795 }
4796 }
4797
4798 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004799#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004800 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004801#elif defined(DEFAULT_X86_CODEGEN)
4802 pGen = new X86CodeGenerator();
4803#endif
4804 }
4805 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004806 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004807 } else {
4808 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004809 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004810 }
4811 }
4812
Jack Palevich77ae76e2009-05-10 19:59:24 -07004813public:
Jack Palevich22305132009-05-13 10:58:45 -07004814 struct args {
4815 args() {
4816 architecture = 0;
4817 }
4818 const char* architecture;
4819 };
4820
Jack Paleviche7b59062009-05-19 17:12:17 -07004821 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004822 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004823 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004824 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004825
Jack Paleviche7b59062009-05-19 17:12:17 -07004826 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004827 cleanup();
4828 }
4829
Jack Palevich8c246a92009-07-14 21:14:10 -07004830 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4831 mpSymbolLookupFn = pFn;
4832 mpSymbolLookupContext = pContext;
4833 }
4834
Jack Palevich1cdef202009-05-22 12:06:27 -07004835 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004836 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004837
Jack Palevich2ff5c222009-07-23 15:11:22 -07004838 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004839 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004840 cleanup();
4841 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004842 mTokenTable.setArena(&mGlobalArena);
4843 mGlobals.setArena(&mGlobalArena);
4844 mGlobals.setTokenTable(&mTokenTable);
4845 mLocals.setArena(&mLocalArena);
4846 mLocals.setTokenTable(&mTokenTable);
4847
4848 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004849 codeBuf.init(ALLOC_SIZE);
4850 setArchitecture(NULL);
4851 if (!pGen) {
4852 return -1;
4853 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004854#ifdef PROVIDE_TRACE_CODEGEN
4855 pGen = new TraceCodeGenerator(pGen);
4856#endif
4857 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004858 pGen->init(&codeBuf);
4859 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004860 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4861 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004862 inp();
4863 next();
4864 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004865 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004866 result = pGen->finishCompile();
4867 if (result == 0) {
4868 if (mErrorBuf.len()) {
4869 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004870 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004871 }
Jack Palevichce105a92009-07-16 14:30:33 -07004872 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004873 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004874 }
4875
Jack Palevich86351982009-06-30 18:09:56 -07004876 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004877 mkpInt = createType(TY_INT, NULL, NULL);
4878 mkpChar = createType(TY_CHAR, NULL, NULL);
4879 mkpVoid = createType(TY_VOID, NULL, NULL);
4880 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4881 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4882 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4883 mkpIntPtr = createPtrType(mkpInt);
4884 mkpCharPtr = createPtrType(mkpChar);
4885 mkpFloatPtr = createPtrType(mkpFloat);
4886 mkpDoublePtr = createPtrType(mkpDouble);
4887 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004888 }
4889
Jack Palevicha6baa232009-06-12 11:25:59 -07004890 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004891 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004892 }
4893
Jack Palevich569f1352009-06-29 14:29:08 -07004894 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004895 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004896 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004897 }
4898
Jack Palevich569f1352009-06-29 14:29:08 -07004899 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004900 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004901 error("Undefined forward reference: %s",
4902 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004903 }
4904 return true;
4905 }
4906
Jack Palevich21a15a22009-05-11 14:49:29 -07004907 int dump(FILE* out) {
4908 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4909 return 0;
4910 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004911
Jack Palevicha6535612009-05-13 16:24:17 -07004912 int disassemble(FILE* out) {
4913 return pGen->disassemble(out);
4914 }
4915
Jack Palevich1cdef202009-05-22 12:06:27 -07004916 /* Look through the symbol table to find a symbol.
4917 * If found, return its value.
4918 */
4919 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004920 if (mCompileResult == 0) {
4921 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4922 VariableInfo* pVariableInfo = VI(tok);
4923 if (pVariableInfo) {
4924 return pVariableInfo->pAddress;
4925 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004926 }
4927 return NULL;
4928 }
4929
Jack Palevicheedf9d22009-06-04 16:23:40 -07004930 void getPragmas(ACCsizei* actualStringCount,
4931 ACCsizei maxStringCount, ACCchar** strings) {
4932 int stringCount = mPragmaStringCount;
4933 if (actualStringCount) {
4934 *actualStringCount = stringCount;
4935 }
4936 if (stringCount > maxStringCount) {
4937 stringCount = maxStringCount;
4938 }
4939 if (strings) {
4940 char* pPragmas = mPragmas.getUnwrapped();
4941 while (stringCount-- > 0) {
4942 *strings++ = pPragmas;
4943 pPragmas += strlen(pPragmas) + 1;
4944 }
4945 }
4946 }
4947
Jack Palevichac0e95e2009-05-29 13:53:44 -07004948 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004949 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004950 }
4951
Jack Palevich77ae76e2009-05-10 19:59:24 -07004952};
4953
Jack Paleviche7b59062009-05-19 17:12:17 -07004954const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004955 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4956
Jack Paleviche7b59062009-05-19 17:12:17 -07004957const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004958 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4959 5, 5, /* ==, != */
4960 9, 10, /* &&, || */
4961 6, 7, 8, /* & ^ | */
4962 2, 2 /* ~ ! */
4963 };
4964
Jack Palevich8b0624c2009-05-20 12:12:06 -07004965#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004966FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004967#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004968
Jack Palevich8b0624c2009-05-20 12:12:06 -07004969#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004970const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004971 0x1, // ++
4972 0xff, // --
4973 0xc1af0f, // *
4974 0xf9f79991, // /
4975 0xf9f79991, // % (With manual assist to swap results)
4976 0xc801, // +
4977 0xd8f7c829, // -
4978 0xe0d391, // <<
4979 0xf8d391, // >>
4980 0xe, // <=
4981 0xd, // >=
4982 0xc, // <
4983 0xf, // >
4984 0x4, // ==
4985 0x5, // !=
4986 0x0, // &&
4987 0x1, // ||
4988 0xc821, // &
4989 0xc831, // ^
4990 0xc809, // |
4991 0xd0f7, // ~
4992 0x4 // !
4993};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004994#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004995
Jack Palevich1cdef202009-05-22 12:06:27 -07004996struct ACCscript {
4997 ACCscript() {
4998 text = 0;
4999 textLength = 0;
5000 accError = ACC_NO_ERROR;
5001 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005002
Jack Palevich1cdef202009-05-22 12:06:27 -07005003 ~ACCscript() {
5004 delete text;
5005 }
Jack Palevich546b2242009-05-13 15:10:04 -07005006
Jack Palevich8c246a92009-07-14 21:14:10 -07005007 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5008 compiler.registerSymbolCallback(pFn, pContext);
5009 }
5010
Jack Palevich1cdef202009-05-22 12:06:27 -07005011 void setError(ACCenum error) {
5012 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5013 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005014 }
5015 }
5016
Jack Palevich1cdef202009-05-22 12:06:27 -07005017 ACCenum getError() {
5018 ACCenum result = accError;
5019 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005020 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005021 }
5022
Jack Palevich1cdef202009-05-22 12:06:27 -07005023 Compiler compiler;
5024 char* text;
5025 int textLength;
5026 ACCenum accError;
5027};
5028
5029
5030extern "C"
5031ACCscript* accCreateScript() {
5032 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005033}
Jack Palevich1cdef202009-05-22 12:06:27 -07005034
5035extern "C"
5036ACCenum accGetError( ACCscript* script ) {
5037 return script->getError();
5038}
5039
5040extern "C"
5041void accDeleteScript(ACCscript* script) {
5042 delete script;
5043}
5044
5045extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005046void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5047 ACCvoid* pContext) {
5048 script->registerSymbolCallback(pFn, pContext);
5049}
5050
5051extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005052void accScriptSource(ACCscript* script,
5053 ACCsizei count,
5054 const ACCchar ** string,
5055 const ACCint * length) {
5056 int totalLength = 0;
5057 for(int i = 0; i < count; i++) {
5058 int len = -1;
5059 const ACCchar* s = string[i];
5060 if (length) {
5061 len = length[i];
5062 }
5063 if (len < 0) {
5064 len = strlen(s);
5065 }
5066 totalLength += len;
5067 }
5068 delete script->text;
5069 char* text = new char[totalLength + 1];
5070 script->text = text;
5071 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005072 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005073 for(int i = 0; i < count; i++) {
5074 int len = -1;
5075 const ACCchar* s = string[i];
5076 if (length) {
5077 len = length[i];
5078 }
5079 if (len < 0) {
5080 len = strlen(s);
5081 }
Jack Palevich09555c72009-05-27 12:25:55 -07005082 memcpy(dest, s, len);
5083 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005084 }
5085 text[totalLength] = '\0';
5086}
5087
5088extern "C"
5089void accCompileScript(ACCscript* script) {
5090 int result = script->compiler.compile(script->text, script->textLength);
5091 if (result) {
5092 script->setError(ACC_INVALID_OPERATION);
5093 }
5094}
5095
5096extern "C"
5097void accGetScriptiv(ACCscript* script,
5098 ACCenum pname,
5099 ACCint * params) {
5100 switch (pname) {
5101 case ACC_INFO_LOG_LENGTH:
5102 *params = 0;
5103 break;
5104 }
5105}
5106
5107extern "C"
5108void accGetScriptInfoLog(ACCscript* script,
5109 ACCsizei maxLength,
5110 ACCsizei * length,
5111 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005112 char* message = script->compiler.getErrorMessage();
5113 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005114 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005115 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005116 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005117 if (infoLog && maxLength > 0) {
5118 int trimmedLength = maxLength < messageLength ?
5119 maxLength : messageLength;
5120 memcpy(infoLog, message, trimmedLength);
5121 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005122 }
5123}
5124
5125extern "C"
5126void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5127 ACCvoid ** address) {
5128 void* value = script->compiler.lookup(name);
5129 if (value) {
5130 *address = value;
5131 } else {
5132 script->setError(ACC_INVALID_VALUE);
5133 }
5134}
5135
Jack Palevicheedf9d22009-06-04 16:23:40 -07005136extern "C"
5137void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5138 ACCsizei maxStringCount, ACCchar** strings){
5139 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5140}
5141
-b master422972c2009-06-17 19:13:52 -07005142extern "C"
5143void accDisassemble(ACCscript* script) {
5144 script->compiler.disassemble(stderr);
5145}
5146
Jack Palevicheedf9d22009-06-04 16:23:40 -07005147
Jack Palevich1cdef202009-05-22 12:06:27 -07005148} // namespace acc
5149