blob: 15549c7bfa027d9bb8e8fbe78a75e5117fab2156 [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);
Jack Palevicha39749f2009-07-08 20:40:31 -07001338 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001339 }
1340
Jack Palevicha39749f2009-07-08 20:40:31 -07001341 virtual void gUnaryCmp(int op, Type* pResultType) {
1342 if (op != OP_LOGICAL_NOT) {
1343 error("Unknown unary cmp %d", op);
1344 } else {
1345 Type* pR0Type = getR0Type();
1346 TypeTag tag = collapseType(pR0Type->tag);
1347 switch(tag) {
1348 case TY_INT: {
1349 oad(0xb9, 0); /* movl $0, %ecx */
1350 int t = decodeOp(op);
1351 o(0xc139); /* cmp %eax,%ecx */
1352 li(0, NULL);
1353 o(0x0f); /* setxx %al */
1354 o(t + 0x90);
1355 o(0xc0);
1356 }
1357 break;
1358 case TY_FLOAT:
1359 case TY_DOUBLE:
1360 o(0xeed9); // fldz
1361 o(0xe9da); // fucompp
1362 o(0xe0df); // fnstsw %ax
1363 o(0x9e); // sahf
1364 o(0xc0950f); // setne %al
1365 o(0xc29a0f); // setp %dl
1366 o(0xd009); // orl %edx, %eax
1367 o(0xc0b60f); // movzbl %al, %eax
1368 o(0x01f083); // xorl $1, %eax
1369 break;
1370 default:
1371 error("genUnaryCmp unsupported type");
1372 break;
1373 }
1374 }
1375 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001376 }
1377
1378 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001379 Type* pR0Type = getR0Type();
1380 TypeTag tag = collapseType(pR0Type->tag);
1381 switch(tag) {
1382 case TY_INT:
1383 oad(0xb9, 0); /* movl $0, %ecx */
1384 o(decodeOp(op));
1385 break;
1386 case TY_FLOAT:
1387 case TY_DOUBLE:
1388 switch (op) {
1389 case OP_MINUS:
1390 o(0xe0d9); // fchs
1391 break;
1392 case OP_BIT_NOT:
1393 error("Can't apply '~' operator to a float or double.");
1394 break;
1395 default:
1396 error("Unknown unary op %d\n", op);
1397 break;
1398 }
1399 break;
1400 default:
1401 error("genUnaryOp unsupported type");
1402 break;
1403 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001404 }
1405
Jack Palevich1cdef202009-05-22 12:06:27 -07001406 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001407 Type* pR0Type = getR0Type();
1408 TypeTag r0ct = collapseType(pR0Type->tag);
1409 switch(r0ct) {
1410 case TY_INT:
1411 o(0x50); /* push %eax */
1412 break;
1413 case TY_FLOAT:
1414 o(0x50); /* push %eax */
1415 o(0x241cd9); // fstps 0(%esp)
1416 break;
1417 case TY_DOUBLE:
1418 o(0x50); /* push %eax */
1419 o(0x50); /* push %eax */
1420 o(0x241cdd); // fstpl 0(%esp)
1421 break;
1422 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001423 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07001424 break;
1425 }
Jack Palevich8df46192009-07-07 14:48:51 -07001426 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001427 }
1428
Jack Palevich9eed7a22009-07-06 17:24:34 -07001429 virtual void storeR0ToTOS(Type* pPointerType) {
1430 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001431 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001432 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001433 switch (pPointerType->pHead->tag) {
1434 case TY_INT:
1435 o(0x0189); /* movl %eax/%al, (%ecx) */
1436 break;
1437 case TY_CHAR:
1438 o(0x0188); /* movl %eax/%al, (%ecx) */
1439 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001440 case TY_FLOAT:
1441 o(0x19d9); /* fstps (%ecx) */
1442 break;
1443 case TY_DOUBLE:
1444 o(0x19dd); /* fstpl (%ecx) */
1445 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001446 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001447 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001448 break;
1449 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001450 }
1451
Jack Palevich9eed7a22009-07-06 17:24:34 -07001452 virtual void loadR0FromR0(Type* pPointerType) {
1453 assert(pPointerType->tag == TY_POINTER);
1454 switch (pPointerType->pHead->tag) {
1455 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001456 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07001457 break;
1458 case TY_CHAR:
1459 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001460 ob(0); /* add zero in code */
1461 break;
1462 case TY_FLOAT:
1463 o2(0x00d9); // flds (%eax)
1464 break;
1465 case TY_DOUBLE:
1466 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07001467 break;
1468 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001469 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001470 break;
1471 }
Jack Palevich8df46192009-07-07 14:48:51 -07001472 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001473 }
1474
Jack Palevich8df46192009-07-07 14:48:51 -07001475 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001476 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001477 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001478 }
1479
Jack Palevich9cbd2262009-07-08 16:48:41 -07001480 virtual void storeR0(int ea, Type* pType) {
1481 TypeTag tag = pType->tag;
1482 switch (tag) {
1483 case TY_INT:
1484 gmov(6, ea); /* mov %eax, EA */
1485 break;
1486 case TY_FLOAT:
1487 if (ea < -LOCAL || ea > LOCAL) {
1488 oad(0x1dd9, ea); // fstps ea
1489 } else {
1490 oad(0x9dd9, ea); // fstps ea(%ebp)
1491 }
1492 break;
1493 case TY_DOUBLE:
1494 if (ea < -LOCAL || ea > LOCAL) {
1495 oad(0x1ddd, ea); // fstpl ea
1496 } else {
1497 oad(0x9ddd, ea); // fstpl ea(%ebp)
1498 }
1499 break;
1500 default:
1501 error("Unable to store to type %d", tag);
1502 break;
1503 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001504 }
1505
Jack Palevich8df46192009-07-07 14:48:51 -07001506 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001507 TypeTag tag = collapseType(pType->tag);
1508 switch (tag) {
1509 case TY_INT:
1510 gmov(8, ea); /* mov EA, %eax */
1511 if (isIncDec) {
1512 /* Implement post-increment or post decrement.
1513 */
1514 gmov(0, ea); /* 83 ADD */
1515 o(decodeOp(op));
1516 }
1517 break;
1518 case TY_FLOAT:
1519 if (ea < -LOCAL || ea > LOCAL) {
1520 oad(0x05d9, ea); // flds ea
1521 } else {
1522 oad(0x85d9, ea); // flds ea(%ebp)
1523 }
1524 if (isIncDec) {
1525 error("inc/dec not implemented for float.");
1526 }
1527 break;
1528 case TY_DOUBLE:
1529 if (ea < -LOCAL || ea > LOCAL) {
1530 oad(0x05dd, ea); // fldl ea
1531 } else {
1532 oad(0x85dd, ea); // fldl ea(%ebp)
1533 }
1534 if (isIncDec) {
1535 error("inc/dec not implemented for double.");
1536 }
1537 break;
1538 default:
1539 error("Unable to load type %d", tag);
1540 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07001541 }
Jack Palevich8df46192009-07-07 14:48:51 -07001542 setR0Type(pType);
1543 }
1544
1545 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001546 Type* pR0Type = getR0Type();
1547 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001548 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07001549 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07001550 return;
1551 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001552 if (bitsSame(pType, pR0Type)) {
1553 // do nothing special
1554 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
1555 // do nothing special, both held in same register on x87.
1556 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07001557 TypeTag r0Tag = collapseType(pR0Type->tag);
1558 TypeTag destTag = collapseType(pType->tag);
1559 if (r0Tag == TY_INT && isFloatTag(destTag)) {
1560 // Convert R0 from int to float
1561 o(0x50); // push %eax
1562 o(0x2404DB); // fildl 0(%esp)
1563 o(0x58); // pop %eax
1564 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
1565 // Convert R0 from float to int. Complicated because
1566 // need to save and restore the rounding mode.
1567 o(0x50); // push %eax
1568 o(0x50); // push %eax
1569 o(0x02247cD9); // fnstcw 2(%esp)
1570 o(0x2444b70f); // movzwl 2(%esp), %eax
1571 o(0x02);
1572 o(0x0cb4); // movb $12, %ah
1573 o(0x24048966); // movw %ax, 0(%esp)
1574 o(0x242cd9); // fldcw 0(%esp)
1575 o(0x04245cdb); // fistpl 4(%esp)
1576 o(0x02246cd9); // fldcw 2(%esp)
1577 o(0x58); // pop %eax
1578 o(0x58); // pop %eax
1579 } else {
1580 error("Incompatible types old: %d new: %d",
1581 pR0Type->tag, pType->tag);
1582 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001583 }
1584 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001585 }
1586
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001587 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001588 return oad(0xec81, 0); /* sub $xxx, %esp */
1589 }
1590
Jack Palevich1a539db2009-07-08 13:04:41 -07001591 virtual size_t storeR0ToArg(int l) {
1592 Type* pR0Type = getR0Type();
1593 TypeTag r0ct = collapseType(pR0Type->tag);
1594 switch(r0ct) {
1595 case TY_INT:
1596 oad(0x248489, l); /* movl %eax, xxx(%esp) */
1597 return 4;
1598 case TY_FLOAT:
1599 oad(0x249CD9, l); /* fstps xxx(%esp) */
1600 return 4;
1601 case TY_DOUBLE:
1602 oad(0x249CDD, l); /* fstpl xxx(%esp) */
1603 return 8;
1604 default:
1605 assert(false);
1606 return 0;
1607 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001608 }
1609
Jack Palevich7810bc92009-05-15 14:31:47 -07001610 virtual void endFunctionCallArguments(int a, int l) {
1611 * (int*) a = l;
1612 }
1613
Jack Palevich8df46192009-07-07 14:48:51 -07001614 virtual int callForward(int symbol, Type* pFunc) {
1615 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001616 return psym(0xe8, symbol); /* call xxx */
1617 }
1618
Jack Palevich8df46192009-07-07 14:48:51 -07001619 virtual void callRelative(int t, Type* pFunc) {
1620 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001621 psym(0xe8, t); /* call xxx */
1622 }
1623
Jack Palevich8df46192009-07-07 14:48:51 -07001624 virtual void callIndirect(int l, Type* pFunc) {
1625 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07001626 oad(0x2494ff, l); /* call *xxx(%esp) */
1627 }
1628
Jack Palevich7810bc92009-05-15 14:31:47 -07001629 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1630 if (isIndirect) {
1631 l += 4;
1632 }
-b master422972c2009-06-17 19:13:52 -07001633 if (l > 0) {
1634 oad(0xc481, l); /* add $xxx, %esp */
1635 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001636 }
1637
Jack Palevicha6535612009-05-13 16:24:17 -07001638 virtual int jumpOffset() {
1639 return 5;
1640 }
1641
1642 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001643 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07001644 }
1645
Jack Paleviche7b59062009-05-19 17:12:17 -07001646 /* output a symbol and patch all calls to it */
1647 virtual void gsym(int t) {
1648 int n;
1649 int pc = getPC();
1650 while (t) {
1651 n = *(int *) t; /* next value */
1652 *(int *) t = pc - t - 4;
1653 t = n;
1654 }
1655 }
1656
Jack Palevich1cdef202009-05-22 12:06:27 -07001657 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00001658 size_t pagesize = 4096;
1659 size_t base = (size_t) getBase() & ~ (pagesize - 1);
1660 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
1661 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
1662 if (err) {
1663 error("mprotect() failed: %d", errno);
1664 }
1665 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07001666 }
1667
Jack Palevich9eed7a22009-07-06 17:24:34 -07001668 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001669 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001670 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001671 virtual size_t alignment(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001672 switch(pType->tag) {
1673 case TY_DOUBLE:
1674 return 8;
1675 default:
1676 return 4;
1677 }
1678 }
1679
1680 /**
1681 * Array element alignment (in bytes) for this type of data.
1682 */
1683 virtual size_t sizeOf(Type* pType){
1684 switch(pType->tag) {
1685 case TY_INT:
1686 return 4;
1687 case TY_CHAR:
1688 return 1;
1689 default:
1690 return 0;
1691 case TY_FLOAT:
1692 return 4;
1693 case TY_DOUBLE:
1694 return 8;
1695 case TY_POINTER:
1696 return 4;
1697 }
1698 }
1699
Jack Palevich9cbd2262009-07-08 16:48:41 -07001700 virtual size_t stackSizeOf(Type* pType) {
1701 switch(pType->tag) {
1702 case TY_DOUBLE:
1703 return 8;
1704 default:
1705 return 4;
1706 }
1707 }
1708
Jack Palevich21a15a22009-05-11 14:49:29 -07001709 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07001710
1711 /** Output 1 to 4 bytes.
1712 *
1713 */
1714 void o(int n) {
1715 /* cannot use unsigned, so we must do a hack */
1716 while (n && n != -1) {
1717 ob(n & 0xff);
1718 n = n >> 8;
1719 }
1720 }
1721
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001722 /* Output exactly 2 bytes
1723 */
1724 void o2(int n) {
1725 ob(n & 0xff);
1726 ob(0xff & (n >> 8));
1727 }
1728
Jack Paleviche7b59062009-05-19 17:12:17 -07001729 /* psym is used to put an instruction with a data field which is a
1730 reference to a symbol. It is in fact the same as oad ! */
1731 int psym(int n, int t) {
1732 return oad(n, t);
1733 }
1734
1735 /* instruction + address */
1736 int oad(int n, int t) {
1737 o(n);
1738 int result = getPC();
1739 o4(t);
1740 return result;
1741 }
1742
1743
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001744 static const int operatorHelper[];
1745
1746 int decodeOp(int op) {
1747 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001748 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07001749 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001750 }
1751 return operatorHelper[op];
1752 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001753
Jack Palevich546b2242009-05-13 15:10:04 -07001754 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001755 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00001756 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001757 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001758
1759 void setupFloatOperands() {
1760 Type* pR0Type = getR0Type();
1761 Type* pTOSType = getTOSType();
1762 TypeTag tagR0 = pR0Type->tag;
1763 TypeTag tagTOS = pTOSType->tag;
1764 bool isFloatR0 = isFloatTag(tagR0);
1765 bool isFloatTOS = isFloatTag(tagTOS);
1766 if (! isFloatR0) {
1767 // Convert R0 from int to float
1768 o(0x50); // push %eax
1769 o(0x2404DB); // fildl 0(%esp)
1770 o(0x58); // pop %eax
1771 }
1772 if (! isFloatTOS){
1773 o(0x2404DB); // fildl 0(%esp);
1774 o(0x58); // pop %eax
1775 } else {
1776 if (tagTOS == TY_FLOAT) {
1777 o(0x2404d9); // flds (%esp)
1778 o(0x58); // pop %eax
1779 } else {
1780 o(0x2404dd); // fldl (%esp)
1781 o(0x58); // pop %eax
1782 o(0x58); // pop %eax
1783 }
1784 }
1785 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001786 };
1787
Jack Paleviche7b59062009-05-19 17:12:17 -07001788#endif // PROVIDE_X86_CODEGEN
1789
Jack Palevichb67b18f2009-06-11 21:12:23 -07001790#ifdef PROVIDE_TRACE_CODEGEN
1791 class TraceCodeGenerator : public CodeGenerator {
1792 private:
1793 CodeGenerator* mpBase;
1794
1795 public:
1796 TraceCodeGenerator(CodeGenerator* pBase) {
1797 mpBase = pBase;
1798 }
1799
1800 virtual ~TraceCodeGenerator() {
1801 delete mpBase;
1802 }
1803
1804 virtual void init(CodeBuf* pCodeBuf) {
1805 mpBase->init(pCodeBuf);
1806 }
1807
1808 void setErrorSink(ErrorSink* pErrorSink) {
1809 mpBase->setErrorSink(pErrorSink);
1810 }
1811
1812 /* returns address to patch with local variable size
1813 */
1814 virtual int functionEntry(int argCount) {
1815 int result = mpBase->functionEntry(argCount);
1816 fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result);
1817 return result;
1818 }
1819
1820 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
1821 fprintf(stderr, "functionExit(%d, %d, %d)\n",
1822 argCount, localVariableAddress, localVariableSize);
1823 mpBase->functionExit(argCount, localVariableAddress, localVariableSize);
1824 }
1825
1826 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001827 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001828 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001829 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001830 }
1831
Jack Palevich1a539db2009-07-08 13:04:41 -07001832 virtual void loadFloat(int address, Type* pType) {
1833 fprintf(stderr, "loadFloat(%d, type)\n", address);
1834 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001835 }
1836
Jack Palevichb67b18f2009-06-11 21:12:23 -07001837 virtual int gjmp(int t) {
1838 int result = mpBase->gjmp(t);
1839 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
1840 return result;
1841 }
1842
1843 /* l = 0: je, l == 1: jne */
1844 virtual int gtst(bool l, int t) {
1845 int result = mpBase->gtst(l, t);
1846 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
1847 return result;
1848 }
1849
Jack Palevicha39749f2009-07-08 20:40:31 -07001850 virtual void gcmp(int op, Type* pResultType) {
1851 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
1852 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001853 }
1854
1855 virtual void genOp(int op) {
1856 fprintf(stderr, "genOp(%d)\n", op);
1857 mpBase->genOp(op);
1858 }
1859
Jack Palevich9eed7a22009-07-06 17:24:34 -07001860
Jack Palevicha39749f2009-07-08 20:40:31 -07001861 virtual void gUnaryCmp(int op, Type* pResultType) {
1862 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
1863 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001864 }
1865
1866 virtual void genUnaryOp(int op) {
1867 fprintf(stderr, "genUnaryOp(%d)\n", op);
1868 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001869 }
1870
1871 virtual void pushR0() {
1872 fprintf(stderr, "pushR0()\n");
1873 mpBase->pushR0();
1874 }
1875
Jack Palevich9eed7a22009-07-06 17:24:34 -07001876 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001877 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001878 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001879 }
1880
Jack Palevich9eed7a22009-07-06 17:24:34 -07001881 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001882 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001883 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001884 }
1885
Jack Palevich8df46192009-07-07 14:48:51 -07001886 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001887 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07001888 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001889 }
1890
Jack Palevich9cbd2262009-07-08 16:48:41 -07001891 virtual void storeR0(int ea, Type* pType) {
1892 fprintf(stderr, "storeR0(%d, pType)\n", ea);
1893 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001894 }
1895
Jack Palevich8df46192009-07-07 14:48:51 -07001896 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001897 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07001898 mpBase->loadR0(ea, isIncDec, op, pType);
1899 }
1900
1901 virtual void convertR0(Type* pType){
1902 fprintf(stderr, "convertR0(pType)\n");
1903 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001904 }
1905
1906 virtual int beginFunctionCallArguments() {
1907 int result = mpBase->beginFunctionCallArguments();
1908 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
1909 return result;
1910 }
1911
Jack Palevich1a539db2009-07-08 13:04:41 -07001912 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001913 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07001914 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001915 }
1916
1917 virtual void endFunctionCallArguments(int a, int l) {
1918 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
1919 mpBase->endFunctionCallArguments(a, l);
1920 }
1921
Jack Palevich8df46192009-07-07 14:48:51 -07001922 virtual int callForward(int symbol, Type* pFunc) {
1923 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001924 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
1925 return result;
1926 }
1927
Jack Palevich8df46192009-07-07 14:48:51 -07001928 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001929 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001930 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001931 }
1932
Jack Palevich8df46192009-07-07 14:48:51 -07001933 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07001934 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001935 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07001936 }
1937
1938 virtual void adjustStackAfterCall(int l, bool isIndirect) {
1939 fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect);
1940 mpBase->adjustStackAfterCall(l, isIndirect);
1941 }
1942
1943 virtual int jumpOffset() {
1944 return mpBase->jumpOffset();
1945 }
1946
1947 virtual int disassemble(FILE* out) {
1948 return mpBase->disassemble(out);
1949 }
1950
1951 /* output a symbol and patch all calls to it */
1952 virtual void gsym(int t) {
1953 fprintf(stderr, "gsym(%d)\n", t);
1954 mpBase->gsym(t);
1955 }
1956
1957 virtual int finishCompile() {
1958 int result = mpBase->finishCompile();
1959 fprintf(stderr, "finishCompile() = %d\n", result);
1960 return result;
1961 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001962
1963 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001964 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001965 */
Jack Palevich9cbd2262009-07-08 16:48:41 -07001966 virtual size_t alignment(Type* pType){
1967 return mpBase->alignment(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001968 }
1969
1970 /**
1971 * Array element alignment (in bytes) for this type of data.
1972 */
1973 virtual size_t sizeOf(Type* pType){
1974 return mpBase->sizeOf(pType);
1975 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001976
Jack Palevich9cbd2262009-07-08 16:48:41 -07001977
1978 virtual size_t stackSizeOf(Type* pType) {
1979 return mpBase->stackSizeOf(pType);
1980 }
1981
1982
Jack Palevich1a539db2009-07-08 13:04:41 -07001983 virtual Type* getR0Type() {
1984 return mpBase->getR0Type();
1985 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07001986 };
1987
1988#endif // PROVIDE_TRACE_CODEGEN
1989
Jack Palevich569f1352009-06-29 14:29:08 -07001990 class Arena {
1991 public:
1992 // Used to record a given allocation amount.
1993 // Used:
1994 // Mark mark = arena.mark();
1995 // ... lots of arena.allocate()
1996 // arena.free(mark);
1997
1998 struct Mark {
1999 size_t chunk;
2000 size_t offset;
2001 };
2002
2003 Arena() {
2004 mCurrentChunk = 0;
2005 Chunk start(CHUNK_SIZE);
2006 mData.push_back(start);
2007 }
2008
2009 ~Arena() {
2010 for(size_t i = 0; i < mData.size(); i++) {
2011 mData[i].free();
2012 }
2013 }
2014
2015 // Alloc using the standard alignment size safe for any variable
2016 void* alloc(size_t size) {
2017 return alloc(size, 8);
2018 }
2019
2020 Mark mark(){
2021 Mark result;
2022 result.chunk = mCurrentChunk;
2023 result.offset = mData[mCurrentChunk].mOffset;
2024 return result;
2025 }
2026
2027 void freeToMark(const Mark& mark) {
2028 mCurrentChunk = mark.chunk;
2029 mData[mCurrentChunk].mOffset = mark.offset;
2030 }
2031
2032 private:
2033 // Allocate memory aligned to a given size
2034 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2035 // Memory is not zero filled.
2036
2037 void* alloc(size_t size, size_t alignment) {
2038 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2039 if (mCurrentChunk + 1 < mData.size()) {
2040 mCurrentChunk++;
2041 } else {
2042 size_t allocSize = CHUNK_SIZE;
2043 if (allocSize < size + alignment - 1) {
2044 allocSize = size + alignment - 1;
2045 }
2046 Chunk chunk(allocSize);
2047 mData.push_back(chunk);
2048 mCurrentChunk++;
2049 }
2050 }
2051 return mData[mCurrentChunk].allocate(size, alignment);
2052 }
2053
2054 static const size_t CHUNK_SIZE = 128*1024;
2055 // Note: this class does not deallocate its
2056 // memory when it's destroyed. It depends upon
2057 // its parent to deallocate the memory.
2058 struct Chunk {
2059 Chunk() {
2060 mpData = 0;
2061 mSize = 0;
2062 mOffset = 0;
2063 }
2064
2065 Chunk(size_t size) {
2066 mSize = size;
2067 mpData = (char*) malloc(size);
2068 mOffset = 0;
2069 }
2070
2071 ~Chunk() {
2072 // Doesn't deallocate memory.
2073 }
2074
2075 void* allocate(size_t size, size_t alignment) {
2076 size_t alignedOffset = aligned(mOffset, alignment);
2077 void* result = mpData + alignedOffset;
2078 mOffset = alignedOffset + size;
2079 return result;
2080 }
2081
2082 void free() {
2083 if (mpData) {
2084 ::free(mpData);
2085 mpData = 0;
2086 }
2087 }
2088
2089 size_t remainingCapacity(size_t alignment) {
2090 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2091 }
2092
2093 // Assume alignment is a power of two
2094 inline size_t aligned(size_t v, size_t alignment) {
2095 size_t mask = alignment-1;
2096 return (v + mask) & ~mask;
2097 }
2098
2099 char* mpData;
2100 size_t mSize;
2101 size_t mOffset;
2102 };
2103
2104 size_t mCurrentChunk;
2105
2106 Vector<Chunk> mData;
2107 };
2108
Jack Palevich569f1352009-06-29 14:29:08 -07002109 struct VariableInfo;
2110
2111 struct Token {
2112 int hash;
2113 size_t length;
2114 char* pText;
2115 tokenid_t id;
2116
2117 // Current values for the token
2118 char* mpMacroDefinition;
2119 VariableInfo* mpVariableInfo;
2120 };
2121
2122 class TokenTable {
2123 public:
2124 // Don't use 0..0xff, allows characters and operators to be tokens too.
2125
2126 static const int TOKEN_BASE = 0x100;
2127 TokenTable() {
2128 mpMap = hashmapCreate(128, hashFn, equalsFn);
2129 }
2130
2131 ~TokenTable() {
2132 hashmapFree(mpMap);
2133 }
2134
2135 void setArena(Arena* pArena) {
2136 mpArena = pArena;
2137 }
2138
2139 // Returns a token for a given string of characters.
2140 tokenid_t intern(const char* pText, size_t length) {
2141 Token probe;
2142 int hash = hashmapHash((void*) pText, length);
2143 {
2144 Token probe;
2145 probe.hash = hash;
2146 probe.length = length;
2147 probe.pText = (char*) pText;
2148 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2149 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002150 return pValue->id;
2151 }
2152 }
2153
2154 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2155 memset(pToken, 0, sizeof(*pToken));
2156 pToken->hash = hash;
2157 pToken->length = length;
2158 pToken->pText = (char*) mpArena->alloc(length + 1);
2159 memcpy(pToken->pText, pText, length);
2160 pToken->pText[length] = 0;
2161 pToken->id = mTokens.size() + TOKEN_BASE;
2162 mTokens.push_back(pToken);
2163 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002164 return pToken->id;
2165 }
2166
2167 // Return the Token for a given tokenid.
2168 Token& operator[](tokenid_t id) {
2169 return *mTokens[id - TOKEN_BASE];
2170 }
2171
2172 inline size_t size() {
2173 return mTokens.size();
2174 }
2175
2176 private:
2177
2178 static int hashFn(void* pKey) {
2179 Token* pToken = (Token*) pKey;
2180 return pToken->hash;
2181 }
2182
2183 static bool equalsFn(void* keyA, void* keyB) {
2184 Token* pTokenA = (Token*) keyA;
2185 Token* pTokenB = (Token*) keyB;
2186 // Don't need to compare hash values, they should always be equal
2187 return pTokenA->length == pTokenB->length
2188 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2189 }
2190
2191 Hashmap* mpMap;
2192 Vector<Token*> mTokens;
2193 Arena* mpArena;
2194 };
2195
Jack Palevich1cdef202009-05-22 12:06:27 -07002196 class InputStream {
2197 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002198 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002199 int getChar() {
2200 if (bumpLine) {
2201 line++;
2202 bumpLine = false;
2203 }
2204 int ch = get();
2205 if (ch == '\n') {
2206 bumpLine = true;
2207 }
2208 return ch;
2209 }
2210 int getLine() {
2211 return line;
2212 }
2213 protected:
2214 InputStream() :
2215 line(1), bumpLine(false) {
2216 }
2217 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002218 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002219 int line;
2220 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002221 };
2222
2223 class FileInputStream : public InputStream {
2224 public:
2225 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002226 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002227 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002228 FILE* f;
2229 };
2230
2231 class TextInputStream : public InputStream {
2232 public:
2233 TextInputStream(const char* text, size_t textLength)
2234 : pText(text), mTextLength(textLength), mPosition(0) {
2235 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002236
2237 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002238 virtual int get() {
2239 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2240 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002241
Jack Palevich1cdef202009-05-22 12:06:27 -07002242 const char* pText;
2243 size_t mTextLength;
2244 size_t mPosition;
2245 };
2246
Jack Palevicheedf9d22009-06-04 16:23:40 -07002247 class String {
2248 public:
2249 String() {
2250 mpBase = 0;
2251 mUsed = 0;
2252 mSize = 0;
2253 }
2254
Jack Palevich303d8ff2009-06-11 19:06:24 -07002255 String(const char* item, int len, bool adopt) {
2256 if (len < 0) {
2257 len = strlen(item);
2258 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002259 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002260 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002261 mUsed = len;
2262 mSize = len + 1;
2263 } else {
2264 mpBase = 0;
2265 mUsed = 0;
2266 mSize = 0;
2267 appendBytes(item, len);
2268 }
2269 }
2270
Jack Palevich303d8ff2009-06-11 19:06:24 -07002271 String(const String& other) {
2272 mpBase = 0;
2273 mUsed = 0;
2274 mSize = 0;
2275 appendBytes(other.getUnwrapped(), other.len());
2276 }
2277
Jack Palevicheedf9d22009-06-04 16:23:40 -07002278 ~String() {
2279 if (mpBase) {
2280 free(mpBase);
2281 }
2282 }
2283
Jack Palevicha6baa232009-06-12 11:25:59 -07002284 String& operator=(const String& other) {
2285 clear();
2286 appendBytes(other.getUnwrapped(), other.len());
2287 return *this;
2288 }
2289
Jack Palevich303d8ff2009-06-11 19:06:24 -07002290 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002291 return mpBase;
2292 }
2293
Jack Palevich303d8ff2009-06-11 19:06:24 -07002294 void clear() {
2295 mUsed = 0;
2296 if (mSize > 0) {
2297 mpBase[0] = 0;
2298 }
2299 }
2300
Jack Palevicheedf9d22009-06-04 16:23:40 -07002301 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002302 appendBytes(s, strlen(s));
2303 }
2304
2305 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002306 memcpy(ensure(n), s, n + 1);
2307 }
2308
2309 void append(char c) {
2310 * ensure(1) = c;
2311 }
2312
Jack Palevich86351982009-06-30 18:09:56 -07002313 void append(String& other) {
2314 appendBytes(other.getUnwrapped(), other.len());
2315 }
2316
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002317 char* orphan() {
2318 char* result = mpBase;
2319 mpBase = 0;
2320 mUsed = 0;
2321 mSize = 0;
2322 return result;
2323 }
2324
Jack Palevicheedf9d22009-06-04 16:23:40 -07002325 void printf(const char* fmt,...) {
2326 va_list ap;
2327 va_start(ap, fmt);
2328 vprintf(fmt, ap);
2329 va_end(ap);
2330 }
2331
2332 void vprintf(const char* fmt, va_list ap) {
2333 char* temp;
2334 int numChars = vasprintf(&temp, fmt, ap);
2335 memcpy(ensure(numChars), temp, numChars+1);
2336 free(temp);
2337 }
2338
Jack Palevich303d8ff2009-06-11 19:06:24 -07002339 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002340 return mUsed;
2341 }
2342
2343 private:
2344 char* ensure(int n) {
2345 size_t newUsed = mUsed + n;
2346 if (newUsed > mSize) {
2347 size_t newSize = mSize * 2 + 10;
2348 if (newSize < newUsed) {
2349 newSize = newUsed;
2350 }
2351 mpBase = (char*) realloc(mpBase, newSize + 1);
2352 mSize = newSize;
2353 }
2354 mpBase[newUsed] = '\0';
2355 char* result = mpBase + mUsed;
2356 mUsed = newUsed;
2357 return result;
2358 }
2359
2360 char* mpBase;
2361 size_t mUsed;
2362 size_t mSize;
2363 };
2364
Jack Palevich569f1352009-06-29 14:29:08 -07002365 void internKeywords() {
2366 // Note: order has to match TOK_ constants
2367 static const char* keywords[] = {
2368 "int",
2369 "char",
2370 "void",
2371 "if",
2372 "else",
2373 "while",
2374 "break",
2375 "return",
2376 "for",
2377 "pragma",
2378 "define",
2379 "auto",
2380 "case",
2381 "const",
2382 "continue",
2383 "default",
2384 "do",
2385 "double",
2386 "enum",
2387 "extern",
2388 "float",
2389 "goto",
2390 "long",
2391 "register",
2392 "short",
2393 "signed",
2394 "sizeof",
2395 "static",
2396 "struct",
2397 "switch",
2398 "typedef",
2399 "union",
2400 "unsigned",
2401 "volatile",
2402 "_Bool",
2403 "_Complex",
2404 "_Imaginary",
2405 "inline",
2406 "restrict",
2407 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002408
Jack Palevich569f1352009-06-29 14:29:08 -07002409 for(int i = 0; keywords[i]; i++) {
2410 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002411 }
Jack Palevich569f1352009-06-29 14:29:08 -07002412 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002413
Jack Palevich36d94142009-06-08 15:55:32 -07002414 struct InputState {
2415 InputStream* pStream;
2416 int oldCh;
2417 };
2418
Jack Palevich2db168f2009-06-11 14:29:47 -07002419 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002420 void* pAddress;
2421 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002422 tokenid_t tok;
2423 size_t level;
2424 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002425 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002426 };
2427
Jack Palevich303d8ff2009-06-11 19:06:24 -07002428 class SymbolStack {
2429 public:
2430 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002431 mpArena = 0;
2432 mpTokenTable = 0;
2433 }
2434
2435 void setArena(Arena* pArena) {
2436 mpArena = pArena;
2437 }
2438
2439 void setTokenTable(TokenTable* pTokenTable) {
2440 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002441 }
2442
2443 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002444 Mark mark;
2445 mark.mArenaMark = mpArena->mark();
2446 mark.mSymbolHead = mStack.size();
2447 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002448 }
2449
2450 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002451 // Undo any shadowing that was done:
2452 Mark mark = mLevelStack.back();
2453 mLevelStack.pop_back();
2454 while (mStack.size() > mark.mSymbolHead) {
2455 VariableInfo* pV = mStack.back();
2456 mStack.pop_back();
2457 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002458 }
Jack Palevich569f1352009-06-29 14:29:08 -07002459 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002460 }
2461
Jack Palevich569f1352009-06-29 14:29:08 -07002462 bool isDefinedAtCurrentLevel(tokenid_t tok) {
2463 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
2464 return pV && pV->level == level();
2465 }
2466
2467 VariableInfo* add(tokenid_t tok) {
2468 Token& token = (*mpTokenTable)[tok];
2469 VariableInfo* pOldV = token.mpVariableInfo;
2470 VariableInfo* pNewV =
2471 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
2472 memset(pNewV, 0, sizeof(VariableInfo));
2473 pNewV->tok = tok;
2474 pNewV->level = level();
2475 pNewV->pOldDefinition = pOldV;
2476 token.mpVariableInfo = pNewV;
2477 mStack.push_back(pNewV);
2478 return pNewV;
2479 }
2480
Jack Palevich86351982009-06-30 18:09:56 -07002481 VariableInfo* add(Type* pType) {
2482 VariableInfo* pVI = add(pType->id);
2483 pVI->pType = pType;
2484 return pVI;
2485 }
2486
Jack Palevich569f1352009-06-29 14:29:08 -07002487 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
2488 for (size_t i = 0; i < mStack.size(); i++) {
2489 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002490 break;
2491 }
2492 }
Jack Palevicha6baa232009-06-12 11:25:59 -07002493 }
2494
Jack Palevich303d8ff2009-06-11 19:06:24 -07002495 private:
Jack Palevich569f1352009-06-29 14:29:08 -07002496 inline size_t level() {
2497 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07002498 }
2499
Jack Palevich569f1352009-06-29 14:29:08 -07002500 struct Mark {
2501 Arena::Mark mArenaMark;
2502 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002503 };
2504
Jack Palevich569f1352009-06-29 14:29:08 -07002505 Arena* mpArena;
2506 TokenTable* mpTokenTable;
2507 Vector<VariableInfo*> mStack;
2508 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002509 };
Jack Palevich36d94142009-06-08 15:55:32 -07002510
2511 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07002512 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07002513 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002514 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07002515 int tokl; // token operator level
2516 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07002517 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07002518 intptr_t loc; // local variable index
2519 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07002520 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07002521 char* dptr; // Macro state: Points to macro text during macro playback.
2522 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07002523 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07002524
2525 // Arena for the duration of the compile
2526 Arena mGlobalArena;
2527 // Arena for data that's only needed when compiling a single function
2528 Arena mLocalArena;
2529
2530 TokenTable mTokenTable;
2531 SymbolStack mGlobals;
2532 SymbolStack mLocals;
2533
Jack Palevich40600de2009-07-01 15:32:35 -07002534 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07002535 Type* mkpInt; // int
2536 Type* mkpChar; // char
2537 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07002538 Type* mkpFloat;
2539 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07002540 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07002541 Type* mkpIntPtr;
2542 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07002543 Type* mkpFloatPtr;
2544 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07002545 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07002546
Jack Palevich36d94142009-06-08 15:55:32 -07002547 InputStream* file;
2548
2549 CodeBuf codeBuf;
2550 CodeGenerator* pGen;
2551
Jack Palevicheedf9d22009-06-04 16:23:40 -07002552 String mErrorBuf;
2553
Jack Palevicheedf9d22009-06-04 16:23:40 -07002554 String mPragmas;
2555 int mPragmaStringCount;
2556
Jack Palevich21a15a22009-05-11 14:49:29 -07002557 static const int ALLOC_SIZE = 99999;
2558
Jack Palevich303d8ff2009-06-11 19:06:24 -07002559 static const int TOK_DUMMY = 1;
2560 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002561 static const int TOK_NUM_FLOAT = 3;
2562 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002563
2564 // 3..255 are character and/or operators
2565
Jack Palevich2db168f2009-06-11 14:29:47 -07002566 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07002567 // Order has to match string list in "internKeywords".
2568 enum {
2569 TOK_KEYWORD = TokenTable::TOKEN_BASE,
2570 TOK_INT = TOK_KEYWORD,
2571 TOK_CHAR,
2572 TOK_VOID,
2573 TOK_IF,
2574 TOK_ELSE,
2575 TOK_WHILE,
2576 TOK_BREAK,
2577 TOK_RETURN,
2578 TOK_FOR,
2579 TOK_PRAGMA,
2580 TOK_DEFINE,
2581 TOK_AUTO,
2582 TOK_CASE,
2583 TOK_CONST,
2584 TOK_CONTINUE,
2585 TOK_DEFAULT,
2586 TOK_DO,
2587 TOK_DOUBLE,
2588 TOK_ENUM,
2589 TOK_EXTERN,
2590 TOK_FLOAT,
2591 TOK_GOTO,
2592 TOK_LONG,
2593 TOK_REGISTER,
2594 TOK_SHORT,
2595 TOK_SIGNED,
2596 TOK_SIZEOF,
2597 TOK_STATIC,
2598 TOK_STRUCT,
2599 TOK_SWITCH,
2600 TOK_TYPEDEF,
2601 TOK_UNION,
2602 TOK_UNSIGNED,
2603 TOK_VOLATILE,
2604 TOK__BOOL,
2605 TOK__COMPLEX,
2606 TOK__IMAGINARY,
2607 TOK_INLINE,
2608 TOK_RESTRICT,
2609 // Symbols start after tokens
2610 TOK_SYMBOL
2611 };
Jack Palevich21a15a22009-05-11 14:49:29 -07002612
2613 static const int LOCAL = 0x200;
2614
2615 static const int SYM_FORWARD = 0;
2616 static const int SYM_DEFINE = 1;
2617
2618 /* tokens in string heap */
2619 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07002620
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002621 static const int OP_INCREMENT = 0;
2622 static const int OP_DECREMENT = 1;
2623 static const int OP_MUL = 2;
2624 static const int OP_DIV = 3;
2625 static const int OP_MOD = 4;
2626 static const int OP_PLUS = 5;
2627 static const int OP_MINUS = 6;
2628 static const int OP_SHIFT_LEFT = 7;
2629 static const int OP_SHIFT_RIGHT = 8;
2630 static const int OP_LESS_EQUAL = 9;
2631 static const int OP_GREATER_EQUAL = 10;
2632 static const int OP_LESS = 11;
2633 static const int OP_GREATER = 12;
2634 static const int OP_EQUALS = 13;
2635 static const int OP_NOT_EQUALS = 14;
2636 static const int OP_LOGICAL_AND = 15;
2637 static const int OP_LOGICAL_OR = 16;
2638 static const int OP_BIT_AND = 17;
2639 static const int OP_BIT_XOR = 18;
2640 static const int OP_BIT_OR = 19;
2641 static const int OP_BIT_NOT = 20;
2642 static const int OP_LOGICAL_NOT = 21;
2643 static const int OP_COUNT = 22;
2644
2645 /* Operators are searched from front, the two-character operators appear
2646 * before the single-character operators with the same first character.
2647 * @ is used to pad out single-character operators.
2648 */
2649 static const char* operatorChars;
2650 static const char operatorLevel[];
2651
Jack Palevich569f1352009-06-29 14:29:08 -07002652 /* Called when we detect an internal problem. Does nothing in production.
2653 *
2654 */
2655 void internalError() {
2656 * (char*) 0 = 0;
2657 }
2658
Jack Palevich86351982009-06-30 18:09:56 -07002659 void assert(bool isTrue) {
2660 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002661 internalError();
2662 }
Jack Palevich86351982009-06-30 18:09:56 -07002663 }
2664
Jack Palevich40600de2009-07-01 15:32:35 -07002665 bool isSymbol(tokenid_t t) {
2666 return t >= TOK_SYMBOL &&
2667 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
2668 }
2669
2670 bool isSymbolOrKeyword(tokenid_t t) {
2671 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07002672 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07002673 }
2674
Jack Palevich86351982009-06-30 18:09:56 -07002675 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07002676 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002677 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
2678 if (pV && pV->tok != t) {
2679 internalError();
2680 }
2681 return pV;
2682 }
2683
2684 inline bool isDefined(tokenid_t t) {
2685 return t >= TOK_SYMBOL && VI(t) != 0;
2686 }
2687
Jack Palevich40600de2009-07-01 15:32:35 -07002688 const char* nameof(tokenid_t t) {
2689 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07002690 return mTokenTable[t].pText;
2691 }
2692
Jack Palevich21a15a22009-05-11 14:49:29 -07002693 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002694 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002695 }
2696
2697 void inp() {
2698 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002699 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002700 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002701 dptr = 0;
2702 ch = dch;
2703 }
2704 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07002705 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07002706#if 0
2707 printf("ch='%c' 0x%x\n", ch, ch);
2708#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07002709 }
2710
2711 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07002712 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07002713 }
2714
Jack Palevichb4758ff2009-06-12 12:49:14 -07002715 /* read a character constant, advances ch to after end of constant */
2716 int getq() {
2717 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07002718 if (ch == '\\') {
2719 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07002720 if (isoctal(ch)) {
2721 // 1 to 3 octal characters.
2722 val = 0;
2723 for(int i = 0; i < 3; i++) {
2724 if (isoctal(ch)) {
2725 val = (val << 3) + ch - '0';
2726 inp();
2727 }
2728 }
2729 return val;
2730 } else if (ch == 'x' || ch == 'X') {
2731 // N hex chars
2732 inp();
2733 if (! isxdigit(ch)) {
2734 error("'x' character escape requires at least one digit.");
2735 } else {
2736 val = 0;
2737 while (isxdigit(ch)) {
2738 int d = ch;
2739 if (isdigit(d)) {
2740 d -= '0';
2741 } else if (d <= 'F') {
2742 d = d - 'A' + 10;
2743 } else {
2744 d = d - 'a' + 10;
2745 }
2746 val = (val << 4) + d;
2747 inp();
2748 }
2749 }
2750 } else {
2751 int val = ch;
2752 switch (ch) {
2753 case 'a':
2754 val = '\a';
2755 break;
2756 case 'b':
2757 val = '\b';
2758 break;
2759 case 'f':
2760 val = '\f';
2761 break;
2762 case 'n':
2763 val = '\n';
2764 break;
2765 case 'r':
2766 val = '\r';
2767 break;
2768 case 't':
2769 val = '\t';
2770 break;
2771 case 'v':
2772 val = '\v';
2773 break;
2774 case '\\':
2775 val = '\\';
2776 break;
2777 case '\'':
2778 val = '\'';
2779 break;
2780 case '"':
2781 val = '"';
2782 break;
2783 case '?':
2784 val = '?';
2785 break;
2786 default:
2787 error("Undefined character escape %c", ch);
2788 break;
2789 }
2790 inp();
2791 return val;
2792 }
2793 } else {
2794 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07002795 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07002796 return val;
2797 }
2798
2799 static bool isoctal(int ch) {
2800 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07002801 }
2802
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002803 bool acceptCh(int c) {
2804 bool result = c == ch;
2805 if (result) {
2806 pdef(ch);
2807 inp();
2808 }
2809 return result;
2810 }
2811
2812 bool acceptDigitsCh() {
2813 bool result = false;
2814 while (isdigit(ch)) {
2815 result = true;
2816 pdef(ch);
2817 inp();
2818 }
2819 return result;
2820 }
2821
2822 void parseFloat() {
2823 tok = TOK_NUM_DOUBLE;
2824 // mTokenString already has the integral part of the number.
2825 acceptCh('.');
2826 acceptDigitsCh();
2827 bool doExp = true;
2828 if (acceptCh('e') || acceptCh('E')) {
2829 // Don't need to do any extra work
2830 } else if (ch == 'f' || ch == 'F') {
2831 pdef('e'); // So it can be parsed by strtof.
2832 inp();
2833 tok = TOK_NUM_FLOAT;
2834 } else {
2835 doExp = false;
2836 }
2837 if (doExp) {
2838 bool digitsRequired = acceptCh('-');
2839 bool digitsFound = acceptDigitsCh();
2840 if (digitsRequired && ! digitsFound) {
2841 error("malformed exponent");
2842 }
2843 }
2844 char* pText = mTokenString.getUnwrapped();
2845 if (tok == TOK_NUM_FLOAT) {
2846 tokd = strtof(pText, 0);
2847 } else {
2848 tokd = strtod(pText, 0);
2849 }
2850 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
2851 }
2852
Jack Palevich21a15a22009-05-11 14:49:29 -07002853 void next() {
2854 int l, a;
2855
Jack Palevich546b2242009-05-13 15:10:04 -07002856 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002857 if (ch == '#') {
2858 inp();
2859 next();
2860 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002861 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07002862 } else if (tok == TOK_PRAGMA) {
2863 doPragma();
2864 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002865 error("Unsupported preprocessor directive \"%s\"",
2866 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07002867 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002868 }
2869 inp();
2870 }
2871 tokl = 0;
2872 tok = ch;
2873 /* encode identifiers & numbers */
2874 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002875 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07002876 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002877 pdef(ch);
2878 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07002879 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002880 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002881 // Start of a numeric constant. Could be integer, float, or
2882 // double, won't know until we look further.
2883 if (ch == '.' || ch == 'e' || ch == 'e'
2884 || ch == 'f' || ch == 'F') {
2885 parseFloat();
2886 } else {
2887 // It's an integer constant
2888 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
2889 tok = TOK_NUM;
2890 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002891 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07002892 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
2893 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002894 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07002895 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
2896 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002897 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07002898 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002899 dch = ch;
2900 inp();
2901 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002902 }
2903 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002904 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07002905 inp();
2906 if (tok == '\'') {
2907 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07002908 tokc = getq();
2909 if (ch != '\'') {
2910 error("Expected a ' character, got %c", ch);
2911 } else {
2912 inp();
2913 }
Jack Palevich546b2242009-05-13 15:10:04 -07002914 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002915 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002916 while (ch && ch != EOF) {
2917 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07002918 inp();
2919 inp();
2920 if (ch == '/')
2921 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002922 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002923 if (ch == EOF) {
2924 error("End of file inside comment.");
2925 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002926 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07002927 next();
Jack Palevichbd894902009-05-14 19:35:31 -07002928 } else if ((tok == '/') & (ch == '/')) {
2929 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07002930 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07002931 inp();
2932 }
2933 inp();
2934 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07002935 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002936 const char* t = operatorChars;
2937 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07002938 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002939 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002940 tokl = operatorLevel[opIndex];
2941 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07002942 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002943#if 0
2944 printf("%c%c -> tokl=%d tokc=0x%x\n",
2945 l, a, tokl, tokc);
2946#endif
2947 if (a == ch) {
2948 inp();
2949 tok = TOK_DUMMY; /* dummy token for double tokens */
2950 }
2951 break;
2952 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002953 opIndex++;
2954 }
2955 if (l == 0) {
2956 tokl = 0;
2957 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07002958 }
2959 }
2960 }
2961#if 0
2962 {
Jack Palevich569f1352009-06-29 14:29:08 -07002963 String buf;
2964 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07002965 fprintf(stderr, "%s\n", buf.getUnwrapped());
2966 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002967#endif
2968 }
2969
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002970 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07002971 next();
2972 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002973 String* pName = new String();
2974 while (isspace(ch)) {
2975 inp();
2976 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002977 if (ch == '(') {
2978 delete pName;
2979 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07002980 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002981 }
2982 while (isspace(ch)) {
2983 inp();
2984 }
Jack Palevich569f1352009-06-29 14:29:08 -07002985 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002986 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07002987 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002988 inp();
2989 }
Jack Palevich569f1352009-06-29 14:29:08 -07002990 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
2991 memcpy(pDefn, value.getUnwrapped(), value.len());
2992 pDefn[value.len()] = 0;
2993 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002994 }
2995
Jack Palevicheedf9d22009-06-04 16:23:40 -07002996 void doPragma() {
2997 // # pragma name(val)
2998 int state = 0;
2999 while(ch != EOF && ch != '\n' && state < 10) {
3000 switch(state) {
3001 case 0:
3002 if (isspace(ch)) {
3003 inp();
3004 } else {
3005 state++;
3006 }
3007 break;
3008 case 1:
3009 if (isalnum(ch)) {
3010 mPragmas.append(ch);
3011 inp();
3012 } else if (ch == '(') {
3013 mPragmas.append(0);
3014 inp();
3015 state++;
3016 } else {
3017 state = 11;
3018 }
3019 break;
3020 case 2:
3021 if (isalnum(ch)) {
3022 mPragmas.append(ch);
3023 inp();
3024 } else if (ch == ')') {
3025 mPragmas.append(0);
3026 inp();
3027 state = 10;
3028 } else {
3029 state = 11;
3030 }
3031 break;
3032 }
3033 }
3034 if(state != 10) {
3035 error("Unexpected pragma syntax");
3036 }
3037 mPragmaStringCount += 2;
3038 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003039
Jack Palevichac0e95e2009-05-29 13:53:44 -07003040 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003041 mErrorBuf.printf("%ld: ", file->getLine());
3042 mErrorBuf.vprintf(fmt, ap);
3043 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003044 }
3045
Jack Palevich8b0624c2009-05-20 12:12:06 -07003046 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003047 if (tok != c) {
3048 error("'%c' expected", c);
3049 }
3050 next();
3051 }
3052
Jack Palevich86351982009-06-30 18:09:56 -07003053 bool accept(intptr_t c) {
3054 if (tok == c) {
3055 next();
3056 return true;
3057 }
3058 return false;
3059 }
3060
Jack Palevich40600de2009-07-01 15:32:35 -07003061 bool acceptStringLiteral() {
3062 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003063 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003064 // This while loop merges multiple adjacent string constants.
3065 while (tok == '"') {
3066 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003067 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003068 }
3069 if (ch != '"') {
3070 error("Unterminated string constant.");
3071 }
3072 inp();
3073 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003074 }
Jack Palevich40600de2009-07-01 15:32:35 -07003075 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003076 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003077 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003078 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003079
3080 return true;
3081 }
3082 return false;
3083 }
3084 /* Parse and evaluate a unary expression.
3085 * allowAssignment is true if '=' parsing wanted (quick hack)
3086 */
3087 void unary(bool allowAssignment) {
3088 intptr_t n, t, a;
3089 t = 0;
3090 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3091 if (acceptStringLiteral()) {
3092 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003093 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003094 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003095 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003096 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003097 t = tok;
3098 next();
3099 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003100 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003101 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003102 // Align to 4-byte boundary
3103 glo = (char*) (((intptr_t) glo + 3) & -4);
3104 * (float*) glo = (float) ad;
3105 pGen->loadFloat((int) glo, mkpFloat);
3106 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003107 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003108 // Align to 8-byte boundary
3109 glo = (char*) (((intptr_t) glo + 7) & -8);
3110 * (double*) glo = ad;
3111 pGen->loadFloat((int) glo, mkpDouble);
3112 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003113 } else if (c == 2) {
3114 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003115 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003116 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003117 pGen->gUnaryCmp(a, mkpInt);
3118 else if (t == '+') {
3119 // ignore unary plus.
3120 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003121 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003122 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003123 } else if (t == '(') {
3124 expr();
3125 skip(')');
3126 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07003127 /* This is a pointer dereference, but we currently only
3128 * support a pointer dereference if it's immediately
3129 * in front of a cast. So parse the cast right here.
3130 */
Jack Palevich21a15a22009-05-11 14:49:29 -07003131 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07003132 Type* pCast = expectCastTypeDeclaration(mLocalArena);
3133 // We currently only handle 3 types of cast:
3134 // (int*), (char*) , (int (*)())
3135 if(typeEqual(pCast, mkpIntPtr)) {
3136 t = TOK_INT;
3137 } else if (typeEqual(pCast, mkpCharPtr)) {
3138 t = TOK_CHAR;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003139 } else if (typeEqual(pCast, mkpFloatPtr)) {
3140 t = TOK_FLOAT;
3141 } else if (typeEqual(pCast, mkpDoublePtr)) {
3142 t = TOK_DOUBLE;
Jack Palevich3f226492009-07-02 14:46:19 -07003143 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07003144 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07003145 } else {
3146 String buffer;
3147 decodeType(buffer, pCast);
3148 error("Unsupported cast type %s", buffer.getUnwrapped());
3149 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07003150 }
3151 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07003152 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07003153 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07003154 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003155 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07003156 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003157 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003158 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003159 }
Jack Palevich3f226492009-07-02 14:46:19 -07003160 // Else we fall through to the function call below, with
3161 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003162 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003163 VariableInfo* pVI = VI(tok);
3164 pGen->leaR0((int) pVI->pAddress,
3165 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003166 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003167 } else if (t == EOF ) {
3168 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003169 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003170 // Don't have to do anything special here, the error
3171 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003172 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003173 if (!isDefined(t)) {
3174 mGlobals.add(t);
3175 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003176 }
Jack Palevich8df46192009-07-07 14:48:51 -07003177 VariableInfo* pVI = VI(t);
3178 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003179 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003180 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003181 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003182 if (tok == '(') {
3183 pVI->pType = mkpIntFn;
3184 } else {
3185 pVI->pType = mkpInt;
3186 }
Jack Palevich8df46192009-07-07 14:48:51 -07003187 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003188 }
Jack Palevich40600de2009-07-01 15:32:35 -07003189 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003190 /* assignment */
3191 next();
3192 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003193 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003194 } else if (tok != '(') {
3195 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003196 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003197 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003198 }
Jack Palevich8df46192009-07-07 14:48:51 -07003199 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003200 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003201 next();
3202 }
3203 }
3204 }
3205 }
3206
3207 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003208 if (accept('(')) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003209 Type* pArgList = NULL;
3210 VariableInfo* pVI = NULL;
3211 if (n == 1) { // Indirect function call, push address of fn.
3212 pArgList = pGen->getR0Type()->pTail;
Jack Palevich1cdef202009-05-22 12:06:27 -07003213 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003214 } else {
3215 pVI = VI(t);
3216 pArgList = pVI->pType->pTail;
3217 }
3218 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003219 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003220 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003221 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003222 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003223 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003224 if (! varArgs && !pArgList) {
3225 error ("Unexpected argument.");
3226 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003227 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003228 Type* pTargetType;
3229 if (pArgList) {
3230 pTargetType = pArgList->pHead;
3231 pArgList = pArgList->pTail;
3232 } else {
3233 pTargetType = pGen->getR0Type();
3234 if (pTargetType->tag == TY_FLOAT) {
3235 pTargetType = mkpDouble;
3236 }
3237 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003238 if (pTargetType->tag == TY_VOID) {
3239 error("Can't pass void value for argument %d",
3240 argCount + 1);
3241 } else {
3242 pGen->convertR0(pTargetType);
3243 l += pGen->storeR0ToArg(l);
3244 }
Jack Palevich95727a02009-07-06 12:07:15 -07003245 if (accept(',')) {
3246 // fine
3247 } else if ( tok != ')') {
3248 error("Expected ',' or ')'");
3249 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003250 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003251 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003252 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003253 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003254 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003255 pGen->endFunctionCallArguments(a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003256 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003257 if (!n) {
3258 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003259 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3260 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003261 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003262 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003263 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003264 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3265 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003266 }
-b master422972c2009-06-17 19:13:52 -07003267 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003268 }
3269 }
3270
Jack Palevich40600de2009-07-01 15:32:35 -07003271 /* Recursive descent parser for binary operations.
3272 */
3273 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003274 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003275 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003276 if (level-- == 1)
3277 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003278 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003279 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003280 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003281 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003282 n = tok;
3283 t = tokc;
3284 next();
3285
Jack Palevich40600de2009-07-01 15:32:35 -07003286 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003287 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003288 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003289 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003290 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003291 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003292
Jack Palevich40600de2009-07-01 15:32:35 -07003293 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003294 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003295 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003296 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003297 }
3298 }
3299 }
3300 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003301 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003302 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003303 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003304 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003305 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003306 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003307 }
3308 }
3309 }
3310
3311 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003312 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003313 }
3314
3315 int test_expr() {
3316 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003317 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003318 }
3319
Jack Palevicha6baa232009-06-12 11:25:59 -07003320 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003321 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003322
Jack Palevich95727a02009-07-06 12:07:15 -07003323 Type* pBaseType;
3324 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003325 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003326 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003327 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003328 next();
3329 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003330 a = test_expr();
3331 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003332 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003333 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003334 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003335 n = pGen->gjmp(0); /* jmp */
3336 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003337 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003338 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003339 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003340 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003341 }
Jack Palevich546b2242009-05-13 15:10:04 -07003342 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003343 t = tok;
3344 next();
3345 skip('(');
3346 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003347 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003348 a = test_expr();
3349 } else {
3350 if (tok != ';')
3351 expr();
3352 skip(';');
3353 n = codeBuf.getPC();
3354 a = 0;
3355 if (tok != ';')
3356 a = test_expr();
3357 skip(';');
3358 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003359 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003360 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003361 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003362 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003363 n = t + 4;
3364 }
3365 }
3366 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003367 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003368 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003369 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003370 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003371 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003372 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003373 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003374 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003375 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003376 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003377 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003378 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003379 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003380 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003381 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003382 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003383 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003384 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003385 if (pReturnType->tag == TY_VOID) {
3386 error("Must not return a value from a void function");
3387 } else {
3388 pGen->convertR0(pReturnType);
3389 }
3390 } else {
3391 if (pReturnType->tag != TY_VOID) {
3392 error("Must specify a value here");
3393 }
Jack Palevich8df46192009-07-07 14:48:51 -07003394 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003395 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003396 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003397 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003398 } else if (tok != ';')
3399 expr();
3400 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003401 }
3402 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003403
Jack Palevich3f226492009-07-02 14:46:19 -07003404 bool typeEqual(Type* a, Type* b) {
3405 if (a == b) {
3406 return true;
3407 }
3408 if (a == NULL || b == NULL) {
3409 return false;
3410 }
3411 TypeTag at = a->tag;
3412 if (at != b->tag) {
3413 return false;
3414 }
3415 if (at == TY_POINTER) {
3416 return typeEqual(a->pHead, b->pHead);
3417 } else if (at == TY_FUNC || at == TY_PARAM) {
3418 return typeEqual(a->pHead, b->pHead)
3419 && typeEqual(a->pTail, b->pTail);
3420 }
3421 return true;
3422 }
3423
Jack Palevich86351982009-06-30 18:09:56 -07003424 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3425 assert(tag >= TY_INT && tag <= TY_PARAM);
3426 Type* pType = (Type*) arena.alloc(sizeof(Type));
3427 memset(pType, 0, sizeof(*pType));
3428 pType->tag = tag;
3429 pType->pHead = pHead;
3430 pType->pTail = pTail;
3431 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003432 }
3433
Jack Palevich3f226492009-07-02 14:46:19 -07003434 Type* createPtrType(Type* pType, Arena& arena) {
3435 return createType(TY_POINTER, pType, NULL, arena);
3436 }
3437
3438 /**
3439 * Try to print a type in declaration order
3440 */
Jack Palevich86351982009-06-30 18:09:56 -07003441 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003442 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003443 if (pType == NULL) {
3444 buffer.appendCStr("null");
3445 return;
3446 }
Jack Palevich3f226492009-07-02 14:46:19 -07003447 decodeTypeImp(buffer, pType);
3448 }
3449
3450 void decodeTypeImp(String& buffer, Type* pType) {
3451 decodeTypeImpPrefix(buffer, pType);
3452
Jack Palevich86351982009-06-30 18:09:56 -07003453 String temp;
3454 if (pType->id != 0) {
3455 decodeToken(temp, pType->id);
3456 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003457 }
3458
3459 decodeTypeImpPostfix(buffer, pType);
3460 }
3461
3462 void decodeTypeImpPrefix(String& buffer, Type* pType) {
3463 TypeTag tag = pType->tag;
3464
3465 if (tag >= TY_INT && tag <= TY_VOID) {
3466 switch (tag) {
3467 case TY_INT:
3468 buffer.appendCStr("int");
3469 break;
3470 case TY_CHAR:
3471 buffer.appendCStr("char");
3472 break;
3473 case TY_VOID:
3474 buffer.appendCStr("void");
3475 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003476 case TY_FLOAT:
3477 buffer.appendCStr("float");
3478 break;
3479 case TY_DOUBLE:
3480 buffer.appendCStr("double");
3481 break;
Jack Palevich3f226492009-07-02 14:46:19 -07003482 default:
3483 break;
3484 }
Jack Palevich86351982009-06-30 18:09:56 -07003485 buffer.append(' ');
3486 }
Jack Palevich3f226492009-07-02 14:46:19 -07003487
3488 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07003489 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07003490 break;
3491 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07003492 break;
3493 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07003494 break;
Jack Palevich95727a02009-07-06 12:07:15 -07003495 case TY_FLOAT:
3496 break;
3497 case TY_DOUBLE:
3498 break;
Jack Palevich86351982009-06-30 18:09:56 -07003499 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07003500 decodeTypeImpPrefix(buffer, pType->pHead);
3501 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3502 buffer.append('(');
3503 }
3504 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07003505 break;
3506 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07003507 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003508 break;
3509 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07003510 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07003511 break;
3512 default:
3513 String temp;
3514 temp.printf("Unknown tag %d", pType->tag);
3515 buffer.append(temp);
3516 break;
3517 }
Jack Palevich3f226492009-07-02 14:46:19 -07003518 }
3519
3520 void decodeTypeImpPostfix(String& buffer, Type* pType) {
3521 TypeTag tag = pType->tag;
3522
3523 switch(tag) {
3524 case TY_POINTER:
3525 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
3526 buffer.append(')');
3527 }
3528 decodeTypeImpPostfix(buffer, pType->pHead);
3529 break;
3530 case TY_FUNC:
3531 buffer.append('(');
3532 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
3533 decodeTypeImp(buffer, pArg);
3534 if (pArg->pTail) {
3535 buffer.appendCStr(", ");
3536 }
3537 }
3538 buffer.append(')');
3539 break;
3540 default:
3541 break;
Jack Palevich86351982009-06-30 18:09:56 -07003542 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003543 }
3544
Jack Palevich86351982009-06-30 18:09:56 -07003545 void printType(Type* pType) {
3546 String buffer;
3547 decodeType(buffer, pType);
3548 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003549 }
3550
Jack Palevich86351982009-06-30 18:09:56 -07003551 Type* acceptPrimitiveType(Arena& arena) {
3552 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003553 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07003554 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003555 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07003556 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003557 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07003558 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07003559 } else if (tok == TOK_FLOAT) {
3560 pType = mkpFloat;
3561 } else if (tok == TOK_DOUBLE) {
3562 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003563 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003564 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003565 }
3566 next();
Jack Palevich86351982009-06-30 18:09:56 -07003567 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003568 }
3569
Jack Palevich3f226492009-07-02 14:46:19 -07003570 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
3571 Arena& arena) {
3572 tokenid_t declName = 0;
3573 pType = acceptDecl2(pType, declName, nameAllowed,
3574 nameRequired, arena);
3575 if (declName) {
3576 // Clone the parent type so we can set a unique ID
3577 pType = createType(pType->tag, pType->pHead,
3578 pType->pTail, arena);
3579
Jack Palevich86351982009-06-30 18:09:56 -07003580 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07003581 }
Jack Palevich3f226492009-07-02 14:46:19 -07003582 // fprintf(stderr, "Parsed a declaration: ");
3583 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07003584 return pType;
3585 }
3586
Jack Palevich3f226492009-07-02 14:46:19 -07003587 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
3588 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003589 if (! pType) {
3590 error("Expected a declaration");
3591 }
3592 return pType;
3593 }
3594
Jack Palevich3f226492009-07-02 14:46:19 -07003595 /* Used for accepting types that appear in casts */
3596 Type* acceptCastTypeDeclaration(Arena& arena) {
3597 Type* pType = acceptPrimitiveType(arena);
3598 if (pType) {
3599 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003600 }
Jack Palevich86351982009-06-30 18:09:56 -07003601 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003602 }
3603
Jack Palevich3f226492009-07-02 14:46:19 -07003604 Type* expectCastTypeDeclaration(Arena& arena) {
3605 Type* pType = acceptCastTypeDeclaration(arena);
3606 if (! pType) {
3607 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07003608 }
Jack Palevich3f226492009-07-02 14:46:19 -07003609 return pType;
3610 }
3611
3612 Type* acceptDecl2(Type* pType, tokenid_t& declName,
3613 bool nameAllowed, bool nameRequired, Arena& arena) {
3614 int ptrCounter = 0;
3615 while (accept('*')) {
3616 ptrCounter++;
3617 }
3618 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
3619 while (ptrCounter-- > 0) {
3620 pType = createType(TY_POINTER, pType, NULL, arena);
3621 }
3622 return pType;
3623 }
3624
3625 Type* acceptDecl3(Type* pType, tokenid_t& declName,
3626 bool nameAllowed, bool nameRequired, Arena& arena) {
3627 // direct-dcl :
3628 // name
3629 // (dcl)
3630 // direct-dcl()
3631 // direct-dcl[]
3632 Type* pNewHead = NULL;
3633 if (accept('(')) {
3634 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
3635 nameRequired, arena);
3636 skip(')');
3637 } else if ((declName = acceptSymbol()) != 0) {
3638 if (nameAllowed == false && declName) {
3639 error("Symbol %s not allowed here", nameof(declName));
3640 } else if (nameRequired && ! declName) {
3641 String temp;
3642 decodeToken(temp, tok);
3643 error("Expected symbol. Got %s", temp.getUnwrapped());
3644 }
3645 }
3646 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07003647 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07003648 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07003649 pType = createType(TY_FUNC, pType, pTail, arena);
3650 skip(')');
3651 }
Jack Palevich3f226492009-07-02 14:46:19 -07003652
3653 if (pNewHead) {
3654 Type* pA = pNewHead;
3655 while (pA->pHead) {
3656 pA = pA->pHead;
3657 }
3658 pA->pHead = pType;
3659 pType = pNewHead;
3660 }
Jack Palevich86351982009-06-30 18:09:56 -07003661 return pType;
3662 }
3663
Jack Palevich3f226492009-07-02 14:46:19 -07003664 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07003665 Type* pHead = NULL;
3666 Type* pTail = NULL;
3667 for(;;) {
3668 Type* pBaseArg = acceptPrimitiveType(arena);
3669 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07003670 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
3671 arena);
Jack Palevich86351982009-06-30 18:09:56 -07003672 if (pArg) {
3673 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
3674 if (!pHead) {
3675 pHead = pParam;
3676 pTail = pParam;
3677 } else {
3678 pTail->pTail = pParam;
3679 pTail = pParam;
3680 }
3681 }
3682 }
3683 if (! accept(',')) {
3684 break;
3685 }
3686 }
3687 return pHead;
3688 }
3689
3690 Type* expectPrimitiveType(Arena& arena) {
3691 Type* pType = acceptPrimitiveType(arena);
3692 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07003693 String buf;
3694 decodeToken(buf, tok);
3695 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07003696 }
Jack Palevich86351982009-06-30 18:09:56 -07003697 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003698 }
3699
Jack Palevich86351982009-06-30 18:09:56 -07003700 void addGlobalSymbol(Type* pDecl) {
3701 tokenid_t t = pDecl->id;
3702 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003703 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003704 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003705 }
Jack Palevich86351982009-06-30 18:09:56 -07003706 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07003707 }
3708
Jack Palevich86351982009-06-30 18:09:56 -07003709 void reportDuplicate(tokenid_t t) {
3710 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003711 }
3712
Jack Palevich86351982009-06-30 18:09:56 -07003713 void addLocalSymbol(Type* pDecl) {
3714 tokenid_t t = pDecl->id;
3715 if (mLocals.isDefinedAtCurrentLevel(t)) {
3716 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07003717 }
Jack Palevich86351982009-06-30 18:09:56 -07003718 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003719 }
3720
Jack Palevich95727a02009-07-06 12:07:15 -07003721 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003722 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003723
Jack Palevich95727a02009-07-06 12:07:15 -07003724 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003725 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003726 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
3727 if (!pDecl) {
3728 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003729 }
Jack Palevich86351982009-06-30 18:09:56 -07003730 int variableAddress = 0;
3731 addLocalSymbol(pDecl);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003732 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07003733 loc = loc + 4;
3734 variableAddress = -loc;
3735 VI(pDecl->id)->pAddress = (void*) variableAddress;
3736 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003737 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07003738 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003739 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07003740 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003741 if (tok == ',')
3742 next();
3743 }
3744 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07003745 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07003746 }
3747 }
3748
Jack Palevichf1728be2009-06-12 13:53:51 -07003749 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07003750 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003751 }
3752
Jack Palevich569f1352009-06-29 14:29:08 -07003753 void decodeToken(String& buffer, tokenid_t token) {
3754 if (token == EOF ) {
3755 buffer.printf("EOF");
3756 } else if (token == TOK_NUM) {
3757 buffer.printf("numeric constant");
3758 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07003759 if (token < 32) {
3760 buffer.printf("'\\x%02x'", token);
3761 } else {
3762 buffer.printf("'%c'", token);
3763 }
Jack Palevich569f1352009-06-29 14:29:08 -07003764 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
3765 buffer.printf("keyword \"%s\"", nameof(token));
3766 } else {
3767 buffer.printf("symbol \"%s\"", nameof(token));
3768 }
3769 }
3770
Jack Palevich40600de2009-07-01 15:32:35 -07003771 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07003772 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07003773 if (!result) {
3774 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07003775 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07003776 error("Expected symbol. Got %s", temp.getUnwrapped());
3777 }
3778 return result;
3779 }
3780
Jack Palevich86351982009-06-30 18:09:56 -07003781 tokenid_t acceptSymbol() {
3782 tokenid_t result = 0;
3783 if (tok >= TOK_SYMBOL) {
3784 result = tok;
3785 next();
Jack Palevich86351982009-06-30 18:09:56 -07003786 }
3787 return result;
3788 }
3789
Jack Palevichb7c81e92009-06-04 19:56:13 -07003790 void globalDeclarations() {
3791 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07003792 Type* pBaseType = expectPrimitiveType(mGlobalArena);
3793 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07003794 break;
3795 }
Jack Palevich86351982009-06-30 18:09:56 -07003796 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
3797 if (!pDecl) {
3798 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07003799 }
Jack Palevich86351982009-06-30 18:09:56 -07003800 if (! isDefined(pDecl->id)) {
3801 addGlobalSymbol(pDecl);
3802 }
3803 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07003804 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07003805 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07003806 }
Jack Palevich86351982009-06-30 18:09:56 -07003807 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003808 // it's a variable declaration
3809 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07003810 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003811 name->pAddress = (int*) allocGlobalSpace(
3812 pGen->alignment(name->pType),
3813 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07003814 }
Jack Palevich86351982009-06-30 18:09:56 -07003815 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07003816 if (tok == TOK_NUM) {
3817 if (name) {
3818 * (int*) name->pAddress = tokc;
3819 }
3820 next();
3821 } else {
3822 error("Expected an integer constant");
3823 }
3824 }
Jack Palevich86351982009-06-30 18:09:56 -07003825 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07003826 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07003827 }
Jack Palevich86351982009-06-30 18:09:56 -07003828 pDecl = expectDeclaration(pBaseType, mGlobalArena);
3829 if (!pDecl) {
3830 break;
3831 }
3832 if (! isDefined(pDecl->id)) {
3833 addGlobalSymbol(pDecl);
3834 }
3835 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07003836 }
3837 skip(';');
3838 } else {
Jack Palevich86351982009-06-30 18:09:56 -07003839 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07003840 if (accept(';')) {
3841 // forward declaration.
3842 } else {
3843 if (name) {
3844 /* patch forward references (XXX: does not work for function
3845 pointers) */
3846 pGen->gsym((int) name->pForward);
3847 /* put function address */
3848 name->pAddress = (void*) codeBuf.getPC();
3849 }
3850 // Calculate stack offsets for parameters
3851 mLocals.pushLevel();
3852 intptr_t a = 8;
3853 int argCount = 0;
3854 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
3855 Type* pArg = pP->pHead;
3856 addLocalSymbol(pArg);
3857 /* read param name and compute offset */
3858 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003859 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07003860 argCount++;
3861 }
3862 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07003863 pReturnType = pDecl->pHead;
Jack Palevich95727a02009-07-06 12:07:15 -07003864 a = pGen->functionEntry(argCount);
3865 block(0, true);
3866 pGen->gsym(rsym);
3867 pGen->functionExit(argCount, a, loc);
3868 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003869 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003870 }
3871 }
3872 }
3873
Jack Palevich9cbd2262009-07-08 16:48:41 -07003874 char* allocGlobalSpace(size_t alignment, size_t bytes) {
3875 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
3876 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07003877 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003878 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07003879 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003880 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07003881 char* result = (char*) base;
3882 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003883 return result;
3884 }
3885
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003887 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003888 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07003889 pGlobalBase = 0;
3890 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 if (pGen) {
3892 delete pGen;
3893 pGen = 0;
3894 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003895 if (file) {
3896 delete file;
3897 file = 0;
3898 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003899 }
3900
3901 void clear() {
3902 tok = 0;
3903 tokc = 0;
3904 tokl = 0;
3905 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003906 rsym = 0;
3907 loc = 0;
3908 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003909 dptr = 0;
3910 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003911 file = 0;
3912 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003913 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003914 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003915 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003916
Jack Palevich22305132009-05-13 10:58:45 -07003917 void setArchitecture(const char* architecture) {
3918 delete pGen;
3919 pGen = 0;
3920
3921 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003922#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003923 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003924 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003925 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003926#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07003927#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07003928 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07003929 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07003930 }
Jack Paleviche7b59062009-05-19 17:12:17 -07003931#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07003932 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003933 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07003934 }
3935 }
3936
3937 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07003938#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07003939 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07003940#elif defined(DEFAULT_X86_CODEGEN)
3941 pGen = new X86CodeGenerator();
3942#endif
3943 }
3944 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003945 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07003946 } else {
3947 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07003948 }
3949 }
3950
Jack Palevich77ae76e2009-05-10 19:59:24 -07003951public:
Jack Palevich22305132009-05-13 10:58:45 -07003952 struct args {
3953 args() {
3954 architecture = 0;
3955 }
3956 const char* architecture;
3957 };
3958
Jack Paleviche7b59062009-05-19 17:12:17 -07003959 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003960 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003961 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07003962
Jack Paleviche7b59062009-05-19 17:12:17 -07003963 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07003964 cleanup();
3965 }
3966
Jack Palevich1cdef202009-05-22 12:06:27 -07003967 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003968 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07003969
3970 cleanup();
3971 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07003972 mTokenTable.setArena(&mGlobalArena);
3973 mGlobals.setArena(&mGlobalArena);
3974 mGlobals.setTokenTable(&mTokenTable);
3975 mLocals.setArena(&mLocalArena);
3976 mLocals.setTokenTable(&mTokenTable);
3977
3978 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07003979 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07003980 codeBuf.init(ALLOC_SIZE);
3981 setArchitecture(NULL);
3982 if (!pGen) {
3983 return -1;
3984 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003985#ifdef PROVIDE_TRACE_CODEGEN
3986 pGen = new TraceCodeGenerator(pGen);
3987#endif
3988 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07003989 pGen->init(&codeBuf);
3990 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07003991 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
3992 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07003993 inp();
3994 next();
3995 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07003996 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07003997 result = pGen->finishCompile();
3998 if (result == 0) {
3999 if (mErrorBuf.len()) {
4000 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004001 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004002 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004003 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004004 }
4005
Jack Palevich86351982009-06-30 18:09:56 -07004006 void createPrimitiveTypes() {
4007 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4008 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4009 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004010 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4011 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004012 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004013 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4014 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004015 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4016 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004017 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004018 }
4019
Jack Palevicha6baa232009-06-12 11:25:59 -07004020 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004021 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004022 }
4023
Jack Palevich569f1352009-06-29 14:29:08 -07004024 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004025 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004026 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004027 }
4028
Jack Palevich569f1352009-06-29 14:29:08 -07004029 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004030 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004031 error("Undefined forward reference: %s",
4032 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004033 }
4034 return true;
4035 }
4036
Jack Palevich21a15a22009-05-11 14:49:29 -07004037 int dump(FILE* out) {
4038 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4039 return 0;
4040 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004041
Jack Palevicha6535612009-05-13 16:24:17 -07004042 int disassemble(FILE* out) {
4043 return pGen->disassemble(out);
4044 }
4045
Jack Palevich1cdef202009-05-22 12:06:27 -07004046 /* Look through the symbol table to find a symbol.
4047 * If found, return its value.
4048 */
4049 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004050 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4051 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004052 if (pVariableInfo) {
4053 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004054 }
4055 return NULL;
4056 }
4057
Jack Palevicheedf9d22009-06-04 16:23:40 -07004058 void getPragmas(ACCsizei* actualStringCount,
4059 ACCsizei maxStringCount, ACCchar** strings) {
4060 int stringCount = mPragmaStringCount;
4061 if (actualStringCount) {
4062 *actualStringCount = stringCount;
4063 }
4064 if (stringCount > maxStringCount) {
4065 stringCount = maxStringCount;
4066 }
4067 if (strings) {
4068 char* pPragmas = mPragmas.getUnwrapped();
4069 while (stringCount-- > 0) {
4070 *strings++ = pPragmas;
4071 pPragmas += strlen(pPragmas) + 1;
4072 }
4073 }
4074 }
4075
Jack Palevichac0e95e2009-05-29 13:53:44 -07004076 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004077 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004078 }
4079
Jack Palevich77ae76e2009-05-10 19:59:24 -07004080};
4081
Jack Paleviche7b59062009-05-19 17:12:17 -07004082const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004083 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4084
Jack Paleviche7b59062009-05-19 17:12:17 -07004085const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004086 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4087 5, 5, /* ==, != */
4088 9, 10, /* &&, || */
4089 6, 7, 8, /* & ^ | */
4090 2, 2 /* ~ ! */
4091 };
4092
Jack Palevich8b0624c2009-05-20 12:12:06 -07004093#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004094FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004095#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004096
Jack Palevich8b0624c2009-05-20 12:12:06 -07004097#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004098const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004099 0x1, // ++
4100 0xff, // --
4101 0xc1af0f, // *
4102 0xf9f79991, // /
4103 0xf9f79991, // % (With manual assist to swap results)
4104 0xc801, // +
4105 0xd8f7c829, // -
4106 0xe0d391, // <<
4107 0xf8d391, // >>
4108 0xe, // <=
4109 0xd, // >=
4110 0xc, // <
4111 0xf, // >
4112 0x4, // ==
4113 0x5, // !=
4114 0x0, // &&
4115 0x1, // ||
4116 0xc821, // &
4117 0xc831, // ^
4118 0xc809, // |
4119 0xd0f7, // ~
4120 0x4 // !
4121};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004122#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004123
Jack Palevich1cdef202009-05-22 12:06:27 -07004124struct ACCscript {
4125 ACCscript() {
4126 text = 0;
4127 textLength = 0;
4128 accError = ACC_NO_ERROR;
4129 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004130
Jack Palevich1cdef202009-05-22 12:06:27 -07004131 ~ACCscript() {
4132 delete text;
4133 }
Jack Palevich546b2242009-05-13 15:10:04 -07004134
Jack Palevich1cdef202009-05-22 12:06:27 -07004135 void setError(ACCenum error) {
4136 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4137 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004138 }
4139 }
4140
Jack Palevich1cdef202009-05-22 12:06:27 -07004141 ACCenum getError() {
4142 ACCenum result = accError;
4143 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004144 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004145 }
4146
Jack Palevich1cdef202009-05-22 12:06:27 -07004147 Compiler compiler;
4148 char* text;
4149 int textLength;
4150 ACCenum accError;
4151};
4152
4153
4154extern "C"
4155ACCscript* accCreateScript() {
4156 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004157}
Jack Palevich1cdef202009-05-22 12:06:27 -07004158
4159extern "C"
4160ACCenum accGetError( ACCscript* script ) {
4161 return script->getError();
4162}
4163
4164extern "C"
4165void accDeleteScript(ACCscript* script) {
4166 delete script;
4167}
4168
4169extern "C"
4170void accScriptSource(ACCscript* script,
4171 ACCsizei count,
4172 const ACCchar ** string,
4173 const ACCint * length) {
4174 int totalLength = 0;
4175 for(int i = 0; i < count; i++) {
4176 int len = -1;
4177 const ACCchar* s = string[i];
4178 if (length) {
4179 len = length[i];
4180 }
4181 if (len < 0) {
4182 len = strlen(s);
4183 }
4184 totalLength += len;
4185 }
4186 delete script->text;
4187 char* text = new char[totalLength + 1];
4188 script->text = text;
4189 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004190 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004191 for(int i = 0; i < count; i++) {
4192 int len = -1;
4193 const ACCchar* s = string[i];
4194 if (length) {
4195 len = length[i];
4196 }
4197 if (len < 0) {
4198 len = strlen(s);
4199 }
Jack Palevich09555c72009-05-27 12:25:55 -07004200 memcpy(dest, s, len);
4201 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004202 }
4203 text[totalLength] = '\0';
4204}
4205
4206extern "C"
4207void accCompileScript(ACCscript* script) {
4208 int result = script->compiler.compile(script->text, script->textLength);
4209 if (result) {
4210 script->setError(ACC_INVALID_OPERATION);
4211 }
4212}
4213
4214extern "C"
4215void accGetScriptiv(ACCscript* script,
4216 ACCenum pname,
4217 ACCint * params) {
4218 switch (pname) {
4219 case ACC_INFO_LOG_LENGTH:
4220 *params = 0;
4221 break;
4222 }
4223}
4224
4225extern "C"
4226void accGetScriptInfoLog(ACCscript* script,
4227 ACCsizei maxLength,
4228 ACCsizei * length,
4229 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004230 char* message = script->compiler.getErrorMessage();
4231 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004232 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004233 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004234 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004235 if (infoLog && maxLength > 0) {
4236 int trimmedLength = maxLength < messageLength ?
4237 maxLength : messageLength;
4238 memcpy(infoLog, message, trimmedLength);
4239 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004240 }
4241}
4242
4243extern "C"
4244void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4245 ACCvoid ** address) {
4246 void* value = script->compiler.lookup(name);
4247 if (value) {
4248 *address = value;
4249 } else {
4250 script->setError(ACC_INVALID_VALUE);
4251 }
4252}
4253
Jack Palevicheedf9d22009-06-04 16:23:40 -07004254extern "C"
4255void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4256 ACCsizei maxStringCount, ACCchar** strings){
4257 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4258}
4259
-b master422972c2009-06-17 19:13:52 -07004260extern "C"
4261void accDisassemble(ACCscript* script) {
4262 script->compiler.disassemble(stderr);
4263}
4264
Jack Palevicheedf9d22009-06-04 16:23:40 -07004265
Jack Palevich1cdef202009-05-22 12:06:27 -07004266} // namespace acc
4267