blob: adc860909bfbf6383219ffc5365624123f8c16b3 [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>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070041#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070042#endif
Jack Palevicha6535612009-05-13 16:24:17 -070043
Jack Palevich1cdef202009-05-22 12:06:27 -070044#include <acc/acc.h>
45
Jack Palevich09555c72009-05-27 12:25:55 -070046#define LOG_API(...) do {} while(0)
47// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070048
-b master422972c2009-06-17 19:13:52 -070049#define LOG_STACK(...) do {} while(0)
50// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
51
52// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070053// #define PROVIDE_TRACE_CODEGEN
54
Jack Palevichbbf8ab52009-05-11 11:54:30 -070055namespace acc {
56
Jack Palevich8df46192009-07-07 14:48:51 -070057// Subset of STL vector.
58template<class E> class Vector {
59 public:
60 Vector() {
61 mpBase = 0;
62 mUsed = 0;
63 mSize = 0;
64 }
65
66 ~Vector() {
67 if (mpBase) {
68 for(size_t i = 0; i < mUsed; i++) {
69 mpBase[mUsed].~E();
70 }
71 free(mpBase);
72 }
73 }
74
75 inline E& operator[](size_t i) {
76 return mpBase[i];
77 }
78
79 inline E& front() {
80 return mpBase[0];
81 }
82
83 inline E& back() {
84 return mpBase[mUsed - 1];
85 }
86
87 void pop_back() {
88 mUsed -= 1;
89 mpBase[mUsed].~E();
90 }
91
92 void push_back(const E& item) {
93 * ensure(1) = item;
94 }
95
96 size_t size() {
97 return mUsed;
98 }
99
100private:
101 E* ensure(int n) {
102 size_t newUsed = mUsed + n;
103 if (newUsed > mSize) {
104 size_t newSize = mSize * 2 + 10;
105 if (newSize < newUsed) {
106 newSize = newUsed;
107 }
108 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
109 mSize = newSize;
110 }
111 E* result = mpBase + mUsed;
112 mUsed = newUsed;
113 return result;
114 }
115
116 E* mpBase;
117 size_t mUsed;
118 size_t mSize;
119};
120
Jack Palevichac0e95e2009-05-29 13:53:44 -0700121class ErrorSink {
122public:
123 void error(const char *fmt, ...) {
124 va_list ap;
125 va_start(ap, fmt);
126 verror(fmt, ap);
127 va_end(ap);
128 }
129
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700130 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700131 virtual void verror(const char* fmt, va_list ap) = 0;
132};
133
134class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700135 typedef int tokenid_t;
136 enum TypeTag {
137 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
138 TY_POINTER, TY_FUNC, TY_PARAM
139 };
140
141 struct Type {
142 TypeTag tag;
143 tokenid_t id; // For function arguments
144 Type* pHead;
145 Type* pTail;
146 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700147
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700149 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700150 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700151 ErrorSink* mErrorSink;
152 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700153 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700154
Jack Palevich21a15a22009-05-11 14:49:29 -0700155 void release() {
156 if (pProgramBase != 0) {
157 free(pProgramBase);
158 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700159 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700160 }
161
Jack Palevich0a280a02009-06-11 10:53:51 -0700162 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700163 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700164 bool overflow = newSize > mSize;
165 if (overflow && !mOverflowed) {
166 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700167 if (mErrorSink) {
168 mErrorSink->error("Code too large: %d bytes", newSize);
169 }
170 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700171 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 }
173
Jack Palevich21a15a22009-05-11 14:49:29 -0700174 public:
175 CodeBuf() {
176 pProgramBase = 0;
177 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 mErrorSink = 0;
179 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700180 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 }
182
183 ~CodeBuf() {
184 release();
185 }
186
187 void init(int size) {
188 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 pProgramBase = (char*) calloc(1, size);
191 ind = pProgramBase;
192 }
193
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 void setErrorSink(ErrorSink* pErrorSink) {
195 mErrorSink = pErrorSink;
196 }
197
Jack Palevich546b2242009-05-13 15:10:04 -0700198 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700199 if(check(4)) {
200 return 0;
201 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700202 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700203 * (int*) ind = n;
204 ind += 4;
205 return result;
206 }
207
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 /*
209 * Output a byte. Handles all values, 0..ff.
210 */
211 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(1)) {
213 return;
214 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 *ind++ = n;
216 }
217
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 inline void* getBase() {
219 return (void*) pProgramBase;
220 }
221
Jack Palevich8b0624c2009-05-20 12:12:06 -0700222 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 return ind - pProgramBase;
224 }
225
Jack Palevich8b0624c2009-05-20 12:12:06 -0700226 intptr_t getPC() {
227 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 }
229 };
230
Jack Palevich1cdef202009-05-22 12:06:27 -0700231 /**
232 * A code generator creates an in-memory program, generating the code on
233 * the fly. There is one code generator implementation for each supported
234 * architecture.
235 *
236 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700237 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 * FP - a frame pointer for accessing function arguments and local
239 * variables.
240 * SP - a stack pointer for storing intermediate results while evaluating
241 * expressions. The stack pointer grows downwards.
242 *
243 * The function calling convention is that all arguments are placed on the
244 * stack such that the first argument has the lowest address.
245 * After the call, the result is in R0. The caller is responsible for
246 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700247 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700248 * FP and SP registers are saved.
249 */
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 class CodeGenerator {
252 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700253 CodeGenerator() {
254 mErrorSink = 0;
255 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700256 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700257 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 virtual ~CodeGenerator() {}
259
Jack Palevich22305132009-05-13 10:58:45 -0700260 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700262 pCodeBuf->setErrorSink(mErrorSink);
263 }
264
Jack Palevichb67b18f2009-06-11 21:12:23 -0700265 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 mErrorSink = pErrorSink;
267 if (pCodeBuf) {
268 pCodeBuf->setErrorSink(mErrorSink);
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 }
271
Jack Palevich1cdef202009-05-22 12:06:27 -0700272 /* Emit a function prolog.
273 * argCount is the number of arguments.
274 * Save the old value of the FP.
275 * Set the new value of the FP.
276 * Convert from the native platform calling convention to
277 * our stack-based calling convention. This may require
278 * pushing arguments from registers to the stack.
279 * Allocate "N" bytes of stack space. N isn't known yet, so
280 * just emit the instructions for adjusting the stack, and return
281 * the address to patch up. The patching will be done in
282 * functionExit().
283 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700284 */
Jack Palevich546b2242009-05-13 15:10:04 -0700285 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700286
Jack Palevich1cdef202009-05-22 12:06:27 -0700287 /* Emit a function epilog.
288 * Restore the old SP and FP register values.
289 * Return to the calling function.
290 * argCount - the number of arguments to the function.
291 * localVariableAddress - returned from functionEntry()
292 * localVariableSize - the size in bytes of the local variables.
293 */
294 virtual void functionExit(int argCount, int localVariableAddress,
295 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700298 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700299
Jack Palevich1a539db2009-07-08 13:04:41 -0700300 /* Load floating point value from global address. */
301 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Jump to a target, and return the address of the word that
304 * holds the target data, in case it needs to be fixed up later.
305 */
Jack Palevich22305132009-05-13 10:58:45 -0700306 virtual int gjmp(int t) = 0;
307
Jack Palevich1cdef202009-05-22 12:06:27 -0700308 /* Test R0 and jump to a target if the test succeeds.
309 * l = 0: je, l == 1: jne
310 * Return the address of the word that holds the targed data, in
311 * case it needs to be fixed up later.
312 */
Jack Palevich22305132009-05-13 10:58:45 -0700313 virtual int gtst(bool l, int t) = 0;
314
Jack Palevich9eed7a22009-07-06 17:24:34 -0700315 /* Compare TOS against R0, and store the boolean result in R0.
316 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 * op specifies the comparison.
318 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700319 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700320
Jack Palevich9eed7a22009-07-06 17:24:34 -0700321 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700322 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700323 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 */
Jack Palevich546b2242009-05-13 15:10:04 -0700325 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700326
Jack Palevich9eed7a22009-07-06 17:24:34 -0700327 /* Compare 0 against R0, and store the boolean result in R0.
328 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700330 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700331
332 /* Perform the arithmetic op specified by op. 0 is the
333 * left argument, R0 is the right argument.
334 */
335 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700336
Jack Palevich1cdef202009-05-22 12:06:27 -0700337 /* Push R0 onto the stack.
338 */
339 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700340
Jack Palevich9eed7a22009-07-06 17:24:34 -0700341 /* Store R0 to the address stored in TOS.
342 * The TOS is popped.
343 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700346
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700350 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700351
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 /* Load the absolute address of a variable to R0.
353 * If ea <= LOCAL, then this is a local variable, or an
354 * argument, addressed relative to FP.
355 * else it is an absolute global address.
356 */
Jack Palevich8df46192009-07-07 14:48:51 -0700357 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevich1cdef202009-05-22 12:06:27 -0700359 /* Store R0 to a variable.
360 * If ea <= LOCAL, then this is a local variable, or an
361 * argument, addressed relative to FP.
362 * else it is an absolute global address.
363 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700364 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700365
Jack Palevich1cdef202009-05-22 12:06:27 -0700366 /* load R0 from a variable.
367 * If ea <= LOCAL, then this is a local variable, or an
368 * argument, addressed relative to FP.
369 * else it is an absolute global address.
370 * If isIncDec is true, then the stored variable's value
371 * should be post-incremented or post-decremented, based
372 * on the value of op.
373 */
Jack Palevich8df46192009-07-07 14:48:51 -0700374 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
375
376 /**
377 * Convert R0 to the given type.
378 */
379 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700380
Jack Palevich1cdef202009-05-22 12:06:27 -0700381 /* Emit code to adjust the stack for a function call. Return the
382 * label for the address of the instruction that adjusts the
383 * stack size. This will be passed as argument "a" to
384 * endFunctionCallArguments.
385 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700386 virtual int beginFunctionCallArguments() = 0;
387
Jack Palevich1cdef202009-05-22 12:06:27 -0700388 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700389 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700391 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700392
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 /* Patch the function call preamble.
394 * a is the address returned from beginFunctionCallArguments
395 * l is the number of bytes the arguments took on the stack.
396 * Typically you would also emit code to convert the argument
397 * list into whatever the native function calling convention is.
398 * On ARM for example you would pop the first 5 arguments into
399 * R0..R4
400 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700401 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700402
Jack Palevich1cdef202009-05-22 12:06:27 -0700403 /* Emit a call to an unknown function. The argument "symbol" needs to
404 * be stored in the location where the address should go. It forms
405 * a chain. The address will be patched later.
406 * Return the address of the word that has to be patched.
407 */
Jack Palevich8df46192009-07-07 14:48:51 -0700408 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Call a function using PC-relative addressing. t is the PC-relative
411 * address of the function. It has already been adjusted for the
412 * architectural jump offset, so just store it as-is.
413 */
Jack Palevich8df46192009-07-07 14:48:51 -0700414 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700415
Jack Palevich1cdef202009-05-22 12:06:27 -0700416 /* Call a function pointer. L is the number of bytes the arguments
417 * take on the stack. The address of the function is stored at
418 * location SP + l.
419 */
Jack Palevich8df46192009-07-07 14:48:51 -0700420 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700421
Jack Palevich1cdef202009-05-22 12:06:27 -0700422 /* Adjust SP after returning from a function call. l is the
423 * number of bytes of arguments stored on the stack. isIndirect
424 * is true if this was an indirect call. (In which case the
425 * address of the function is stored at location SP + l.)
426 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700427 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700428
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 /* Print a disassembly of the assembled code to out. Return
430 * non-zero if there is an error.
431 */
Jack Palevicha6535612009-05-13 16:24:17 -0700432 virtual int disassemble(FILE* out) = 0;
433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Generate a symbol at the current PC. t is the head of a
435 * linked list of addresses to patch.
436 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700437 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700438
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 /*
440 * Do any cleanup work required at the end of a compile.
441 * For example, an instruction cache might need to be
442 * invalidated.
443 * Return non-zero if there is an error.
444 */
445 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700446
Jack Palevicha6535612009-05-13 16:24:17 -0700447 /**
448 * Adjust relative branches by this amount.
449 */
450 virtual int jumpOffset() = 0;
451
Jack Palevich9eed7a22009-07-06 17:24:34 -0700452 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700453 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700454 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700455 virtual size_t alignment(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700456
457 /**
458 * Array element alignment (in bytes) for this type of data.
459 */
460 virtual size_t sizeOf(Type* type) = 0;
461
Jack Palevich9cbd2262009-07-08 16:48:41 -0700462 /**
463 * Stack argument size of this data type.
464 */
465 virtual size_t stackSizeOf(Type* pType) = 0;
466
Jack Palevich1a539db2009-07-08 13:04:41 -0700467 virtual Type* getR0Type() {
468 return mExpressionStack.back();
469 }
470
Jack Palevich21a15a22009-05-11 14:49:29 -0700471 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700472 /*
473 * Output a byte. Handles all values, 0..ff.
474 */
475 void ob(int n) {
476 pCodeBuf->ob(n);
477 }
478
Jack Palevich8b0624c2009-05-20 12:12:06 -0700479 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700480 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700481 }
482
Jack Palevich8b0624c2009-05-20 12:12:06 -0700483 intptr_t getBase() {
484 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700485 }
486
Jack Palevich8b0624c2009-05-20 12:12:06 -0700487 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700488 return pCodeBuf->getPC();
489 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700490
491 intptr_t getSize() {
492 return pCodeBuf->getSize();
493 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700494
495 void error(const char* fmt,...) {
496 va_list ap;
497 va_start(ap, fmt);
498 mErrorSink->verror(fmt, ap);
499 va_end(ap);
500 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700501
502 void assert(bool test) {
503 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700504 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505 error("code generator assertion failed.");
506 }
507 }
Jack Palevich8df46192009-07-07 14:48:51 -0700508
509 void setR0Type(Type* pType) {
510 mExpressionStack.back() = pType;
511 }
512
Jack Palevich8df46192009-07-07 14:48:51 -0700513 Type* getTOSType() {
514 return mExpressionStack[mExpressionStack.size()-2];
515 }
516
517 void pushType() {
518 mExpressionStack.push_back(NULL);
519 }
520
521 void popType() {
522 mExpressionStack.pop_back();
523 }
524
525 bool bitsSame(Type* pA, Type* pB) {
526 return collapseType(pA->tag) == collapseType(pB->tag);
527 }
528
529 TypeTag collapseType(TypeTag tag) {
530 static const TypeTag collapsedTag[] = {
531 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
532 TY_VOID, TY_VOID};
533 return collapsedTag[tag];
534 }
535
Jack Palevich1a539db2009-07-08 13:04:41 -0700536 TypeTag collapseTypeR0() {
537 return collapseType(getR0Type()->tag);
538 }
539
540 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700541 return isFloatTag(pType->tag);
542 }
543
544 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700545 return tag == TY_FLOAT || tag == TY_DOUBLE;
546 }
547
Jack Palevich21a15a22009-05-11 14:49:29 -0700548 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700549 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700550 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700551 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700552 };
553
Jack Paleviche7b59062009-05-19 17:12:17 -0700554#ifdef PROVIDE_ARM_CODEGEN
555
Jack Palevich22305132009-05-13 10:58:45 -0700556 class ARMCodeGenerator : public CodeGenerator {
557 public:
558 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700559
Jack Palevich22305132009-05-13 10:58:45 -0700560 virtual ~ARMCodeGenerator() {}
561
562 /* returns address to patch with local variable size
563 */
Jack Palevich546b2242009-05-13 15:10:04 -0700564 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700565 LOG_API("functionEntry(%d);\n", argCount);
-b master422972c2009-06-17 19:13:52 -0700566 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700567 // sp -> arg4 arg5 ...
568 // Push our register-based arguments back on the stack
569 if (argCount > 0) {
570 int regArgCount = argCount <= 4 ? argCount : 4;
571 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
-b master422972c2009-06-17 19:13:52 -0700572 mStackUse += regArgCount * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700573 }
574 // sp -> arg0 arg1 ...
575 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700576 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700577 // sp, fp -> oldfp, retadr, arg0 arg1 ....
578 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700579 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700580 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700581 // We don't know how many local variables we are going to use,
582 // but we will round the allocation up to a multiple of
583 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700584 }
585
Jack Palevich546b2242009-05-13 15:10:04 -0700586 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700587 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700588 // Round local variable size up to a multiple of stack alignment
589 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
590 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700591 // Patch local variable allocation code:
592 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700593 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700594 }
Jack Palevich69796b62009-05-14 15:42:26 -0700595 *(char*) (localVariableAddress) = localVariableSize;
596
597 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
598 o4(0xE1A0E00B); // mov lr, fp
599 o4(0xE59BB000); // ldr fp, [fp]
600 o4(0xE28ED004); // add sp, lr, #4
601 // sp -> retadr, arg0, ...
602 o4(0xE8BD4000); // ldmfd sp!, {lr}
603 // sp -> arg0 ....
604 if (argCount > 0) {
605 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700606 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700607 // earlier. We don't need to actually store them anywhere,
608 // just adjust the stack.
609 int regArgCount = argCount <= 4 ? argCount : 4;
610 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
611 }
612 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700613 }
614
615 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700616 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700617 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700618 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700619 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700620 } else if (t >= -256 && t < 0) {
621 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700622 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700623 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700624 o4(0xE51F0000); // ldr r0, .L3
625 o4(0xEA000000); // b .L99
626 o4(t); // .L3: .word 0
627 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700628 }
Jack Palevich8df46192009-07-07 14:48:51 -0700629 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700630 }
631
Jack Palevich1a539db2009-07-08 13:04:41 -0700632 virtual void loadFloat(int address, Type* pType) {
633 error("Unimplemented.\n");
Jack Palevich8df46192009-07-07 14:48:51 -0700634 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700635 }
636
Jack Palevich22305132009-05-13 10:58:45 -0700637 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700638 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700639 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700640 }
641
642 /* l = 0: je, l == 1: jne */
643 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700644 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700645 o4(0xE3500000); // cmp r0,#0
646 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
647 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700648 }
649
Jack Palevicha39749f2009-07-08 20:40:31 -0700650 virtual void gcmp(int op, Type* pResultType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700651 LOG_API("gcmp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700652 o4(0xE8BD0002); // ldmfd sp!,{r1}
653 mStackUse -= 4;
Jack Palevich8de461d2009-05-14 17:21:45 -0700654 o4(0xE1510000); // cmp r1, r1
655 switch(op) {
656 case OP_EQUALS:
657 o4(0x03A00001); // moveq r0,#1
658 o4(0x13A00000); // movne r0,#0
659 break;
660 case OP_NOT_EQUALS:
661 o4(0x03A00000); // moveq r0,#0
662 o4(0x13A00001); // movne r0,#1
663 break;
664 case OP_LESS_EQUAL:
665 o4(0xD3A00001); // movle r0,#1
666 o4(0xC3A00000); // movgt r0,#0
667 break;
668 case OP_GREATER:
669 o4(0xD3A00000); // movle r0,#0
670 o4(0xC3A00001); // movgt r0,#1
671 break;
672 case OP_GREATER_EQUAL:
673 o4(0xA3A00001); // movge r0,#1
674 o4(0xB3A00000); // movlt r0,#0
675 break;
676 case OP_LESS:
677 o4(0xA3A00000); // movge r0,#0
678 o4(0xB3A00001); // movlt r0,#1
679 break;
680 default:
681 error("Unknown comparison op %d", op);
682 break;
683 }
Jack Palevich8df46192009-07-07 14:48:51 -0700684 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700685 }
686
Jack Palevich546b2242009-05-13 15:10:04 -0700687 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700688 LOG_API("genOp(%d);\n", op);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700689 o4(0xE8BD0002); // ldmfd sp!,{r1}
690 mStackUse -= 4;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700691 switch(op) {
692 case OP_MUL:
693 o4(0x0E0000091); // mul r0,r1,r0
694 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700695 case OP_DIV:
696 callRuntime(runtime_DIV);
697 break;
698 case OP_MOD:
699 callRuntime(runtime_MOD);
700 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700701 case OP_PLUS:
702 o4(0xE0810000); // add r0,r1,r0
703 break;
704 case OP_MINUS:
705 o4(0xE0410000); // sub r0,r1,r0
706 break;
707 case OP_SHIFT_LEFT:
708 o4(0xE1A00011); // lsl r0,r1,r0
709 break;
710 case OP_SHIFT_RIGHT:
711 o4(0xE1A00051); // asr r0,r1,r0
712 break;
713 case OP_BIT_AND:
714 o4(0xE0010000); // and r0,r1,r0
715 break;
716 case OP_BIT_XOR:
717 o4(0xE0210000); // eor r0,r1,r0
718 break;
719 case OP_BIT_OR:
720 o4(0xE1810000); // orr r0,r1,r0
721 break;
722 case OP_BIT_NOT:
723 o4(0xE1E00000); // mvn r0, r0
724 break;
725 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700726 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700727 break;
728 }
Jack Palevich8df46192009-07-07 14:48:51 -0700729 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700730 }
731
Jack Palevicha39749f2009-07-08 20:40:31 -0700732 virtual void gUnaryCmp(int op, Type* pResultType) {
733 LOG_API("gUnaryCmp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700734 o4(0xE3A01000); // mov r1, #0
Jack Palevich9eed7a22009-07-06 17:24:34 -0700735 o4(0xE1510000); // cmp r1, r1
736 switch(op) {
Jack Palevicha39749f2009-07-08 20:40:31 -0700737 case OP_LOGICAL_NOT:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700738 o4(0x03A00000); // moveq r0,#0
739 o4(0x13A00001); // movne r0,#1
740 break;
741 default:
742 error("Unknown unary comparison op %d", op);
743 break;
744 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700745 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700746 }
747
748 virtual void genUnaryOp(int op) {
749 LOG_API("genOp(%d);\n", op);
750 switch(op) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700751 case OP_MINUS:
752 o4(0xE3A01000); // mov r1, #0
753 o4(0xE0410000); // sub r0,r1,r0
754 break;
755 case OP_BIT_NOT:
756 o4(0xE1E00000); // mvn r0, r0
757 break;
758 default:
759 error("Unknown unary op %d\n", op);
760 break;
761 }
Jack Palevich22305132009-05-13 10:58:45 -0700762 }
763
Jack Palevich1cdef202009-05-22 12:06:27 -0700764 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700765 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700766 o4(0xE92D0001); // stmfd sp!,{r0}
-b master422972c2009-06-17 19:13:52 -0700767 mStackUse += 4;
Jack Palevich8df46192009-07-07 14:48:51 -0700768 pushType();
-b master422972c2009-06-17 19:13:52 -0700769 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700770 }
771
Jack Palevich9eed7a22009-07-06 17:24:34 -0700772 virtual void storeR0ToTOS(Type* pPointerType) {
773 LOG_API("storeR0ToTOS(%d);\n", isInt);
774 assert(pPointerType->tag == TY_POINTER);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700775 o4(0xE8BD0002); // ldmfd sp!,{r1}
-b master422972c2009-06-17 19:13:52 -0700776 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700777 switch (pPointerType->pHead->tag) {
778 case TY_INT:
779 o4(0xE5810000); // str r0, [r1]
780 break;
781 case TY_CHAR:
782 o4(0xE5C10000); // strb r0, [r1]
783 break;
784 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700785 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700786 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700787 }
Jack Palevich8df46192009-07-07 14:48:51 -0700788 popType();
Jack Palevich22305132009-05-13 10:58:45 -0700789 }
790
Jack Palevich9eed7a22009-07-06 17:24:34 -0700791 virtual void loadR0FromR0(Type* pPointerType) {
792 LOG_API("loadR0FromR0(%d);\n", pPointerType);
793 assert(pPointerType->tag == TY_POINTER);
794 switch (pPointerType->pHead->tag) {
795 case TY_INT:
796 o4(0xE5900000); // ldr r0, [r0]
797 break;
798 case TY_CHAR:
799 o4(0xE5D00000); // ldrb r0, [r0]
800 break;
801 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700802 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700803 break;
804 }
Jack Palevich8df46192009-07-07 14:48:51 -0700805 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700806 }
807
Jack Palevich8df46192009-07-07 14:48:51 -0700808 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700809 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700810 if (ea < LOCAL) {
811 // Local, fp relative
812 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
813 error("Offset out of range: %08x", ea);
814 }
815 if (ea < 0) {
816 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
817 } else {
818 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
819 }
Jack Palevichbd894902009-05-14 19:35:31 -0700820 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700821 // Global, absolute.
822 o4(0xE59F0000); // ldr r0, .L1
823 o4(0xEA000000); // b .L99
824 o4(ea); // .L1: .word 0
825 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700826 }
Jack Palevich8df46192009-07-07 14:48:51 -0700827 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -0700828 }
829
Jack Palevich9cbd2262009-07-08 16:48:41 -0700830 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700831 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700832 if (ea < LOCAL) {
833 // Local, fp relative
834 if (ea < -4095 || ea > 4095) {
835 error("Offset out of range: %08x", ea);
836 }
837 if (ea < 0) {
838 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
839 } else {
840 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
841 }
842 } else{
843 // Global, absolute
844 o4(0xE59F1000); // ldr r1, .L1
845 o4(0xEA000000); // b .L99
846 o4(ea); // .L1: .word 0
847 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700848 }
Jack Palevich22305132009-05-13 10:58:45 -0700849 }
850
Jack Palevich8df46192009-07-07 14:48:51 -0700851 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700852 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich4d93f302009-05-15 13:30:00 -0700853 if (ea < LOCAL) {
854 // Local, fp relative
855 if (ea < -4095 || ea > 4095) {
856 error("Offset out of range: %08x", ea);
857 }
858 if (ea < 0) {
859 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
860 } else {
861 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
862 }
Jack Palevich69796b62009-05-14 15:42:26 -0700863 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700864 // Global, absolute
865 o4(0xE59F2000); // ldr r2, .L1
866 o4(0xEA000000); // b .L99
867 o4(ea); // .L1: .word ea
868 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700869 }
Jack Palevich22305132009-05-13 10:58:45 -0700870
Jack Palevich4d93f302009-05-15 13:30:00 -0700871 if (isIncDec) {
872 switch (op) {
873 case OP_INCREMENT:
874 o4(0xE2801001); // add r1, r0, #1
875 break;
876 case OP_DECREMENT:
877 o4(0xE2401001); // sub r1, r0, #1
878 break;
879 default:
880 error("unknown opcode: %d", op);
881 }
882 if (ea < LOCAL) {
883 // Local, fp relative
884 // Don't need range check, was already checked above
885 if (ea < 0) {
886 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
887 } else {
888 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
889 }
890 } else{
891 // Global, absolute
892 // r2 is already set up from before.
893 o4(0xE5821000); // str r1, [r2]
894 }
Jack Palevichbd894902009-05-14 19:35:31 -0700895 }
Jack Palevich8df46192009-07-07 14:48:51 -0700896 setR0Type(pType);
897 }
898
899 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -0700900 Type* pR0Type = getR0Type();
901 if (bitsSame(pType, pR0Type)) {
902 // do nothing special
903 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
904 // do nothing special, both held in same register on x87.
905 } else {
906 error("Incompatible types old: %d new: %d",
907 pR0Type->tag, pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -0700908 }
Jack Palevich1a539db2009-07-08 13:04:41 -0700909 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700910 }
911
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700912 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700913 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700914 return o4(0xE24DDF00); // Placeholder
915 }
916
Jack Palevich1a539db2009-07-08 13:04:41 -0700917 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700918 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700919 if (l < 0 || l > 4096-4) {
920 error("l out of range for stack offset: 0x%08x", l);
921 }
922 o4(0xE58D0000 + l); // str r0, [sp, #4]
Jack Palevich1a539db2009-07-08 13:04:41 -0700923 return 4;
Jack Palevich7810bc92009-05-15 14:31:47 -0700924 }
925
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700926 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700927 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -0700928 int argCount = l >> 2;
929 int argumentStackUse = l;
930 if (argCount > 0) {
931 int regArgCount = argCount > 4 ? 4 : argCount;
932 argumentStackUse -= regArgCount * 4;
933 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
934 }
935 mStackUse += argumentStackUse;
936
937 // Align stack.
938 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
939 * STACK_ALIGNMENT);
940 mStackAlignmentAdjustment = 0;
941 if (missalignment > 0) {
942 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
943 }
944 l += mStackAlignmentAdjustment;
945
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700946 if (l < 0 || l > 0x3FC) {
947 error("L out of range for stack adjustment: 0x%08x", l);
948 }
949 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -0700950 mStackUse += mStackAlignmentAdjustment;
951 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
952 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -0700953 }
954
Jack Palevich8df46192009-07-07 14:48:51 -0700955 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700956 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -0700957 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700958 // Forward calls are always short (local)
959 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700960 }
961
Jack Palevich8df46192009-07-07 14:48:51 -0700962 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700963 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -0700964 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700965 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700966 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700967 if (t >= - (1 << 25) && t < (1 << 25)) {
968 o4(0xEB000000 | encodeAddress(t));
969 } else {
970 // Long call.
971 o4(0xE59FC000); // ldr r12, .L1
972 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700973 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700974 o4(0xE08CC00F); // .L99: add r12,pc
975 o4(0xE12FFF3C); // blx r12
976 }
Jack Palevich22305132009-05-13 10:58:45 -0700977 }
978
Jack Palevich8df46192009-07-07 14:48:51 -0700979 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -0700980 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -0700981 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -0700982 int argCount = l >> 2;
983 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -0700984 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -0700985 if (adjustedL < 0 || adjustedL > 4096-4) {
986 error("l out of range for stack offset: 0x%08x", l);
987 }
988 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
989 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700990 }
991
Jack Palevich7810bc92009-05-15 14:31:47 -0700992 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700993 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700994 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700995 int stackArgs = argCount > 4 ? argCount - 4 : 0;
-b master422972c2009-06-17 19:13:52 -0700996 int stackUse = stackArgs + (isIndirect ? 1 : 0)
997 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -0700998 if (stackUse) {
999 if (stackUse < 0 || stackUse > 255) {
1000 error("L out of range for stack adjustment: 0x%08x", l);
1001 }
1002 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001003 mStackUse -= stackUse * 4;
1004 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001005 }
Jack Palevich22305132009-05-13 10:58:45 -07001006 }
1007
Jack Palevicha6535612009-05-13 16:24:17 -07001008 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001009 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001010 }
1011
1012 /* output a symbol and patch all calls to it */
1013 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001014 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001015 int n;
1016 int base = getBase();
1017 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001018 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001019 while (t) {
1020 int data = * (int*) t;
1021 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1022 if (decodedOffset == 0) {
1023 n = 0;
1024 } else {
1025 n = base + decodedOffset; /* next value */
1026 }
1027 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1028 | encodeRelAddress(pc - t - 8);
1029 t = n;
1030 }
1031 }
1032
Jack Palevich1cdef202009-05-22 12:06:27 -07001033 virtual int finishCompile() {
1034#if defined(__arm__)
1035 const long base = long(getBase());
1036 const long curr = long(getPC());
1037 int err = cacheflush(base, curr, 0);
1038 return err;
1039#else
1040 return 0;
1041#endif
1042 }
1043
Jack Palevicha6535612009-05-13 16:24:17 -07001044 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001045#ifdef ENABLE_ARM_DISASSEMBLY
1046 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001047 disasm_interface_t di;
1048 di.di_readword = disassemble_readword;
1049 di.di_printaddr = disassemble_printaddr;
1050 di.di_printf = disassemble_printf;
1051
1052 int base = getBase();
1053 int pc = getPC();
1054 for(int i = base; i < pc; i += 4) {
1055 fprintf(out, "%08x: %08x ", i, *(int*) i);
1056 ::disasm(&di, i, 0);
1057 }
Jack Palevich09555c72009-05-27 12:25:55 -07001058#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001059 return 0;
1060 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001061
Jack Palevich9eed7a22009-07-06 17:24:34 -07001062 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001063 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001064 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001065 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001066 switch(pType->tag) {
1067 case TY_DOUBLE:
1068 return 8;
1069 default:
1070 return 4;
1071 }
1072 }
1073
1074 /**
1075 * Array element alignment (in bytes) for this type of data.
1076 */
1077 virtual size_t sizeOf(Type* pType){
1078 switch(pType->tag) {
1079 case TY_INT:
1080 return 4;
1081 case TY_CHAR:
1082 return 1;
1083 default:
1084 return 0;
1085 case TY_FLOAT:
1086 return 4;
1087 case TY_DOUBLE:
1088 return 8;
1089 case TY_POINTER:
1090 return 4;
1091 }
1092 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001093
1094 virtual size_t stackSizeOf(Type* pType) {
1095 switch(pType->tag) {
1096 case TY_DOUBLE:
1097 return 8;
1098 default:
1099 return 4;
1100 }
1101 }
1102
Jack Palevich22305132009-05-13 10:58:45 -07001103 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001104 static FILE* disasmOut;
1105
1106 static u_int
1107 disassemble_readword(u_int address)
1108 {
1109 return(*((u_int *)address));
1110 }
1111
1112 static void
1113 disassemble_printaddr(u_int address)
1114 {
1115 fprintf(disasmOut, "0x%08x", address);
1116 }
1117
1118 static void
1119 disassemble_printf(const char *fmt, ...) {
1120 va_list ap;
1121 va_start(ap, fmt);
1122 vfprintf(disasmOut, fmt, ap);
1123 va_end(ap);
1124 }
1125
1126 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1127
1128 /** Encode a relative address that might also be
1129 * a label.
1130 */
1131 int encodeAddress(int value) {
1132 int base = getBase();
1133 if (value >= base && value <= getPC() ) {
1134 // This is a label, encode it relative to the base.
1135 value = value - base;
1136 }
1137 return encodeRelAddress(value);
1138 }
1139
1140 int encodeRelAddress(int value) {
1141 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1142 }
Jack Palevich22305132009-05-13 10:58:45 -07001143
Jack Palevich3d474a72009-05-15 15:12:38 -07001144 typedef int (*int2FnPtr)(int a, int b);
1145 void callRuntime(int2FnPtr fn) {
1146 o4(0xE59F2000); // ldr r2, .L1
1147 o4(0xEA000000); // b .L99
1148 o4((int) fn); //.L1: .word fn
1149 o4(0xE12FFF32); //.L99: blx r2
1150 }
1151
1152 static int runtime_DIV(int a, int b) {
1153 return b / a;
1154 }
1155
1156 static int runtime_MOD(int a, int b) {
1157 return b % a;
1158 }
-b master422972c2009-06-17 19:13:52 -07001159
1160 static const int STACK_ALIGNMENT = 8;
1161 int mStackUse;
1162 // This variable holds the amount we adjusted the stack in the most
1163 // recent endFunctionCallArguments call. It's examined by the
1164 // following adjustStackAfterCall call.
1165 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001166 };
1167
Jack Palevich09555c72009-05-27 12:25:55 -07001168#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001169
1170#ifdef PROVIDE_X86_CODEGEN
1171
Jack Palevich21a15a22009-05-11 14:49:29 -07001172 class X86CodeGenerator : public CodeGenerator {
1173 public:
1174 X86CodeGenerator() {}
1175 virtual ~X86CodeGenerator() {}
1176
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001177 /* returns address to patch with local variable size
1178 */
Jack Palevich546b2242009-05-13 15:10:04 -07001179 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001180 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1181 return oad(0xec81, 0); /* sub $xxx, %esp */
1182 }
1183
Jack Palevich546b2242009-05-13 15:10:04 -07001184 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001185 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001186 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001187 }
1188
Jack Palevich21a15a22009-05-11 14:49:29 -07001189 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001190 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001191 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001192 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001193 }
1194
Jack Palevich1a539db2009-07-08 13:04:41 -07001195 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001196 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001197 switch (pType->tag) {
1198 case TY_FLOAT:
1199 oad(0x05D9, address); // flds
1200 break;
1201 case TY_DOUBLE:
1202 oad(0x05DD, address); // fldl
1203 break;
1204 default:
1205 assert(false);
1206 break;
1207 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001208 }
1209
Jack Palevich22305132009-05-13 10:58:45 -07001210 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001211 return psym(0xe9, t);
1212 }
1213
1214 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001215 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001216 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
1217 return psym(0x84 + l, t);
1218 }
1219
Jack Palevicha39749f2009-07-08 20:40:31 -07001220 virtual void gcmp(int op, Type* pResultType) {
1221 Type* pR0Type = getR0Type();
1222 Type* pTOSType = getTOSType();
1223 TypeTag tagR0 = pR0Type->tag;
1224 TypeTag tagTOS = pTOSType->tag;
1225 bool isFloatR0 = isFloatTag(tagR0);
1226 bool isFloatTOS = isFloatTag(tagTOS);
1227 if (!isFloatR0 && !isFloatTOS) {
1228 int t = decodeOp(op);
1229 o(0x59); /* pop %ecx */
1230 o(0xc139); /* cmp %eax,%ecx */
1231 li(0, NULL);
1232 o(0x0f); /* setxx %al */
1233 o(t + 0x90);
1234 o(0xc0);
1235 popType();
1236 } else {
1237 setupFloatOperands();
1238 switch (op) {
1239 case OP_EQUALS:
1240 o(0xe9da); // fucompp
1241 o(0xe0df); // fnstsw %ax
1242 o(0x9e); // sahf
1243 o(0xc0940f); // sete %al
1244 o(0xc29b0f); // setnp %dl
1245 o(0xd021); // andl %edx, %eax
1246 break;
1247 case OP_NOT_EQUALS:
1248 o(0xe9da); // fucompp
1249 o(0xe0df); // fnstsw %ax
1250 o(0x9e); // sahf
1251 o(0xc0950f); // setne %al
1252 o(0xc29a0f); // setp %dl
1253 o(0xd009); // orl %edx, %eax
1254 break;
1255 case OP_GREATER_EQUAL:
1256 o(0xe9da); // fucompp
1257 o(0xe0df); // fnstsw %ax
1258 o(0x05c4f6); // testb $5, %ah
1259 o(0xc0940f); // sete %al
1260 break;
1261 case OP_LESS:
1262 o(0xc9d9); // fxch %st(1)
1263 o(0xe9da); // fucompp
1264 o(0xe0df); // fnstsw %ax
1265 o(0x9e); // sahf
1266 o(0xc0970f); // seta %al
1267 break;
1268 case OP_LESS_EQUAL:
1269 o(0xc9d9); // fxch %st(1)
1270 o(0xe9da); // fucompp
1271 o(0xe0df); // fnstsw %ax
1272 o(0x9e); // sahf
1273 o(0xc0930f); // setea %al
1274 break;
1275 case OP_GREATER:
1276 o(0xe9da); // fucompp
1277 o(0xe0df); // fnstsw %ax
1278 o(0x45c4f6); // testb $69, %ah
1279 o(0xc0940f); // sete %al
1280 break;
1281 default:
1282 error("Unknown comparison op");
1283 }
1284 o(0xc0b60f); // movzbl %al, %eax
1285 }
1286 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001287 }
1288
Jack Palevich546b2242009-05-13 15:10:04 -07001289 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001290 Type* pR0Type = getR0Type();
1291 Type* pTOSType = getTOSType();
1292 TypeTag tagR0 = pR0Type->tag;
1293 TypeTag tagTOS = pTOSType->tag;
1294 bool isFloatR0 = isFloatTag(tagR0);
1295 bool isFloatTOS = isFloatTag(tagTOS);
1296 if (!isFloatR0 && !isFloatTOS) {
1297 // TODO: Deal with pointer arithmetic
1298 o(0x59); /* pop %ecx */
1299 o(decodeOp(op));
1300 if (op == OP_MOD)
1301 o(0x92); /* xchg %edx, %eax */
1302 popType();
1303 } else {
1304 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1305 setupFloatOperands();
1306 // Both float. x87 R0 == left hand, x87 R1 == right hand
1307 switch (op) {
1308 case OP_MUL:
1309 o(0xc9de); // fmulp
1310 break;
1311 case OP_DIV:
1312 o(0xf1de); // fdivp
1313 break;
1314 case OP_PLUS:
1315 o(0xc1de); // faddp
1316 break;
1317 case OP_MINUS:
1318 o(0xe1de); // fsubp
1319 break;
1320 default:
1321 error("Unsupported binary floating operation.");
1322 break;
1323 }
1324 popType();
1325 setR0Type(pResultType);
1326 printf("genop: result type %d\n", pResultType->tag);
1327 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001328 }
1329
Jack Palevicha39749f2009-07-08 20:40:31 -07001330
1331
1332 virtual void gUnaryCmp(int op, Type* pResultType) {
1333 if (op != OP_LOGICAL_NOT) {
1334 error("Unknown unary cmp %d", op);
1335 } else {
1336 Type* pR0Type = getR0Type();
1337 TypeTag tag = collapseType(pR0Type->tag);
1338 switch(tag) {
1339 case TY_INT: {
1340 oad(0xb9, 0); /* movl $0, %ecx */
1341 int t = decodeOp(op);
1342 o(0xc139); /* cmp %eax,%ecx */
1343 li(0, NULL);
1344 o(0x0f); /* setxx %al */
1345 o(t + 0x90);
1346 o(0xc0);
1347 }
1348 break;
1349 case TY_FLOAT:
1350 case TY_DOUBLE:
1351 o(0xeed9); // fldz
1352 o(0xe9da); // fucompp
1353 o(0xe0df); // fnstsw %ax
1354 o(0x9e); // sahf
1355 o(0xc0950f); // setne %al
1356 o(0xc29a0f); // setp %dl
1357 o(0xd009); // orl %edx, %eax
1358 o(0xc0b60f); // movzbl %al, %eax
1359 o(0x01f083); // xorl $1, %eax
1360 break;
1361 default:
1362 error("genUnaryCmp unsupported type");
1363 break;
1364 }
1365 }
1366 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001367 }
1368
1369 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001370 Type* pR0Type = getR0Type();
1371 TypeTag tag = collapseType(pR0Type->tag);
1372 switch(tag) {
1373 case TY_INT:
1374 oad(0xb9, 0); /* movl $0, %ecx */
1375 o(decodeOp(op));
1376 break;
1377 case TY_FLOAT:
1378 case TY_DOUBLE:
1379 switch (op) {
1380 case OP_MINUS:
1381 o(0xe0d9); // fchs
1382 break;
1383 case OP_BIT_NOT:
1384 error("Can't apply '~' operator to a float or double.");
1385 break;
1386 default:
1387 error("Unknown unary op %d\n", op);
1388 break;
1389 }
1390 break;
1391 default:
1392 error("genUnaryOp unsupported type");
1393 break;
1394 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001395 }
1396
Jack Palevich1cdef202009-05-22 12:06:27 -07001397 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001398 Type* pR0Type = getR0Type();
1399 TypeTag r0ct = collapseType(pR0Type->tag);
1400 switch(r0ct) {
1401 case TY_INT:
1402 o(0x50); /* push %eax */
1403 break;
1404 case TY_FLOAT:
1405 o(0x50); /* push %eax */
1406 o(0x241cd9); // fstps 0(%esp)
1407 break;
1408 case TY_DOUBLE:
1409 o(0x50); /* push %eax */
1410 o(0x50); /* push %eax */
1411 o(0x241cdd); // fstpl 0(%esp)
1412 break;
1413 default:
1414 error("pushR0 %d", r0ct);
1415 break;
1416 }
Jack Palevich8df46192009-07-07 14:48:51 -07001417 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001418 }
1419
Jack Palevich9eed7a22009-07-06 17:24:34 -07001420 virtual void storeR0ToTOS(Type* pPointerType) {
1421 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001422 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001423 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001424 switch (pPointerType->pHead->tag) {
1425 case TY_INT:
1426 o(0x0189); /* movl %eax/%al, (%ecx) */
1427 break;
1428 case TY_CHAR:
1429 o(0x0188); /* movl %eax/%al, (%ecx) */
1430 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001431 case TY_FLOAT:
1432 o(0x19d9); /* fstps (%ecx) */
1433 break;
1434 case TY_DOUBLE:
1435 o(0x19dd); /* fstpl (%ecx) */
1436 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001437 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001438 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001439 break;
1440 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001441 }
1442
Jack Palevich9eed7a22009-07-06 17:24:34 -07001443 virtual void loadR0FromR0(Type* pPointerType) {
1444 assert(pPointerType->tag == TY_POINTER);
1445 switch (pPointerType->pHead->tag) {
1446 case TY_INT:
1447 o(0x8b); /* mov (%eax), %eax */
1448 break;
1449 case TY_CHAR:
1450 o(0xbe0f); /* movsbl (%eax), %eax */
1451 break;
1452 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001453 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001454 break;
1455 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001456 ob(0); /* add zero in code */
Jack Palevich8df46192009-07-07 14:48:51 -07001457 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001458 }
1459
Jack Palevich8df46192009-07-07 14:48:51 -07001460 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001461 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001462 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001463 }
1464
Jack Palevich9cbd2262009-07-08 16:48:41 -07001465 virtual void storeR0(int ea, Type* pType) {
1466 TypeTag tag = pType->tag;
1467 switch (tag) {
1468 case TY_INT:
1469 gmov(6, ea); /* mov %eax, EA */
1470 break;
1471 case TY_FLOAT:
1472 if (ea < -LOCAL || ea > LOCAL) {
1473 oad(0x1dd9, ea); // fstps ea
1474 } else {
1475 oad(0x9dd9, ea); // fstps ea(%ebp)
1476 }
1477 break;
1478 case TY_DOUBLE:
1479 if (ea < -LOCAL || ea > LOCAL) {
1480 oad(0x1ddd, ea); // fstpl ea
1481 } else {
1482 oad(0x9ddd, ea); // fstpl ea(%ebp)
1483 }
1484 break;
1485 default:
1486 error("Unable to store to type %d", tag);
1487 break;
1488 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001489 }
1490
Jack Palevich8df46192009-07-07 14:48:51 -07001491 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001492 TypeTag tag = collapseType(pType->tag);
1493 switch (tag) {
1494 case TY_INT:
1495 gmov(8, ea); /* mov EA, %eax */
1496 if (isIncDec) {
1497 /* Implement post-increment or post decrement.
1498 */
1499 gmov(0, ea); /* 83 ADD */
1500 o(decodeOp(op));
1501 }
1502 break;
1503 case TY_FLOAT:
1504 if (ea < -LOCAL || ea > LOCAL) {
1505 oad(0x05d9, ea); // flds ea
1506 } else {
1507 oad(0x85d9, ea); // flds ea(%ebp)
1508 }
1509 if (isIncDec) {
1510 error("inc/dec not implemented for float.");
1511 }
1512 break;
1513 case TY_DOUBLE:
1514 if (ea < -LOCAL || ea > LOCAL) {
1515 oad(0x05dd, ea); // fldl ea
1516 } else {
1517 oad(0x85dd, ea); // fldl ea(%ebp)
1518 }
1519 if (isIncDec) {
1520 error("inc/dec not implemented for double.");
1521 }
1522 break;
1523 default:
1524 error("Unable to load type %d", tag);
1525 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07001526 }
Jack Palevich8df46192009-07-07 14:48:51 -07001527 setR0Type(pType);
1528 }
1529
1530 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001531 Type* pR0Type = getR0Type();
1532 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001533 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07001534 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001535 return;
1536 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001537 if (bitsSame(pType, pR0Type)) {
1538 // do nothing special
1539 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1540 // do nothing special, both held in same register on x87.
1541 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001542 TypeTag r0Tag = collapseType(pR0Type->tag);
1543 TypeTag destTag = collapseType(pType->tag);
1544 if (r0Tag == TY_INT && isFloatTag(destTag)) {
1545 // Convert R0 from int to float
1546 o(0x50); // push %eax
1547 o(0x2404DB); // fildl 0(%esp)
1548 o(0x58); // pop %eax
1549 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
1550 // Convert R0 from float to int. Complicated because
1551 // need to save and restore the rounding mode.
1552 o(0x50); // push %eax
1553 o(0x50); // push %eax
1554 o(0x02247cD9); // fnstcw 2(%esp)
1555 o(0x2444b70f); // movzwl 2(%esp), %eax
1556 o(0x02);
1557 o(0x0cb4); // movb $12, %ah
1558 o(0x24048966); // movw %ax, 0(%esp)
1559 o(0x242cd9); // fldcw 0(%esp)
1560 o(0x04245cdb); // fistpl 4(%esp)
1561 o(0x02246cd9); // fldcw 2(%esp)
1562 o(0x58); // pop %eax
1563 o(0x58); // pop %eax
1564 } else {
1565 error("Incompatible types old: %d new: %d",
1566 pR0Type->tag, pType->tag);
1567 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001568 }
1569 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001570 }
1571
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001572 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001573 return oad(0xec81, 0); /* sub $xxx, %esp */
1574 }
1575
Jack Palevich1a539db2009-07-08 13:04:41 -07001576 virtual size_t storeR0ToArg(int l) {
1577 Type* pR0Type = getR0Type();
1578 TypeTag r0ct = collapseType(pR0Type->tag);
1579 switch(r0ct) {
1580 case TY_INT:
1581 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1582 return 4;
1583 case TY_FLOAT:
1584 oad(0x249CD9, l); /* fstps xxx(%esp) */
1585 return 4;
1586 case TY_DOUBLE:
1587 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1588 return 8;
1589 default:
1590 assert(false);
1591 return 0;
1592 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001593 }
1594
Jack Palevich7810bc92009-05-15 14:31:47 -07001595 virtual void endFunctionCallArguments(int a, int l) {
1596 * (int*) a = l;
1597 }
1598
Jack Palevich8df46192009-07-07 14:48:51 -07001599 virtual int callForward(int symbol, Type* pFunc) {
1600 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001601 return psym(0xe8, symbol); /* call xxx */
1602 }
1603
Jack Palevich8df46192009-07-07 14:48:51 -07001604 virtual void callRelative(int t, Type* pFunc) {
1605 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001606 psym(0xe8, t); /* call xxx */
1607 }
1608
Jack Palevich8df46192009-07-07 14:48:51 -07001609 virtual void callIndirect(int l, Type* pFunc) {
1610 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001611 oad(0x2494ff, l); /* call *xxx(%esp) */
1612 }
1613
Jack Palevich7810bc92009-05-15 14:31:47 -07001614 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1615 if (isIndirect) {
1616 l += 4;
1617 }
-b master422972c2009-06-17 19:13:52 -07001618 if (l > 0) {
1619 oad(0xc481, l); /* add $xxx, %esp */
1620 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001621 }
1622
Jack Palevicha6535612009-05-13 16:24:17 -07001623 virtual int jumpOffset() {
1624 return 5;
1625 }
1626
1627 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001628 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001629 }
1630
Jack Paleviche7b59062009-05-19 17:12:17 -07001631 /* output a symbol and patch all calls to it */
1632 virtual void gsym(int t) {
1633 int n;
1634 int pc = getPC();
1635 while (t) {
1636 n = *(int *) t; /* next value */
1637 *(int *) t = pc - t - 4;
1638 t = n;
1639 }
1640 }
1641
Jack Palevich1cdef202009-05-22 12:06:27 -07001642 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001643 size_t pagesize = 4096;
1644 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1645 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1646 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1647 if (err) {
1648 error("mprotect() failed: %d", errno);
1649 }
1650 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001651 }
1652
Jack Palevich9eed7a22009-07-06 17:24:34 -07001653 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001654 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001655 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001656 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001657 switch(pType->tag) {
1658 case TY_DOUBLE:
1659 return 8;
1660 default:
1661 return 4;
1662 }
1663 }
1664
1665 /**
1666 * Array element alignment (in bytes) for this type of data.
1667 */
1668 virtual size_t sizeOf(Type* pType){
1669 switch(pType->tag) {
1670 case TY_INT:
1671 return 4;
1672 case TY_CHAR:
1673 return 1;
1674 default:
1675 return 0;
1676 case TY_FLOAT:
1677 return 4;
1678 case TY_DOUBLE:
1679 return 8;
1680 case TY_POINTER:
1681 return 4;
1682 }
1683 }
1684
Jack Palevich9cbd2262009-07-08 16:48:41 -07001685 virtual size_t stackSizeOf(Type* pType) {
1686 switch(pType->tag) {
1687 case TY_DOUBLE:
1688 return 8;
1689 default:
1690 return 4;
1691 }
1692 }
1693
Jack Palevich21a15a22009-05-11 14:49:29 -07001694 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001695
1696 /** Output 1 to 4 bytes.
1697 *
1698 */
1699 void o(int n) {
1700 /* cannot use unsigned, so we must do a hack */
1701 while (n && n != -1) {
1702 ob(n & 0xff);
1703 n = n >> 8;
1704 }
1705 }
1706
1707 /* psym is used to put an instruction with a data field which is a
1708 reference to a symbol. It is in fact the same as oad ! */
1709 int psym(int n, int t) {
1710 return oad(n, t);
1711 }
1712
1713 /* instruction + address */
1714 int oad(int n, int t) {
1715 o(n);
1716 int result = getPC();
1717 o4(t);
1718 return result;
1719 }
1720
1721
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001722 static const int operatorHelper[];
1723
1724 int decodeOp(int op) {
1725 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001726 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001727 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001728 }
1729 return operatorHelper[op];
1730 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001731
Jack Palevich546b2242009-05-13 15:10:04 -07001732 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001733 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001734 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001735 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001736
1737 void setupFloatOperands() {
1738 Type* pR0Type = getR0Type();
1739 Type* pTOSType = getTOSType();
1740 TypeTag tagR0 = pR0Type->tag;
1741 TypeTag tagTOS = pTOSType->tag;
1742 bool isFloatR0 = isFloatTag(tagR0);
1743 bool isFloatTOS = isFloatTag(tagTOS);
1744 if (! isFloatR0) {
1745 // Convert R0 from int to float
1746 o(0x50); // push %eax
1747 o(0x2404DB); // fildl 0(%esp)
1748 o(0x58); // pop %eax
1749 }
1750 if (! isFloatTOS){
1751 o(0x2404DB); // fildl 0(%esp);
1752 o(0x58); // pop %eax
1753 } else {
1754 if (tagTOS == TY_FLOAT) {
1755 o(0x2404d9); // flds (%esp)
1756 o(0x58); // pop %eax
1757 } else {
1758 o(0x2404dd); // fldl (%esp)
1759 o(0x58); // pop %eax
1760 o(0x58); // pop %eax
1761 }
1762 }
1763 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001764 };
1765
Jack Paleviche7b59062009-05-19 17:12:17 -07001766#endif // PROVIDE_X86_CODEGEN
1767
Jack Palevichb67b18f2009-06-11 21:12:23 -07001768#ifdef PROVIDE_TRACE_CODEGEN
1769 class TraceCodeGenerator : public CodeGenerator {
1770 private:
1771 CodeGenerator* mpBase;
1772
1773 public:
1774 TraceCodeGenerator(CodeGenerator* pBase) {
1775 mpBase = pBase;
1776 }
1777
1778 virtual ~TraceCodeGenerator() {
1779 delete mpBase;
1780 }
1781
1782 virtual void init(CodeBuf* pCodeBuf) {
1783 mpBase->init(pCodeBuf);
1784 }
1785
1786 void setErrorSink(ErrorSink* pErrorSink) {
1787 mpBase->setErrorSink(pErrorSink);
1788 }
1789
1790 /* returns address to patch with local variable size
1791 */
1792 virtual int functionEntry(int argCount) {
1793 int result = mpBase->functionEntry(argCount);
1794 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1795 return result;
1796 }
1797
1798 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1799 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1800 argCount, localVariableAddress, localVariableSize);
1801 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1802 }
1803
1804 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001805 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001806 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001807 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001808 }
1809
Jack Palevich1a539db2009-07-08 13:04:41 -07001810 virtual void loadFloat(int address, Type* pType) {
1811 fprintf(stderr, "loadFloat(%d, type)\n", address);
1812 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001813 }
1814
Jack Palevichb67b18f2009-06-11 21:12:23 -07001815 virtual int gjmp(int t) {
1816 int result = mpBase->gjmp(t);
1817 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1818 return result;
1819 }
1820
1821 /* l = 0: je, l == 1: jne */
1822 virtual int gtst(bool l, int t) {
1823 int result = mpBase->gtst(l, t);
1824 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1825 return result;
1826 }
1827
Jack Palevicha39749f2009-07-08 20:40:31 -07001828 virtual void gcmp(int op, Type* pResultType) {
1829 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
1830 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001831 }
1832
1833 virtual void genOp(int op) {
1834 fprintf(stderr, "genOp(%d)\n", op);
1835 mpBase->genOp(op);
1836 }
1837
Jack Palevich9eed7a22009-07-06 17:24:34 -07001838
Jack Palevicha39749f2009-07-08 20:40:31 -07001839 virtual void gUnaryCmp(int op, Type* pResultType) {
1840 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
1841 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001842 }
1843
1844 virtual void genUnaryOp(int op) {
1845 fprintf(stderr, "genUnaryOp(%d)\n", op);
1846 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001847 }
1848
1849 virtual void pushR0() {
1850 fprintf(stderr, "pushR0()\n");
1851 mpBase->pushR0();
1852 }
1853
Jack Palevich9eed7a22009-07-06 17:24:34 -07001854 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001855 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001856 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001857 }
1858
Jack Palevich9eed7a22009-07-06 17:24:34 -07001859 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001860 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001861 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001862 }
1863
Jack Palevich8df46192009-07-07 14:48:51 -07001864 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001865 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001866 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001867 }
1868
Jack Palevich9cbd2262009-07-08 16:48:41 -07001869 virtual void storeR0(int ea, Type* pType) {
1870 fprintf(stderr, "storeR0(%d, pType)\n", ea);
1871 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001872 }
1873
Jack Palevich8df46192009-07-07 14:48:51 -07001874 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001875 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001876 mpBase->loadR0(ea, isIncDec, op, pType);
1877 }
1878
1879 virtual void convertR0(Type* pType){
1880 fprintf(stderr, "convertR0(pType)\n");
1881 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001882 }
1883
1884 virtual int beginFunctionCallArguments() {
1885 int result = mpBase->beginFunctionCallArguments();
1886 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1887 return result;
1888 }
1889
Jack Palevich1a539db2009-07-08 13:04:41 -07001890 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001891 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001892 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001893 }
1894
1895 virtual void endFunctionCallArguments(int a, int l) {
1896 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1897 mpBase->endFunctionCallArguments(a, l);
1898 }
1899
Jack Palevich8df46192009-07-07 14:48:51 -07001900 virtual int callForward(int symbol, Type* pFunc) {
1901 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001902 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1903 return result;
1904 }
1905
Jack Palevich8df46192009-07-07 14:48:51 -07001906 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001907 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001908 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001909 }
1910
Jack Palevich8df46192009-07-07 14:48:51 -07001911 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001912 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001913 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001914 }
1915
1916 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1917 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1918 mpBase->adjustStackAfterCall(l, isIndirect);
1919 }
1920
1921 virtual int jumpOffset() {
1922 return mpBase->jumpOffset();
1923 }
1924
1925 virtual int disassemble(FILE* out) {
1926 return mpBase->disassemble(out);
1927 }
1928
1929 /* output a symbol and patch all calls to it */
1930 virtual void gsym(int t) {
1931 fprintf(stderr, "gsym(%d)\n", t);
1932 mpBase->gsym(t);
1933 }
1934
1935 virtual int finishCompile() {
1936 int result = mpBase->finishCompile();
1937 fprintf(stderr, "finishCompile() = %d\n", result);
1938 return result;
1939 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001940
1941 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001942 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001943 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001944 virtual size_t alignment(Type* pType){
1945 return mpBase->alignment(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001946 }
1947
1948 /**
1949 * Array element alignment (in bytes) for this type of data.
1950 */
1951 virtual size_t sizeOf(Type* pType){
1952 return mpBase->sizeOf(pType);
1953 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001954
Jack Palevich9cbd2262009-07-08 16:48:41 -07001955
1956 virtual size_t stackSizeOf(Type* pType) {
1957 return mpBase->stackSizeOf(pType);
1958 }
1959
1960
Jack Palevich1a539db2009-07-08 13:04:41 -07001961 virtual Type* getR0Type() {
1962 return mpBase->getR0Type();
1963 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001964 };
1965
1966#endif // PROVIDE_TRACE_CODEGEN
1967
Jack Palevich569f1352009-06-29 14:29:08 -07001968 class Arena {
1969 public:
1970 // Used to record a given allocation amount.
1971 // Used:
1972 // Mark mark = arena.mark();
1973 // ... lots of arena.allocate()
1974 // arena.free(mark);
1975
1976 struct Mark {
1977 size_t chunk;
1978 size_t offset;
1979 };
1980
1981 Arena() {
1982 mCurrentChunk = 0;
1983 Chunk start(CHUNK_SIZE);
1984 mData.push_back(start);
1985 }
1986
1987 ~Arena() {
1988 for(size_t i = 0; i < mData.size(); i++) {
1989 mData[i].free();
1990 }
1991 }
1992
1993 // Alloc using the standard alignment size safe for any variable
1994 void* alloc(size_t size) {
1995 return alloc(size, 8);
1996 }
1997
1998 Mark mark(){
1999 Mark result;
2000 result.chunk = mCurrentChunk;
2001 result.offset = mData[mCurrentChunk].mOffset;
2002 return result;
2003 }
2004
2005 void freeToMark(const Mark& mark) {
2006 mCurrentChunk = mark.chunk;
2007 mData[mCurrentChunk].mOffset = mark.offset;
2008 }
2009
2010 private:
2011 // Allocate memory aligned to a given size
2012 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2013 // Memory is not zero filled.
2014
2015 void* alloc(size_t size, size_t alignment) {
2016 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2017 if (mCurrentChunk + 1 < mData.size()) {
2018 mCurrentChunk++;
2019 } else {
2020 size_t allocSize = CHUNK_SIZE;
2021 if (allocSize < size + alignment - 1) {
2022 allocSize = size + alignment - 1;
2023 }
2024 Chunk chunk(allocSize);
2025 mData.push_back(chunk);
2026 mCurrentChunk++;
2027 }
2028 }
2029 return mData[mCurrentChunk].allocate(size, alignment);
2030 }
2031
2032 static const size_t CHUNK_SIZE = 128*1024;
2033 // Note: this class does not deallocate its
2034 // memory when it's destroyed. It depends upon
2035 // its parent to deallocate the memory.
2036 struct Chunk {
2037 Chunk() {
2038 mpData = 0;
2039 mSize = 0;
2040 mOffset = 0;
2041 }
2042
2043 Chunk(size_t size) {
2044 mSize = size;
2045 mpData = (char*) malloc(size);
2046 mOffset = 0;
2047 }
2048
2049 ~Chunk() {
2050 // Doesn't deallocate memory.
2051 }
2052
2053 void* allocate(size_t size, size_t alignment) {
2054 size_t alignedOffset = aligned(mOffset, alignment);
2055 void* result = mpData + alignedOffset;
2056 mOffset = alignedOffset + size;
2057 return result;
2058 }
2059
2060 void free() {
2061 if (mpData) {
2062 ::free(mpData);
2063 mpData = 0;
2064 }
2065 }
2066
2067 size_t remainingCapacity(size_t alignment) {
2068 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2069 }
2070
2071 // Assume alignment is a power of two
2072 inline size_t aligned(size_t v, size_t alignment) {
2073 size_t mask = alignment-1;
2074 return (v + mask) & ~mask;
2075 }
2076
2077 char* mpData;
2078 size_t mSize;
2079 size_t mOffset;
2080 };
2081
2082 size_t mCurrentChunk;
2083
2084 Vector<Chunk> mData;
2085 };
2086
Jack Palevich569f1352009-06-29 14:29:08 -07002087 struct VariableInfo;
2088
2089 struct Token {
2090 int hash;
2091 size_t length;
2092 char* pText;
2093 tokenid_t id;
2094
2095 // Current values for the token
2096 char* mpMacroDefinition;
2097 VariableInfo* mpVariableInfo;
2098 };
2099
2100 class TokenTable {
2101 public:
2102 // Don't use 0..0xff, allows characters and operators to be tokens too.
2103
2104 static const int TOKEN_BASE = 0x100;
2105 TokenTable() {
2106 mpMap = hashmapCreate(128, hashFn, equalsFn);
2107 }
2108
2109 ~TokenTable() {
2110 hashmapFree(mpMap);
2111 }
2112
2113 void setArena(Arena* pArena) {
2114 mpArena = pArena;
2115 }
2116
2117 // Returns a token for a given string of characters.
2118 tokenid_t intern(const char* pText, size_t length) {
2119 Token probe;
2120 int hash = hashmapHash((void*) pText, length);
2121 {
2122 Token probe;
2123 probe.hash = hash;
2124 probe.length = length;
2125 probe.pText = (char*) pText;
2126 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2127 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002128 return pValue->id;
2129 }
2130 }
2131
2132 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2133 memset(pToken, 0, sizeof(*pToken));
2134 pToken->hash = hash;
2135 pToken->length = length;
2136 pToken->pText = (char*) mpArena->alloc(length + 1);
2137 memcpy(pToken->pText, pText, length);
2138 pToken->pText[length] = 0;
2139 pToken->id = mTokens.size() + TOKEN_BASE;
2140 mTokens.push_back(pToken);
2141 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002142 return pToken->id;
2143 }
2144
2145 // Return the Token for a given tokenid.
2146 Token& operator[](tokenid_t id) {
2147 return *mTokens[id - TOKEN_BASE];
2148 }
2149
2150 inline size_t size() {
2151 return mTokens.size();
2152 }
2153
2154 private:
2155
2156 static int hashFn(void* pKey) {
2157 Token* pToken = (Token*) pKey;
2158 return pToken->hash;
2159 }
2160
2161 static bool equalsFn(void* keyA, void* keyB) {
2162 Token* pTokenA = (Token*) keyA;
2163 Token* pTokenB = (Token*) keyB;
2164 // Don't need to compare hash values, they should always be equal
2165 return pTokenA->length == pTokenB->length
2166 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2167 }
2168
2169 Hashmap* mpMap;
2170 Vector<Token*> mTokens;
2171 Arena* mpArena;
2172 };
2173
Jack Palevich1cdef202009-05-22 12:06:27 -07002174 class InputStream {
2175 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002176 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002177 int getChar() {
2178 if (bumpLine) {
2179 line++;
2180 bumpLine = false;
2181 }
2182 int ch = get();
2183 if (ch == '\n') {
2184 bumpLine = true;
2185 }
2186 return ch;
2187 }
2188 int getLine() {
2189 return line;
2190 }
2191 protected:
2192 InputStream() :
2193 line(1), bumpLine(false) {
2194 }
2195 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002196 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002197 int line;
2198 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002199 };
2200
2201 class FileInputStream : public InputStream {
2202 public:
2203 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002204 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002205 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002206 FILE* f;
2207 };
2208
2209 class TextInputStream : public InputStream {
2210 public:
2211 TextInputStream(const char* text, size_t textLength)
2212 : pText(text), mTextLength(textLength), mPosition(0) {
2213 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002214
2215 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002216 virtual int get() {
2217 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2218 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002219
Jack Palevich1cdef202009-05-22 12:06:27 -07002220 const char* pText;
2221 size_t mTextLength;
2222 size_t mPosition;
2223 };
2224
Jack Palevicheedf9d22009-06-04 16:23:40 -07002225 class String {
2226 public:
2227 String() {
2228 mpBase = 0;
2229 mUsed = 0;
2230 mSize = 0;
2231 }
2232
Jack Palevich303d8ff2009-06-11 19:06:24 -07002233 String(const char* item, int len, bool adopt) {
2234 if (len < 0) {
2235 len = strlen(item);
2236 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002237 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002238 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002239 mUsed = len;
2240 mSize = len + 1;
2241 } else {
2242 mpBase = 0;
2243 mUsed = 0;
2244 mSize = 0;
2245 appendBytes(item, len);
2246 }
2247 }
2248
Jack Palevich303d8ff2009-06-11 19:06:24 -07002249 String(const String& other) {
2250 mpBase = 0;
2251 mUsed = 0;
2252 mSize = 0;
2253 appendBytes(other.getUnwrapped(), other.len());
2254 }
2255
Jack Palevicheedf9d22009-06-04 16:23:40 -07002256 ~String() {
2257 if (mpBase) {
2258 free(mpBase);
2259 }
2260 }
2261
Jack Palevicha6baa232009-06-12 11:25:59 -07002262 String& operator=(const String& other) {
2263 clear();
2264 appendBytes(other.getUnwrapped(), other.len());
2265 return *this;
2266 }
2267
Jack Palevich303d8ff2009-06-11 19:06:24 -07002268 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002269 return mpBase;
2270 }
2271
Jack Palevich303d8ff2009-06-11 19:06:24 -07002272 void clear() {
2273 mUsed = 0;
2274 if (mSize > 0) {
2275 mpBase[0] = 0;
2276 }
2277 }
2278
Jack Palevicheedf9d22009-06-04 16:23:40 -07002279 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002280 appendBytes(s, strlen(s));
2281 }
2282
2283 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002284 memcpy(ensure(n), s, n + 1);
2285 }
2286
2287 void append(char c) {
2288 * ensure(1) = c;
2289 }
2290
Jack Palevich86351982009-06-30 18:09:56 -07002291 void append(String& other) {
2292 appendBytes(other.getUnwrapped(), other.len());
2293 }
2294
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002295 char* orphan() {
2296 char* result = mpBase;
2297 mpBase = 0;
2298 mUsed = 0;
2299 mSize = 0;
2300 return result;
2301 }
2302
Jack Palevicheedf9d22009-06-04 16:23:40 -07002303 void printf(const char* fmt,...) {
2304 va_list ap;
2305 va_start(ap, fmt);
2306 vprintf(fmt, ap);
2307 va_end(ap);
2308 }
2309
2310 void vprintf(const char* fmt, va_list ap) {
2311 char* temp;
2312 int numChars = vasprintf(&temp, fmt, ap);
2313 memcpy(ensure(numChars), temp, numChars+1);
2314 free(temp);
2315 }
2316
Jack Palevich303d8ff2009-06-11 19:06:24 -07002317 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002318 return mUsed;
2319 }
2320
2321 private:
2322 char* ensure(int n) {
2323 size_t newUsed = mUsed + n;
2324 if (newUsed > mSize) {
2325 size_t newSize = mSize * 2 + 10;
2326 if (newSize < newUsed) {
2327 newSize = newUsed;
2328 }
2329 mpBase = (char*) realloc(mpBase, newSize + 1);
2330 mSize = newSize;
2331 }
2332 mpBase[newUsed] = '\0';
2333 char* result = mpBase + mUsed;
2334 mUsed = newUsed;
2335 return result;
2336 }
2337
2338 char* mpBase;
2339 size_t mUsed;
2340 size_t mSize;
2341 };
2342
Jack Palevich569f1352009-06-29 14:29:08 -07002343 void internKeywords() {
2344 // Note: order has to match TOK_ constants
2345 static const char* keywords[] = {
2346 "int",
2347 "char",
2348 "void",
2349 "if",
2350 "else",
2351 "while",
2352 "break",
2353 "return",
2354 "for",
2355 "pragma",
2356 "define",
2357 "auto",
2358 "case",
2359 "const",
2360 "continue",
2361 "default",
2362 "do",
2363 "double",
2364 "enum",
2365 "extern",
2366 "float",
2367 "goto",
2368 "long",
2369 "register",
2370 "short",
2371 "signed",
2372 "sizeof",
2373 "static",
2374 "struct",
2375 "switch",
2376 "typedef",
2377 "union",
2378 "unsigned",
2379 "volatile",
2380 "_Bool",
2381 "_Complex",
2382 "_Imaginary",
2383 "inline",
2384 "restrict",
2385 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002386
Jack Palevich569f1352009-06-29 14:29:08 -07002387 for(int i = 0; keywords[i]; i++) {
2388 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002389 }
Jack Palevich569f1352009-06-29 14:29:08 -07002390 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002391
Jack Palevich36d94142009-06-08 15:55:32 -07002392 struct InputState {
2393 InputStream* pStream;
2394 int oldCh;
2395 };
2396
Jack Palevich2db168f2009-06-11 14:29:47 -07002397 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002398 void* pAddress;
2399 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002400 tokenid_t tok;
2401 size_t level;
2402 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002403 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002404 };
2405
Jack Palevich303d8ff2009-06-11 19:06:24 -07002406 class SymbolStack {
2407 public:
2408 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002409 mpArena = 0;
2410 mpTokenTable = 0;
2411 }
2412
2413 void setArena(Arena* pArena) {
2414 mpArena = pArena;
2415 }
2416
2417 void setTokenTable(TokenTable* pTokenTable) {
2418 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002419 }
2420
2421 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002422 Mark mark;
2423 mark.mArenaMark = mpArena->mark();
2424 mark.mSymbolHead = mStack.size();
2425 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002426 }
2427
2428 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002429 // Undo any shadowing that was done:
2430 Mark mark = mLevelStack.back();
2431 mLevelStack.pop_back();
2432 while (mStack.size() > mark.mSymbolHead) {
2433 VariableInfo* pV = mStack.back();
2434 mStack.pop_back();
2435 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002436 }
Jack Palevich569f1352009-06-29 14:29:08 -07002437 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002438 }
2439
Jack Palevich569f1352009-06-29 14:29:08 -07002440 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2441 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2442 return pV && pV->level == level();
2443 }
2444
2445 VariableInfo* add(tokenid_t tok) {
2446 Token& token = (*mpTokenTable)[tok];
2447 VariableInfo* pOldV = token.mpVariableInfo;
2448 VariableInfo* pNewV =
2449 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2450 memset(pNewV, 0, sizeof(VariableInfo));
2451 pNewV->tok = tok;
2452 pNewV->level = level();
2453 pNewV->pOldDefinition = pOldV;
2454 token.mpVariableInfo = pNewV;
2455 mStack.push_back(pNewV);
2456 return pNewV;
2457 }
2458
Jack Palevich86351982009-06-30 18:09:56 -07002459 VariableInfo* add(Type* pType) {
2460 VariableInfo* pVI = add(pType->id);
2461 pVI->pType = pType;
2462 return pVI;
2463 }
2464
Jack Palevich569f1352009-06-29 14:29:08 -07002465 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2466 for (size_t i = 0; i < mStack.size(); i++) {
2467 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002468 break;
2469 }
2470 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002471 }
2472
Jack Palevich303d8ff2009-06-11 19:06:24 -07002473 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002474 inline size_t level() {
2475 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002476 }
2477
Jack Palevich569f1352009-06-29 14:29:08 -07002478 struct Mark {
2479 Arena::Mark mArenaMark;
2480 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002481 };
2482
Jack Palevich569f1352009-06-29 14:29:08 -07002483 Arena* mpArena;
2484 TokenTable* mpTokenTable;
2485 Vector<VariableInfo*> mStack;
2486 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002487 };
Jack Palevich36d94142009-06-08 15:55:32 -07002488
2489 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002490 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002491 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002492 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002493 int tokl; // token operator level
2494 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002495 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002496 intptr_t loc; // local variable index
2497 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002498 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002499 char* dptr; // Macro state: Points to macro text during macro playback.
2500 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002501 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002502
2503 // Arena for the duration of the compile
2504 Arena mGlobalArena;
2505 // Arena for data that's only needed when compiling a single function
2506 Arena mLocalArena;
2507
2508 TokenTable mTokenTable;
2509 SymbolStack mGlobals;
2510 SymbolStack mLocals;
2511
Jack Palevich40600de2009-07-01 15:32:35 -07002512 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002513 Type* mkpInt; // int
2514 Type* mkpChar; // char
2515 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002516 Type* mkpFloat;
2517 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002518 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002519 Type* mkpIntPtr;
2520 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002521 Type* mkpFloatPtr;
2522 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002523 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002524
Jack Palevich36d94142009-06-08 15:55:32 -07002525 InputStream* file;
2526
2527 CodeBuf codeBuf;
2528 CodeGenerator* pGen;
2529
Jack Palevicheedf9d22009-06-04 16:23:40 -07002530 String mErrorBuf;
2531
Jack Palevicheedf9d22009-06-04 16:23:40 -07002532 String mPragmas;
2533 int mPragmaStringCount;
2534
Jack Palevich21a15a22009-05-11 14:49:29 -07002535 static const int ALLOC_SIZE = 99999;
2536
Jack Palevich303d8ff2009-06-11 19:06:24 -07002537 static const int TOK_DUMMY = 1;
2538 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002539 static const int TOK_NUM_FLOAT = 3;
2540 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002541
2542 // 3..255 are character and/or operators
2543
Jack Palevich2db168f2009-06-11 14:29:47 -07002544 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002545 // Order has to match string list in "internKeywords".
2546 enum {
2547 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2548 TOK_INT = TOK_KEYWORD,
2549 TOK_CHAR,
2550 TOK_VOID,
2551 TOK_IF,
2552 TOK_ELSE,
2553 TOK_WHILE,
2554 TOK_BREAK,
2555 TOK_RETURN,
2556 TOK_FOR,
2557 TOK_PRAGMA,
2558 TOK_DEFINE,
2559 TOK_AUTO,
2560 TOK_CASE,
2561 TOK_CONST,
2562 TOK_CONTINUE,
2563 TOK_DEFAULT,
2564 TOK_DO,
2565 TOK_DOUBLE,
2566 TOK_ENUM,
2567 TOK_EXTERN,
2568 TOK_FLOAT,
2569 TOK_GOTO,
2570 TOK_LONG,
2571 TOK_REGISTER,
2572 TOK_SHORT,
2573 TOK_SIGNED,
2574 TOK_SIZEOF,
2575 TOK_STATIC,
2576 TOK_STRUCT,
2577 TOK_SWITCH,
2578 TOK_TYPEDEF,
2579 TOK_UNION,
2580 TOK_UNSIGNED,
2581 TOK_VOLATILE,
2582 TOK__BOOL,
2583 TOK__COMPLEX,
2584 TOK__IMAGINARY,
2585 TOK_INLINE,
2586 TOK_RESTRICT,
2587 // Symbols start after tokens
2588 TOK_SYMBOL
2589 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002590
2591 static const int LOCAL = 0x200;
2592
2593 static const int SYM_FORWARD = 0;
2594 static const int SYM_DEFINE = 1;
2595
2596 /* tokens in string heap */
2597 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002598
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002599 static const int OP_INCREMENT = 0;
2600 static const int OP_DECREMENT = 1;
2601 static const int OP_MUL = 2;
2602 static const int OP_DIV = 3;
2603 static const int OP_MOD = 4;
2604 static const int OP_PLUS = 5;
2605 static const int OP_MINUS = 6;
2606 static const int OP_SHIFT_LEFT = 7;
2607 static const int OP_SHIFT_RIGHT = 8;
2608 static const int OP_LESS_EQUAL = 9;
2609 static const int OP_GREATER_EQUAL = 10;
2610 static const int OP_LESS = 11;
2611 static const int OP_GREATER = 12;
2612 static const int OP_EQUALS = 13;
2613 static const int OP_NOT_EQUALS = 14;
2614 static const int OP_LOGICAL_AND = 15;
2615 static const int OP_LOGICAL_OR = 16;
2616 static const int OP_BIT_AND = 17;
2617 static const int OP_BIT_XOR = 18;
2618 static const int OP_BIT_OR = 19;
2619 static const int OP_BIT_NOT = 20;
2620 static const int OP_LOGICAL_NOT = 21;
2621 static const int OP_COUNT = 22;
2622
2623 /* Operators are searched from front, the two-character operators appear
2624 * before the single-character operators with the same first character.
2625 * @ is used to pad out single-character operators.
2626 */
2627 static const char* operatorChars;
2628 static const char operatorLevel[];
2629
Jack Palevich569f1352009-06-29 14:29:08 -07002630 /* Called when we detect an internal problem. Does nothing in production.
2631 *
2632 */
2633 void internalError() {
2634 * (char*) 0 = 0;
2635 }
2636
Jack Palevich86351982009-06-30 18:09:56 -07002637 void assert(bool isTrue) {
2638 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002639 internalError();
2640 }
Jack Palevich86351982009-06-30 18:09:56 -07002641 }
2642
Jack Palevich40600de2009-07-01 15:32:35 -07002643 bool isSymbol(tokenid_t t) {
2644 return t >= TOK_SYMBOL &&
2645 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2646 }
2647
2648 bool isSymbolOrKeyword(tokenid_t t) {
2649 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002650 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002651 }
2652
Jack Palevich86351982009-06-30 18:09:56 -07002653 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002654 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002655 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2656 if (pV && pV->tok != t) {
2657 internalError();
2658 }
2659 return pV;
2660 }
2661
2662 inline bool isDefined(tokenid_t t) {
2663 return t >= TOK_SYMBOL && VI(t) != 0;
2664 }
2665
Jack Palevich40600de2009-07-01 15:32:35 -07002666 const char* nameof(tokenid_t t) {
2667 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002668 return mTokenTable[t].pText;
2669 }
2670
Jack Palevich21a15a22009-05-11 14:49:29 -07002671 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002672 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002673 }
2674
2675 void inp() {
2676 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002677 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002678 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002679 dptr = 0;
2680 ch = dch;
2681 }
2682 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002683 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002684#if 0
2685 printf("ch='%c' 0x%x\n", ch, ch);
2686#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002687 }
2688
2689 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002690 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002691 }
2692
Jack Palevichb4758ff2009-06-12 12:49:14 -07002693 /* read a character constant, advances ch to after end of constant */
2694 int getq() {
2695 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002696 if (ch == '\\') {
2697 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002698 if (isoctal(ch)) {
2699 // 1 to 3 octal characters.
2700 val = 0;
2701 for(int i = 0; i < 3; i++) {
2702 if (isoctal(ch)) {
2703 val = (val << 3) + ch - '0';
2704 inp();
2705 }
2706 }
2707 return val;
2708 } else if (ch == 'x' || ch == 'X') {
2709 // N hex chars
2710 inp();
2711 if (! isxdigit(ch)) {
2712 error("'x' character escape requires at least one digit.");
2713 } else {
2714 val = 0;
2715 while (isxdigit(ch)) {
2716 int d = ch;
2717 if (isdigit(d)) {
2718 d -= '0';
2719 } else if (d <= 'F') {
2720 d = d - 'A' + 10;
2721 } else {
2722 d = d - 'a' + 10;
2723 }
2724 val = (val << 4) + d;
2725 inp();
2726 }
2727 }
2728 } else {
2729 int val = ch;
2730 switch (ch) {
2731 case 'a':
2732 val = '\a';
2733 break;
2734 case 'b':
2735 val = '\b';
2736 break;
2737 case 'f':
2738 val = '\f';
2739 break;
2740 case 'n':
2741 val = '\n';
2742 break;
2743 case 'r':
2744 val = '\r';
2745 break;
2746 case 't':
2747 val = '\t';
2748 break;
2749 case 'v':
2750 val = '\v';
2751 break;
2752 case '\\':
2753 val = '\\';
2754 break;
2755 case '\'':
2756 val = '\'';
2757 break;
2758 case '"':
2759 val = '"';
2760 break;
2761 case '?':
2762 val = '?';
2763 break;
2764 default:
2765 error("Undefined character escape %c", ch);
2766 break;
2767 }
2768 inp();
2769 return val;
2770 }
2771 } else {
2772 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002773 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002774 return val;
2775 }
2776
2777 static bool isoctal(int ch) {
2778 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002779 }
2780
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002781 bool acceptCh(int c) {
2782 bool result = c == ch;
2783 if (result) {
2784 pdef(ch);
2785 inp();
2786 }
2787 return result;
2788 }
2789
2790 bool acceptDigitsCh() {
2791 bool result = false;
2792 while (isdigit(ch)) {
2793 result = true;
2794 pdef(ch);
2795 inp();
2796 }
2797 return result;
2798 }
2799
2800 void parseFloat() {
2801 tok = TOK_NUM_DOUBLE;
2802 // mTokenString already has the integral part of the number.
2803 acceptCh('.');
2804 acceptDigitsCh();
2805 bool doExp = true;
2806 if (acceptCh('e') || acceptCh('E')) {
2807 // Don't need to do any extra work
2808 } else if (ch == 'f' || ch == 'F') {
2809 pdef('e'); // So it can be parsed by strtof.
2810 inp();
2811 tok = TOK_NUM_FLOAT;
2812 } else {
2813 doExp = false;
2814 }
2815 if (doExp) {
2816 bool digitsRequired = acceptCh('-');
2817 bool digitsFound = acceptDigitsCh();
2818 if (digitsRequired && ! digitsFound) {
2819 error("malformed exponent");
2820 }
2821 }
2822 char* pText = mTokenString.getUnwrapped();
2823 if (tok == TOK_NUM_FLOAT) {
2824 tokd = strtof(pText, 0);
2825 } else {
2826 tokd = strtod(pText, 0);
2827 }
2828 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2829 }
2830
Jack Palevich21a15a22009-05-11 14:49:29 -07002831 void next() {
2832 int l, a;
2833
Jack Palevich546b2242009-05-13 15:10:04 -07002834 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002835 if (ch == '#') {
2836 inp();
2837 next();
2838 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002839 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002840 } else if (tok == TOK_PRAGMA) {
2841 doPragma();
2842 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002843 error("Unsupported preprocessor directive \"%s\"",
2844 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002845 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002846 }
2847 inp();
2848 }
2849 tokl = 0;
2850 tok = ch;
2851 /* encode identifiers & numbers */
2852 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002853 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002854 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002855 pdef(ch);
2856 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002857 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002858 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002859 // Start of a numeric constant. Could be integer, float, or
2860 // double, won't know until we look further.
2861 if (ch == '.' || ch == 'e' || ch == 'e'
2862 || ch == 'f' || ch == 'F') {
2863 parseFloat();
2864 } else {
2865 // It's an integer constant
2866 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2867 tok = TOK_NUM;
2868 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002869 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002870 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2871 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002872 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002873 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2874 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002875 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002876 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002877 dch = ch;
2878 inp();
2879 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002880 }
2881 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002882 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002883 inp();
2884 if (tok == '\'') {
2885 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002886 tokc = getq();
2887 if (ch != '\'') {
2888 error("Expected a ' character, got %c", ch);
2889 } else {
2890 inp();
2891 }
Jack Palevich546b2242009-05-13 15:10:04 -07002892 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002893 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002894 while (ch && ch != EOF) {
2895 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002896 inp();
2897 inp();
2898 if (ch == '/')
2899 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002900 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002901 if (ch == EOF) {
2902 error("End of file inside comment.");
2903 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002904 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002905 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002906 } else if ((tok == '/') & (ch == '/')) {
2907 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002908 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002909 inp();
2910 }
2911 inp();
2912 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002913 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002914 const char* t = operatorChars;
2915 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002916 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002917 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002918 tokl = operatorLevel[opIndex];
2919 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002920 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002921#if 0
2922 printf("%c%c -> tokl=%d tokc=0x%x\n",
2923 l, a, tokl, tokc);
2924#endif
2925 if (a == ch) {
2926 inp();
2927 tok = TOK_DUMMY; /* dummy token for double tokens */
2928 }
2929 break;
2930 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002931 opIndex++;
2932 }
2933 if (l == 0) {
2934 tokl = 0;
2935 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002936 }
2937 }
2938 }
2939#if 0
2940 {
Jack Palevich569f1352009-06-29 14:29:08 -07002941 String buf;
2942 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002943 fprintf(stderr, "%s\n", buf.getUnwrapped());
2944 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002945#endif
2946 }
2947
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002948 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002949 next();
2950 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002951 String* pName = new String();
2952 while (isspace(ch)) {
2953 inp();
2954 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002955 if (ch == '(') {
2956 delete pName;
2957 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002958 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002959 }
2960 while (isspace(ch)) {
2961 inp();
2962 }
Jack Palevich569f1352009-06-29 14:29:08 -07002963 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002964 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002965 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002966 inp();
2967 }
Jack Palevich569f1352009-06-29 14:29:08 -07002968 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2969 memcpy(pDefn, value.getUnwrapped(), value.len());
2970 pDefn[value.len()] = 0;
2971 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002972 }
2973
Jack Palevicheedf9d22009-06-04 16:23:40 -07002974 void doPragma() {
2975 // # pragma name(val)
2976 int state = 0;
2977 while(ch != EOF && ch != '\n' && state < 10) {
2978 switch(state) {
2979 case 0:
2980 if (isspace(ch)) {
2981 inp();
2982 } else {
2983 state++;
2984 }
2985 break;
2986 case 1:
2987 if (isalnum(ch)) {
2988 mPragmas.append(ch);
2989 inp();
2990 } else if (ch == '(') {
2991 mPragmas.append(0);
2992 inp();
2993 state++;
2994 } else {
2995 state = 11;
2996 }
2997 break;
2998 case 2:
2999 if (isalnum(ch)) {
3000 mPragmas.append(ch);
3001 inp();
3002 } else if (ch == ')') {
3003 mPragmas.append(0);
3004 inp();
3005 state = 10;
3006 } else {
3007 state = 11;
3008 }
3009 break;
3010 }
3011 }
3012 if(state != 10) {
3013 error("Unexpected pragma syntax");
3014 }
3015 mPragmaStringCount += 2;
3016 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003017
Jack Palevichac0e95e2009-05-29 13:53:44 -07003018 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003019 mErrorBuf.printf("%ld: ", file->getLine());
3020 mErrorBuf.vprintf(fmt, ap);
3021 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003022 }
3023
Jack Palevich8b0624c2009-05-20 12:12:06 -07003024 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003025 if (tok != c) {
3026 error("'%c' expected", c);
3027 }
3028 next();
3029 }
3030
Jack Palevich86351982009-06-30 18:09:56 -07003031 bool accept(intptr_t c) {
3032 if (tok == c) {
3033 next();
3034 return true;
3035 }
3036 return false;
3037 }
3038
Jack Palevich40600de2009-07-01 15:32:35 -07003039 bool acceptStringLiteral() {
3040 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003041 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003042 // This while loop merges multiple adjacent string constants.
3043 while (tok == '"') {
3044 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003045 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003046 }
3047 if (ch != '"') {
3048 error("Unterminated string constant.");
3049 }
3050 inp();
3051 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003052 }
Jack Palevich40600de2009-07-01 15:32:35 -07003053 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003054 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003055 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003056 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003057
3058 return true;
3059 }
3060 return false;
3061 }
3062 /* Parse and evaluate a unary expression.
3063 * allowAssignment is true if '=' parsing wanted (quick hack)
3064 */
3065 void unary(bool allowAssignment) {
3066 intptr_t n, t, a;
3067 t = 0;
3068 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3069 if (acceptStringLiteral()) {
3070 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003071 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003072 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003073 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003074 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003075 t = tok;
3076 next();
3077 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003078 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003079 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003080 // Align to 4-byte boundary
3081 glo = (char*) (((intptr_t) glo + 3) & -4);
3082 * (float*) glo = (float) ad;
3083 pGen->loadFloat((int) glo, mkpFloat);
3084 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003085 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003086 // Align to 8-byte boundary
3087 glo = (char*) (((intptr_t) glo + 7) & -8);
3088 * (double*) glo = ad;
3089 pGen->loadFloat((int) glo, mkpDouble);
3090 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003091 } else if (c == 2) {
3092 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003093 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003094 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003095 pGen->gUnaryCmp(a, mkpInt);
3096 else if (t == '+') {
3097 // ignore unary plus.
3098 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003099 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003100 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003101 } else if (t == '(') {
3102 expr();
3103 skip(')');
3104 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07003105 /* This is a pointer dereference, but we currently only
3106 * support a pointer dereference if it's immediately
3107 * in front of a cast. So parse the cast right here.
3108 */
Jack Palevich21a15a22009-05-11 14:49:29 -07003109 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07003110 Type* pCast = expectCastTypeDeclaration(mLocalArena);
3111 // We currently only handle 3 types of cast:
3112 // (int*), (char*) , (int (*)())
3113 if(typeEqual(pCast, mkpIntPtr)) {
3114 t = TOK_INT;
3115 } else if (typeEqual(pCast, mkpCharPtr)) {
3116 t = TOK_CHAR;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003117 } else if (typeEqual(pCast, mkpFloatPtr)) {
3118 t = TOK_FLOAT;
3119 } else if (typeEqual(pCast, mkpDoublePtr)) {
3120 t = TOK_DOUBLE;
Jack Palevich3f226492009-07-02 14:46:19 -07003121 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07003122 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07003123 } else {
3124 String buffer;
3125 decodeType(buffer, pCast);
3126 error("Unsupported cast type %s", buffer.getUnwrapped());
3127 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07003128 }
3129 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07003130 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07003131 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07003132 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003133 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07003134 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003135 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003136 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003137 }
Jack Palevich3f226492009-07-02 14:46:19 -07003138 // Else we fall through to the function call below, with
3139 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003140 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003141 VariableInfo* pVI = VI(tok);
3142 pGen->leaR0((int) pVI->pAddress,
3143 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003144 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003145 } else if (t == EOF ) {
3146 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003147 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003148 // Don't have to do anything special here, the error
3149 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003150 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003151 if (!isDefined(t)) {
3152 mGlobals.add(t);
3153 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003154 }
Jack Palevich8df46192009-07-07 14:48:51 -07003155 VariableInfo* pVI = VI(t);
3156 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003157 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003158 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003159 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003160 if (tok == '(') {
3161 pVI->pType = mkpIntFn;
3162 } else {
3163 pVI->pType = mkpInt;
3164 }
Jack Palevich8df46192009-07-07 14:48:51 -07003165 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003166 }
Jack Palevich40600de2009-07-01 15:32:35 -07003167 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003168 /* assignment */
3169 next();
3170 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003171 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003172 } else if (tok != '(') {
3173 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003174 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003175 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003176 }
Jack Palevich8df46192009-07-07 14:48:51 -07003177 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003178 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003179 next();
3180 }
3181 }
3182 }
3183 }
3184
3185 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003186 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003187 Type* pArgList = NULL;
3188 VariableInfo* pVI = NULL;
3189 if (n == 1) { // Indirect function call, push address of fn.
3190 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07003191 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003192 } else {
3193 pVI = VI(t);
3194 pArgList = pVI->pType->pTail;
3195 }
3196 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003197 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003198 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003199 int l = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003200 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003201 if (! varArgs && !pArgList) {
3202 error ("Unexpected argument.");
3203 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003204 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003205 Type* pTargetType;
3206 if (pArgList) {
3207 pTargetType = pArgList->pHead;
3208 pArgList = pArgList->pTail;
3209 } else {
3210 pTargetType = pGen->getR0Type();
3211 if (pTargetType->tag == TY_FLOAT) {
3212 pTargetType = mkpDouble;
3213 }
3214 }
3215 pGen->convertR0(pTargetType);
3216 l += pGen->storeR0ToArg(l);
Jack Palevich95727a02009-07-06 12:07:15 -07003217 if (accept(',')) {
3218 // fine
3219 } else if ( tok != ')') {
3220 error("Expected ',' or ')'");
3221 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003222 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003223 if (! varArgs && pArgList) {
3224 error ("Expected more argument(s).");
3225 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003226 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003227 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003228 if (!n) {
3229 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003230 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3231 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003232 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003233 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003234 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003235 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3236 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003237 }
-b master422972c2009-06-17 19:13:52 -07003238 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003239 }
3240 }
3241
Jack Palevich40600de2009-07-01 15:32:35 -07003242 /* Recursive descent parser for binary operations.
3243 */
3244 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003245 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003246 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003247 if (level-- == 1)
3248 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003249 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003250 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003251 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003252 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003253 n = tok;
3254 t = tokc;
3255 next();
3256
Jack Palevich40600de2009-07-01 15:32:35 -07003257 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003258 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003259 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003260 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003261 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003262 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003263
Jack Palevich40600de2009-07-01 15:32:35 -07003264 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003265 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003266 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003267 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003268 }
3269 }
3270 }
3271 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003272 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003273 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003274 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003275 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003276 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003277 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003278 }
3279 }
3280 }
3281
3282 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003283 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003284 }
3285
3286 int test_expr() {
3287 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003288 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003289 }
3290
Jack Palevicha6baa232009-06-12 11:25:59 -07003291 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003292 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003293
Jack Palevich95727a02009-07-06 12:07:15 -07003294 Type* pBaseType;
3295 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003296 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003297 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003298 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003299 next();
3300 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003301 a = test_expr();
3302 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003303 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003304 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003305 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003306 n = pGen->gjmp(0); /* jmp */
3307 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003308 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003309 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003310 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003311 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003312 }
Jack Palevich546b2242009-05-13 15:10:04 -07003313 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003314 t = tok;
3315 next();
3316 skip('(');
3317 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003318 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003319 a = test_expr();
3320 } else {
3321 if (tok != ';')
3322 expr();
3323 skip(';');
3324 n = codeBuf.getPC();
3325 a = 0;
3326 if (tok != ';')
3327 a = test_expr();
3328 skip(';');
3329 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003330 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003331 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003332 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003333 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003334 n = t + 4;
3335 }
3336 }
3337 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003338 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003339 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003340 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003341 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003342 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003343 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003344 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003345 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003346 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003347 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003348 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003349 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003350 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003351 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003352 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003353 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003354 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003355 expr();
Jack Palevich8df46192009-07-07 14:48:51 -07003356 pGen->convertR0(pReturnType);
3357 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003358 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003359 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003360 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003361 } else if (tok != ';')
3362 expr();
3363 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003364 }
3365 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003366
Jack Palevich3f226492009-07-02 14:46:19 -07003367 bool typeEqual(Type* a, Type* b) {
3368 if (a == b) {
3369 return true;
3370 }
3371 if (a == NULL || b == NULL) {
3372 return false;
3373 }
3374 TypeTag at = a->tag;
3375 if (at != b->tag) {
3376 return false;
3377 }
3378 if (at == TY_POINTER) {
3379 return typeEqual(a->pHead, b->pHead);
3380 } else if (at == TY_FUNC || at == TY_PARAM) {
3381 return typeEqual(a->pHead, b->pHead)
3382 && typeEqual(a->pTail, b->pTail);
3383 }
3384 return true;
3385 }
3386
Jack Palevich86351982009-06-30 18:09:56 -07003387 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3388 assert(tag >= TY_INT && tag <= TY_PARAM);
3389 Type* pType = (Type*) arena.alloc(sizeof(Type));
3390 memset(pType, 0, sizeof(*pType));
3391 pType->tag = tag;
3392 pType->pHead = pHead;
3393 pType->pTail = pTail;
3394 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003395 }
3396
Jack Palevich3f226492009-07-02 14:46:19 -07003397 Type* createPtrType(Type* pType, Arena& arena) {
3398 return createType(TY_POINTER, pType, NULL, arena);
3399 }
3400
3401 /**
3402 * Try to print a type in declaration order
3403 */
Jack Palevich86351982009-06-30 18:09:56 -07003404 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003405 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003406 if (pType == NULL) {
3407 buffer.appendCStr("null");
3408 return;
3409 }
Jack Palevich3f226492009-07-02 14:46:19 -07003410 decodeTypeImp(buffer, pType);
3411 }
3412
3413 void decodeTypeImp(String& buffer, Type* pType) {
3414 decodeTypeImpPrefix(buffer, pType);
3415
Jack Palevich86351982009-06-30 18:09:56 -07003416 String temp;
3417 if (pType->id != 0) {
3418 decodeToken(temp, pType->id);
3419 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003420 }
3421
3422 decodeTypeImpPostfix(buffer, pType);
3423 }
3424
3425 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3426 TypeTag tag = pType->tag;
3427
3428 if (tag >= TY_INT && tag <= TY_VOID) {
3429 switch (tag) {
3430 case TY_INT:
3431 buffer.appendCStr("int");
3432 break;
3433 case TY_CHAR:
3434 buffer.appendCStr("char");
3435 break;
3436 case TY_VOID:
3437 buffer.appendCStr("void");
3438 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003439 case TY_FLOAT:
3440 buffer.appendCStr("float");
3441 break;
3442 case TY_DOUBLE:
3443 buffer.appendCStr("double");
3444 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003445 default:
3446 break;
3447 }
Jack Palevich86351982009-06-30 18:09:56 -07003448 buffer.append(' ');
3449 }
Jack Palevich3f226492009-07-02 14:46:19 -07003450
3451 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003452 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003453 break;
3454 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003455 break;
3456 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003457 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003458 case TY_FLOAT:
3459 break;
3460 case TY_DOUBLE:
3461 break;
Jack Palevich86351982009-06-30 18:09:56 -07003462 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003463 decodeTypeImpPrefix(buffer, pType->pHead);
3464 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3465 buffer.append('(');
3466 }
3467 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003468 break;
3469 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003470 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003471 break;
3472 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003473 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003474 break;
3475 default:
3476 String temp;
3477 temp.printf("Unknown tag %d", pType->tag);
3478 buffer.append(temp);
3479 break;
3480 }
Jack Palevich3f226492009-07-02 14:46:19 -07003481 }
3482
3483 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3484 TypeTag tag = pType->tag;
3485
3486 switch(tag) {
3487 case TY_POINTER:
3488 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3489 buffer.append(')');
3490 }
3491 decodeTypeImpPostfix(buffer, pType->pHead);
3492 break;
3493 case TY_FUNC:
3494 buffer.append('(');
3495 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3496 decodeTypeImp(buffer, pArg);
3497 if (pArg->pTail) {
3498 buffer.appendCStr(", ");
3499 }
3500 }
3501 buffer.append(')');
3502 break;
3503 default:
3504 break;
Jack Palevich86351982009-06-30 18:09:56 -07003505 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003506 }
3507
Jack Palevich86351982009-06-30 18:09:56 -07003508 void printType(Type* pType) {
3509 String buffer;
3510 decodeType(buffer, pType);
3511 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003512 }
3513
Jack Palevich86351982009-06-30 18:09:56 -07003514 Type* acceptPrimitiveType(Arena& arena) {
3515 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003516 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003517 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003518 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003519 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003520 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003521 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003522 } else if (tok == TOK_FLOAT) {
3523 pType = mkpFloat;
3524 } else if (tok == TOK_DOUBLE) {
3525 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003526 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003527 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003528 }
3529 next();
Jack Palevich86351982009-06-30 18:09:56 -07003530 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003531 }
3532
Jack Palevich3f226492009-07-02 14:46:19 -07003533 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3534 Arena& arena) {
3535 tokenid_t declName = 0;
3536 pType = acceptDecl2(pType, declName, nameAllowed,
3537 nameRequired, arena);
3538 if (declName) {
3539 // Clone the parent type so we can set a unique ID
3540 pType = createType(pType->tag, pType->pHead,
3541 pType->pTail, arena);
3542
Jack Palevich86351982009-06-30 18:09:56 -07003543 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003544 }
Jack Palevich3f226492009-07-02 14:46:19 -07003545 // fprintf(stderr, "Parsed a declaration: ");
3546 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003547 return pType;
3548 }
3549
Jack Palevich3f226492009-07-02 14:46:19 -07003550 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3551 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003552 if (! pType) {
3553 error("Expected a declaration");
3554 }
3555 return pType;
3556 }
3557
Jack Palevich3f226492009-07-02 14:46:19 -07003558 /* Used for accepting types that appear in casts */
3559 Type* acceptCastTypeDeclaration(Arena& arena) {
3560 Type* pType = acceptPrimitiveType(arena);
3561 if (pType) {
3562 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003563 }
Jack Palevich86351982009-06-30 18:09:56 -07003564 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003565 }
3566
Jack Palevich3f226492009-07-02 14:46:19 -07003567 Type* expectCastTypeDeclaration(Arena& arena) {
3568 Type* pType = acceptCastTypeDeclaration(arena);
3569 if (! pType) {
3570 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003571 }
Jack Palevich3f226492009-07-02 14:46:19 -07003572 return pType;
3573 }
3574
3575 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3576 bool nameAllowed, bool nameRequired, Arena& arena) {
3577 int ptrCounter = 0;
3578 while (accept('*')) {
3579 ptrCounter++;
3580 }
3581 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3582 while (ptrCounter-- > 0) {
3583 pType = createType(TY_POINTER, pType, NULL, arena);
3584 }
3585 return pType;
3586 }
3587
3588 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3589 bool nameAllowed, bool nameRequired, Arena& arena) {
3590 // direct-dcl :
3591 // name
3592 // (dcl)
3593 // direct-dcl()
3594 // direct-dcl[]
3595 Type* pNewHead = NULL;
3596 if (accept('(')) {
3597 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3598 nameRequired, arena);
3599 skip(')');
3600 } else if ((declName = acceptSymbol()) != 0) {
3601 if (nameAllowed == false && declName) {
3602 error("Symbol %s not allowed here", nameof(declName));
3603 } else if (nameRequired && ! declName) {
3604 String temp;
3605 decodeToken(temp, tok);
3606 error("Expected symbol. Got %s", temp.getUnwrapped());
3607 }
3608 }
3609 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003610 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003611 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003612 pType = createType(TY_FUNC, pType, pTail, arena);
3613 skip(')');
3614 }
Jack Palevich3f226492009-07-02 14:46:19 -07003615
3616 if (pNewHead) {
3617 Type* pA = pNewHead;
3618 while (pA->pHead) {
3619 pA = pA->pHead;
3620 }
3621 pA->pHead = pType;
3622 pType = pNewHead;
3623 }
Jack Palevich86351982009-06-30 18:09:56 -07003624 return pType;
3625 }
3626
Jack Palevich3f226492009-07-02 14:46:19 -07003627 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003628 Type* pHead = NULL;
3629 Type* pTail = NULL;
3630 for(;;) {
3631 Type* pBaseArg = acceptPrimitiveType(arena);
3632 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003633 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3634 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003635 if (pArg) {
3636 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3637 if (!pHead) {
3638 pHead = pParam;
3639 pTail = pParam;
3640 } else {
3641 pTail->pTail = pParam;
3642 pTail = pParam;
3643 }
3644 }
3645 }
3646 if (! accept(',')) {
3647 break;
3648 }
3649 }
3650 return pHead;
3651 }
3652
3653 Type* expectPrimitiveType(Arena& arena) {
3654 Type* pType = acceptPrimitiveType(arena);
3655 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003656 String buf;
3657 decodeToken(buf, tok);
3658 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003659 }
Jack Palevich86351982009-06-30 18:09:56 -07003660 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003661 }
3662
Jack Palevich86351982009-06-30 18:09:56 -07003663 void addGlobalSymbol(Type* pDecl) {
3664 tokenid_t t = pDecl->id;
3665 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003666 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003667 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003668 }
Jack Palevich86351982009-06-30 18:09:56 -07003669 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003670 }
3671
Jack Palevich86351982009-06-30 18:09:56 -07003672 void reportDuplicate(tokenid_t t) {
3673 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003674 }
3675
Jack Palevich86351982009-06-30 18:09:56 -07003676 void addLocalSymbol(Type* pDecl) {
3677 tokenid_t t = pDecl->id;
3678 if (mLocals.isDefinedAtCurrentLevel(t)) {
3679 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003680 }
Jack Palevich86351982009-06-30 18:09:56 -07003681 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003682 }
3683
Jack Palevich95727a02009-07-06 12:07:15 -07003684 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003685 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003686
Jack Palevich95727a02009-07-06 12:07:15 -07003687 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003688 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003689 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3690 if (!pDecl) {
3691 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003692 }
Jack Palevich86351982009-06-30 18:09:56 -07003693 int variableAddress = 0;
3694 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003695 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003696 loc = loc + 4;
3697 variableAddress = -loc;
3698 VI(pDecl->id)->pAddress = (void*) variableAddress;
3699 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003700 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003701 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003702 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07003703 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003704 if (tok == ',')
3705 next();
3706 }
3707 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003708 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003709 }
3710 }
3711
Jack Palevichf1728be2009-06-12 13:53:51 -07003712 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003713 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003714 }
3715
Jack Palevich569f1352009-06-29 14:29:08 -07003716 void decodeToken(String& buffer, tokenid_t token) {
3717 if (token == EOF ) {
3718 buffer.printf("EOF");
3719 } else if (token == TOK_NUM) {
3720 buffer.printf("numeric constant");
3721 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003722 if (token < 32) {
3723 buffer.printf("'\\x%02x'", token);
3724 } else {
3725 buffer.printf("'%c'", token);
3726 }
Jack Palevich569f1352009-06-29 14:29:08 -07003727 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3728 buffer.printf("keyword \"%s\"", nameof(token));
3729 } else {
3730 buffer.printf("symbol \"%s\"", nameof(token));
3731 }
3732 }
3733
Jack Palevich40600de2009-07-01 15:32:35 -07003734 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003735 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003736 if (!result) {
3737 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003738 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003739 error("Expected symbol. Got %s", temp.getUnwrapped());
3740 }
3741 return result;
3742 }
3743
Jack Palevich86351982009-06-30 18:09:56 -07003744 tokenid_t acceptSymbol() {
3745 tokenid_t result = 0;
3746 if (tok >= TOK_SYMBOL) {
3747 result = tok;
3748 next();
Jack Palevich86351982009-06-30 18:09:56 -07003749 }
3750 return result;
3751 }
3752
Jack Palevichb7c81e92009-06-04 19:56:13 -07003753 void globalDeclarations() {
3754 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003755 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3756 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003757 break;
3758 }
Jack Palevich86351982009-06-30 18:09:56 -07003759 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3760 if (!pDecl) {
3761 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003762 }
Jack Palevich86351982009-06-30 18:09:56 -07003763 if (! isDefined(pDecl->id)) {
3764 addGlobalSymbol(pDecl);
3765 }
3766 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003767 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003768 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003769 }
Jack Palevich86351982009-06-30 18:09:56 -07003770 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003771 // it's a variable declaration
3772 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003773 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003774 name->pAddress = (int*) allocGlobalSpace(
3775 pGen->alignment(name->pType),
3776 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07003777 }
Jack Palevich86351982009-06-30 18:09:56 -07003778 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003779 if (tok == TOK_NUM) {
3780 if (name) {
3781 * (int*) name->pAddress = tokc;
3782 }
3783 next();
3784 } else {
3785 error("Expected an integer constant");
3786 }
3787 }
Jack Palevich86351982009-06-30 18:09:56 -07003788 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003789 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003790 }
Jack Palevich86351982009-06-30 18:09:56 -07003791 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3792 if (!pDecl) {
3793 break;
3794 }
3795 if (! isDefined(pDecl->id)) {
3796 addGlobalSymbol(pDecl);
3797 }
3798 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003799 }
3800 skip(';');
3801 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003802 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003803 if (accept(';')) {
3804 // forward declaration.
3805 } else {
3806 if (name) {
3807 /* patch forward references (XXX: does not work for function
3808 pointers) */
3809 pGen->gsym((int) name->pForward);
3810 /* put function address */
3811 name->pAddress = (void*) codeBuf.getPC();
3812 }
3813 // Calculate stack offsets for parameters
3814 mLocals.pushLevel();
3815 intptr_t a = 8;
3816 int argCount = 0;
3817 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3818 Type* pArg = pP->pHead;
3819 addLocalSymbol(pArg);
3820 /* read param name and compute offset */
3821 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003822 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07003823 argCount++;
3824 }
3825 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003826 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003827 a = pGen->functionEntry(argCount);
3828 block(0, true);
3829 pGen->gsym(rsym);
3830 pGen->functionExit(argCount, a, loc);
3831 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003832 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003833 }
3834 }
3835 }
3836
Jack Palevich9cbd2262009-07-08 16:48:41 -07003837 char* allocGlobalSpace(size_t alignment, size_t bytes) {
3838 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
3839 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07003840 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003841 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003842 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003843 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07003844 char* result = (char*) base;
3845 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003846 return result;
3847 }
3848
Jack Palevich21a15a22009-05-11 14:49:29 -07003849 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003850 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003851 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003852 pGlobalBase = 0;
3853 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003854 if (pGen) {
3855 delete pGen;
3856 pGen = 0;
3857 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003858 if (file) {
3859 delete file;
3860 file = 0;
3861 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003862 }
3863
3864 void clear() {
3865 tok = 0;
3866 tokc = 0;
3867 tokl = 0;
3868 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003869 rsym = 0;
3870 loc = 0;
3871 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003872 dptr = 0;
3873 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003874 file = 0;
3875 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003876 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003877 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003878 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003879
Jack Palevich22305132009-05-13 10:58:45 -07003880 void setArchitecture(const char* architecture) {
3881 delete pGen;
3882 pGen = 0;
3883
3884 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003885#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003886 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003887 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003888 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003889#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003890#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003891 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003892 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003893 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003894#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003895 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003896 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003897 }
3898 }
3899
3900 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003901#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003902 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003903#elif defined(DEFAULT_X86_CODEGEN)
3904 pGen = new X86CodeGenerator();
3905#endif
3906 }
3907 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003908 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003909 } else {
3910 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003911 }
3912 }
3913
Jack Palevich77ae76e2009-05-10 19:59:24 -07003914public:
Jack Palevich22305132009-05-13 10:58:45 -07003915 struct args {
3916 args() {
3917 architecture = 0;
3918 }
3919 const char* architecture;
3920 };
3921
Jack Paleviche7b59062009-05-19 17:12:17 -07003922 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003923 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003924 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003925
Jack Paleviche7b59062009-05-19 17:12:17 -07003926 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003927 cleanup();
3928 }
3929
Jack Palevich1cdef202009-05-22 12:06:27 -07003930 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003931 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003932
3933 cleanup();
3934 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003935 mTokenTable.setArena(&mGlobalArena);
3936 mGlobals.setArena(&mGlobalArena);
3937 mGlobals.setTokenTable(&mTokenTable);
3938 mLocals.setArena(&mLocalArena);
3939 mLocals.setTokenTable(&mTokenTable);
3940
3941 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003942 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003943 codeBuf.init(ALLOC_SIZE);
3944 setArchitecture(NULL);
3945 if (!pGen) {
3946 return -1;
3947 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003948#ifdef PROVIDE_TRACE_CODEGEN
3949 pGen = new TraceCodeGenerator(pGen);
3950#endif
3951 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003952 pGen->init(&codeBuf);
3953 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003954 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3955 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003956 inp();
3957 next();
3958 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003959 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003960 result = pGen->finishCompile();
3961 if (result == 0) {
3962 if (mErrorBuf.len()) {
3963 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07003964 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07003965 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07003966 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07003967 }
3968
Jack Palevich86351982009-06-30 18:09:56 -07003969 void createPrimitiveTypes() {
3970 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
3971 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
3972 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07003973 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
3974 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003975 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07003976 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
3977 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07003978 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
3979 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07003980 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07003981 }
3982
Jack Palevicha6baa232009-06-12 11:25:59 -07003983 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07003984 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07003985 }
3986
Jack Palevich569f1352009-06-29 14:29:08 -07003987 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003988 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07003989 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07003990 }
3991
Jack Palevich569f1352009-06-29 14:29:08 -07003992 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07003993 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07003994 error("Undefined forward reference: %s",
3995 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07003996 }
3997 return true;
3998 }
3999
Jack Palevich21a15a22009-05-11 14:49:29 -07004000 int dump(FILE* out) {
4001 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4002 return 0;
4003 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004004
Jack Palevicha6535612009-05-13 16:24:17 -07004005 int disassemble(FILE* out) {
4006 return pGen->disassemble(out);
4007 }
4008
Jack Palevich1cdef202009-05-22 12:06:27 -07004009 /* Look through the symbol table to find a symbol.
4010 * If found, return its value.
4011 */
4012 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004013 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4014 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004015 if (pVariableInfo) {
4016 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004017 }
4018 return NULL;
4019 }
4020
Jack Palevicheedf9d22009-06-04 16:23:40 -07004021 void getPragmas(ACCsizei* actualStringCount,
4022 ACCsizei maxStringCount, ACCchar** strings) {
4023 int stringCount = mPragmaStringCount;
4024 if (actualStringCount) {
4025 *actualStringCount = stringCount;
4026 }
4027 if (stringCount > maxStringCount) {
4028 stringCount = maxStringCount;
4029 }
4030 if (strings) {
4031 char* pPragmas = mPragmas.getUnwrapped();
4032 while (stringCount-- > 0) {
4033 *strings++ = pPragmas;
4034 pPragmas += strlen(pPragmas) + 1;
4035 }
4036 }
4037 }
4038
Jack Palevichac0e95e2009-05-29 13:53:44 -07004039 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004040 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004041 }
4042
Jack Palevich77ae76e2009-05-10 19:59:24 -07004043};
4044
Jack Paleviche7b59062009-05-19 17:12:17 -07004045const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004046 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4047
Jack Paleviche7b59062009-05-19 17:12:17 -07004048const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004049 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4050 5, 5, /* ==, != */
4051 9, 10, /* &&, || */
4052 6, 7, 8, /* & ^ | */
4053 2, 2 /* ~ ! */
4054 };
4055
Jack Palevich8b0624c2009-05-20 12:12:06 -07004056#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004057FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004058#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004059
Jack Palevich8b0624c2009-05-20 12:12:06 -07004060#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004061const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004062 0x1, // ++
4063 0xff, // --
4064 0xc1af0f, // *
4065 0xf9f79991, // /
4066 0xf9f79991, // % (With manual assist to swap results)
4067 0xc801, // +
4068 0xd8f7c829, // -
4069 0xe0d391, // <<
4070 0xf8d391, // >>
4071 0xe, // <=
4072 0xd, // >=
4073 0xc, // <
4074 0xf, // >
4075 0x4, // ==
4076 0x5, // !=
4077 0x0, // &&
4078 0x1, // ||
4079 0xc821, // &
4080 0xc831, // ^
4081 0xc809, // |
4082 0xd0f7, // ~
4083 0x4 // !
4084};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004085#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004086
Jack Palevich1cdef202009-05-22 12:06:27 -07004087struct ACCscript {
4088 ACCscript() {
4089 text = 0;
4090 textLength = 0;
4091 accError = ACC_NO_ERROR;
4092 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004093
Jack Palevich1cdef202009-05-22 12:06:27 -07004094 ~ACCscript() {
4095 delete text;
4096 }
Jack Palevich546b2242009-05-13 15:10:04 -07004097
Jack Palevich1cdef202009-05-22 12:06:27 -07004098 void setError(ACCenum error) {
4099 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4100 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004101 }
4102 }
4103
Jack Palevich1cdef202009-05-22 12:06:27 -07004104 ACCenum getError() {
4105 ACCenum result = accError;
4106 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004107 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004108 }
4109
Jack Palevich1cdef202009-05-22 12:06:27 -07004110 Compiler compiler;
4111 char* text;
4112 int textLength;
4113 ACCenum accError;
4114};
4115
4116
4117extern "C"
4118ACCscript* accCreateScript() {
4119 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004120}
Jack Palevich1cdef202009-05-22 12:06:27 -07004121
4122extern "C"
4123ACCenum accGetError( ACCscript* script ) {
4124 return script->getError();
4125}
4126
4127extern "C"
4128void accDeleteScript(ACCscript* script) {
4129 delete script;
4130}
4131
4132extern "C"
4133void accScriptSource(ACCscript* script,
4134 ACCsizei count,
4135 const ACCchar ** string,
4136 const ACCint * length) {
4137 int totalLength = 0;
4138 for(int i = 0; i < count; i++) {
4139 int len = -1;
4140 const ACCchar* s = string[i];
4141 if (length) {
4142 len = length[i];
4143 }
4144 if (len < 0) {
4145 len = strlen(s);
4146 }
4147 totalLength += len;
4148 }
4149 delete script->text;
4150 char* text = new char[totalLength + 1];
4151 script->text = text;
4152 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004153 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004154 for(int i = 0; i < count; i++) {
4155 int len = -1;
4156 const ACCchar* s = string[i];
4157 if (length) {
4158 len = length[i];
4159 }
4160 if (len < 0) {
4161 len = strlen(s);
4162 }
Jack Palevich09555c72009-05-27 12:25:55 -07004163 memcpy(dest, s, len);
4164 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004165 }
4166 text[totalLength] = '\0';
4167}
4168
4169extern "C"
4170void accCompileScript(ACCscript* script) {
4171 int result = script->compiler.compile(script->text, script->textLength);
4172 if (result) {
4173 script->setError(ACC_INVALID_OPERATION);
4174 }
4175}
4176
4177extern "C"
4178void accGetScriptiv(ACCscript* script,
4179 ACCenum pname,
4180 ACCint * params) {
4181 switch (pname) {
4182 case ACC_INFO_LOG_LENGTH:
4183 *params = 0;
4184 break;
4185 }
4186}
4187
4188extern "C"
4189void accGetScriptInfoLog(ACCscript* script,
4190 ACCsizei maxLength,
4191 ACCsizei * length,
4192 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004193 char* message = script->compiler.getErrorMessage();
4194 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004195 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004196 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004197 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004198 if (infoLog && maxLength > 0) {
4199 int trimmedLength = maxLength < messageLength ?
4200 maxLength : messageLength;
4201 memcpy(infoLog, message, trimmedLength);
4202 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004203 }
4204}
4205
4206extern "C"
4207void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4208 ACCvoid ** address) {
4209 void* value = script->compiler.lookup(name);
4210 if (value) {
4211 *address = value;
4212 } else {
4213 script->setError(ACC_INVALID_VALUE);
4214 }
4215}
4216
Jack Palevicheedf9d22009-06-04 16:23:40 -07004217extern "C"
4218void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4219 ACCsizei maxStringCount, ACCchar** strings){
4220 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4221}
4222
-b master422972c2009-06-17 19:13:52 -07004223extern "C"
4224void accDisassemble(ACCscript* script) {
4225 script->compiler.disassemble(stderr);
4226}
4227
Jack Palevicheedf9d22009-06-04 16:23:40 -07004228
Jack Palevich1cdef202009-05-22 12:06:27 -07004229} // namespace acc
4230