blob: c2dea56ab25e0c23a287eabe3af7621a0f215473 [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 Palevich2a4e1a92009-07-09 13:34:25 -07001216 Type* pR0Type = getR0Type();
1217 TypeTag tagR0 = pR0Type->tag;
1218 bool isFloatR0 = isFloatTag(tagR0);
1219 if (isFloatR0) {
1220 o(0xeed9); // fldz
1221 o(0xe9da); // fucompp
1222 o(0xe0df); // fnstsw %ax
1223 o(0x9e); // sahf
1224 } else {
1225 o(0xc085); // test %eax, %eax
1226 }
1227 // Use two output statements to generate one instruction.
1228 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001229 return psym(0x84 + l, t);
1230 }
1231
Jack Palevicha39749f2009-07-08 20:40:31 -07001232 virtual void gcmp(int op, Type* pResultType) {
1233 Type* pR0Type = getR0Type();
1234 Type* pTOSType = getTOSType();
1235 TypeTag tagR0 = pR0Type->tag;
1236 TypeTag tagTOS = pTOSType->tag;
1237 bool isFloatR0 = isFloatTag(tagR0);
1238 bool isFloatTOS = isFloatTag(tagTOS);
1239 if (!isFloatR0 && !isFloatTOS) {
1240 int t = decodeOp(op);
1241 o(0x59); /* pop %ecx */
1242 o(0xc139); /* cmp %eax,%ecx */
1243 li(0, NULL);
1244 o(0x0f); /* setxx %al */
1245 o(t + 0x90);
1246 o(0xc0);
1247 popType();
1248 } else {
1249 setupFloatOperands();
1250 switch (op) {
1251 case OP_EQUALS:
1252 o(0xe9da); // fucompp
1253 o(0xe0df); // fnstsw %ax
1254 o(0x9e); // sahf
1255 o(0xc0940f); // sete %al
1256 o(0xc29b0f); // setnp %dl
1257 o(0xd021); // andl %edx, %eax
1258 break;
1259 case OP_NOT_EQUALS:
1260 o(0xe9da); // fucompp
1261 o(0xe0df); // fnstsw %ax
1262 o(0x9e); // sahf
1263 o(0xc0950f); // setne %al
1264 o(0xc29a0f); // setp %dl
1265 o(0xd009); // orl %edx, %eax
1266 break;
1267 case OP_GREATER_EQUAL:
1268 o(0xe9da); // fucompp
1269 o(0xe0df); // fnstsw %ax
1270 o(0x05c4f6); // testb $5, %ah
1271 o(0xc0940f); // sete %al
1272 break;
1273 case OP_LESS:
1274 o(0xc9d9); // fxch %st(1)
1275 o(0xe9da); // fucompp
1276 o(0xe0df); // fnstsw %ax
1277 o(0x9e); // sahf
1278 o(0xc0970f); // seta %al
1279 break;
1280 case OP_LESS_EQUAL:
1281 o(0xc9d9); // fxch %st(1)
1282 o(0xe9da); // fucompp
1283 o(0xe0df); // fnstsw %ax
1284 o(0x9e); // sahf
1285 o(0xc0930f); // setea %al
1286 break;
1287 case OP_GREATER:
1288 o(0xe9da); // fucompp
1289 o(0xe0df); // fnstsw %ax
1290 o(0x45c4f6); // testb $69, %ah
1291 o(0xc0940f); // sete %al
1292 break;
1293 default:
1294 error("Unknown comparison op");
1295 }
1296 o(0xc0b60f); // movzbl %al, %eax
1297 }
1298 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001299 }
1300
Jack Palevich546b2242009-05-13 15:10:04 -07001301 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001302 Type* pR0Type = getR0Type();
1303 Type* pTOSType = getTOSType();
1304 TypeTag tagR0 = pR0Type->tag;
1305 TypeTag tagTOS = pTOSType->tag;
1306 bool isFloatR0 = isFloatTag(tagR0);
1307 bool isFloatTOS = isFloatTag(tagTOS);
1308 if (!isFloatR0 && !isFloatTOS) {
1309 // TODO: Deal with pointer arithmetic
1310 o(0x59); /* pop %ecx */
1311 o(decodeOp(op));
1312 if (op == OP_MOD)
1313 o(0x92); /* xchg %edx, %eax */
1314 popType();
1315 } else {
1316 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1317 setupFloatOperands();
1318 // Both float. x87 R0 == left hand, x87 R1 == right hand
1319 switch (op) {
1320 case OP_MUL:
1321 o(0xc9de); // fmulp
1322 break;
1323 case OP_DIV:
1324 o(0xf1de); // fdivp
1325 break;
1326 case OP_PLUS:
1327 o(0xc1de); // faddp
1328 break;
1329 case OP_MINUS:
1330 o(0xe1de); // fsubp
1331 break;
1332 default:
1333 error("Unsupported binary floating operation.");
1334 break;
1335 }
1336 popType();
1337 setR0Type(pResultType);
1338 printf("genop: result type %d\n", pResultType->tag);
1339 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001340 }
1341
Jack Palevicha39749f2009-07-08 20:40:31 -07001342 virtual void gUnaryCmp(int op, Type* pResultType) {
1343 if (op != OP_LOGICAL_NOT) {
1344 error("Unknown unary cmp %d", op);
1345 } else {
1346 Type* pR0Type = getR0Type();
1347 TypeTag tag = collapseType(pR0Type->tag);
1348 switch(tag) {
1349 case TY_INT: {
1350 oad(0xb9, 0); /* movl $0, %ecx */
1351 int t = decodeOp(op);
1352 o(0xc139); /* cmp %eax,%ecx */
1353 li(0, NULL);
1354 o(0x0f); /* setxx %al */
1355 o(t + 0x90);
1356 o(0xc0);
1357 }
1358 break;
1359 case TY_FLOAT:
1360 case TY_DOUBLE:
1361 o(0xeed9); // fldz
1362 o(0xe9da); // fucompp
1363 o(0xe0df); // fnstsw %ax
1364 o(0x9e); // sahf
1365 o(0xc0950f); // setne %al
1366 o(0xc29a0f); // setp %dl
1367 o(0xd009); // orl %edx, %eax
1368 o(0xc0b60f); // movzbl %al, %eax
1369 o(0x01f083); // xorl $1, %eax
1370 break;
1371 default:
1372 error("genUnaryCmp unsupported type");
1373 break;
1374 }
1375 }
1376 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001377 }
1378
1379 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001380 Type* pR0Type = getR0Type();
1381 TypeTag tag = collapseType(pR0Type->tag);
1382 switch(tag) {
1383 case TY_INT:
1384 oad(0xb9, 0); /* movl $0, %ecx */
1385 o(decodeOp(op));
1386 break;
1387 case TY_FLOAT:
1388 case TY_DOUBLE:
1389 switch (op) {
1390 case OP_MINUS:
1391 o(0xe0d9); // fchs
1392 break;
1393 case OP_BIT_NOT:
1394 error("Can't apply '~' operator to a float or double.");
1395 break;
1396 default:
1397 error("Unknown unary op %d\n", op);
1398 break;
1399 }
1400 break;
1401 default:
1402 error("genUnaryOp unsupported type");
1403 break;
1404 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001405 }
1406
Jack Palevich1cdef202009-05-22 12:06:27 -07001407 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001408 Type* pR0Type = getR0Type();
1409 TypeTag r0ct = collapseType(pR0Type->tag);
1410 switch(r0ct) {
1411 case TY_INT:
1412 o(0x50); /* push %eax */
1413 break;
1414 case TY_FLOAT:
1415 o(0x50); /* push %eax */
1416 o(0x241cd9); // fstps 0(%esp)
1417 break;
1418 case TY_DOUBLE:
1419 o(0x50); /* push %eax */
1420 o(0x50); /* push %eax */
1421 o(0x241cdd); // fstpl 0(%esp)
1422 break;
1423 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001424 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07001425 break;
1426 }
Jack Palevich8df46192009-07-07 14:48:51 -07001427 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001428 }
1429
Jack Palevich9eed7a22009-07-06 17:24:34 -07001430 virtual void storeR0ToTOS(Type* pPointerType) {
1431 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001432 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001433 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001434 switch (pPointerType->pHead->tag) {
1435 case TY_INT:
1436 o(0x0189); /* movl %eax/%al, (%ecx) */
1437 break;
1438 case TY_CHAR:
1439 o(0x0188); /* movl %eax/%al, (%ecx) */
1440 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001441 case TY_FLOAT:
1442 o(0x19d9); /* fstps (%ecx) */
1443 break;
1444 case TY_DOUBLE:
1445 o(0x19dd); /* fstpl (%ecx) */
1446 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001447 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001448 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001449 break;
1450 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001451 }
1452
Jack Palevich9eed7a22009-07-06 17:24:34 -07001453 virtual void loadR0FromR0(Type* pPointerType) {
1454 assert(pPointerType->tag == TY_POINTER);
1455 switch (pPointerType->pHead->tag) {
1456 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001457 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001458 break;
1459 case TY_CHAR:
1460 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001461 ob(0); /* add zero in code */
1462 break;
1463 case TY_FLOAT:
1464 o2(0x00d9); // flds (%eax)
1465 break;
1466 case TY_DOUBLE:
1467 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07001468 break;
1469 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001470 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001471 break;
1472 }
Jack Palevich8df46192009-07-07 14:48:51 -07001473 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001474 }
1475
Jack Palevich8df46192009-07-07 14:48:51 -07001476 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001477 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001478 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001479 }
1480
Jack Palevich9cbd2262009-07-08 16:48:41 -07001481 virtual void storeR0(int ea, Type* pType) {
1482 TypeTag tag = pType->tag;
1483 switch (tag) {
1484 case TY_INT:
1485 gmov(6, ea); /* mov %eax, EA */
1486 break;
1487 case TY_FLOAT:
1488 if (ea < -LOCAL || ea > LOCAL) {
1489 oad(0x1dd9, ea); // fstps ea
1490 } else {
1491 oad(0x9dd9, ea); // fstps ea(%ebp)
1492 }
1493 break;
1494 case TY_DOUBLE:
1495 if (ea < -LOCAL || ea > LOCAL) {
1496 oad(0x1ddd, ea); // fstpl ea
1497 } else {
1498 oad(0x9ddd, ea); // fstpl ea(%ebp)
1499 }
1500 break;
1501 default:
1502 error("Unable to store to type %d", tag);
1503 break;
1504 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001505 }
1506
Jack Palevich8df46192009-07-07 14:48:51 -07001507 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001508 TypeTag tag = collapseType(pType->tag);
1509 switch (tag) {
1510 case TY_INT:
1511 gmov(8, ea); /* mov EA, %eax */
1512 if (isIncDec) {
1513 /* Implement post-increment or post decrement.
1514 */
1515 gmov(0, ea); /* 83 ADD */
1516 o(decodeOp(op));
1517 }
1518 break;
1519 case TY_FLOAT:
1520 if (ea < -LOCAL || ea > LOCAL) {
1521 oad(0x05d9, ea); // flds ea
1522 } else {
1523 oad(0x85d9, ea); // flds ea(%ebp)
1524 }
1525 if (isIncDec) {
1526 error("inc/dec not implemented for float.");
1527 }
1528 break;
1529 case TY_DOUBLE:
1530 if (ea < -LOCAL || ea > LOCAL) {
1531 oad(0x05dd, ea); // fldl ea
1532 } else {
1533 oad(0x85dd, ea); // fldl ea(%ebp)
1534 }
1535 if (isIncDec) {
1536 error("inc/dec not implemented for double.");
1537 }
1538 break;
1539 default:
1540 error("Unable to load type %d", tag);
1541 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07001542 }
Jack Palevich8df46192009-07-07 14:48:51 -07001543 setR0Type(pType);
1544 }
1545
1546 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001547 Type* pR0Type = getR0Type();
1548 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001549 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07001550 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001551 return;
1552 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001553 if (bitsSame(pType, pR0Type)) {
1554 // do nothing special
1555 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1556 // do nothing special, both held in same register on x87.
1557 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001558 TypeTag r0Tag = collapseType(pR0Type->tag);
1559 TypeTag destTag = collapseType(pType->tag);
1560 if (r0Tag == TY_INT && isFloatTag(destTag)) {
1561 // Convert R0 from int to float
1562 o(0x50); // push %eax
1563 o(0x2404DB); // fildl 0(%esp)
1564 o(0x58); // pop %eax
1565 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
1566 // Convert R0 from float to int. Complicated because
1567 // need to save and restore the rounding mode.
1568 o(0x50); // push %eax
1569 o(0x50); // push %eax
1570 o(0x02247cD9); // fnstcw 2(%esp)
1571 o(0x2444b70f); // movzwl 2(%esp), %eax
1572 o(0x02);
1573 o(0x0cb4); // movb $12, %ah
1574 o(0x24048966); // movw %ax, 0(%esp)
1575 o(0x242cd9); // fldcw 0(%esp)
1576 o(0x04245cdb); // fistpl 4(%esp)
1577 o(0x02246cd9); // fldcw 2(%esp)
1578 o(0x58); // pop %eax
1579 o(0x58); // pop %eax
1580 } else {
1581 error("Incompatible types old: %d new: %d",
1582 pR0Type->tag, pType->tag);
1583 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001584 }
1585 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001586 }
1587
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001588 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001589 return oad(0xec81, 0); /* sub $xxx, %esp */
1590 }
1591
Jack Palevich1a539db2009-07-08 13:04:41 -07001592 virtual size_t storeR0ToArg(int l) {
1593 Type* pR0Type = getR0Type();
1594 TypeTag r0ct = collapseType(pR0Type->tag);
1595 switch(r0ct) {
1596 case TY_INT:
1597 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1598 return 4;
1599 case TY_FLOAT:
1600 oad(0x249CD9, l); /* fstps xxx(%esp) */
1601 return 4;
1602 case TY_DOUBLE:
1603 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1604 return 8;
1605 default:
1606 assert(false);
1607 return 0;
1608 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001609 }
1610
Jack Palevich7810bc92009-05-15 14:31:47 -07001611 virtual void endFunctionCallArguments(int a, int l) {
1612 * (int*) a = l;
1613 }
1614
Jack Palevich8df46192009-07-07 14:48:51 -07001615 virtual int callForward(int symbol, Type* pFunc) {
1616 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001617 return psym(0xe8, symbol); /* call xxx */
1618 }
1619
Jack Palevich8df46192009-07-07 14:48:51 -07001620 virtual void callRelative(int t, Type* pFunc) {
1621 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001622 psym(0xe8, t); /* call xxx */
1623 }
1624
Jack Palevich8df46192009-07-07 14:48:51 -07001625 virtual void callIndirect(int l, Type* pFunc) {
1626 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001627 oad(0x2494ff, l); /* call *xxx(%esp) */
1628 }
1629
Jack Palevich7810bc92009-05-15 14:31:47 -07001630 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1631 if (isIndirect) {
1632 l += 4;
1633 }
-b master422972c2009-06-17 19:13:52 -07001634 if (l > 0) {
1635 oad(0xc481, l); /* add $xxx, %esp */
1636 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001637 }
1638
Jack Palevicha6535612009-05-13 16:24:17 -07001639 virtual int jumpOffset() {
1640 return 5;
1641 }
1642
1643 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001644 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001645 }
1646
Jack Paleviche7b59062009-05-19 17:12:17 -07001647 /* output a symbol and patch all calls to it */
1648 virtual void gsym(int t) {
1649 int n;
1650 int pc = getPC();
1651 while (t) {
1652 n = *(int *) t; /* next value */
1653 *(int *) t = pc - t - 4;
1654 t = n;
1655 }
1656 }
1657
Jack Palevich1cdef202009-05-22 12:06:27 -07001658 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001659 size_t pagesize = 4096;
1660 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1661 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1662 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1663 if (err) {
1664 error("mprotect() failed: %d", errno);
1665 }
1666 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001667 }
1668
Jack Palevich9eed7a22009-07-06 17:24:34 -07001669 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001670 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001671 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001672 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001673 switch(pType->tag) {
1674 case TY_DOUBLE:
1675 return 8;
1676 default:
1677 return 4;
1678 }
1679 }
1680
1681 /**
1682 * Array element alignment (in bytes) for this type of data.
1683 */
1684 virtual size_t sizeOf(Type* pType){
1685 switch(pType->tag) {
1686 case TY_INT:
1687 return 4;
1688 case TY_CHAR:
1689 return 1;
1690 default:
1691 return 0;
1692 case TY_FLOAT:
1693 return 4;
1694 case TY_DOUBLE:
1695 return 8;
1696 case TY_POINTER:
1697 return 4;
1698 }
1699 }
1700
Jack Palevich9cbd2262009-07-08 16:48:41 -07001701 virtual size_t stackSizeOf(Type* pType) {
1702 switch(pType->tag) {
1703 case TY_DOUBLE:
1704 return 8;
1705 default:
1706 return 4;
1707 }
1708 }
1709
Jack Palevich21a15a22009-05-11 14:49:29 -07001710 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001711
1712 /** Output 1 to 4 bytes.
1713 *
1714 */
1715 void o(int n) {
1716 /* cannot use unsigned, so we must do a hack */
1717 while (n && n != -1) {
1718 ob(n & 0xff);
1719 n = n >> 8;
1720 }
1721 }
1722
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001723 /* Output exactly 2 bytes
1724 */
1725 void o2(int n) {
1726 ob(n & 0xff);
1727 ob(0xff & (n >> 8));
1728 }
1729
Jack Paleviche7b59062009-05-19 17:12:17 -07001730 /* psym is used to put an instruction with a data field which is a
1731 reference to a symbol. It is in fact the same as oad ! */
1732 int psym(int n, int t) {
1733 return oad(n, t);
1734 }
1735
1736 /* instruction + address */
1737 int oad(int n, int t) {
1738 o(n);
1739 int result = getPC();
1740 o4(t);
1741 return result;
1742 }
1743
1744
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001745 static const int operatorHelper[];
1746
1747 int decodeOp(int op) {
1748 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001749 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001750 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001751 }
1752 return operatorHelper[op];
1753 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001754
Jack Palevich546b2242009-05-13 15:10:04 -07001755 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001756 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001757 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001758 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001759
1760 void setupFloatOperands() {
1761 Type* pR0Type = getR0Type();
1762 Type* pTOSType = getTOSType();
1763 TypeTag tagR0 = pR0Type->tag;
1764 TypeTag tagTOS = pTOSType->tag;
1765 bool isFloatR0 = isFloatTag(tagR0);
1766 bool isFloatTOS = isFloatTag(tagTOS);
1767 if (! isFloatR0) {
1768 // Convert R0 from int to float
1769 o(0x50); // push %eax
1770 o(0x2404DB); // fildl 0(%esp)
1771 o(0x58); // pop %eax
1772 }
1773 if (! isFloatTOS){
1774 o(0x2404DB); // fildl 0(%esp);
1775 o(0x58); // pop %eax
1776 } else {
1777 if (tagTOS == TY_FLOAT) {
1778 o(0x2404d9); // flds (%esp)
1779 o(0x58); // pop %eax
1780 } else {
1781 o(0x2404dd); // fldl (%esp)
1782 o(0x58); // pop %eax
1783 o(0x58); // pop %eax
1784 }
1785 }
1786 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001787 };
1788
Jack Paleviche7b59062009-05-19 17:12:17 -07001789#endif // PROVIDE_X86_CODEGEN
1790
Jack Palevichb67b18f2009-06-11 21:12:23 -07001791#ifdef PROVIDE_TRACE_CODEGEN
1792 class TraceCodeGenerator : public CodeGenerator {
1793 private:
1794 CodeGenerator* mpBase;
1795
1796 public:
1797 TraceCodeGenerator(CodeGenerator* pBase) {
1798 mpBase = pBase;
1799 }
1800
1801 virtual ~TraceCodeGenerator() {
1802 delete mpBase;
1803 }
1804
1805 virtual void init(CodeBuf* pCodeBuf) {
1806 mpBase->init(pCodeBuf);
1807 }
1808
1809 void setErrorSink(ErrorSink* pErrorSink) {
1810 mpBase->setErrorSink(pErrorSink);
1811 }
1812
1813 /* returns address to patch with local variable size
1814 */
1815 virtual int functionEntry(int argCount) {
1816 int result = mpBase->functionEntry(argCount);
1817 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1818 return result;
1819 }
1820
1821 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1822 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1823 argCount, localVariableAddress, localVariableSize);
1824 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1825 }
1826
1827 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001828 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001829 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001830 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001831 }
1832
Jack Palevich1a539db2009-07-08 13:04:41 -07001833 virtual void loadFloat(int address, Type* pType) {
1834 fprintf(stderr, "loadFloat(%d, type)\n", address);
1835 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001836 }
1837
Jack Palevichb67b18f2009-06-11 21:12:23 -07001838 virtual int gjmp(int t) {
1839 int result = mpBase->gjmp(t);
1840 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1841 return result;
1842 }
1843
1844 /* l = 0: je, l == 1: jne */
1845 virtual int gtst(bool l, int t) {
1846 int result = mpBase->gtst(l, t);
1847 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1848 return result;
1849 }
1850
Jack Palevicha39749f2009-07-08 20:40:31 -07001851 virtual void gcmp(int op, Type* pResultType) {
1852 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
1853 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001854 }
1855
1856 virtual void genOp(int op) {
1857 fprintf(stderr, "genOp(%d)\n", op);
1858 mpBase->genOp(op);
1859 }
1860
Jack Palevich9eed7a22009-07-06 17:24:34 -07001861
Jack Palevicha39749f2009-07-08 20:40:31 -07001862 virtual void gUnaryCmp(int op, Type* pResultType) {
1863 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
1864 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001865 }
1866
1867 virtual void genUnaryOp(int op) {
1868 fprintf(stderr, "genUnaryOp(%d)\n", op);
1869 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001870 }
1871
1872 virtual void pushR0() {
1873 fprintf(stderr, "pushR0()\n");
1874 mpBase->pushR0();
1875 }
1876
Jack Palevich9eed7a22009-07-06 17:24:34 -07001877 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001878 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001879 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001880 }
1881
Jack Palevich9eed7a22009-07-06 17:24:34 -07001882 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001883 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001884 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001885 }
1886
Jack Palevich8df46192009-07-07 14:48:51 -07001887 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001888 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001889 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001890 }
1891
Jack Palevich9cbd2262009-07-08 16:48:41 -07001892 virtual void storeR0(int ea, Type* pType) {
1893 fprintf(stderr, "storeR0(%d, pType)\n", ea);
1894 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001895 }
1896
Jack Palevich8df46192009-07-07 14:48:51 -07001897 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001898 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001899 mpBase->loadR0(ea, isIncDec, op, pType);
1900 }
1901
1902 virtual void convertR0(Type* pType){
1903 fprintf(stderr, "convertR0(pType)\n");
1904 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001905 }
1906
1907 virtual int beginFunctionCallArguments() {
1908 int result = mpBase->beginFunctionCallArguments();
1909 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1910 return result;
1911 }
1912
Jack Palevich1a539db2009-07-08 13:04:41 -07001913 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001914 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001915 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001916 }
1917
1918 virtual void endFunctionCallArguments(int a, int l) {
1919 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1920 mpBase->endFunctionCallArguments(a, l);
1921 }
1922
Jack Palevich8df46192009-07-07 14:48:51 -07001923 virtual int callForward(int symbol, Type* pFunc) {
1924 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001925 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1926 return result;
1927 }
1928
Jack Palevich8df46192009-07-07 14:48:51 -07001929 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001930 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001931 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001932 }
1933
Jack Palevich8df46192009-07-07 14:48:51 -07001934 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001935 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001936 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001937 }
1938
1939 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1940 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1941 mpBase->adjustStackAfterCall(l, isIndirect);
1942 }
1943
1944 virtual int jumpOffset() {
1945 return mpBase->jumpOffset();
1946 }
1947
1948 virtual int disassemble(FILE* out) {
1949 return mpBase->disassemble(out);
1950 }
1951
1952 /* output a symbol and patch all calls to it */
1953 virtual void gsym(int t) {
1954 fprintf(stderr, "gsym(%d)\n", t);
1955 mpBase->gsym(t);
1956 }
1957
1958 virtual int finishCompile() {
1959 int result = mpBase->finishCompile();
1960 fprintf(stderr, "finishCompile() = %d\n", result);
1961 return result;
1962 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001963
1964 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001965 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001966 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001967 virtual size_t alignment(Type* pType){
1968 return mpBase->alignment(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001969 }
1970
1971 /**
1972 * Array element alignment (in bytes) for this type of data.
1973 */
1974 virtual size_t sizeOf(Type* pType){
1975 return mpBase->sizeOf(pType);
1976 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001977
Jack Palevich9cbd2262009-07-08 16:48:41 -07001978
1979 virtual size_t stackSizeOf(Type* pType) {
1980 return mpBase->stackSizeOf(pType);
1981 }
1982
1983
Jack Palevich1a539db2009-07-08 13:04:41 -07001984 virtual Type* getR0Type() {
1985 return mpBase->getR0Type();
1986 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001987 };
1988
1989#endif // PROVIDE_TRACE_CODEGEN
1990
Jack Palevich569f1352009-06-29 14:29:08 -07001991 class Arena {
1992 public:
1993 // Used to record a given allocation amount.
1994 // Used:
1995 // Mark mark = arena.mark();
1996 // ... lots of arena.allocate()
1997 // arena.free(mark);
1998
1999 struct Mark {
2000 size_t chunk;
2001 size_t offset;
2002 };
2003
2004 Arena() {
2005 mCurrentChunk = 0;
2006 Chunk start(CHUNK_SIZE);
2007 mData.push_back(start);
2008 }
2009
2010 ~Arena() {
2011 for(size_t i = 0; i < mData.size(); i++) {
2012 mData[i].free();
2013 }
2014 }
2015
2016 // Alloc using the standard alignment size safe for any variable
2017 void* alloc(size_t size) {
2018 return alloc(size, 8);
2019 }
2020
2021 Mark mark(){
2022 Mark result;
2023 result.chunk = mCurrentChunk;
2024 result.offset = mData[mCurrentChunk].mOffset;
2025 return result;
2026 }
2027
2028 void freeToMark(const Mark& mark) {
2029 mCurrentChunk = mark.chunk;
2030 mData[mCurrentChunk].mOffset = mark.offset;
2031 }
2032
2033 private:
2034 // Allocate memory aligned to a given size
2035 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2036 // Memory is not zero filled.
2037
2038 void* alloc(size_t size, size_t alignment) {
2039 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2040 if (mCurrentChunk + 1 < mData.size()) {
2041 mCurrentChunk++;
2042 } else {
2043 size_t allocSize = CHUNK_SIZE;
2044 if (allocSize < size + alignment - 1) {
2045 allocSize = size + alignment - 1;
2046 }
2047 Chunk chunk(allocSize);
2048 mData.push_back(chunk);
2049 mCurrentChunk++;
2050 }
2051 }
2052 return mData[mCurrentChunk].allocate(size, alignment);
2053 }
2054
2055 static const size_t CHUNK_SIZE = 128*1024;
2056 // Note: this class does not deallocate its
2057 // memory when it's destroyed. It depends upon
2058 // its parent to deallocate the memory.
2059 struct Chunk {
2060 Chunk() {
2061 mpData = 0;
2062 mSize = 0;
2063 mOffset = 0;
2064 }
2065
2066 Chunk(size_t size) {
2067 mSize = size;
2068 mpData = (char*) malloc(size);
2069 mOffset = 0;
2070 }
2071
2072 ~Chunk() {
2073 // Doesn't deallocate memory.
2074 }
2075
2076 void* allocate(size_t size, size_t alignment) {
2077 size_t alignedOffset = aligned(mOffset, alignment);
2078 void* result = mpData + alignedOffset;
2079 mOffset = alignedOffset + size;
2080 return result;
2081 }
2082
2083 void free() {
2084 if (mpData) {
2085 ::free(mpData);
2086 mpData = 0;
2087 }
2088 }
2089
2090 size_t remainingCapacity(size_t alignment) {
2091 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2092 }
2093
2094 // Assume alignment is a power of two
2095 inline size_t aligned(size_t v, size_t alignment) {
2096 size_t mask = alignment-1;
2097 return (v + mask) & ~mask;
2098 }
2099
2100 char* mpData;
2101 size_t mSize;
2102 size_t mOffset;
2103 };
2104
2105 size_t mCurrentChunk;
2106
2107 Vector<Chunk> mData;
2108 };
2109
Jack Palevich569f1352009-06-29 14:29:08 -07002110 struct VariableInfo;
2111
2112 struct Token {
2113 int hash;
2114 size_t length;
2115 char* pText;
2116 tokenid_t id;
2117
2118 // Current values for the token
2119 char* mpMacroDefinition;
2120 VariableInfo* mpVariableInfo;
2121 };
2122
2123 class TokenTable {
2124 public:
2125 // Don't use 0..0xff, allows characters and operators to be tokens too.
2126
2127 static const int TOKEN_BASE = 0x100;
2128 TokenTable() {
2129 mpMap = hashmapCreate(128, hashFn, equalsFn);
2130 }
2131
2132 ~TokenTable() {
2133 hashmapFree(mpMap);
2134 }
2135
2136 void setArena(Arena* pArena) {
2137 mpArena = pArena;
2138 }
2139
2140 // Returns a token for a given string of characters.
2141 tokenid_t intern(const char* pText, size_t length) {
2142 Token probe;
2143 int hash = hashmapHash((void*) pText, length);
2144 {
2145 Token probe;
2146 probe.hash = hash;
2147 probe.length = length;
2148 probe.pText = (char*) pText;
2149 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2150 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002151 return pValue->id;
2152 }
2153 }
2154
2155 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2156 memset(pToken, 0, sizeof(*pToken));
2157 pToken->hash = hash;
2158 pToken->length = length;
2159 pToken->pText = (char*) mpArena->alloc(length + 1);
2160 memcpy(pToken->pText, pText, length);
2161 pToken->pText[length] = 0;
2162 pToken->id = mTokens.size() + TOKEN_BASE;
2163 mTokens.push_back(pToken);
2164 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002165 return pToken->id;
2166 }
2167
2168 // Return the Token for a given tokenid.
2169 Token& operator[](tokenid_t id) {
2170 return *mTokens[id - TOKEN_BASE];
2171 }
2172
2173 inline size_t size() {
2174 return mTokens.size();
2175 }
2176
2177 private:
2178
2179 static int hashFn(void* pKey) {
2180 Token* pToken = (Token*) pKey;
2181 return pToken->hash;
2182 }
2183
2184 static bool equalsFn(void* keyA, void* keyB) {
2185 Token* pTokenA = (Token*) keyA;
2186 Token* pTokenB = (Token*) keyB;
2187 // Don't need to compare hash values, they should always be equal
2188 return pTokenA->length == pTokenB->length
2189 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2190 }
2191
2192 Hashmap* mpMap;
2193 Vector<Token*> mTokens;
2194 Arena* mpArena;
2195 };
2196
Jack Palevich1cdef202009-05-22 12:06:27 -07002197 class InputStream {
2198 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002199 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002200 int getChar() {
2201 if (bumpLine) {
2202 line++;
2203 bumpLine = false;
2204 }
2205 int ch = get();
2206 if (ch == '\n') {
2207 bumpLine = true;
2208 }
2209 return ch;
2210 }
2211 int getLine() {
2212 return line;
2213 }
2214 protected:
2215 InputStream() :
2216 line(1), bumpLine(false) {
2217 }
2218 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002219 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002220 int line;
2221 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002222 };
2223
2224 class FileInputStream : public InputStream {
2225 public:
2226 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002227 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002228 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002229 FILE* f;
2230 };
2231
2232 class TextInputStream : public InputStream {
2233 public:
2234 TextInputStream(const char* text, size_t textLength)
2235 : pText(text), mTextLength(textLength), mPosition(0) {
2236 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002237
2238 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002239 virtual int get() {
2240 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2241 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002242
Jack Palevich1cdef202009-05-22 12:06:27 -07002243 const char* pText;
2244 size_t mTextLength;
2245 size_t mPosition;
2246 };
2247
Jack Palevicheedf9d22009-06-04 16:23:40 -07002248 class String {
2249 public:
2250 String() {
2251 mpBase = 0;
2252 mUsed = 0;
2253 mSize = 0;
2254 }
2255
Jack Palevich303d8ff2009-06-11 19:06:24 -07002256 String(const char* item, int len, bool adopt) {
2257 if (len < 0) {
2258 len = strlen(item);
2259 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002260 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002261 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002262 mUsed = len;
2263 mSize = len + 1;
2264 } else {
2265 mpBase = 0;
2266 mUsed = 0;
2267 mSize = 0;
2268 appendBytes(item, len);
2269 }
2270 }
2271
Jack Palevich303d8ff2009-06-11 19:06:24 -07002272 String(const String& other) {
2273 mpBase = 0;
2274 mUsed = 0;
2275 mSize = 0;
2276 appendBytes(other.getUnwrapped(), other.len());
2277 }
2278
Jack Palevicheedf9d22009-06-04 16:23:40 -07002279 ~String() {
2280 if (mpBase) {
2281 free(mpBase);
2282 }
2283 }
2284
Jack Palevicha6baa232009-06-12 11:25:59 -07002285 String& operator=(const String& other) {
2286 clear();
2287 appendBytes(other.getUnwrapped(), other.len());
2288 return *this;
2289 }
2290
Jack Palevich303d8ff2009-06-11 19:06:24 -07002291 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002292 return mpBase;
2293 }
2294
Jack Palevich303d8ff2009-06-11 19:06:24 -07002295 void clear() {
2296 mUsed = 0;
2297 if (mSize > 0) {
2298 mpBase[0] = 0;
2299 }
2300 }
2301
Jack Palevicheedf9d22009-06-04 16:23:40 -07002302 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002303 appendBytes(s, strlen(s));
2304 }
2305
2306 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002307 memcpy(ensure(n), s, n + 1);
2308 }
2309
2310 void append(char c) {
2311 * ensure(1) = c;
2312 }
2313
Jack Palevich86351982009-06-30 18:09:56 -07002314 void append(String& other) {
2315 appendBytes(other.getUnwrapped(), other.len());
2316 }
2317
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002318 char* orphan() {
2319 char* result = mpBase;
2320 mpBase = 0;
2321 mUsed = 0;
2322 mSize = 0;
2323 return result;
2324 }
2325
Jack Palevicheedf9d22009-06-04 16:23:40 -07002326 void printf(const char* fmt,...) {
2327 va_list ap;
2328 va_start(ap, fmt);
2329 vprintf(fmt, ap);
2330 va_end(ap);
2331 }
2332
2333 void vprintf(const char* fmt, va_list ap) {
2334 char* temp;
2335 int numChars = vasprintf(&temp, fmt, ap);
2336 memcpy(ensure(numChars), temp, numChars+1);
2337 free(temp);
2338 }
2339
Jack Palevich303d8ff2009-06-11 19:06:24 -07002340 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002341 return mUsed;
2342 }
2343
2344 private:
2345 char* ensure(int n) {
2346 size_t newUsed = mUsed + n;
2347 if (newUsed > mSize) {
2348 size_t newSize = mSize * 2 + 10;
2349 if (newSize < newUsed) {
2350 newSize = newUsed;
2351 }
2352 mpBase = (char*) realloc(mpBase, newSize + 1);
2353 mSize = newSize;
2354 }
2355 mpBase[newUsed] = '\0';
2356 char* result = mpBase + mUsed;
2357 mUsed = newUsed;
2358 return result;
2359 }
2360
2361 char* mpBase;
2362 size_t mUsed;
2363 size_t mSize;
2364 };
2365
Jack Palevich569f1352009-06-29 14:29:08 -07002366 void internKeywords() {
2367 // Note: order has to match TOK_ constants
2368 static const char* keywords[] = {
2369 "int",
2370 "char",
2371 "void",
2372 "if",
2373 "else",
2374 "while",
2375 "break",
2376 "return",
2377 "for",
2378 "pragma",
2379 "define",
2380 "auto",
2381 "case",
2382 "const",
2383 "continue",
2384 "default",
2385 "do",
2386 "double",
2387 "enum",
2388 "extern",
2389 "float",
2390 "goto",
2391 "long",
2392 "register",
2393 "short",
2394 "signed",
2395 "sizeof",
2396 "static",
2397 "struct",
2398 "switch",
2399 "typedef",
2400 "union",
2401 "unsigned",
2402 "volatile",
2403 "_Bool",
2404 "_Complex",
2405 "_Imaginary",
2406 "inline",
2407 "restrict",
2408 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002409
Jack Palevich569f1352009-06-29 14:29:08 -07002410 for(int i = 0; keywords[i]; i++) {
2411 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002412 }
Jack Palevich569f1352009-06-29 14:29:08 -07002413 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002414
Jack Palevich36d94142009-06-08 15:55:32 -07002415 struct InputState {
2416 InputStream* pStream;
2417 int oldCh;
2418 };
2419
Jack Palevich2db168f2009-06-11 14:29:47 -07002420 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002421 void* pAddress;
2422 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002423 tokenid_t tok;
2424 size_t level;
2425 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002426 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002427 };
2428
Jack Palevich303d8ff2009-06-11 19:06:24 -07002429 class SymbolStack {
2430 public:
2431 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002432 mpArena = 0;
2433 mpTokenTable = 0;
2434 }
2435
2436 void setArena(Arena* pArena) {
2437 mpArena = pArena;
2438 }
2439
2440 void setTokenTable(TokenTable* pTokenTable) {
2441 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002442 }
2443
2444 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002445 Mark mark;
2446 mark.mArenaMark = mpArena->mark();
2447 mark.mSymbolHead = mStack.size();
2448 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002449 }
2450
2451 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002452 // Undo any shadowing that was done:
2453 Mark mark = mLevelStack.back();
2454 mLevelStack.pop_back();
2455 while (mStack.size() > mark.mSymbolHead) {
2456 VariableInfo* pV = mStack.back();
2457 mStack.pop_back();
2458 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002459 }
Jack Palevich569f1352009-06-29 14:29:08 -07002460 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002461 }
2462
Jack Palevich569f1352009-06-29 14:29:08 -07002463 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2464 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2465 return pV && pV->level == level();
2466 }
2467
2468 VariableInfo* add(tokenid_t tok) {
2469 Token& token = (*mpTokenTable)[tok];
2470 VariableInfo* pOldV = token.mpVariableInfo;
2471 VariableInfo* pNewV =
2472 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2473 memset(pNewV, 0, sizeof(VariableInfo));
2474 pNewV->tok = tok;
2475 pNewV->level = level();
2476 pNewV->pOldDefinition = pOldV;
2477 token.mpVariableInfo = pNewV;
2478 mStack.push_back(pNewV);
2479 return pNewV;
2480 }
2481
Jack Palevich86351982009-06-30 18:09:56 -07002482 VariableInfo* add(Type* pType) {
2483 VariableInfo* pVI = add(pType->id);
2484 pVI->pType = pType;
2485 return pVI;
2486 }
2487
Jack Palevich569f1352009-06-29 14:29:08 -07002488 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2489 for (size_t i = 0; i < mStack.size(); i++) {
2490 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002491 break;
2492 }
2493 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002494 }
2495
Jack Palevich303d8ff2009-06-11 19:06:24 -07002496 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002497 inline size_t level() {
2498 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002499 }
2500
Jack Palevich569f1352009-06-29 14:29:08 -07002501 struct Mark {
2502 Arena::Mark mArenaMark;
2503 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002504 };
2505
Jack Palevich569f1352009-06-29 14:29:08 -07002506 Arena* mpArena;
2507 TokenTable* mpTokenTable;
2508 Vector<VariableInfo*> mStack;
2509 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002510 };
Jack Palevich36d94142009-06-08 15:55:32 -07002511
2512 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002513 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002514 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002515 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002516 int tokl; // token operator level
2517 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002518 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002519 intptr_t loc; // local variable index
2520 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002521 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002522 char* dptr; // Macro state: Points to macro text during macro playback.
2523 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002524 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002525
2526 // Arena for the duration of the compile
2527 Arena mGlobalArena;
2528 // Arena for data that's only needed when compiling a single function
2529 Arena mLocalArena;
2530
2531 TokenTable mTokenTable;
2532 SymbolStack mGlobals;
2533 SymbolStack mLocals;
2534
Jack Palevich40600de2009-07-01 15:32:35 -07002535 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002536 Type* mkpInt; // int
2537 Type* mkpChar; // char
2538 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002539 Type* mkpFloat;
2540 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002541 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002542 Type* mkpIntPtr;
2543 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002544 Type* mkpFloatPtr;
2545 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002546 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002547
Jack Palevich36d94142009-06-08 15:55:32 -07002548 InputStream* file;
2549
2550 CodeBuf codeBuf;
2551 CodeGenerator* pGen;
2552
Jack Palevicheedf9d22009-06-04 16:23:40 -07002553 String mErrorBuf;
2554
Jack Palevicheedf9d22009-06-04 16:23:40 -07002555 String mPragmas;
2556 int mPragmaStringCount;
2557
Jack Palevich21a15a22009-05-11 14:49:29 -07002558 static const int ALLOC_SIZE = 99999;
2559
Jack Palevich303d8ff2009-06-11 19:06:24 -07002560 static const int TOK_DUMMY = 1;
2561 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002562 static const int TOK_NUM_FLOAT = 3;
2563 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002564
2565 // 3..255 are character and/or operators
2566
Jack Palevich2db168f2009-06-11 14:29:47 -07002567 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002568 // Order has to match string list in "internKeywords".
2569 enum {
2570 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2571 TOK_INT = TOK_KEYWORD,
2572 TOK_CHAR,
2573 TOK_VOID,
2574 TOK_IF,
2575 TOK_ELSE,
2576 TOK_WHILE,
2577 TOK_BREAK,
2578 TOK_RETURN,
2579 TOK_FOR,
2580 TOK_PRAGMA,
2581 TOK_DEFINE,
2582 TOK_AUTO,
2583 TOK_CASE,
2584 TOK_CONST,
2585 TOK_CONTINUE,
2586 TOK_DEFAULT,
2587 TOK_DO,
2588 TOK_DOUBLE,
2589 TOK_ENUM,
2590 TOK_EXTERN,
2591 TOK_FLOAT,
2592 TOK_GOTO,
2593 TOK_LONG,
2594 TOK_REGISTER,
2595 TOK_SHORT,
2596 TOK_SIGNED,
2597 TOK_SIZEOF,
2598 TOK_STATIC,
2599 TOK_STRUCT,
2600 TOK_SWITCH,
2601 TOK_TYPEDEF,
2602 TOK_UNION,
2603 TOK_UNSIGNED,
2604 TOK_VOLATILE,
2605 TOK__BOOL,
2606 TOK__COMPLEX,
2607 TOK__IMAGINARY,
2608 TOK_INLINE,
2609 TOK_RESTRICT,
2610 // Symbols start after tokens
2611 TOK_SYMBOL
2612 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002613
2614 static const int LOCAL = 0x200;
2615
2616 static const int SYM_FORWARD = 0;
2617 static const int SYM_DEFINE = 1;
2618
2619 /* tokens in string heap */
2620 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002621
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002622 static const int OP_INCREMENT = 0;
2623 static const int OP_DECREMENT = 1;
2624 static const int OP_MUL = 2;
2625 static const int OP_DIV = 3;
2626 static const int OP_MOD = 4;
2627 static const int OP_PLUS = 5;
2628 static const int OP_MINUS = 6;
2629 static const int OP_SHIFT_LEFT = 7;
2630 static const int OP_SHIFT_RIGHT = 8;
2631 static const int OP_LESS_EQUAL = 9;
2632 static const int OP_GREATER_EQUAL = 10;
2633 static const int OP_LESS = 11;
2634 static const int OP_GREATER = 12;
2635 static const int OP_EQUALS = 13;
2636 static const int OP_NOT_EQUALS = 14;
2637 static const int OP_LOGICAL_AND = 15;
2638 static const int OP_LOGICAL_OR = 16;
2639 static const int OP_BIT_AND = 17;
2640 static const int OP_BIT_XOR = 18;
2641 static const int OP_BIT_OR = 19;
2642 static const int OP_BIT_NOT = 20;
2643 static const int OP_LOGICAL_NOT = 21;
2644 static const int OP_COUNT = 22;
2645
2646 /* Operators are searched from front, the two-character operators appear
2647 * before the single-character operators with the same first character.
2648 * @ is used to pad out single-character operators.
2649 */
2650 static const char* operatorChars;
2651 static const char operatorLevel[];
2652
Jack Palevich569f1352009-06-29 14:29:08 -07002653 /* Called when we detect an internal problem. Does nothing in production.
2654 *
2655 */
2656 void internalError() {
2657 * (char*) 0 = 0;
2658 }
2659
Jack Palevich86351982009-06-30 18:09:56 -07002660 void assert(bool isTrue) {
2661 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002662 internalError();
2663 }
Jack Palevich86351982009-06-30 18:09:56 -07002664 }
2665
Jack Palevich40600de2009-07-01 15:32:35 -07002666 bool isSymbol(tokenid_t t) {
2667 return t >= TOK_SYMBOL &&
2668 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2669 }
2670
2671 bool isSymbolOrKeyword(tokenid_t t) {
2672 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002673 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002674 }
2675
Jack Palevich86351982009-06-30 18:09:56 -07002676 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002677 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002678 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2679 if (pV && pV->tok != t) {
2680 internalError();
2681 }
2682 return pV;
2683 }
2684
2685 inline bool isDefined(tokenid_t t) {
2686 return t >= TOK_SYMBOL && VI(t) != 0;
2687 }
2688
Jack Palevich40600de2009-07-01 15:32:35 -07002689 const char* nameof(tokenid_t t) {
2690 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002691 return mTokenTable[t].pText;
2692 }
2693
Jack Palevich21a15a22009-05-11 14:49:29 -07002694 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002695 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002696 }
2697
2698 void inp() {
2699 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002700 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002701 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002702 dptr = 0;
2703 ch = dch;
2704 }
2705 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002706 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002707#if 0
2708 printf("ch='%c' 0x%x\n", ch, ch);
2709#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002710 }
2711
2712 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002713 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002714 }
2715
Jack Palevichb4758ff2009-06-12 12:49:14 -07002716 /* read a character constant, advances ch to after end of constant */
2717 int getq() {
2718 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002719 if (ch == '\\') {
2720 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002721 if (isoctal(ch)) {
2722 // 1 to 3 octal characters.
2723 val = 0;
2724 for(int i = 0; i < 3; i++) {
2725 if (isoctal(ch)) {
2726 val = (val << 3) + ch - '0';
2727 inp();
2728 }
2729 }
2730 return val;
2731 } else if (ch == 'x' || ch == 'X') {
2732 // N hex chars
2733 inp();
2734 if (! isxdigit(ch)) {
2735 error("'x' character escape requires at least one digit.");
2736 } else {
2737 val = 0;
2738 while (isxdigit(ch)) {
2739 int d = ch;
2740 if (isdigit(d)) {
2741 d -= '0';
2742 } else if (d <= 'F') {
2743 d = d - 'A' + 10;
2744 } else {
2745 d = d - 'a' + 10;
2746 }
2747 val = (val << 4) + d;
2748 inp();
2749 }
2750 }
2751 } else {
2752 int val = ch;
2753 switch (ch) {
2754 case 'a':
2755 val = '\a';
2756 break;
2757 case 'b':
2758 val = '\b';
2759 break;
2760 case 'f':
2761 val = '\f';
2762 break;
2763 case 'n':
2764 val = '\n';
2765 break;
2766 case 'r':
2767 val = '\r';
2768 break;
2769 case 't':
2770 val = '\t';
2771 break;
2772 case 'v':
2773 val = '\v';
2774 break;
2775 case '\\':
2776 val = '\\';
2777 break;
2778 case '\'':
2779 val = '\'';
2780 break;
2781 case '"':
2782 val = '"';
2783 break;
2784 case '?':
2785 val = '?';
2786 break;
2787 default:
2788 error("Undefined character escape %c", ch);
2789 break;
2790 }
2791 inp();
2792 return val;
2793 }
2794 } else {
2795 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002796 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002797 return val;
2798 }
2799
2800 static bool isoctal(int ch) {
2801 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002802 }
2803
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002804 bool acceptCh(int c) {
2805 bool result = c == ch;
2806 if (result) {
2807 pdef(ch);
2808 inp();
2809 }
2810 return result;
2811 }
2812
2813 bool acceptDigitsCh() {
2814 bool result = false;
2815 while (isdigit(ch)) {
2816 result = true;
2817 pdef(ch);
2818 inp();
2819 }
2820 return result;
2821 }
2822
2823 void parseFloat() {
2824 tok = TOK_NUM_DOUBLE;
2825 // mTokenString already has the integral part of the number.
2826 acceptCh('.');
2827 acceptDigitsCh();
2828 bool doExp = true;
2829 if (acceptCh('e') || acceptCh('E')) {
2830 // Don't need to do any extra work
2831 } else if (ch == 'f' || ch == 'F') {
2832 pdef('e'); // So it can be parsed by strtof.
2833 inp();
2834 tok = TOK_NUM_FLOAT;
2835 } else {
2836 doExp = false;
2837 }
2838 if (doExp) {
2839 bool digitsRequired = acceptCh('-');
2840 bool digitsFound = acceptDigitsCh();
2841 if (digitsRequired && ! digitsFound) {
2842 error("malformed exponent");
2843 }
2844 }
2845 char* pText = mTokenString.getUnwrapped();
2846 if (tok == TOK_NUM_FLOAT) {
2847 tokd = strtof(pText, 0);
2848 } else {
2849 tokd = strtod(pText, 0);
2850 }
2851 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2852 }
2853
Jack Palevich21a15a22009-05-11 14:49:29 -07002854 void next() {
2855 int l, a;
2856
Jack Palevich546b2242009-05-13 15:10:04 -07002857 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002858 if (ch == '#') {
2859 inp();
2860 next();
2861 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002862 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002863 } else if (tok == TOK_PRAGMA) {
2864 doPragma();
2865 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002866 error("Unsupported preprocessor directive \"%s\"",
2867 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002868 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002869 }
2870 inp();
2871 }
2872 tokl = 0;
2873 tok = ch;
2874 /* encode identifiers & numbers */
2875 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002876 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002877 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002878 pdef(ch);
2879 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002880 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002881 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002882 // Start of a numeric constant. Could be integer, float, or
2883 // double, won't know until we look further.
2884 if (ch == '.' || ch == 'e' || ch == 'e'
2885 || ch == 'f' || ch == 'F') {
2886 parseFloat();
2887 } else {
2888 // It's an integer constant
2889 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2890 tok = TOK_NUM;
2891 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002892 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002893 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2894 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002895 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002896 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2897 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002898 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002899 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002900 dch = ch;
2901 inp();
2902 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002903 }
2904 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002905 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002906 inp();
2907 if (tok == '\'') {
2908 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002909 tokc = getq();
2910 if (ch != '\'') {
2911 error("Expected a ' character, got %c", ch);
2912 } else {
2913 inp();
2914 }
Jack Palevich546b2242009-05-13 15:10:04 -07002915 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002916 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002917 while (ch && ch != EOF) {
2918 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002919 inp();
2920 inp();
2921 if (ch == '/')
2922 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002923 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002924 if (ch == EOF) {
2925 error("End of file inside comment.");
2926 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002927 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002928 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002929 } else if ((tok == '/') & (ch == '/')) {
2930 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002931 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002932 inp();
2933 }
2934 inp();
2935 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002936 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002937 const char* t = operatorChars;
2938 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002939 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002940 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002941 tokl = operatorLevel[opIndex];
2942 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002943 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002944#if 0
2945 printf("%c%c -> tokl=%d tokc=0x%x\n",
2946 l, a, tokl, tokc);
2947#endif
2948 if (a == ch) {
2949 inp();
2950 tok = TOK_DUMMY; /* dummy token for double tokens */
2951 }
2952 break;
2953 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002954 opIndex++;
2955 }
2956 if (l == 0) {
2957 tokl = 0;
2958 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002959 }
2960 }
2961 }
2962#if 0
2963 {
Jack Palevich569f1352009-06-29 14:29:08 -07002964 String buf;
2965 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002966 fprintf(stderr, "%s\n", buf.getUnwrapped());
2967 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002968#endif
2969 }
2970
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002971 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002972 next();
2973 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002974 String* pName = new String();
2975 while (isspace(ch)) {
2976 inp();
2977 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002978 if (ch == '(') {
2979 delete pName;
2980 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002981 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002982 }
2983 while (isspace(ch)) {
2984 inp();
2985 }
Jack Palevich569f1352009-06-29 14:29:08 -07002986 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002987 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002988 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002989 inp();
2990 }
Jack Palevich569f1352009-06-29 14:29:08 -07002991 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2992 memcpy(pDefn, value.getUnwrapped(), value.len());
2993 pDefn[value.len()] = 0;
2994 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002995 }
2996
Jack Palevicheedf9d22009-06-04 16:23:40 -07002997 void doPragma() {
2998 // # pragma name(val)
2999 int state = 0;
3000 while(ch != EOF && ch != '\n' && state < 10) {
3001 switch(state) {
3002 case 0:
3003 if (isspace(ch)) {
3004 inp();
3005 } else {
3006 state++;
3007 }
3008 break;
3009 case 1:
3010 if (isalnum(ch)) {
3011 mPragmas.append(ch);
3012 inp();
3013 } else if (ch == '(') {
3014 mPragmas.append(0);
3015 inp();
3016 state++;
3017 } else {
3018 state = 11;
3019 }
3020 break;
3021 case 2:
3022 if (isalnum(ch)) {
3023 mPragmas.append(ch);
3024 inp();
3025 } else if (ch == ')') {
3026 mPragmas.append(0);
3027 inp();
3028 state = 10;
3029 } else {
3030 state = 11;
3031 }
3032 break;
3033 }
3034 }
3035 if(state != 10) {
3036 error("Unexpected pragma syntax");
3037 }
3038 mPragmaStringCount += 2;
3039 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003040
Jack Palevichac0e95e2009-05-29 13:53:44 -07003041 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003042 mErrorBuf.printf("%ld: ", file->getLine());
3043 mErrorBuf.vprintf(fmt, ap);
3044 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003045 }
3046
Jack Palevich8b0624c2009-05-20 12:12:06 -07003047 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003048 if (tok != c) {
3049 error("'%c' expected", c);
3050 }
3051 next();
3052 }
3053
Jack Palevich86351982009-06-30 18:09:56 -07003054 bool accept(intptr_t c) {
3055 if (tok == c) {
3056 next();
3057 return true;
3058 }
3059 return false;
3060 }
3061
Jack Palevich40600de2009-07-01 15:32:35 -07003062 bool acceptStringLiteral() {
3063 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003064 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003065 // This while loop merges multiple adjacent string constants.
3066 while (tok == '"') {
3067 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003068 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003069 }
3070 if (ch != '"') {
3071 error("Unterminated string constant.");
3072 }
3073 inp();
3074 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003075 }
Jack Palevich40600de2009-07-01 15:32:35 -07003076 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003077 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003078 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003079 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003080
3081 return true;
3082 }
3083 return false;
3084 }
3085 /* Parse and evaluate a unary expression.
3086 * allowAssignment is true if '=' parsing wanted (quick hack)
3087 */
3088 void unary(bool allowAssignment) {
3089 intptr_t n, t, a;
3090 t = 0;
3091 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3092 if (acceptStringLiteral()) {
3093 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003094 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003095 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003096 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003097 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003098 t = tok;
3099 next();
3100 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003101 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003102 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003103 // Align to 4-byte boundary
3104 glo = (char*) (((intptr_t) glo + 3) & -4);
3105 * (float*) glo = (float) ad;
3106 pGen->loadFloat((int) glo, mkpFloat);
3107 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003108 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003109 // Align to 8-byte boundary
3110 glo = (char*) (((intptr_t) glo + 7) & -8);
3111 * (double*) glo = ad;
3112 pGen->loadFloat((int) glo, mkpDouble);
3113 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003114 } else if (c == 2) {
3115 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003116 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003117 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003118 pGen->gUnaryCmp(a, mkpInt);
3119 else if (t == '+') {
3120 // ignore unary plus.
3121 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003122 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003123 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003124 } else if (t == '(') {
3125 expr();
3126 skip(')');
3127 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07003128 /* This is a pointer dereference, but we currently only
3129 * support a pointer dereference if it's immediately
3130 * in front of a cast. So parse the cast right here.
3131 */
Jack Palevich21a15a22009-05-11 14:49:29 -07003132 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07003133 Type* pCast = expectCastTypeDeclaration(mLocalArena);
3134 // We currently only handle 3 types of cast:
3135 // (int*), (char*) , (int (*)())
3136 if(typeEqual(pCast, mkpIntPtr)) {
3137 t = TOK_INT;
3138 } else if (typeEqual(pCast, mkpCharPtr)) {
3139 t = TOK_CHAR;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003140 } else if (typeEqual(pCast, mkpFloatPtr)) {
3141 t = TOK_FLOAT;
3142 } else if (typeEqual(pCast, mkpDoublePtr)) {
3143 t = TOK_DOUBLE;
Jack Palevich3f226492009-07-02 14:46:19 -07003144 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07003145 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07003146 } else {
3147 String buffer;
3148 decodeType(buffer, pCast);
3149 error("Unsupported cast type %s", buffer.getUnwrapped());
3150 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07003151 }
3152 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07003153 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07003154 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07003155 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003156 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07003157 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003158 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003159 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003160 }
Jack Palevich3f226492009-07-02 14:46:19 -07003161 // Else we fall through to the function call below, with
3162 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003163 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003164 VariableInfo* pVI = VI(tok);
3165 pGen->leaR0((int) pVI->pAddress,
3166 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003167 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003168 } else if (t == EOF ) {
3169 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003170 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003171 // Don't have to do anything special here, the error
3172 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003173 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003174 if (!isDefined(t)) {
3175 mGlobals.add(t);
3176 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003177 }
Jack Palevich8df46192009-07-07 14:48:51 -07003178 VariableInfo* pVI = VI(t);
3179 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003180 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003181 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003182 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003183 if (tok == '(') {
3184 pVI->pType = mkpIntFn;
3185 } else {
3186 pVI->pType = mkpInt;
3187 }
Jack Palevich8df46192009-07-07 14:48:51 -07003188 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003189 }
Jack Palevich40600de2009-07-01 15:32:35 -07003190 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003191 /* assignment */
3192 next();
3193 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003194 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003195 } else if (tok != '(') {
3196 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003197 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003198 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003199 }
Jack Palevich8df46192009-07-07 14:48:51 -07003200 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003201 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003202 next();
3203 }
3204 }
3205 }
3206 }
3207
3208 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003209 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003210 Type* pArgList = NULL;
3211 VariableInfo* pVI = NULL;
3212 if (n == 1) { // Indirect function call, push address of fn.
3213 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07003214 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003215 } else {
3216 pVI = VI(t);
3217 pArgList = pVI->pType->pTail;
3218 }
3219 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003220 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003221 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003222 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003223 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003224 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003225 if (! varArgs && !pArgList) {
3226 error ("Unexpected argument.");
3227 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003228 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003229 Type* pTargetType;
3230 if (pArgList) {
3231 pTargetType = pArgList->pHead;
3232 pArgList = pArgList->pTail;
3233 } else {
3234 pTargetType = pGen->getR0Type();
3235 if (pTargetType->tag == TY_FLOAT) {
3236 pTargetType = mkpDouble;
3237 }
3238 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003239 if (pTargetType->tag == TY_VOID) {
3240 error("Can't pass void value for argument %d",
3241 argCount + 1);
3242 } else {
3243 pGen->convertR0(pTargetType);
3244 l += pGen->storeR0ToArg(l);
3245 }
Jack Palevich95727a02009-07-06 12:07:15 -07003246 if (accept(',')) {
3247 // fine
3248 } else if ( tok != ')') {
3249 error("Expected ',' or ')'");
3250 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003251 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003252 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003253 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003254 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003255 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003256 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003257 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003258 if (!n) {
3259 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003260 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3261 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003262 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003263 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003264 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003265 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3266 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003267 }
-b master422972c2009-06-17 19:13:52 -07003268 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003269 }
3270 }
3271
Jack Palevich40600de2009-07-01 15:32:35 -07003272 /* Recursive descent parser for binary operations.
3273 */
3274 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003275 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003276 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003277 if (level-- == 1)
3278 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003279 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003280 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003281 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003282 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003283 n = tok;
3284 t = tokc;
3285 next();
3286
Jack Palevich40600de2009-07-01 15:32:35 -07003287 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003288 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003289 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003290 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003291 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003292 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003293
Jack Palevich40600de2009-07-01 15:32:35 -07003294 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003295 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003296 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003297 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003298 }
3299 }
3300 }
3301 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003302 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003303 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003304 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003305 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003306 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003307 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003308 }
3309 }
3310 }
3311
3312 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003313 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003314 }
3315
3316 int test_expr() {
3317 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003318 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003319 }
3320
Jack Palevicha6baa232009-06-12 11:25:59 -07003321 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003322 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003323
Jack Palevich95727a02009-07-06 12:07:15 -07003324 Type* pBaseType;
3325 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003326 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003327 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003328 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003329 next();
3330 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003331 a = test_expr();
3332 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003333 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003334 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003335 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003336 n = pGen->gjmp(0); /* jmp */
3337 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003338 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003339 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003340 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003341 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003342 }
Jack Palevich546b2242009-05-13 15:10:04 -07003343 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003344 t = tok;
3345 next();
3346 skip('(');
3347 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003348 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003349 a = test_expr();
3350 } else {
3351 if (tok != ';')
3352 expr();
3353 skip(';');
3354 n = codeBuf.getPC();
3355 a = 0;
3356 if (tok != ';')
3357 a = test_expr();
3358 skip(';');
3359 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003360 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003361 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003362 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003363 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003364 n = t + 4;
3365 }
3366 }
3367 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003368 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003369 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003370 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003371 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003372 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003373 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003374 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003375 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003376 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003377 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003378 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003379 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003380 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003381 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003382 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003383 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003384 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003385 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003386 if (pReturnType->tag == TY_VOID) {
3387 error("Must not return a value from a void function");
3388 } else {
3389 pGen->convertR0(pReturnType);
3390 }
3391 } else {
3392 if (pReturnType->tag != TY_VOID) {
3393 error("Must specify a value here");
3394 }
Jack Palevich8df46192009-07-07 14:48:51 -07003395 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003396 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003397 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003398 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003399 } else if (tok != ';')
3400 expr();
3401 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003402 }
3403 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003404
Jack Palevich3f226492009-07-02 14:46:19 -07003405 bool typeEqual(Type* a, Type* b) {
3406 if (a == b) {
3407 return true;
3408 }
3409 if (a == NULL || b == NULL) {
3410 return false;
3411 }
3412 TypeTag at = a->tag;
3413 if (at != b->tag) {
3414 return false;
3415 }
3416 if (at == TY_POINTER) {
3417 return typeEqual(a->pHead, b->pHead);
3418 } else if (at == TY_FUNC || at == TY_PARAM) {
3419 return typeEqual(a->pHead, b->pHead)
3420 && typeEqual(a->pTail, b->pTail);
3421 }
3422 return true;
3423 }
3424
Jack Palevich86351982009-06-30 18:09:56 -07003425 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3426 assert(tag >= TY_INT && tag <= TY_PARAM);
3427 Type* pType = (Type*) arena.alloc(sizeof(Type));
3428 memset(pType, 0, sizeof(*pType));
3429 pType->tag = tag;
3430 pType->pHead = pHead;
3431 pType->pTail = pTail;
3432 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003433 }
3434
Jack Palevich3f226492009-07-02 14:46:19 -07003435 Type* createPtrType(Type* pType, Arena& arena) {
3436 return createType(TY_POINTER, pType, NULL, arena);
3437 }
3438
3439 /**
3440 * Try to print a type in declaration order
3441 */
Jack Palevich86351982009-06-30 18:09:56 -07003442 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003443 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003444 if (pType == NULL) {
3445 buffer.appendCStr("null");
3446 return;
3447 }
Jack Palevich3f226492009-07-02 14:46:19 -07003448 decodeTypeImp(buffer, pType);
3449 }
3450
3451 void decodeTypeImp(String& buffer, Type* pType) {
3452 decodeTypeImpPrefix(buffer, pType);
3453
Jack Palevich86351982009-06-30 18:09:56 -07003454 String temp;
3455 if (pType->id != 0) {
3456 decodeToken(temp, pType->id);
3457 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003458 }
3459
3460 decodeTypeImpPostfix(buffer, pType);
3461 }
3462
3463 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3464 TypeTag tag = pType->tag;
3465
3466 if (tag >= TY_INT && tag <= TY_VOID) {
3467 switch (tag) {
3468 case TY_INT:
3469 buffer.appendCStr("int");
3470 break;
3471 case TY_CHAR:
3472 buffer.appendCStr("char");
3473 break;
3474 case TY_VOID:
3475 buffer.appendCStr("void");
3476 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003477 case TY_FLOAT:
3478 buffer.appendCStr("float");
3479 break;
3480 case TY_DOUBLE:
3481 buffer.appendCStr("double");
3482 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003483 default:
3484 break;
3485 }
Jack Palevich86351982009-06-30 18:09:56 -07003486 buffer.append(' ');
3487 }
Jack Palevich3f226492009-07-02 14:46:19 -07003488
3489 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003490 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003491 break;
3492 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003493 break;
3494 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003495 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003496 case TY_FLOAT:
3497 break;
3498 case TY_DOUBLE:
3499 break;
Jack Palevich86351982009-06-30 18:09:56 -07003500 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003501 decodeTypeImpPrefix(buffer, pType->pHead);
3502 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3503 buffer.append('(');
3504 }
3505 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003506 break;
3507 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003508 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003509 break;
3510 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003511 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003512 break;
3513 default:
3514 String temp;
3515 temp.printf("Unknown tag %d", pType->tag);
3516 buffer.append(temp);
3517 break;
3518 }
Jack Palevich3f226492009-07-02 14:46:19 -07003519 }
3520
3521 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3522 TypeTag tag = pType->tag;
3523
3524 switch(tag) {
3525 case TY_POINTER:
3526 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3527 buffer.append(')');
3528 }
3529 decodeTypeImpPostfix(buffer, pType->pHead);
3530 break;
3531 case TY_FUNC:
3532 buffer.append('(');
3533 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3534 decodeTypeImp(buffer, pArg);
3535 if (pArg->pTail) {
3536 buffer.appendCStr(", ");
3537 }
3538 }
3539 buffer.append(')');
3540 break;
3541 default:
3542 break;
Jack Palevich86351982009-06-30 18:09:56 -07003543 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003544 }
3545
Jack Palevich86351982009-06-30 18:09:56 -07003546 void printType(Type* pType) {
3547 String buffer;
3548 decodeType(buffer, pType);
3549 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003550 }
3551
Jack Palevich86351982009-06-30 18:09:56 -07003552 Type* acceptPrimitiveType(Arena& arena) {
3553 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003554 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003555 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003556 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003557 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003558 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003559 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003560 } else if (tok == TOK_FLOAT) {
3561 pType = mkpFloat;
3562 } else if (tok == TOK_DOUBLE) {
3563 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003564 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003565 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003566 }
3567 next();
Jack Palevich86351982009-06-30 18:09:56 -07003568 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003569 }
3570
Jack Palevich3f226492009-07-02 14:46:19 -07003571 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3572 Arena& arena) {
3573 tokenid_t declName = 0;
3574 pType = acceptDecl2(pType, declName, nameAllowed,
3575 nameRequired, arena);
3576 if (declName) {
3577 // Clone the parent type so we can set a unique ID
3578 pType = createType(pType->tag, pType->pHead,
3579 pType->pTail, arena);
3580
Jack Palevich86351982009-06-30 18:09:56 -07003581 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003582 }
Jack Palevich3f226492009-07-02 14:46:19 -07003583 // fprintf(stderr, "Parsed a declaration: ");
3584 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003585 return pType;
3586 }
3587
Jack Palevich3f226492009-07-02 14:46:19 -07003588 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3589 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003590 if (! pType) {
3591 error("Expected a declaration");
3592 }
3593 return pType;
3594 }
3595
Jack Palevich3f226492009-07-02 14:46:19 -07003596 /* Used for accepting types that appear in casts */
3597 Type* acceptCastTypeDeclaration(Arena& arena) {
3598 Type* pType = acceptPrimitiveType(arena);
3599 if (pType) {
3600 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003601 }
Jack Palevich86351982009-06-30 18:09:56 -07003602 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003603 }
3604
Jack Palevich3f226492009-07-02 14:46:19 -07003605 Type* expectCastTypeDeclaration(Arena& arena) {
3606 Type* pType = acceptCastTypeDeclaration(arena);
3607 if (! pType) {
3608 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003609 }
Jack Palevich3f226492009-07-02 14:46:19 -07003610 return pType;
3611 }
3612
3613 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3614 bool nameAllowed, bool nameRequired, Arena& arena) {
3615 int ptrCounter = 0;
3616 while (accept('*')) {
3617 ptrCounter++;
3618 }
3619 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3620 while (ptrCounter-- > 0) {
3621 pType = createType(TY_POINTER, pType, NULL, arena);
3622 }
3623 return pType;
3624 }
3625
3626 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3627 bool nameAllowed, bool nameRequired, Arena& arena) {
3628 // direct-dcl :
3629 // name
3630 // (dcl)
3631 // direct-dcl()
3632 // direct-dcl[]
3633 Type* pNewHead = NULL;
3634 if (accept('(')) {
3635 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3636 nameRequired, arena);
3637 skip(')');
3638 } else if ((declName = acceptSymbol()) != 0) {
3639 if (nameAllowed == false && declName) {
3640 error("Symbol %s not allowed here", nameof(declName));
3641 } else if (nameRequired && ! declName) {
3642 String temp;
3643 decodeToken(temp, tok);
3644 error("Expected symbol. Got %s", temp.getUnwrapped());
3645 }
3646 }
3647 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003648 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003649 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003650 pType = createType(TY_FUNC, pType, pTail, arena);
3651 skip(')');
3652 }
Jack Palevich3f226492009-07-02 14:46:19 -07003653
3654 if (pNewHead) {
3655 Type* pA = pNewHead;
3656 while (pA->pHead) {
3657 pA = pA->pHead;
3658 }
3659 pA->pHead = pType;
3660 pType = pNewHead;
3661 }
Jack Palevich86351982009-06-30 18:09:56 -07003662 return pType;
3663 }
3664
Jack Palevich3f226492009-07-02 14:46:19 -07003665 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003666 Type* pHead = NULL;
3667 Type* pTail = NULL;
3668 for(;;) {
3669 Type* pBaseArg = acceptPrimitiveType(arena);
3670 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003671 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3672 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003673 if (pArg) {
3674 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3675 if (!pHead) {
3676 pHead = pParam;
3677 pTail = pParam;
3678 } else {
3679 pTail->pTail = pParam;
3680 pTail = pParam;
3681 }
3682 }
3683 }
3684 if (! accept(',')) {
3685 break;
3686 }
3687 }
3688 return pHead;
3689 }
3690
3691 Type* expectPrimitiveType(Arena& arena) {
3692 Type* pType = acceptPrimitiveType(arena);
3693 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003694 String buf;
3695 decodeToken(buf, tok);
3696 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003697 }
Jack Palevich86351982009-06-30 18:09:56 -07003698 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003699 }
3700
Jack Palevich86351982009-06-30 18:09:56 -07003701 void addGlobalSymbol(Type* pDecl) {
3702 tokenid_t t = pDecl->id;
3703 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003704 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003705 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003706 }
Jack Palevich86351982009-06-30 18:09:56 -07003707 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003708 }
3709
Jack Palevich86351982009-06-30 18:09:56 -07003710 void reportDuplicate(tokenid_t t) {
3711 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003712 }
3713
Jack Palevich86351982009-06-30 18:09:56 -07003714 void addLocalSymbol(Type* pDecl) {
3715 tokenid_t t = pDecl->id;
3716 if (mLocals.isDefinedAtCurrentLevel(t)) {
3717 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003718 }
Jack Palevich86351982009-06-30 18:09:56 -07003719 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003720 }
3721
Jack Palevich95727a02009-07-06 12:07:15 -07003722 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003723 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003724
Jack Palevich95727a02009-07-06 12:07:15 -07003725 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003726 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003727 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3728 if (!pDecl) {
3729 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003730 }
Jack Palevich86351982009-06-30 18:09:56 -07003731 int variableAddress = 0;
3732 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003733 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003734 loc = loc + 4;
3735 variableAddress = -loc;
3736 VI(pDecl->id)->pAddress = (void*) variableAddress;
3737 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003738 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003739 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003740 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07003741 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003742 if (tok == ',')
3743 next();
3744 }
3745 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003746 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003747 }
3748 }
3749
Jack Palevichf1728be2009-06-12 13:53:51 -07003750 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003751 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003752 }
3753
Jack Palevich569f1352009-06-29 14:29:08 -07003754 void decodeToken(String& buffer, tokenid_t token) {
3755 if (token == EOF ) {
3756 buffer.printf("EOF");
3757 } else if (token == TOK_NUM) {
3758 buffer.printf("numeric constant");
3759 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003760 if (token < 32) {
3761 buffer.printf("'\\x%02x'", token);
3762 } else {
3763 buffer.printf("'%c'", token);
3764 }
Jack Palevich569f1352009-06-29 14:29:08 -07003765 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3766 buffer.printf("keyword \"%s\"", nameof(token));
3767 } else {
3768 buffer.printf("symbol \"%s\"", nameof(token));
3769 }
3770 }
3771
Jack Palevich40600de2009-07-01 15:32:35 -07003772 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003773 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003774 if (!result) {
3775 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003776 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003777 error("Expected symbol. Got %s", temp.getUnwrapped());
3778 }
3779 return result;
3780 }
3781
Jack Palevich86351982009-06-30 18:09:56 -07003782 tokenid_t acceptSymbol() {
3783 tokenid_t result = 0;
3784 if (tok >= TOK_SYMBOL) {
3785 result = tok;
3786 next();
Jack Palevich86351982009-06-30 18:09:56 -07003787 }
3788 return result;
3789 }
3790
Jack Palevichb7c81e92009-06-04 19:56:13 -07003791 void globalDeclarations() {
3792 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003793 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3794 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003795 break;
3796 }
Jack Palevich86351982009-06-30 18:09:56 -07003797 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3798 if (!pDecl) {
3799 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003800 }
Jack Palevich86351982009-06-30 18:09:56 -07003801 if (! isDefined(pDecl->id)) {
3802 addGlobalSymbol(pDecl);
3803 }
3804 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003805 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003806 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003807 }
Jack Palevich86351982009-06-30 18:09:56 -07003808 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003809 // it's a variable declaration
3810 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003811 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003812 name->pAddress = (int*) allocGlobalSpace(
3813 pGen->alignment(name->pType),
3814 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07003815 }
Jack Palevich86351982009-06-30 18:09:56 -07003816 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003817 if (tok == TOK_NUM) {
3818 if (name) {
3819 * (int*) name->pAddress = tokc;
3820 }
3821 next();
3822 } else {
3823 error("Expected an integer constant");
3824 }
3825 }
Jack Palevich86351982009-06-30 18:09:56 -07003826 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003827 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003828 }
Jack Palevich86351982009-06-30 18:09:56 -07003829 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3830 if (!pDecl) {
3831 break;
3832 }
3833 if (! isDefined(pDecl->id)) {
3834 addGlobalSymbol(pDecl);
3835 }
3836 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003837 }
3838 skip(';');
3839 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003840 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003841 if (accept(';')) {
3842 // forward declaration.
3843 } else {
3844 if (name) {
3845 /* patch forward references (XXX: does not work for function
3846 pointers) */
3847 pGen->gsym((int) name->pForward);
3848 /* put function address */
3849 name->pAddress = (void*) codeBuf.getPC();
3850 }
3851 // Calculate stack offsets for parameters
3852 mLocals.pushLevel();
3853 intptr_t a = 8;
3854 int argCount = 0;
3855 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3856 Type* pArg = pP->pHead;
3857 addLocalSymbol(pArg);
3858 /* read param name and compute offset */
3859 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003860 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07003861 argCount++;
3862 }
3863 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003864 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003865 a = pGen->functionEntry(argCount);
3866 block(0, true);
3867 pGen->gsym(rsym);
3868 pGen->functionExit(argCount, a, loc);
3869 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003870 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003871 }
3872 }
3873 }
3874
Jack Palevich9cbd2262009-07-08 16:48:41 -07003875 char* allocGlobalSpace(size_t alignment, size_t bytes) {
3876 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
3877 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07003878 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003879 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003880 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003881 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07003882 char* result = (char*) base;
3883 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003884 return result;
3885 }
3886
Jack Palevich21a15a22009-05-11 14:49:29 -07003887 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003888 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003889 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003890 pGlobalBase = 0;
3891 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003892 if (pGen) {
3893 delete pGen;
3894 pGen = 0;
3895 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003896 if (file) {
3897 delete file;
3898 file = 0;
3899 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003900 }
3901
3902 void clear() {
3903 tok = 0;
3904 tokc = 0;
3905 tokl = 0;
3906 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003907 rsym = 0;
3908 loc = 0;
3909 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003910 dptr = 0;
3911 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 file = 0;
3913 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003914 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003915 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003916 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003917
Jack Palevich22305132009-05-13 10:58:45 -07003918 void setArchitecture(const char* architecture) {
3919 delete pGen;
3920 pGen = 0;
3921
3922 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003923#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003924 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003925 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003926 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003927#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003928#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003929 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003930 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003931 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003932#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003933 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003934 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003935 }
3936 }
3937
3938 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003939#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003940 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003941#elif defined(DEFAULT_X86_CODEGEN)
3942 pGen = new X86CodeGenerator();
3943#endif
3944 }
3945 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003946 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003947 } else {
3948 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003949 }
3950 }
3951
Jack Palevich77ae76e2009-05-10 19:59:24 -07003952public:
Jack Palevich22305132009-05-13 10:58:45 -07003953 struct args {
3954 args() {
3955 architecture = 0;
3956 }
3957 const char* architecture;
3958 };
3959
Jack Paleviche7b59062009-05-19 17:12:17 -07003960 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003961 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003962 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003963
Jack Paleviche7b59062009-05-19 17:12:17 -07003964 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003965 cleanup();
3966 }
3967
Jack Palevich1cdef202009-05-22 12:06:27 -07003968 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003969 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003970
3971 cleanup();
3972 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003973 mTokenTable.setArena(&mGlobalArena);
3974 mGlobals.setArena(&mGlobalArena);
3975 mGlobals.setTokenTable(&mTokenTable);
3976 mLocals.setArena(&mLocalArena);
3977 mLocals.setTokenTable(&mTokenTable);
3978
3979 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003980 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003981 codeBuf.init(ALLOC_SIZE);
3982 setArchitecture(NULL);
3983 if (!pGen) {
3984 return -1;
3985 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003986#ifdef PROVIDE_TRACE_CODEGEN
3987 pGen = new TraceCodeGenerator(pGen);
3988#endif
3989 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003990 pGen->init(&codeBuf);
3991 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003992 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3993 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003994 inp();
3995 next();
3996 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003997 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003998 result = pGen->finishCompile();
3999 if (result == 0) {
4000 if (mErrorBuf.len()) {
4001 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004002 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004003 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004004 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004005 }
4006
Jack Palevich86351982009-06-30 18:09:56 -07004007 void createPrimitiveTypes() {
4008 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4009 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4010 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004011 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4012 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004013 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004014 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4015 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004016 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4017 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004018 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004019 }
4020
Jack Palevicha6baa232009-06-12 11:25:59 -07004021 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004022 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004023 }
4024
Jack Palevich569f1352009-06-29 14:29:08 -07004025 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004026 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004027 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004028 }
4029
Jack Palevich569f1352009-06-29 14:29:08 -07004030 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004031 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004032 error("Undefined forward reference: %s",
4033 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004034 }
4035 return true;
4036 }
4037
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 int dump(FILE* out) {
4039 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4040 return 0;
4041 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004042
Jack Palevicha6535612009-05-13 16:24:17 -07004043 int disassemble(FILE* out) {
4044 return pGen->disassemble(out);
4045 }
4046
Jack Palevich1cdef202009-05-22 12:06:27 -07004047 /* Look through the symbol table to find a symbol.
4048 * If found, return its value.
4049 */
4050 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004051 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4052 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004053 if (pVariableInfo) {
4054 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004055 }
4056 return NULL;
4057 }
4058
Jack Palevicheedf9d22009-06-04 16:23:40 -07004059 void getPragmas(ACCsizei* actualStringCount,
4060 ACCsizei maxStringCount, ACCchar** strings) {
4061 int stringCount = mPragmaStringCount;
4062 if (actualStringCount) {
4063 *actualStringCount = stringCount;
4064 }
4065 if (stringCount > maxStringCount) {
4066 stringCount = maxStringCount;
4067 }
4068 if (strings) {
4069 char* pPragmas = mPragmas.getUnwrapped();
4070 while (stringCount-- > 0) {
4071 *strings++ = pPragmas;
4072 pPragmas += strlen(pPragmas) + 1;
4073 }
4074 }
4075 }
4076
Jack Palevichac0e95e2009-05-29 13:53:44 -07004077 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004078 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004079 }
4080
Jack Palevich77ae76e2009-05-10 19:59:24 -07004081};
4082
Jack Paleviche7b59062009-05-19 17:12:17 -07004083const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004084 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4085
Jack Paleviche7b59062009-05-19 17:12:17 -07004086const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004087 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4088 5, 5, /* ==, != */
4089 9, 10, /* &&, || */
4090 6, 7, 8, /* & ^ | */
4091 2, 2 /* ~ ! */
4092 };
4093
Jack Palevich8b0624c2009-05-20 12:12:06 -07004094#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004095FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004096#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004097
Jack Palevich8b0624c2009-05-20 12:12:06 -07004098#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004099const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004100 0x1, // ++
4101 0xff, // --
4102 0xc1af0f, // *
4103 0xf9f79991, // /
4104 0xf9f79991, // % (With manual assist to swap results)
4105 0xc801, // +
4106 0xd8f7c829, // -
4107 0xe0d391, // <<
4108 0xf8d391, // >>
4109 0xe, // <=
4110 0xd, // >=
4111 0xc, // <
4112 0xf, // >
4113 0x4, // ==
4114 0x5, // !=
4115 0x0, // &&
4116 0x1, // ||
4117 0xc821, // &
4118 0xc831, // ^
4119 0xc809, // |
4120 0xd0f7, // ~
4121 0x4 // !
4122};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004123#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004124
Jack Palevich1cdef202009-05-22 12:06:27 -07004125struct ACCscript {
4126 ACCscript() {
4127 text = 0;
4128 textLength = 0;
4129 accError = ACC_NO_ERROR;
4130 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004131
Jack Palevich1cdef202009-05-22 12:06:27 -07004132 ~ACCscript() {
4133 delete text;
4134 }
Jack Palevich546b2242009-05-13 15:10:04 -07004135
Jack Palevich1cdef202009-05-22 12:06:27 -07004136 void setError(ACCenum error) {
4137 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4138 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004139 }
4140 }
4141
Jack Palevich1cdef202009-05-22 12:06:27 -07004142 ACCenum getError() {
4143 ACCenum result = accError;
4144 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004145 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004146 }
4147
Jack Palevich1cdef202009-05-22 12:06:27 -07004148 Compiler compiler;
4149 char* text;
4150 int textLength;
4151 ACCenum accError;
4152};
4153
4154
4155extern "C"
4156ACCscript* accCreateScript() {
4157 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004158}
Jack Palevich1cdef202009-05-22 12:06:27 -07004159
4160extern "C"
4161ACCenum accGetError( ACCscript* script ) {
4162 return script->getError();
4163}
4164
4165extern "C"
4166void accDeleteScript(ACCscript* script) {
4167 delete script;
4168}
4169
4170extern "C"
4171void accScriptSource(ACCscript* script,
4172 ACCsizei count,
4173 const ACCchar ** string,
4174 const ACCint * length) {
4175 int totalLength = 0;
4176 for(int i = 0; i < count; i++) {
4177 int len = -1;
4178 const ACCchar* s = string[i];
4179 if (length) {
4180 len = length[i];
4181 }
4182 if (len < 0) {
4183 len = strlen(s);
4184 }
4185 totalLength += len;
4186 }
4187 delete script->text;
4188 char* text = new char[totalLength + 1];
4189 script->text = text;
4190 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004191 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004192 for(int i = 0; i < count; i++) {
4193 int len = -1;
4194 const ACCchar* s = string[i];
4195 if (length) {
4196 len = length[i];
4197 }
4198 if (len < 0) {
4199 len = strlen(s);
4200 }
Jack Palevich09555c72009-05-27 12:25:55 -07004201 memcpy(dest, s, len);
4202 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004203 }
4204 text[totalLength] = '\0';
4205}
4206
4207extern "C"
4208void accCompileScript(ACCscript* script) {
4209 int result = script->compiler.compile(script->text, script->textLength);
4210 if (result) {
4211 script->setError(ACC_INVALID_OPERATION);
4212 }
4213}
4214
4215extern "C"
4216void accGetScriptiv(ACCscript* script,
4217 ACCenum pname,
4218 ACCint * params) {
4219 switch (pname) {
4220 case ACC_INFO_LOG_LENGTH:
4221 *params = 0;
4222 break;
4223 }
4224}
4225
4226extern "C"
4227void accGetScriptInfoLog(ACCscript* script,
4228 ACCsizei maxLength,
4229 ACCsizei * length,
4230 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004231 char* message = script->compiler.getErrorMessage();
4232 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004233 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004234 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004235 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004236 if (infoLog && maxLength > 0) {
4237 int trimmedLength = maxLength < messageLength ?
4238 maxLength : messageLength;
4239 memcpy(infoLog, message, trimmedLength);
4240 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004241 }
4242}
4243
4244extern "C"
4245void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4246 ACCvoid ** address) {
4247 void* value = script->compiler.lookup(name);
4248 if (value) {
4249 *address = value;
4250 } else {
4251 script->setError(ACC_INVALID_VALUE);
4252 }
4253}
4254
Jack Palevicheedf9d22009-06-04 16:23:40 -07004255extern "C"
4256void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4257 ACCsizei maxStringCount, ACCchar** strings){
4258 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4259}
4260
-b master422972c2009-06-17 19:13:52 -07004261extern "C"
4262void accDisassemble(ACCscript* script) {
4263 script->compiler.disassemble(stderr);
4264}
4265
Jack Palevicheedf9d22009-06-04 16:23:40 -07004266
Jack Palevich1cdef202009-05-22 12:06:27 -07004267} // namespace acc
4268