blob: 7739e2d7b50dd16d2d3b4cb610808c5c2e4f175f [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 Palevicha6535612009-05-13 16:24:17 -07004134 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
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 Palevich21a15a22009-05-11 14:49:29 -07004137 }
4138 }
4139 }
4140
4141 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004142 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004143 }
4144
4145 int test_expr() {
4146 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004147 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004148 }
4149
Jack Palevicha6baa232009-06-12 11:25:59 -07004150 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004151 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004152
Jack Palevich95727a02009-07-06 12:07:15 -07004153 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004154 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004155 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004156 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004157 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004158 next();
4159 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004160 a = test_expr();
4161 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004162 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004163 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004164 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004165 n = pGen->gjmp(0); /* jmp */
4166 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004167 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004168 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004169 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004170 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004171 }
Jack Palevich546b2242009-05-13 15:10:04 -07004172 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004173 t = tok;
4174 next();
4175 skip('(');
4176 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004177 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004178 a = test_expr();
4179 } else {
4180 if (tok != ';')
4181 expr();
4182 skip(';');
4183 n = codeBuf.getPC();
4184 a = 0;
4185 if (tok != ';')
4186 a = test_expr();
4187 skip(';');
4188 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004189 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004190 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004191 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004192 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004193 n = t + 4;
4194 }
4195 }
4196 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004197 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004198 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004199 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004200 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004201 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004202 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004203 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004204 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004205 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004206 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004207 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004208 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004209 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004210 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004211 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004212 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004213 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004214 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004215 if (pReturnType->tag == TY_VOID) {
4216 error("Must not return a value from a void function");
4217 } else {
4218 pGen->convertR0(pReturnType);
4219 }
4220 } else {
4221 if (pReturnType->tag != TY_VOID) {
4222 error("Must specify a value here");
4223 }
Jack Palevich8df46192009-07-07 14:48:51 -07004224 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004225 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004226 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004227 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004228 } else if (tok != ';')
4229 expr();
4230 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004231 }
4232 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004233
Jack Palevicha8f427f2009-07-13 18:40:08 -07004234 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004235 if (a == b) {
4236 return true;
4237 }
4238 if (a == NULL || b == NULL) {
4239 return false;
4240 }
4241 TypeTag at = a->tag;
4242 if (at != b->tag) {
4243 return false;
4244 }
4245 if (at == TY_POINTER) {
4246 return typeEqual(a->pHead, b->pHead);
4247 } else if (at == TY_FUNC || at == TY_PARAM) {
4248 return typeEqual(a->pHead, b->pHead)
4249 && typeEqual(a->pTail, b->pTail);
4250 }
4251 return true;
4252 }
4253
Jack Palevich2ff5c222009-07-23 15:11:22 -07004254 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004255 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004256 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004257 memset(pType, 0, sizeof(*pType));
4258 pType->tag = tag;
4259 pType->pHead = pHead;
4260 pType->pTail = pTail;
4261 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004262 }
4263
Jack Palevich2ff5c222009-07-23 15:11:22 -07004264 Type* createPtrType(Type* pType) {
4265 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004266 }
4267
4268 /**
4269 * Try to print a type in declaration order
4270 */
Jack Palevich86351982009-06-30 18:09:56 -07004271 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004272 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004273 if (pType == NULL) {
4274 buffer.appendCStr("null");
4275 return;
4276 }
Jack Palevich3f226492009-07-02 14:46:19 -07004277 decodeTypeImp(buffer, pType);
4278 }
4279
4280 void decodeTypeImp(String& buffer, Type* pType) {
4281 decodeTypeImpPrefix(buffer, pType);
4282
Jack Palevich86351982009-06-30 18:09:56 -07004283 String temp;
4284 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004285 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004286 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004287 }
4288
4289 decodeTypeImpPostfix(buffer, pType);
4290 }
4291
4292 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4293 TypeTag tag = pType->tag;
4294
Jack Palevich37c54bd2009-07-14 18:35:36 -07004295 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004296 switch (tag) {
4297 case TY_INT:
4298 buffer.appendCStr("int");
4299 break;
4300 case TY_CHAR:
4301 buffer.appendCStr("char");
4302 break;
4303 case TY_VOID:
4304 buffer.appendCStr("void");
4305 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004306 case TY_FLOAT:
4307 buffer.appendCStr("float");
4308 break;
4309 case TY_DOUBLE:
4310 buffer.appendCStr("double");
4311 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004312 default:
4313 break;
4314 }
Jack Palevich86351982009-06-30 18:09:56 -07004315 buffer.append(' ');
4316 }
Jack Palevich3f226492009-07-02 14:46:19 -07004317
4318 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004319 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004320 break;
4321 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004322 break;
4323 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004324 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004325 case TY_FLOAT:
4326 break;
4327 case TY_DOUBLE:
4328 break;
Jack Palevich86351982009-06-30 18:09:56 -07004329 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004330 decodeTypeImpPrefix(buffer, pType->pHead);
4331 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4332 buffer.append('(');
4333 }
4334 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004335 break;
4336 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004337 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004338 break;
4339 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004340 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004341 break;
4342 default:
4343 String temp;
4344 temp.printf("Unknown tag %d", pType->tag);
4345 buffer.append(temp);
4346 break;
4347 }
Jack Palevich3f226492009-07-02 14:46:19 -07004348 }
4349
4350 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4351 TypeTag tag = pType->tag;
4352
4353 switch(tag) {
4354 case TY_POINTER:
4355 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4356 buffer.append(')');
4357 }
4358 decodeTypeImpPostfix(buffer, pType->pHead);
4359 break;
4360 case TY_FUNC:
4361 buffer.append('(');
4362 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4363 decodeTypeImp(buffer, pArg);
4364 if (pArg->pTail) {
4365 buffer.appendCStr(", ");
4366 }
4367 }
4368 buffer.append(')');
4369 break;
4370 default:
4371 break;
Jack Palevich86351982009-06-30 18:09:56 -07004372 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004373 }
4374
Jack Palevich86351982009-06-30 18:09:56 -07004375 void printType(Type* pType) {
4376 String buffer;
4377 decodeType(buffer, pType);
4378 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004379 }
4380
Jack Palevich2ff5c222009-07-23 15:11:22 -07004381 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004382 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004383 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004384 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004385 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004386 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004387 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004388 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004389 } else if (tok == TOK_FLOAT) {
4390 pType = mkpFloat;
4391 } else if (tok == TOK_DOUBLE) {
4392 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004393 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004394 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004395 }
4396 next();
Jack Palevich86351982009-06-30 18:09:56 -07004397 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004398 }
4399
Jack Palevich2ff5c222009-07-23 15:11:22 -07004400 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004401 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004402 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004403 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004404 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004405 if (declName) {
4406 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004407 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004408
Jack Palevich86351982009-06-30 18:09:56 -07004409 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004410 }
Jack Palevich3f226492009-07-02 14:46:19 -07004411 // fprintf(stderr, "Parsed a declaration: ");
4412 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004413 if (reportFailure) {
4414 return NULL;
4415 }
Jack Palevich86351982009-06-30 18:09:56 -07004416 return pType;
4417 }
4418
Jack Palevich2ff5c222009-07-23 15:11:22 -07004419 Type* expectDeclaration(Type* pBaseType) {
4420 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004421 if (! pType) {
4422 error("Expected a declaration");
4423 }
4424 return pType;
4425 }
4426
Jack Palevich3f226492009-07-02 14:46:19 -07004427 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004428 Type* acceptCastTypeDeclaration() {
4429 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004430 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004431 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004432 }
Jack Palevich86351982009-06-30 18:09:56 -07004433 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004434 }
4435
Jack Palevich2ff5c222009-07-23 15:11:22 -07004436 Type* expectCastTypeDeclaration() {
4437 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004438 if (! pType) {
4439 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004440 }
Jack Palevich3f226492009-07-02 14:46:19 -07004441 return pType;
4442 }
4443
4444 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004445 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004446 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004447 int ptrCounter = 0;
4448 while (accept('*')) {
4449 ptrCounter++;
4450 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004451 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004452 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004453 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004454 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004455 }
4456 return pType;
4457 }
4458
4459 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004460 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004461 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004462 // direct-dcl :
4463 // name
4464 // (dcl)
4465 // direct-dcl()
4466 // direct-dcl[]
4467 Type* pNewHead = NULL;
4468 if (accept('(')) {
4469 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004470 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004471 skip(')');
4472 } else if ((declName = acceptSymbol()) != 0) {
4473 if (nameAllowed == false && declName) {
4474 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004475 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004476 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004477 } else if (nameRequired && ! declName) {
4478 String temp;
4479 decodeToken(temp, tok, true);
4480 error("Expected name. Got %s", temp.getUnwrapped());
4481 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004482 }
4483 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004484 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004485 Type* pTail = acceptArgs(nameAllowed);
4486 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004487 skip(')');
4488 }
Jack Palevich3f226492009-07-02 14:46:19 -07004489
4490 if (pNewHead) {
4491 Type* pA = pNewHead;
4492 while (pA->pHead) {
4493 pA = pA->pHead;
4494 }
4495 pA->pHead = pType;
4496 pType = pNewHead;
4497 }
Jack Palevich86351982009-06-30 18:09:56 -07004498 return pType;
4499 }
4500
Jack Palevich2ff5c222009-07-23 15:11:22 -07004501 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004502 Type* pHead = NULL;
4503 Type* pTail = NULL;
4504 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004505 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004506 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004507 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004508 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004509 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004510 if (!pHead) {
4511 pHead = pParam;
4512 pTail = pParam;
4513 } else {
4514 pTail->pTail = pParam;
4515 pTail = pParam;
4516 }
4517 }
4518 }
4519 if (! accept(',')) {
4520 break;
4521 }
4522 }
4523 return pHead;
4524 }
4525
Jack Palevich2ff5c222009-07-23 15:11:22 -07004526 Type* expectPrimitiveType() {
4527 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004528 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004529 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004530 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004531 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004532 }
Jack Palevich86351982009-06-30 18:09:56 -07004533 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004534 }
4535
Jack Palevich86351982009-06-30 18:09:56 -07004536 void addGlobalSymbol(Type* pDecl) {
4537 tokenid_t t = pDecl->id;
4538 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004539 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004540 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004541 }
Jack Palevich86351982009-06-30 18:09:56 -07004542 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004543 }
4544
Jack Palevich86351982009-06-30 18:09:56 -07004545 void reportDuplicate(tokenid_t t) {
4546 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004547 }
4548
Jack Palevich86351982009-06-30 18:09:56 -07004549 void addLocalSymbol(Type* pDecl) {
4550 tokenid_t t = pDecl->id;
4551 if (mLocals.isDefinedAtCurrentLevel(t)) {
4552 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004553 }
Jack Palevich86351982009-06-30 18:09:56 -07004554 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004555 }
4556
Jack Palevich95727a02009-07-06 12:07:15 -07004557 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004558 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004559
Jack Palevich95727a02009-07-06 12:07:15 -07004560 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004561 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004562 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004563 if (!pDecl) {
4564 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004565 }
Jack Palevich86351982009-06-30 18:09:56 -07004566 int variableAddress = 0;
4567 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004568 size_t alignment = pGen->stackAlignmentOf(pDecl);
4569 size_t alignmentMask = ~ (alignment - 1);
4570 size_t sizeOf = pGen->sizeOf(pDecl);
4571 loc = (loc + alignment - 1) & alignmentMask;
4572 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4573 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004574 variableAddress = -loc;
4575 VI(pDecl->id)->pAddress = (void*) variableAddress;
4576 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004577 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004578 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004579 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004580 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004581 if (tok == ',')
4582 next();
4583 }
4584 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004585 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004586 }
4587 }
4588
Jack Palevichf1728be2009-06-12 13:53:51 -07004589 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004590 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004591 }
4592
Jack Palevich37c54bd2009-07-14 18:35:36 -07004593 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004594 if (token == EOF ) {
4595 buffer.printf("EOF");
4596 } else if (token == TOK_NUM) {
4597 buffer.printf("numeric constant");
4598 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004599 if (token < 32) {
4600 buffer.printf("'\\x%02x'", token);
4601 } else {
4602 buffer.printf("'%c'", token);
4603 }
Jack Palevich569f1352009-06-29 14:29:08 -07004604 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004605 if (quote) {
4606 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4607 buffer.printf("keyword \"%s\"", nameof(token));
4608 } else {
4609 buffer.printf("symbol \"%s\"", nameof(token));
4610 }
4611 } else {
4612 buffer.printf("%s", nameof(token));
4613 }
Jack Palevich569f1352009-06-29 14:29:08 -07004614 }
4615 }
4616
Jack Palevich40600de2009-07-01 15:32:35 -07004617 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004618 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004619 if (!result) {
4620 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004621 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004622 error("Expected symbol. Got %s", temp.getUnwrapped());
4623 }
4624 return result;
4625 }
4626
Jack Palevich86351982009-06-30 18:09:56 -07004627 tokenid_t acceptSymbol() {
4628 tokenid_t result = 0;
4629 if (tok >= TOK_SYMBOL) {
4630 result = tok;
4631 next();
Jack Palevich86351982009-06-30 18:09:56 -07004632 }
4633 return result;
4634 }
4635
Jack Palevichb7c81e92009-06-04 19:56:13 -07004636 void globalDeclarations() {
4637 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004638 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004639 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004640 break;
4641 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004642 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004643 if (!pDecl) {
4644 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004645 }
Jack Palevich86351982009-06-30 18:09:56 -07004646 if (! isDefined(pDecl->id)) {
4647 addGlobalSymbol(pDecl);
4648 }
4649 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004650 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004651 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004652 }
Jack Palevich86351982009-06-30 18:09:56 -07004653 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004654 // it's a variable declaration
4655 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004656 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004657 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004658 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004659 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004660 }
Jack Palevich86351982009-06-30 18:09:56 -07004661 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004662 if (tok == TOK_NUM) {
4663 if (name) {
4664 * (int*) name->pAddress = tokc;
4665 }
4666 next();
4667 } else {
4668 error("Expected an integer constant");
4669 }
4670 }
Jack Palevich86351982009-06-30 18:09:56 -07004671 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004672 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004673 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004674 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004675 if (!pDecl) {
4676 break;
4677 }
4678 if (! isDefined(pDecl->id)) {
4679 addGlobalSymbol(pDecl);
4680 }
4681 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004682 }
4683 skip(';');
4684 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004685 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004686 if (accept(';')) {
4687 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004688 } else if (tok != '{') {
4689 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004690 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004691 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004692 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004693 /* patch forward references */
4694 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004695 /* put function address */
4696 name->pAddress = (void*) codeBuf.getPC();
4697 }
4698 // Calculate stack offsets for parameters
4699 mLocals.pushLevel();
4700 intptr_t a = 8;
4701 int argCount = 0;
4702 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4703 Type* pArg = pP->pHead;
4704 addLocalSymbol(pArg);
4705 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004706 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004707 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004708 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004709 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004710 argCount++;
4711 }
4712 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004713 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004714 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004715 block(0, true);
4716 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004717 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004718 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004719 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004720 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004721 }
4722 }
4723 }
4724
Jack Palevich9cbd2262009-07-08 16:48:41 -07004725 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4726 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4727 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004728 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004729 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004730 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004731 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004732 char* result = (char*) base;
4733 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004734 return result;
4735 }
4736
Jack Palevich21a15a22009-05-11 14:49:29 -07004737 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004738 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004739 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004740 pGlobalBase = 0;
4741 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004742 if (pGen) {
4743 delete pGen;
4744 pGen = 0;
4745 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004746 if (file) {
4747 delete file;
4748 file = 0;
4749 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004750 }
4751
Jack Palevich8c246a92009-07-14 21:14:10 -07004752 // One-time initialization, when class is constructed.
4753 void init() {
4754 mpSymbolLookupFn = 0;
4755 mpSymbolLookupContext = 0;
4756 }
4757
Jack Palevich21a15a22009-05-11 14:49:29 -07004758 void clear() {
4759 tok = 0;
4760 tokc = 0;
4761 tokl = 0;
4762 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004763 rsym = 0;
4764 loc = 0;
4765 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004766 dptr = 0;
4767 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004768 file = 0;
4769 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004770 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004771 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004772 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004773 mLineNumber = 1;
4774 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004775 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004776
Jack Palevich22305132009-05-13 10:58:45 -07004777 void setArchitecture(const char* architecture) {
4778 delete pGen;
4779 pGen = 0;
4780
4781 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004782#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004783 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004784 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004785 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004786#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004787#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004788 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004789 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004790 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004791#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004792 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004793 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004794 }
4795 }
4796
4797 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004798#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004799 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004800#elif defined(DEFAULT_X86_CODEGEN)
4801 pGen = new X86CodeGenerator();
4802#endif
4803 }
4804 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004805 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004806 } else {
4807 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004808 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004809 }
4810 }
4811
Jack Palevich77ae76e2009-05-10 19:59:24 -07004812public:
Jack Palevich22305132009-05-13 10:58:45 -07004813 struct args {
4814 args() {
4815 architecture = 0;
4816 }
4817 const char* architecture;
4818 };
4819
Jack Paleviche7b59062009-05-19 17:12:17 -07004820 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004821 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004822 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004823 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004824
Jack Paleviche7b59062009-05-19 17:12:17 -07004825 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004826 cleanup();
4827 }
4828
Jack Palevich8c246a92009-07-14 21:14:10 -07004829 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4830 mpSymbolLookupFn = pFn;
4831 mpSymbolLookupContext = pContext;
4832 }
4833
Jack Palevich1cdef202009-05-22 12:06:27 -07004834 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004835 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004836
Jack Palevich2ff5c222009-07-23 15:11:22 -07004837 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004838 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004839 cleanup();
4840 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004841 mTokenTable.setArena(&mGlobalArena);
4842 mGlobals.setArena(&mGlobalArena);
4843 mGlobals.setTokenTable(&mTokenTable);
4844 mLocals.setArena(&mLocalArena);
4845 mLocals.setTokenTable(&mTokenTable);
4846
4847 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004848 codeBuf.init(ALLOC_SIZE);
4849 setArchitecture(NULL);
4850 if (!pGen) {
4851 return -1;
4852 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004853#ifdef PROVIDE_TRACE_CODEGEN
4854 pGen = new TraceCodeGenerator(pGen);
4855#endif
4856 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004857 pGen->init(&codeBuf);
4858 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004859 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4860 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004861 inp();
4862 next();
4863 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004864 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004865 result = pGen->finishCompile();
4866 if (result == 0) {
4867 if (mErrorBuf.len()) {
4868 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004869 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004870 }
Jack Palevichce105a92009-07-16 14:30:33 -07004871 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004872 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004873 }
4874
Jack Palevich86351982009-06-30 18:09:56 -07004875 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004876 mkpInt = createType(TY_INT, NULL, NULL);
4877 mkpChar = createType(TY_CHAR, NULL, NULL);
4878 mkpVoid = createType(TY_VOID, NULL, NULL);
4879 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4880 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4881 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4882 mkpIntPtr = createPtrType(mkpInt);
4883 mkpCharPtr = createPtrType(mkpChar);
4884 mkpFloatPtr = createPtrType(mkpFloat);
4885 mkpDoublePtr = createPtrType(mkpDouble);
4886 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004887 }
4888
Jack Palevicha6baa232009-06-12 11:25:59 -07004889 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004890 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004891 }
4892
Jack Palevich569f1352009-06-29 14:29:08 -07004893 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004894 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004895 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004896 }
4897
Jack Palevich569f1352009-06-29 14:29:08 -07004898 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004899 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004900 error("Undefined forward reference: %s",
4901 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004902 }
4903 return true;
4904 }
4905
Jack Palevich21a15a22009-05-11 14:49:29 -07004906 int dump(FILE* out) {
4907 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4908 return 0;
4909 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004910
Jack Palevicha6535612009-05-13 16:24:17 -07004911 int disassemble(FILE* out) {
4912 return pGen->disassemble(out);
4913 }
4914
Jack Palevich1cdef202009-05-22 12:06:27 -07004915 /* Look through the symbol table to find a symbol.
4916 * If found, return its value.
4917 */
4918 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004919 if (mCompileResult == 0) {
4920 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4921 VariableInfo* pVariableInfo = VI(tok);
4922 if (pVariableInfo) {
4923 return pVariableInfo->pAddress;
4924 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004925 }
4926 return NULL;
4927 }
4928
Jack Palevicheedf9d22009-06-04 16:23:40 -07004929 void getPragmas(ACCsizei* actualStringCount,
4930 ACCsizei maxStringCount, ACCchar** strings) {
4931 int stringCount = mPragmaStringCount;
4932 if (actualStringCount) {
4933 *actualStringCount = stringCount;
4934 }
4935 if (stringCount > maxStringCount) {
4936 stringCount = maxStringCount;
4937 }
4938 if (strings) {
4939 char* pPragmas = mPragmas.getUnwrapped();
4940 while (stringCount-- > 0) {
4941 *strings++ = pPragmas;
4942 pPragmas += strlen(pPragmas) + 1;
4943 }
4944 }
4945 }
4946
Jack Palevichac0e95e2009-05-29 13:53:44 -07004947 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004948 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004949 }
4950
Jack Palevich77ae76e2009-05-10 19:59:24 -07004951};
4952
Jack Paleviche7b59062009-05-19 17:12:17 -07004953const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004954 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4955
Jack Paleviche7b59062009-05-19 17:12:17 -07004956const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004957 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4958 5, 5, /* ==, != */
4959 9, 10, /* &&, || */
4960 6, 7, 8, /* & ^ | */
4961 2, 2 /* ~ ! */
4962 };
4963
Jack Palevich8b0624c2009-05-20 12:12:06 -07004964#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004965FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004966#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004967
Jack Palevich8b0624c2009-05-20 12:12:06 -07004968#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004969const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004970 0x1, // ++
4971 0xff, // --
4972 0xc1af0f, // *
4973 0xf9f79991, // /
4974 0xf9f79991, // % (With manual assist to swap results)
4975 0xc801, // +
4976 0xd8f7c829, // -
4977 0xe0d391, // <<
4978 0xf8d391, // >>
4979 0xe, // <=
4980 0xd, // >=
4981 0xc, // <
4982 0xf, // >
4983 0x4, // ==
4984 0x5, // !=
4985 0x0, // &&
4986 0x1, // ||
4987 0xc821, // &
4988 0xc831, // ^
4989 0xc809, // |
4990 0xd0f7, // ~
4991 0x4 // !
4992};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004993#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004994
Jack Palevich1cdef202009-05-22 12:06:27 -07004995struct ACCscript {
4996 ACCscript() {
4997 text = 0;
4998 textLength = 0;
4999 accError = ACC_NO_ERROR;
5000 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005001
Jack Palevich1cdef202009-05-22 12:06:27 -07005002 ~ACCscript() {
5003 delete text;
5004 }
Jack Palevich546b2242009-05-13 15:10:04 -07005005
Jack Palevich8c246a92009-07-14 21:14:10 -07005006 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5007 compiler.registerSymbolCallback(pFn, pContext);
5008 }
5009
Jack Palevich1cdef202009-05-22 12:06:27 -07005010 void setError(ACCenum error) {
5011 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5012 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005013 }
5014 }
5015
Jack Palevich1cdef202009-05-22 12:06:27 -07005016 ACCenum getError() {
5017 ACCenum result = accError;
5018 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005019 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005020 }
5021
Jack Palevich1cdef202009-05-22 12:06:27 -07005022 Compiler compiler;
5023 char* text;
5024 int textLength;
5025 ACCenum accError;
5026};
5027
5028
5029extern "C"
5030ACCscript* accCreateScript() {
5031 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005032}
Jack Palevich1cdef202009-05-22 12:06:27 -07005033
5034extern "C"
5035ACCenum accGetError( ACCscript* script ) {
5036 return script->getError();
5037}
5038
5039extern "C"
5040void accDeleteScript(ACCscript* script) {
5041 delete script;
5042}
5043
5044extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005045void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5046 ACCvoid* pContext) {
5047 script->registerSymbolCallback(pFn, pContext);
5048}
5049
5050extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005051void accScriptSource(ACCscript* script,
5052 ACCsizei count,
5053 const ACCchar ** string,
5054 const ACCint * length) {
5055 int totalLength = 0;
5056 for(int i = 0; i < count; i++) {
5057 int len = -1;
5058 const ACCchar* s = string[i];
5059 if (length) {
5060 len = length[i];
5061 }
5062 if (len < 0) {
5063 len = strlen(s);
5064 }
5065 totalLength += len;
5066 }
5067 delete script->text;
5068 char* text = new char[totalLength + 1];
5069 script->text = text;
5070 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005071 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005072 for(int i = 0; i < count; i++) {
5073 int len = -1;
5074 const ACCchar* s = string[i];
5075 if (length) {
5076 len = length[i];
5077 }
5078 if (len < 0) {
5079 len = strlen(s);
5080 }
Jack Palevich09555c72009-05-27 12:25:55 -07005081 memcpy(dest, s, len);
5082 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005083 }
5084 text[totalLength] = '\0';
5085}
5086
5087extern "C"
5088void accCompileScript(ACCscript* script) {
5089 int result = script->compiler.compile(script->text, script->textLength);
5090 if (result) {
5091 script->setError(ACC_INVALID_OPERATION);
5092 }
5093}
5094
5095extern "C"
5096void accGetScriptiv(ACCscript* script,
5097 ACCenum pname,
5098 ACCint * params) {
5099 switch (pname) {
5100 case ACC_INFO_LOG_LENGTH:
5101 *params = 0;
5102 break;
5103 }
5104}
5105
5106extern "C"
5107void accGetScriptInfoLog(ACCscript* script,
5108 ACCsizei maxLength,
5109 ACCsizei * length,
5110 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005111 char* message = script->compiler.getErrorMessage();
5112 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005113 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005114 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005115 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005116 if (infoLog && maxLength > 0) {
5117 int trimmedLength = maxLength < messageLength ?
5118 maxLength : messageLength;
5119 memcpy(infoLog, message, trimmedLength);
5120 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005121 }
5122}
5123
5124extern "C"
5125void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5126 ACCvoid ** address) {
5127 void* value = script->compiler.lookup(name);
5128 if (value) {
5129 *address = value;
5130 } else {
5131 script->setError(ACC_INVALID_VALUE);
5132 }
5133}
5134
Jack Palevicheedf9d22009-06-04 16:23:40 -07005135extern "C"
5136void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5137 ACCsizei maxStringCount, ACCchar** strings){
5138 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5139}
5140
-b master422972c2009-06-17 19:13:52 -07005141extern "C"
5142void accDisassemble(ACCscript* script) {
5143 script->compiler.disassemble(stderr);
5144}
5145
Jack Palevicheedf9d22009-06-04 16:23:40 -07005146
Jack Palevich1cdef202009-05-22 12:06:27 -07005147} // namespace acc
5148