blob: 36f30a14951a6671899ba6005fc8987e9b4c65b1 [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 Palevicha8f427f2009-07-13 18:40:08 -0700272 void setTypes(Type* pInt) {
273 mkpInt = pInt;
274 }
275
Jack Palevich1cdef202009-05-22 12:06:27 -0700276 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700277 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700278 * Save the old value of the FP.
279 * Set the new value of the FP.
280 * Convert from the native platform calling convention to
281 * our stack-based calling convention. This may require
282 * pushing arguments from registers to the stack.
283 * Allocate "N" bytes of stack space. N isn't known yet, so
284 * just emit the instructions for adjusting the stack, and return
285 * the address to patch up. The patching will be done in
286 * functionExit().
287 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700288 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700289 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700290
Jack Palevich1cdef202009-05-22 12:06:27 -0700291 /* Emit a function epilog.
292 * Restore the old SP and FP register values.
293 * Return to the calling function.
294 * argCount - the number of arguments to the function.
295 * localVariableAddress - returned from functionEntry()
296 * localVariableSize - the size in bytes of the local variables.
297 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700298 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700299 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700300
Jack Palevich1cdef202009-05-22 12:06:27 -0700301 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700302 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700303
Jack Palevich1a539db2009-07-08 13:04:41 -0700304 /* Load floating point value from global address. */
305 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700306
Jack Palevich1cdef202009-05-22 12:06:27 -0700307 /* Jump to a target, and return the address of the word that
308 * holds the target data, in case it needs to be fixed up later.
309 */
Jack Palevich22305132009-05-13 10:58:45 -0700310 virtual int gjmp(int t) = 0;
311
Jack Palevich1cdef202009-05-22 12:06:27 -0700312 /* Test R0 and jump to a target if the test succeeds.
313 * l = 0: je, l == 1: jne
314 * Return the address of the word that holds the targed data, in
315 * case it needs to be fixed up later.
316 */
Jack Palevich22305132009-05-13 10:58:45 -0700317 virtual int gtst(bool l, int t) = 0;
318
Jack Palevich9eed7a22009-07-06 17:24:34 -0700319 /* Compare TOS against R0, and store the boolean result in R0.
320 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700321 * op specifies the comparison.
322 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700323 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700324
Jack Palevich9eed7a22009-07-06 17:24:34 -0700325 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700326 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700327 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 */
Jack Palevich546b2242009-05-13 15:10:04 -0700329 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700330
Jack Palevich9eed7a22009-07-06 17:24:34 -0700331 /* Compare 0 against R0, and store the boolean result in R0.
332 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700333 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700334 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700335
336 /* Perform the arithmetic op specified by op. 0 is the
337 * left argument, R0 is the right argument.
338 */
339 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700340
Jack Palevich1cdef202009-05-22 12:06:27 -0700341 /* Push R0 onto the stack.
342 */
343 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700344
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 /* Store R0 to the address stored in TOS.
346 * The TOS is popped.
347 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700348 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700350
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700352 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700353 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700354 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700355
Jack Palevich1cdef202009-05-22 12:06:27 -0700356 /* Load the absolute address of a variable to R0.
357 * If ea <= LOCAL, then this is a local variable, or an
358 * argument, addressed relative to FP.
359 * else it is an absolute global address.
360 */
Jack Palevich8df46192009-07-07 14:48:51 -0700361 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 /* Store R0 to a variable.
364 * If ea <= LOCAL, then this is a local variable, or an
365 * argument, addressed relative to FP.
366 * else it is an absolute global address.
367 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700368 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700369
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 /* load R0 from a variable.
371 * If ea <= LOCAL, then this is a local variable, or an
372 * argument, addressed relative to FP.
373 * else it is an absolute global address.
374 * If isIncDec is true, then the stored variable's value
375 * should be post-incremented or post-decremented, based
376 * on the value of op.
377 */
Jack Palevich8df46192009-07-07 14:48:51 -0700378 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
379
380 /**
381 * Convert R0 to the given type.
382 */
383 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700384
Jack Palevich1cdef202009-05-22 12:06:27 -0700385 /* Emit code to adjust the stack for a function call. Return the
386 * label for the address of the instruction that adjusts the
387 * stack size. This will be passed as argument "a" to
388 * endFunctionCallArguments.
389 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700390 virtual int beginFunctionCallArguments() = 0;
391
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700393 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700394 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700395 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700396
Jack Palevich1cdef202009-05-22 12:06:27 -0700397 /* Patch the function call preamble.
398 * a is the address returned from beginFunctionCallArguments
399 * l is the number of bytes the arguments took on the stack.
400 * Typically you would also emit code to convert the argument
401 * list into whatever the native function calling convention is.
402 * On ARM for example you would pop the first 5 arguments into
403 * R0..R4
404 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700405 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700406
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 /* Emit a call to an unknown function. The argument "symbol" needs to
408 * be stored in the location where the address should go. It forms
409 * a chain. The address will be patched later.
410 * Return the address of the word that has to be patched.
411 */
Jack Palevich8df46192009-07-07 14:48:51 -0700412 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700413
Jack Palevich1cdef202009-05-22 12:06:27 -0700414 /* Call a function using PC-relative addressing. t is the PC-relative
415 * address of the function. It has already been adjusted for the
416 * architectural jump offset, so just store it as-is.
417 */
Jack Palevich8df46192009-07-07 14:48:51 -0700418 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 /* Call a function pointer. L is the number of bytes the arguments
421 * take on the stack. The address of the function is stored at
422 * location SP + l.
423 */
Jack Palevich8df46192009-07-07 14:48:51 -0700424 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700425
Jack Palevich1cdef202009-05-22 12:06:27 -0700426 /* Adjust SP after returning from a function call. l is the
427 * number of bytes of arguments stored on the stack. isIndirect
428 * is true if this was an indirect call. (In which case the
429 * address of the function is stored at location SP + l.)
430 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700431 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700432
Jack Palevich1cdef202009-05-22 12:06:27 -0700433 /* Print a disassembly of the assembled code to out. Return
434 * non-zero if there is an error.
435 */
Jack Palevicha6535612009-05-13 16:24:17 -0700436 virtual int disassemble(FILE* out) = 0;
437
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 /* Generate a symbol at the current PC. t is the head of a
439 * linked list of addresses to patch.
440 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700441 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700442
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 /*
444 * Do any cleanup work required at the end of a compile.
445 * For example, an instruction cache might need to be
446 * invalidated.
447 * Return non-zero if there is an error.
448 */
449 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700450
Jack Palevicha6535612009-05-13 16:24:17 -0700451 /**
452 * Adjust relative branches by this amount.
453 */
454 virtual int jumpOffset() = 0;
455
Jack Palevich9eed7a22009-07-06 17:24:34 -0700456 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700457 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700458 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700459 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700460
461 /**
462 * Array element alignment (in bytes) for this type of data.
463 */
464 virtual size_t sizeOf(Type* type) = 0;
465
Jack Palevich9cbd2262009-07-08 16:48:41 -0700466 /**
467 * Stack argument size of this data type.
468 */
469 virtual size_t stackSizeOf(Type* pType) = 0;
470
Jack Palevich1a539db2009-07-08 13:04:41 -0700471 virtual Type* getR0Type() {
472 return mExpressionStack.back();
473 }
474
Jack Palevich21a15a22009-05-11 14:49:29 -0700475 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700476 /*
477 * Output a byte. Handles all values, 0..ff.
478 */
479 void ob(int n) {
480 pCodeBuf->ob(n);
481 }
482
Jack Palevich8b0624c2009-05-20 12:12:06 -0700483 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700484 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700485 }
486
Jack Palevich8b0624c2009-05-20 12:12:06 -0700487 intptr_t getBase() {
488 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700489 }
490
Jack Palevich8b0624c2009-05-20 12:12:06 -0700491 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700492 return pCodeBuf->getPC();
493 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700494
495 intptr_t getSize() {
496 return pCodeBuf->getSize();
497 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700498
499 void error(const char* fmt,...) {
500 va_list ap;
501 va_start(ap, fmt);
502 mErrorSink->verror(fmt, ap);
503 va_end(ap);
504 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505
506 void assert(bool test) {
507 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700508 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700509 error("code generator assertion failed.");
510 }
511 }
Jack Palevich8df46192009-07-07 14:48:51 -0700512
513 void setR0Type(Type* pType) {
514 mExpressionStack.back() = pType;
515 }
516
Jack Palevich8df46192009-07-07 14:48:51 -0700517 Type* getTOSType() {
518 return mExpressionStack[mExpressionStack.size()-2];
519 }
520
521 void pushType() {
522 mExpressionStack.push_back(NULL);
523 }
524
525 void popType() {
526 mExpressionStack.pop_back();
527 }
528
529 bool bitsSame(Type* pA, Type* pB) {
530 return collapseType(pA->tag) == collapseType(pB->tag);
531 }
532
533 TypeTag collapseType(TypeTag tag) {
534 static const TypeTag collapsedTag[] = {
535 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
536 TY_VOID, TY_VOID};
537 return collapsedTag[tag];
538 }
539
Jack Palevich1a539db2009-07-08 13:04:41 -0700540 TypeTag collapseTypeR0() {
541 return collapseType(getR0Type()->tag);
542 }
543
544 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700545 return isFloatTag(pType->tag);
546 }
547
548 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700549 return tag == TY_FLOAT || tag == TY_DOUBLE;
550 }
551
Jack Palevicha8f427f2009-07-13 18:40:08 -0700552 Type* mkpInt;
553
Jack Palevich21a15a22009-05-11 14:49:29 -0700554 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700555 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700557 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700558 };
559
Jack Paleviche7b59062009-05-19 17:12:17 -0700560#ifdef PROVIDE_ARM_CODEGEN
561
Jack Palevich22305132009-05-13 10:58:45 -0700562 class ARMCodeGenerator : public CodeGenerator {
563 public:
564 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700565
Jack Palevich22305132009-05-13 10:58:45 -0700566 virtual ~ARMCodeGenerator() {}
567
568 /* returns address to patch with local variable size
569 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700570 virtual int functionEntry(Type* pDecl) {
571 LOG_API("functionEntry(%d);\n", pDecl);
-b master422972c2009-06-17 19:13:52 -0700572 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700573 // sp -> arg4 arg5 ...
574 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700575 int regArgCount = calcRegArgCount(pDecl);
576 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700577 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700578 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700579 }
580 // sp -> arg0 arg1 ...
581 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700582 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700583 // sp, fp -> oldfp, retadr, arg0 arg1 ....
584 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700585 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700586 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700587 // We don't know how many local variables we are going to use,
588 // but we will round the allocation up to a multiple of
589 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700590 }
591
Jack Palevichb7718b92009-07-09 22:00:24 -0700592 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700593 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700594 // Round local variable size up to a multiple of stack alignment
595 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
596 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700597 // Patch local variable allocation code:
598 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700599 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700600 }
Jack Palevich69796b62009-05-14 15:42:26 -0700601 *(char*) (localVariableAddress) = localVariableSize;
602
603 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
604 o4(0xE1A0E00B); // mov lr, fp
605 o4(0xE59BB000); // ldr fp, [fp]
606 o4(0xE28ED004); // add sp, lr, #4
607 // sp -> retadr, arg0, ...
608 o4(0xE8BD4000); // ldmfd sp!, {lr}
609 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700610
611 // We store the PC into the lr so we can adjust the sp before
612 // returning. We need to pull off the registers we pushed
613 // earlier. We don't need to actually store them anywhere,
614 // just adjust the stack.
615 int regArgCount = calcRegArgCount(pDecl);
616 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700617 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
618 }
619 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700620 }
621
622 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700623 virtual void li(int t, Type* pType) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700624 liReg(t, 0);
Jack Palevich8df46192009-07-07 14:48:51 -0700625 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700626 }
627
Jack Palevich1a539db2009-07-08 13:04:41 -0700628 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700629 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700630 // Global, absolute address
631 o4(0xE59F0000); // ldr r0, .L1
632 o4(0xEA000000); // b .L99
633 o4(address); // .L1: .word ea
634 // .L99:
635
636 switch (pType->tag) {
637 case TY_FLOAT:
638 o4(0xE5900000); // ldr r0, [r0]
639 break;
640 case TY_DOUBLE:
641 o4(0xE1C000D0); // ldrd r0, [r0]
642 break;
643 default:
644 assert(false);
645 break;
646 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700647 }
648
Jack Palevich22305132009-05-13 10:58:45 -0700649 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700650 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700651 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700652 }
653
654 /* l = 0: je, l == 1: jne */
655 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700656 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevichb7718b92009-07-09 22:00:24 -0700657 Type* pR0Type = getR0Type();
658 TypeTag tagR0 = pR0Type->tag;
659 switch(tagR0) {
660 case TY_FLOAT:
661 callRuntime((void*) runtime_is_non_zero_f);
662 break;
663 case TY_DOUBLE:
664 callRuntime((void*) runtime_is_non_zero_d);
665 break;
666 default:
667 break;
668 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700669 o4(0xE3500000); // cmp r0,#0
670 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
671 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700672 }
673
Jack Palevicha39749f2009-07-08 20:40:31 -0700674 virtual void gcmp(int op, Type* pResultType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700675 LOG_API("gcmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700676 Type* pR0Type = getR0Type();
677 Type* pTOSType = getTOSType();
678 TypeTag tagR0 = collapseType(pR0Type->tag);
679 TypeTag tagTOS = collapseType(pTOSType->tag);
680 if (tagR0 == TY_INT && tagTOS == TY_INT) {
681 o4(0xE8BD0002); // ldmfd sp!,{r1}
682 mStackUse -= 4;
683 o4(0xE1510000); // cmp r1, r1
684 switch(op) {
685 case OP_EQUALS:
686 o4(0x03A00001); // moveq r0,#1
687 o4(0x13A00000); // movne r0,#0
688 break;
689 case OP_NOT_EQUALS:
690 o4(0x03A00000); // moveq r0,#0
691 o4(0x13A00001); // movne r0,#1
692 break;
693 case OP_LESS_EQUAL:
694 o4(0xD3A00001); // movle r0,#1
695 o4(0xC3A00000); // movgt r0,#0
696 break;
697 case OP_GREATER:
698 o4(0xD3A00000); // movle r0,#0
699 o4(0xC3A00001); // movgt r0,#1
700 break;
701 case OP_GREATER_EQUAL:
702 o4(0xA3A00001); // movge r0,#1
703 o4(0xB3A00000); // movlt r0,#0
704 break;
705 case OP_LESS:
706 o4(0xA3A00000); // movge r0,#0
707 o4(0xB3A00001); // movlt r0,#1
708 break;
709 default:
710 error("Unknown comparison op %d", op);
711 break;
712 }
713 popType();
714 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
715 setupDoubleArgs();
716 switch(op) {
717 case OP_EQUALS:
718 callRuntime((void*) runtime_cmp_eq_dd);
719 break;
720 case OP_NOT_EQUALS:
721 callRuntime((void*) runtime_cmp_ne_dd);
722 break;
723 case OP_LESS_EQUAL:
724 callRuntime((void*) runtime_cmp_le_dd);
725 break;
726 case OP_GREATER:
727 callRuntime((void*) runtime_cmp_gt_dd);
728 break;
729 case OP_GREATER_EQUAL:
730 callRuntime((void*) runtime_cmp_ge_dd);
731 break;
732 case OP_LESS:
733 callRuntime((void*) runtime_cmp_lt_dd);
734 break;
735 default:
736 error("Unknown comparison op %d", op);
737 break;
738 }
739 } else {
740 setupFloatArgs();
741 switch(op) {
742 case OP_EQUALS:
743 callRuntime((void*) runtime_cmp_eq_ff);
744 break;
745 case OP_NOT_EQUALS:
746 callRuntime((void*) runtime_cmp_ne_ff);
747 break;
748 case OP_LESS_EQUAL:
749 callRuntime((void*) runtime_cmp_le_ff);
750 break;
751 case OP_GREATER:
752 callRuntime((void*) runtime_cmp_gt_ff);
753 break;
754 case OP_GREATER_EQUAL:
755 callRuntime((void*) runtime_cmp_ge_ff);
756 break;
757 case OP_LESS:
758 callRuntime((void*) runtime_cmp_lt_ff);
759 break;
760 default:
761 error("Unknown comparison op %d", op);
762 break;
763 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700764 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700765 setR0Type(pResultType);
Jack Palevich22305132009-05-13 10:58:45 -0700766 }
767
Jack Palevich546b2242009-05-13 15:10:04 -0700768 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700769 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700770 Type* pR0Type = getR0Type();
771 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700772 TypeTag tagR0 = pR0Type->tag;
773 TypeTag tagTOS = pTOSType->tag;
774 bool isFloatR0 = isFloatTag(tagR0);
775 bool isFloatTOS = isFloatTag(tagTOS);
776 if (!isFloatR0 && !isFloatTOS) {
777 bool isPtrR0 = tagR0 == TY_POINTER;
778 bool isPtrTOS = tagTOS == TY_POINTER;
779 if (isPtrR0 || isPtrTOS) {
780 if (isPtrR0 && isPtrTOS) {
781 if (op != OP_MINUS) {
782 error("Unsupported pointer-pointer operation %d.", op);
783 }
784 if (! typeEqual(pR0Type, pTOSType)) {
785 error("Incompatible pointer types for subtraction.");
786 }
787 o4(0xE8BD0002); // ldmfd sp!,{r1}
788 o4(0xE0410000); // sub r0,r1,r0
789 popType();
790 setR0Type(mkpInt);
791 int size = sizeOf(pR0Type->pHead);
792 if (size != 1) {
793 pushR0();
794 li(size, mkpInt);
795 // TODO: Optimize for power-of-two.
796 genOp(OP_DIV);
797 }
798 } else {
799 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
800 error("Unsupported pointer-scalar operation %d", op);
801 }
802 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
803 o4(0xE8BD0002); // ldmfd sp!,{r1}
804 int size = sizeOf(pPtrType->pHead);
805 if (size != 1) {
806 // TODO: Optimize for power-of-two.
807 liReg(size, 2);
808 if (isPtrR0) {
809 o4(0x0E0010192); // mul r1,r2,r1
810 } else {
811 o4(0x0E0000092); // mul r0,r2,r0
812 }
813 }
814 switch(op) {
815 case OP_PLUS:
816 o4(0xE0810000); // add r0,r1,r0
817 break;
818 case OP_MINUS:
819 o4(0xE0410000); // sub r0,r1,r0
820 break;
821 }
822 popType();
823 setR0Type(pPtrType);
824 }
825 } else {
826 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevichb7718b92009-07-09 22:00:24 -0700827 mStackUse -= 4;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700828 switch(op) {
829 case OP_MUL:
830 o4(0x0E0000091); // mul r0,r1,r0
831 break;
832 case OP_DIV:
833 callRuntime((void*) runtime_DIV);
834 break;
835 case OP_MOD:
836 callRuntime((void*) runtime_MOD);
837 break;
838 case OP_PLUS:
839 o4(0xE0810000); // add r0,r1,r0
840 break;
841 case OP_MINUS:
842 o4(0xE0410000); // sub r0,r1,r0
843 break;
844 case OP_SHIFT_LEFT:
845 o4(0xE1A00011); // lsl r0,r1,r0
846 break;
847 case OP_SHIFT_RIGHT:
848 o4(0xE1A00051); // asr r0,r1,r0
849 break;
850 case OP_BIT_AND:
851 o4(0xE0010000); // and r0,r1,r0
852 break;
853 case OP_BIT_XOR:
854 o4(0xE0210000); // eor r0,r1,r0
855 break;
856 case OP_BIT_OR:
857 o4(0xE1810000); // orr r0,r1,r0
858 break;
859 case OP_BIT_NOT:
860 o4(0xE1E00000); // mvn r0, r0
861 break;
862 default:
863 error("Unimplemented op %d\n", op);
864 break;
865 }
866 popType();
Jack Palevichb7718b92009-07-09 22:00:24 -0700867 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700868 } else {
869 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
870 if (pResultType->tag == TY_DOUBLE) {
871 setupDoubleArgs();
872 switch(op) {
873 case OP_MUL:
874 callRuntime((void*) runtime_op_mul_dd);
875 break;
876 case OP_DIV:
877 callRuntime((void*) runtime_op_div_dd);
878 break;
879 case OP_PLUS:
880 callRuntime((void*) runtime_op_add_dd);
881 break;
882 case OP_MINUS:
883 callRuntime((void*) runtime_op_sub_dd);
884 break;
885 default:
886 error("Unsupported binary floating operation %d\n", op);
887 break;
888 }
889 } else {
890 setupFloatArgs();
891 switch(op) {
892 case OP_MUL:
893 callRuntime((void*) runtime_op_mul_ff);
894 break;
895 case OP_DIV:
896 callRuntime((void*) runtime_op_div_ff);
897 break;
898 case OP_PLUS:
899 callRuntime((void*) runtime_op_add_ff);
900 break;
901 case OP_MINUS:
902 callRuntime((void*) runtime_op_sub_ff);
903 break;
904 default:
905 error("Unsupported binary floating operation %d\n", op);
906 break;
907 }
908 }
909 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700910 }
Jack Palevich22305132009-05-13 10:58:45 -0700911 }
912
Jack Palevicha39749f2009-07-08 20:40:31 -0700913 virtual void gUnaryCmp(int op, Type* pResultType) {
914 LOG_API("gUnaryCmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700915 if (op != OP_LOGICAL_NOT) {
916 error("Unknown unary cmp %d", op);
917 } else {
918 Type* pR0Type = getR0Type();
919 TypeTag tag = collapseType(pR0Type->tag);
920 switch(tag) {
921 case TY_INT:
922 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700923 o4(0xE1510000); // cmp r1, r0
924 o4(0x03A00001); // moveq r0,#1
925 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700926 break;
927 case TY_FLOAT:
928 callRuntime((void*) runtime_is_zero_f);
929 break;
930 case TY_DOUBLE:
931 callRuntime((void*) runtime_is_zero_d);
932 break;
933 default:
934 error("gUnaryCmp unsupported type");
935 break;
936 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700937 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700938 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700939 }
940
941 virtual void genUnaryOp(int op) {
942 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700943 Type* pR0Type = getR0Type();
944 TypeTag tag = collapseType(pR0Type->tag);
945 switch(tag) {
946 case TY_INT:
947 switch(op) {
948 case OP_MINUS:
949 o4(0xE3A01000); // mov r1, #0
950 o4(0xE0410000); // sub r0,r1,r0
951 break;
952 case OP_BIT_NOT:
953 o4(0xE1E00000); // mvn r0, r0
954 break;
955 default:
956 error("Unknown unary op %d\n", op);
957 break;
958 }
959 break;
960 case TY_FLOAT:
961 case TY_DOUBLE:
962 switch (op) {
963 case OP_MINUS:
964 if (tag == TY_FLOAT) {
965 callRuntime((void*) runtime_op_neg_f);
966 } else {
967 callRuntime((void*) runtime_op_neg_d);
968 }
969 break;
970 case OP_BIT_NOT:
971 error("Can't apply '~' operator to a float or double.");
972 break;
973 default:
974 error("Unknown unary op %d\n", op);
975 break;
976 }
977 break;
978 default:
979 error("genUnaryOp unsupported type");
980 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700981 }
Jack Palevich22305132009-05-13 10:58:45 -0700982 }
983
Jack Palevich1cdef202009-05-22 12:06:27 -0700984 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700985 LOG_API("pushR0();\n");
Jack Palevichb7718b92009-07-09 22:00:24 -0700986 Type* pR0Type = getR0Type();
987 TypeTag r0ct = collapseType(pR0Type->tag);
988 if (r0ct != TY_DOUBLE) {
989 o4(0xE92D0001); // stmfd sp!,{r0}
990 mStackUse += 4;
991 } else {
992 o4(0xE92D0003); // stmfd sp!,{r0,r1}
993 mStackUse += 8;
994 }
Jack Palevich8df46192009-07-07 14:48:51 -0700995 pushType();
-b master422972c2009-06-17 19:13:52 -0700996 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700997 }
998
Jack Palevich9eed7a22009-07-06 17:24:34 -0700999 virtual void storeR0ToTOS(Type* pPointerType) {
1000 LOG_API("storeR0ToTOS(%d);\n", isInt);
1001 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001002 o4(0xE8BD0004); // ldmfd sp!,{r2}
1003 popType();
-b master422972c2009-06-17 19:13:52 -07001004 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001005 switch (pPointerType->pHead->tag) {
1006 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001007 case TY_FLOAT:
1008 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001009 break;
1010 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001011 o4(0xE5C20000); // strb r0, [r2]
1012 break;
1013 case TY_DOUBLE:
1014 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001015 break;
1016 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001017 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001018 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001019 }
Jack Palevich22305132009-05-13 10:58:45 -07001020 }
1021
Jack Palevich9eed7a22009-07-06 17:24:34 -07001022 virtual void loadR0FromR0(Type* pPointerType) {
1023 LOG_API("loadR0FromR0(%d);\n", pPointerType);
1024 assert(pPointerType->tag == TY_POINTER);
1025 switch (pPointerType->pHead->tag) {
1026 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001027 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001028 o4(0xE5900000); // ldr r0, [r0]
1029 break;
1030 case TY_CHAR:
1031 o4(0xE5D00000); // ldrb r0, [r0]
1032 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001033 case TY_DOUBLE:
1034 o4(0xE1C000D0); // ldrd r0, [r0]
1035 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001036 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001037 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001038 break;
1039 }
Jack Palevich8df46192009-07-07 14:48:51 -07001040 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001041 }
1042
Jack Palevich8df46192009-07-07 14:48:51 -07001043 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001044 LOG_API("leaR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001046 // Local, fp relative
1047 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1048 error("Offset out of range: %08x", ea);
1049 }
1050 if (ea < 0) {
1051 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1052 } else {
1053 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1054 }
Jack Palevichbd894902009-05-14 19:35:31 -07001055 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001056 // Global, absolute.
1057 o4(0xE59F0000); // ldr r0, .L1
1058 o4(0xEA000000); // b .L99
1059 o4(ea); // .L1: .word 0
1060 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001061 }
Jack Palevich8df46192009-07-07 14:48:51 -07001062 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001063 }
1064
Jack Palevich9cbd2262009-07-08 16:48:41 -07001065 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001066 LOG_API("storeR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001067 TypeTag tag = pType->tag;
1068 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001069 case TY_CHAR:
1070 if (ea > -LOCAL && ea < LOCAL) {
1071 // Local, fp relative
1072 if (ea < -4095 || ea > 4095) {
1073 error("Offset out of range: %08x", ea);
1074 }
1075 if (ea < 0) {
1076 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1077 } else {
1078 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1079 }
1080 } else{
1081 // Global, absolute
1082 o4(0xE59F1000); // ldr r1, .L1
1083 o4(0xEA000000); // b .L99
1084 o4(ea); // .L1: .word 0
1085 o4(0xE5C10000); // .L99: strb r0, [r1]
1086 }
1087 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001088 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001089 case TY_INT:
1090 case TY_FLOAT:
1091 if (ea > -LOCAL && ea < LOCAL) {
1092 // Local, fp relative
1093 if (ea < -4095 || ea > 4095) {
1094 error("Offset out of range: %08x", ea);
1095 }
1096 if (ea < 0) {
1097 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1098 } else {
1099 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1100 }
1101 } else{
1102 // Global, absolute
1103 o4(0xE59F1000); // ldr r1, .L1
1104 o4(0xEA000000); // b .L99
1105 o4(ea); // .L1: .word 0
1106 o4(0xE5810000); // .L99: str r0, [r1]
1107 }
1108 break;
1109 case TY_DOUBLE:
1110 if ((ea & 0x7) != 0) {
1111 error("double address is not aligned: %d", ea);
1112 }
1113 if (ea > -LOCAL && ea < LOCAL) {
1114 // Local, fp relative
1115 if (ea < -4095 || ea > 4095) {
1116 error("Offset out of range: %08x", ea);
1117 }
1118 if (ea < 0) {
1119 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1120 o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4]
1121#if 0
1122 // strd doesn't seem to work. Is encoding wrong?
1123 } else if (ea < 0) {
1124 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1125 } else if (ea < 256) {
1126 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1127#endif
1128 } else {
1129 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1130 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1131 }
1132 } else{
1133 // Global, absolute
1134 o4(0xE59F2000); // ldr r2, .L1
1135 o4(0xEA000000); // b .L99
1136 o4(ea); // .L1: .word 0
1137 o4(0xE1C200F0); // .L99: strd r0, [r2]
1138 }
1139 break;
1140 default:
1141 error("Unable to store to type %d", tag);
1142 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001143 }
Jack Palevich22305132009-05-13 10:58:45 -07001144 }
1145
Jack Palevich8df46192009-07-07 14:48:51 -07001146 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001147 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich25c0cca2009-07-13 16:56:28 -07001148 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001150 case TY_CHAR:
1151 if (ea < LOCAL) {
1152 // Local, fp relative
1153 if (ea < -4095 || ea > 4095) {
1154 error("Offset out of range: %08x", ea);
1155 }
1156 if (ea < 0) {
1157 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1158 } else {
1159 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1160 }
1161 } else {
1162 // Global, absolute
1163 o4(0xE59F2000); // ldr r2, .L1
1164 o4(0xEA000000); // b .L99
1165 o4(ea); // .L1: .word ea
1166 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1167 }
1168
1169 if (isIncDec) {
1170 error("inc/dec not implemented for char.");
1171 }
1172 break;
1173 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001174 case TY_INT:
1175 case TY_FLOAT:
1176 if (ea < LOCAL) {
1177 // Local, fp relative
1178 if (ea < -4095 || ea > 4095) {
1179 error("Offset out of range: %08x", ea);
1180 }
1181 if (ea < 0) {
1182 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1183 } else {
1184 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1185 }
1186 } else {
1187 // Global, absolute
1188 o4(0xE59F2000); // ldr r2, .L1
1189 o4(0xEA000000); // b .L99
1190 o4(ea); // .L1: .word ea
1191 o4(0xE5920000); // .L99: ldr r0, [r2]
1192 }
Jack Palevich22305132009-05-13 10:58:45 -07001193
Jack Palevichb7718b92009-07-09 22:00:24 -07001194 if (isIncDec) {
1195 if (tag == TY_INT) {
1196 switch (op) {
1197 case OP_INCREMENT:
1198 o4(0xE2801001); // add r1, r0, #1
1199 break;
1200 case OP_DECREMENT:
1201 o4(0xE2401001); // sub r1, r0, #1
1202 break;
1203 default:
1204 error("unknown opcode: %d", op);
1205 }
1206 if (ea < LOCAL) {
1207 // Local, fp relative
1208 // Don't need range check, was already checked above
1209 if (ea < 0) {
1210 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1211 } else {
1212 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1213 }
1214 } else{
1215 // Global, absolute
1216 // r2 is already set up from before.
1217 o4(0xE5821000); // str r1, [r2]
1218 }
1219 }
1220 else {
1221 error("inc/dec not implemented for float.");
1222 }
1223 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001224 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001225 case TY_DOUBLE:
1226 if ((ea & 0x7) != 0) {
1227 error("double address is not aligned: %d", ea);
1228 }
1229 if (ea < LOCAL) {
1230 // Local, fp relative
1231 if (ea < -4095 || ea > 4095) {
1232 error("Offset out of range: %08x", ea);
1233 }
1234 if (ea < 0) {
1235 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1236 o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4]
1237 } else {
1238 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1239 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1240 }
1241 } else {
1242 // Global, absolute
1243 o4(0xE59F2000); // ldr r2, .L1
1244 o4(0xEA000000); // b .L99
1245 o4(ea); // .L1: .word ea
1246 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1247 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001248 break;
1249 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001250 error("Unable to load type %d", tag);
1251 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001252 }
Jack Palevich8df46192009-07-07 14:48:51 -07001253 setR0Type(pType);
1254 }
1255
1256 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001257 Type* pR0Type = getR0Type();
1258 if (bitsSame(pType, pR0Type)) {
1259 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001260 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001261 TypeTag r0Tag = collapseType(pR0Type->tag);
1262 TypeTag destTag = collapseType(pType->tag);
1263 if (r0Tag == TY_INT) {
1264 if (destTag == TY_FLOAT) {
1265 callRuntime((void*) runtime_int_to_float);
1266 } else {
1267 assert(destTag == TY_DOUBLE);
1268 callRuntime((void*) runtime_int_to_double);
1269 }
1270 } else if (r0Tag == TY_FLOAT) {
1271 if (destTag == TY_INT) {
1272 callRuntime((void*) runtime_float_to_int);
1273 } else {
1274 assert(destTag == TY_DOUBLE);
1275 callRuntime((void*) runtime_float_to_double);
1276 }
1277 } else {
1278 assert (r0Tag == TY_DOUBLE);
1279 if (destTag == TY_INT) {
1280 callRuntime((void*) runtime_double_to_int);
1281 } else {
1282 assert(destTag == TY_FLOAT);
1283 callRuntime((void*) runtime_double_to_float);
1284 }
1285 }
Jack Palevich8df46192009-07-07 14:48:51 -07001286 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001287 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001288 }
1289
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001290 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001291 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001292 return o4(0xE24DDF00); // Placeholder
1293 }
1294
Jack Palevich1a539db2009-07-08 13:04:41 -07001295 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001296 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevichb7718b92009-07-09 22:00:24 -07001297 Type* pR0Type = getR0Type();
1298 TypeTag r0ct = collapseType(pR0Type->tag);
1299 switch(r0ct) {
1300 case TY_INT:
1301 case TY_FLOAT:
1302 if (l < 0 || l > 4096-4) {
1303 error("l out of range for stack offset: 0x%08x", l);
1304 }
1305 o4(0xE58D0000 + l); // str r0, [sp, #l]
1306 return 4;
1307 case TY_DOUBLE: {
1308 // Align to 8 byte boundary
1309 int l2 = (l + 7) & ~7;
1310 if (l2 < 0 || l2 > 4096-8) {
1311 error("l out of range for stack offset: 0x%08x", l);
1312 }
1313 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1314 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1315 return (l2 - l) + 8;
1316 }
1317 default:
1318 assert(false);
1319 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001320 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001321 }
1322
Jack Palevichb7718b92009-07-09 22:00:24 -07001323 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001324 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001325 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001326 // Have to calculate register arg count from actual stack size,
1327 // in order to properly handle ... functions.
1328 int regArgCount = l >> 2;
1329 if (regArgCount > 4) {
1330 regArgCount = 4;
1331 }
1332 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001333 argumentStackUse -= regArgCount * 4;
1334 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1335 }
1336 mStackUse += argumentStackUse;
1337
1338 // Align stack.
1339 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1340 * STACK_ALIGNMENT);
1341 mStackAlignmentAdjustment = 0;
1342 if (missalignment > 0) {
1343 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1344 }
1345 l += mStackAlignmentAdjustment;
1346
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001347 if (l < 0 || l > 0x3FC) {
1348 error("L out of range for stack adjustment: 0x%08x", l);
1349 }
1350 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001351 mStackUse += mStackAlignmentAdjustment;
1352 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1353 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001354 }
1355
Jack Palevich8df46192009-07-07 14:48:51 -07001356 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001357 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001358 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001359 // Forward calls are always short (local)
1360 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001361 }
1362
Jack Palevich8df46192009-07-07 14:48:51 -07001363 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001364 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001365 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001366 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001367 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001368 if (t >= - (1 << 25) && t < (1 << 25)) {
1369 o4(0xEB000000 | encodeAddress(t));
1370 } else {
1371 // Long call.
1372 o4(0xE59FC000); // ldr r12, .L1
1373 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001374 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001375 o4(0xE08CC00F); // .L99: add r12,pc
1376 o4(0xE12FFF3C); // blx r12
1377 }
Jack Palevich22305132009-05-13 10:58:45 -07001378 }
1379
Jack Palevich8df46192009-07-07 14:48:51 -07001380 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001381 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001382 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001383 int argCount = l >> 2;
1384 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001385 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001386 if (adjustedL < 0 || adjustedL > 4096-4) {
1387 error("l out of range for stack offset: 0x%08x", l);
1388 }
1389 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1390 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001391 }
1392
Jack Palevichb7718b92009-07-09 22:00:24 -07001393 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001394 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001395 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001396 // Have to calculate register arg count from actual stack size,
1397 // in order to properly handle ... functions.
1398 int regArgCount = l >> 2;
1399 if (regArgCount > 4) {
1400 regArgCount = 4;
1401 }
1402 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001403 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1404 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001405 if (stackUse) {
1406 if (stackUse < 0 || stackUse > 255) {
1407 error("L out of range for stack adjustment: 0x%08x", l);
1408 }
1409 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001410 mStackUse -= stackUse * 4;
1411 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001412 }
Jack Palevich22305132009-05-13 10:58:45 -07001413 }
1414
Jack Palevicha6535612009-05-13 16:24:17 -07001415 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001416 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001417 }
1418
1419 /* output a symbol and patch all calls to it */
1420 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001421 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001422 int n;
1423 int base = getBase();
1424 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001425 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001426 while (t) {
1427 int data = * (int*) t;
1428 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1429 if (decodedOffset == 0) {
1430 n = 0;
1431 } else {
1432 n = base + decodedOffset; /* next value */
1433 }
1434 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1435 | encodeRelAddress(pc - t - 8);
1436 t = n;
1437 }
1438 }
1439
Jack Palevich1cdef202009-05-22 12:06:27 -07001440 virtual int finishCompile() {
1441#if defined(__arm__)
1442 const long base = long(getBase());
1443 const long curr = long(getPC());
1444 int err = cacheflush(base, curr, 0);
1445 return err;
1446#else
1447 return 0;
1448#endif
1449 }
1450
Jack Palevicha6535612009-05-13 16:24:17 -07001451 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001452#ifdef ENABLE_ARM_DISASSEMBLY
1453 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001454 disasm_interface_t di;
1455 di.di_readword = disassemble_readword;
1456 di.di_printaddr = disassemble_printaddr;
1457 di.di_printf = disassemble_printf;
1458
1459 int base = getBase();
1460 int pc = getPC();
1461 for(int i = base; i < pc; i += 4) {
1462 fprintf(out, "%08x: %08x ", i, *(int*) i);
1463 ::disasm(&di, i, 0);
1464 }
Jack Palevich09555c72009-05-27 12:25:55 -07001465#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001466 return 0;
1467 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001468
Jack Palevich9eed7a22009-07-06 17:24:34 -07001469 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001470 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001471 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001472 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001473 switch(pType->tag) {
1474 case TY_DOUBLE:
1475 return 8;
1476 default:
1477 return 4;
1478 }
1479 }
1480
1481 /**
1482 * Array element alignment (in bytes) for this type of data.
1483 */
1484 virtual size_t sizeOf(Type* pType){
1485 switch(pType->tag) {
1486 case TY_INT:
1487 return 4;
1488 case TY_CHAR:
1489 return 1;
1490 default:
1491 return 0;
1492 case TY_FLOAT:
1493 return 4;
1494 case TY_DOUBLE:
1495 return 8;
1496 case TY_POINTER:
1497 return 4;
1498 }
1499 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001500
1501 virtual size_t stackSizeOf(Type* pType) {
1502 switch(pType->tag) {
1503 case TY_DOUBLE:
1504 return 8;
1505 default:
1506 return 4;
1507 }
1508 }
1509
Jack Palevich22305132009-05-13 10:58:45 -07001510 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001511 static FILE* disasmOut;
1512
1513 static u_int
1514 disassemble_readword(u_int address)
1515 {
1516 return(*((u_int *)address));
1517 }
1518
1519 static void
1520 disassemble_printaddr(u_int address)
1521 {
1522 fprintf(disasmOut, "0x%08x", address);
1523 }
1524
1525 static void
1526 disassemble_printf(const char *fmt, ...) {
1527 va_list ap;
1528 va_start(ap, fmt);
1529 vfprintf(disasmOut, fmt, ap);
1530 va_end(ap);
1531 }
1532
1533 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1534
1535 /** Encode a relative address that might also be
1536 * a label.
1537 */
1538 int encodeAddress(int value) {
1539 int base = getBase();
1540 if (value >= base && value <= getPC() ) {
1541 // This is a label, encode it relative to the base.
1542 value = value - base;
1543 }
1544 return encodeRelAddress(value);
1545 }
1546
1547 int encodeRelAddress(int value) {
1548 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1549 }
Jack Palevich22305132009-05-13 10:58:45 -07001550
Jack Palevichb7718b92009-07-09 22:00:24 -07001551 int calcRegArgCount(Type* pDecl) {
1552 int reg = 0;
1553 Type* pArgs = pDecl->pTail;
1554 while (pArgs && reg < 4) {
1555 Type* pArg = pArgs->pHead;
1556 if ( pArg->tag == TY_DOUBLE) {
1557 int evenReg = (reg + 1) & ~1;
1558 if (evenReg >= 4) {
1559 break;
1560 }
1561 reg = evenReg + 2;
1562 } else {
1563 reg++;
1564 }
1565 pArgs = pArgs->pTail;
1566 }
1567 return reg;
1568 }
1569
1570 /* Pop TOS to R1
1571 * Make sure both R0 and TOS are floats. (Could be ints)
1572 * We know that at least one of R0 and TOS is already a float
1573 */
1574 void setupFloatArgs() {
1575 Type* pR0Type = getR0Type();
1576 Type* pTOSType = getTOSType();
1577 TypeTag tagR0 = collapseType(pR0Type->tag);
1578 TypeTag tagTOS = collapseType(pTOSType->tag);
1579 if (tagR0 != TY_FLOAT) {
1580 assert(tagR0 == TY_INT);
1581 callRuntime((void*) runtime_int_to_float);
1582 }
1583 if (tagTOS != TY_FLOAT) {
1584 assert(tagTOS == TY_INT);
1585 assert(tagR0 == TY_FLOAT);
1586 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1587 o4(0xE59D0004); // ldr r0, [sp, #4]
1588 callRuntime((void*) runtime_int_to_float);
1589 o4(0xE1A01000); // mov r1, r0
1590 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1591 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1592 } else {
1593 // Pop TOS
1594 o4(0xE8BD0002); // ldmfd sp!,{r1}
1595 }
1596 mStackUse -= 4;
1597 popType();
1598 }
1599
1600 /* Pop TOS into R2..R3
1601 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1602 * We know that at least one of R0 and TOS are already a double.
1603 */
1604
1605 void setupDoubleArgs() {
1606 Type* pR0Type = getR0Type();
1607 Type* pTOSType = getTOSType();
1608 TypeTag tagR0 = collapseType(pR0Type->tag);
1609 TypeTag tagTOS = collapseType(pTOSType->tag);
1610 if (tagR0 != TY_DOUBLE) {
1611 if (tagR0 == TY_INT) {
1612 callRuntime((void*) runtime_int_to_double);
1613 } else {
1614 assert(tagR0 == TY_FLOAT);
1615 callRuntime((void*) runtime_float_to_double);
1616 }
1617 }
1618 if (tagTOS != TY_DOUBLE) {
1619 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1620 o4(0xE59D0008); // ldr r0, [sp, #8]
1621 if (tagTOS == TY_INT) {
1622 callRuntime((void*) runtime_int_to_double);
1623 } else {
1624 assert(tagTOS == TY_FLOAT);
1625 callRuntime((void*) runtime_float_to_double);
1626 }
1627 o4(0xE1A02000); // mov r2, r0
1628 o4(0xE1A03001); // mov r3, r1
1629 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1630 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1631 mStackUse -= 4;
1632 } else {
1633 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1634 mStackUse -= 8;
1635 }
1636 popType();
1637 }
1638
Jack Palevicha8f427f2009-07-13 18:40:08 -07001639 void liReg(int t, int reg) {
1640 assert(reg >= 0 && reg < 16);
1641 int rN = (reg & 0xf) << 12;
1642 if (t >= 0 && t < 255) {
1643 o4((0xE3A00000 + t) | rN); // mov rN, #0
1644 } else if (t >= -256 && t < 0) {
1645 // mvn means move constant ^ ~0
1646 o4((0xE3E00001 - t) | rN); // mvn rN, #0
1647 } else {
1648 o4(0xE51F0000 | rN); // ldr rN, .L3
1649 o4(0xEA000000); // b .L99
1650 o4(t); // .L3: .word 0
1651 // .L99:
1652 }
1653 }
1654
Jack Palevichb7718b92009-07-09 22:00:24 -07001655 void callRuntime(void* fn) {
1656 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001657 o4(0xEA000000); // b .L99
1658 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001659 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001660 }
1661
Jack Palevichb7718b92009-07-09 22:00:24 -07001662 // Integer math:
1663
1664 static int runtime_DIV(int b, int a) {
1665 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001666 }
1667
Jack Palevichb7718b92009-07-09 22:00:24 -07001668 static int runtime_MOD(int b, int a) {
1669 return a % b;
1670 }
1671
1672 // Comparison to zero
1673
1674 static int runtime_is_non_zero_f(float a) {
1675 return a != 0;
1676 }
1677
1678 static int runtime_is_non_zero_d(double a) {
1679 return a != 0;
1680 }
1681
1682 // Comparison to zero
1683
1684 static int runtime_is_zero_f(float a) {
1685 return a == 0;
1686 }
1687
1688 static int runtime_is_zero_d(double a) {
1689 return a == 0;
1690 }
1691
1692 // Type conversion
1693
1694 static int runtime_float_to_int(float a) {
1695 return (int) a;
1696 }
1697
1698 static double runtime_float_to_double(float a) {
1699 return (double) a;
1700 }
1701
1702 static int runtime_double_to_int(double a) {
1703 return (int) a;
1704 }
1705
1706 static float runtime_double_to_float(double a) {
1707 return (float) a;
1708 }
1709
1710 static float runtime_int_to_float(int a) {
1711 return (float) a;
1712 }
1713
1714 static double runtime_int_to_double(int a) {
1715 return (double) a;
1716 }
1717
1718 // Comparisons float
1719
1720 static int runtime_cmp_eq_ff(float b, float a) {
1721 return a == b;
1722 }
1723
1724 static int runtime_cmp_ne_ff(float b, float a) {
1725 return a != b;
1726 }
1727
1728 static int runtime_cmp_lt_ff(float b, float a) {
1729 return a < b;
1730 }
1731
1732 static int runtime_cmp_le_ff(float b, float a) {
1733 return a <= b;
1734 }
1735
1736 static int runtime_cmp_ge_ff(float b, float a) {
1737 return a >= b;
1738 }
1739
1740 static int runtime_cmp_gt_ff(float b, float a) {
1741 return a > b;
1742 }
1743
1744 // Comparisons double
1745
1746 static int runtime_cmp_eq_dd(double b, double a) {
1747 return a == b;
1748 }
1749
1750 static int runtime_cmp_ne_dd(double b, double a) {
1751 return a != b;
1752 }
1753
1754 static int runtime_cmp_lt_dd(double b, double a) {
1755 return a < b;
1756 }
1757
1758 static int runtime_cmp_le_dd(double b, double a) {
1759 return a <= b;
1760 }
1761
1762 static int runtime_cmp_ge_dd(double b, double a) {
1763 return a >= b;
1764 }
1765
1766 static int runtime_cmp_gt_dd(double b, double a) {
1767 return a > b;
1768 }
1769
1770 // Math float
1771
1772 static float runtime_op_add_ff(float b, float a) {
1773 return a + b;
1774 }
1775
1776 static float runtime_op_sub_ff(float b, float a) {
1777 return a - b;
1778 }
1779
1780 static float runtime_op_mul_ff(float b, float a) {
1781 return a * b;
1782 }
1783
1784 static float runtime_op_div_ff(float b, float a) {
1785 return a / b;
1786 }
1787
1788 static float runtime_op_neg_f(float a) {
1789 return -a;
1790 }
1791
1792 // Math double
1793
1794 static double runtime_op_add_dd(double b, double a) {
1795 return a + b;
1796 }
1797
1798 static double runtime_op_sub_dd(double b, double a) {
1799 return a - b;
1800 }
1801
1802 static double runtime_op_mul_dd(double b, double a) {
1803 return a * b;
1804 }
1805
1806 static double runtime_op_div_dd(double b, double a) {
1807 return a / b;
1808 }
1809
1810 static double runtime_op_neg_d(double a) {
1811 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001812 }
-b master422972c2009-06-17 19:13:52 -07001813
1814 static const int STACK_ALIGNMENT = 8;
1815 int mStackUse;
1816 // This variable holds the amount we adjusted the stack in the most
1817 // recent endFunctionCallArguments call. It's examined by the
1818 // following adjustStackAfterCall call.
1819 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001820 };
1821
Jack Palevich09555c72009-05-27 12:25:55 -07001822#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001823
1824#ifdef PROVIDE_X86_CODEGEN
1825
Jack Palevich21a15a22009-05-11 14:49:29 -07001826 class X86CodeGenerator : public CodeGenerator {
1827 public:
1828 X86CodeGenerator() {}
1829 virtual ~X86CodeGenerator() {}
1830
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001831 /* returns address to patch with local variable size
1832 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001833 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001834 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1835 return oad(0xec81, 0); /* sub $xxx, %esp */
1836 }
1837
Jack Palevichb7718b92009-07-09 22:00:24 -07001838 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001839 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001840 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001841 }
1842
Jack Palevich21a15a22009-05-11 14:49:29 -07001843 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001844 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001845 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001846 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001847 }
1848
Jack Palevich1a539db2009-07-08 13:04:41 -07001849 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001850 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001851 switch (pType->tag) {
1852 case TY_FLOAT:
1853 oad(0x05D9, address); // flds
1854 break;
1855 case TY_DOUBLE:
1856 oad(0x05DD, address); // fldl
1857 break;
1858 default:
1859 assert(false);
1860 break;
1861 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001862 }
1863
Jack Palevich22305132009-05-13 10:58:45 -07001864 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001865 return psym(0xe9, t);
1866 }
1867
1868 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001869 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001870 Type* pR0Type = getR0Type();
1871 TypeTag tagR0 = pR0Type->tag;
1872 bool isFloatR0 = isFloatTag(tagR0);
1873 if (isFloatR0) {
1874 o(0xeed9); // fldz
1875 o(0xe9da); // fucompp
1876 o(0xe0df); // fnstsw %ax
1877 o(0x9e); // sahf
1878 } else {
1879 o(0xc085); // test %eax, %eax
1880 }
1881 // Use two output statements to generate one instruction.
1882 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001883 return psym(0x84 + l, t);
1884 }
1885
Jack Palevicha39749f2009-07-08 20:40:31 -07001886 virtual void gcmp(int op, Type* pResultType) {
1887 Type* pR0Type = getR0Type();
1888 Type* pTOSType = getTOSType();
1889 TypeTag tagR0 = pR0Type->tag;
1890 TypeTag tagTOS = pTOSType->tag;
1891 bool isFloatR0 = isFloatTag(tagR0);
1892 bool isFloatTOS = isFloatTag(tagTOS);
1893 if (!isFloatR0 && !isFloatTOS) {
1894 int t = decodeOp(op);
1895 o(0x59); /* pop %ecx */
1896 o(0xc139); /* cmp %eax,%ecx */
1897 li(0, NULL);
1898 o(0x0f); /* setxx %al */
1899 o(t + 0x90);
1900 o(0xc0);
1901 popType();
1902 } else {
1903 setupFloatOperands();
1904 switch (op) {
1905 case OP_EQUALS:
1906 o(0xe9da); // fucompp
1907 o(0xe0df); // fnstsw %ax
1908 o(0x9e); // sahf
1909 o(0xc0940f); // sete %al
1910 o(0xc29b0f); // setnp %dl
1911 o(0xd021); // andl %edx, %eax
1912 break;
1913 case OP_NOT_EQUALS:
1914 o(0xe9da); // fucompp
1915 o(0xe0df); // fnstsw %ax
1916 o(0x9e); // sahf
1917 o(0xc0950f); // setne %al
1918 o(0xc29a0f); // setp %dl
1919 o(0xd009); // orl %edx, %eax
1920 break;
1921 case OP_GREATER_EQUAL:
1922 o(0xe9da); // fucompp
1923 o(0xe0df); // fnstsw %ax
1924 o(0x05c4f6); // testb $5, %ah
1925 o(0xc0940f); // sete %al
1926 break;
1927 case OP_LESS:
1928 o(0xc9d9); // fxch %st(1)
1929 o(0xe9da); // fucompp
1930 o(0xe0df); // fnstsw %ax
1931 o(0x9e); // sahf
1932 o(0xc0970f); // seta %al
1933 break;
1934 case OP_LESS_EQUAL:
1935 o(0xc9d9); // fxch %st(1)
1936 o(0xe9da); // fucompp
1937 o(0xe0df); // fnstsw %ax
1938 o(0x9e); // sahf
1939 o(0xc0930f); // setea %al
1940 break;
1941 case OP_GREATER:
1942 o(0xe9da); // fucompp
1943 o(0xe0df); // fnstsw %ax
1944 o(0x45c4f6); // testb $69, %ah
1945 o(0xc0940f); // sete %al
1946 break;
1947 default:
1948 error("Unknown comparison op");
1949 }
1950 o(0xc0b60f); // movzbl %al, %eax
1951 }
1952 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001953 }
1954
Jack Palevich546b2242009-05-13 15:10:04 -07001955 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001956 Type* pR0Type = getR0Type();
1957 Type* pTOSType = getTOSType();
1958 TypeTag tagR0 = pR0Type->tag;
1959 TypeTag tagTOS = pTOSType->tag;
1960 bool isFloatR0 = isFloatTag(tagR0);
1961 bool isFloatTOS = isFloatTag(tagTOS);
1962 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001963 bool isPtrR0 = tagR0 == TY_POINTER;
1964 bool isPtrTOS = tagTOS == TY_POINTER;
1965 if (isPtrR0 || isPtrTOS) {
1966 if (isPtrR0 && isPtrTOS) {
1967 if (op != OP_MINUS) {
1968 error("Unsupported pointer-pointer operation %d.", op);
1969 }
1970 if (! typeEqual(pR0Type, pTOSType)) {
1971 error("Incompatible pointer types for subtraction.");
1972 }
1973 o(0x59); /* pop %ecx */
1974 o(decodeOp(op));
1975 popType();
1976 setR0Type(mkpInt);
1977 int size = sizeOf(pR0Type->pHead);
1978 if (size != 1) {
1979 pushR0();
1980 li(size, mkpInt);
1981 // TODO: Optimize for power-of-two.
1982 genOp(OP_DIV);
1983 }
1984 } else {
1985 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1986 error("Unsupported pointer-scalar operation %d", op);
1987 }
1988 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1989 o(0x59); /* pop %ecx */
1990 int size = sizeOf(pPtrType->pHead);
1991 if (size != 1) {
1992 // TODO: Optimize for power-of-two.
1993 if (isPtrR0) {
1994 oad(0xC969, size); // imull $size, %ecx
1995 } else {
1996 oad(0xC069, size); // mul $size, %eax
1997 }
1998 }
1999 o(decodeOp(op));
2000 popType();
2001 setR0Type(pPtrType);
2002 }
2003 } else {
2004 o(0x59); /* pop %ecx */
2005 o(decodeOp(op));
2006 if (op == OP_MOD)
2007 o(0x92); /* xchg %edx, %eax */
2008 popType();
2009 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002010 } else {
2011 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2012 setupFloatOperands();
2013 // Both float. x87 R0 == left hand, x87 R1 == right hand
2014 switch (op) {
2015 case OP_MUL:
2016 o(0xc9de); // fmulp
2017 break;
2018 case OP_DIV:
2019 o(0xf1de); // fdivp
2020 break;
2021 case OP_PLUS:
2022 o(0xc1de); // faddp
2023 break;
2024 case OP_MINUS:
2025 o(0xe1de); // fsubp
2026 break;
2027 default:
2028 error("Unsupported binary floating operation.");
2029 break;
2030 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002031 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002032 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002033 }
2034
Jack Palevicha39749f2009-07-08 20:40:31 -07002035 virtual void gUnaryCmp(int op, Type* pResultType) {
2036 if (op != OP_LOGICAL_NOT) {
2037 error("Unknown unary cmp %d", op);
2038 } else {
2039 Type* pR0Type = getR0Type();
2040 TypeTag tag = collapseType(pR0Type->tag);
2041 switch(tag) {
2042 case TY_INT: {
2043 oad(0xb9, 0); /* movl $0, %ecx */
2044 int t = decodeOp(op);
2045 o(0xc139); /* cmp %eax,%ecx */
2046 li(0, NULL);
2047 o(0x0f); /* setxx %al */
2048 o(t + 0x90);
2049 o(0xc0);
2050 }
2051 break;
2052 case TY_FLOAT:
2053 case TY_DOUBLE:
2054 o(0xeed9); // fldz
2055 o(0xe9da); // fucompp
2056 o(0xe0df); // fnstsw %ax
2057 o(0x9e); // sahf
2058 o(0xc0950f); // setne %al
2059 o(0xc29a0f); // setp %dl
2060 o(0xd009); // orl %edx, %eax
2061 o(0xc0b60f); // movzbl %al, %eax
2062 o(0x01f083); // xorl $1, %eax
2063 break;
2064 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002065 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002066 break;
2067 }
2068 }
2069 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002070 }
2071
2072 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002073 Type* pR0Type = getR0Type();
2074 TypeTag tag = collapseType(pR0Type->tag);
2075 switch(tag) {
2076 case TY_INT:
2077 oad(0xb9, 0); /* movl $0, %ecx */
2078 o(decodeOp(op));
2079 break;
2080 case TY_FLOAT:
2081 case TY_DOUBLE:
2082 switch (op) {
2083 case OP_MINUS:
2084 o(0xe0d9); // fchs
2085 break;
2086 case OP_BIT_NOT:
2087 error("Can't apply '~' operator to a float or double.");
2088 break;
2089 default:
2090 error("Unknown unary op %d\n", op);
2091 break;
2092 }
2093 break;
2094 default:
2095 error("genUnaryOp unsupported type");
2096 break;
2097 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002098 }
2099
Jack Palevich1cdef202009-05-22 12:06:27 -07002100 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002101 Type* pR0Type = getR0Type();
2102 TypeTag r0ct = collapseType(pR0Type->tag);
2103 switch(r0ct) {
2104 case TY_INT:
2105 o(0x50); /* push %eax */
2106 break;
2107 case TY_FLOAT:
2108 o(0x50); /* push %eax */
2109 o(0x241cd9); // fstps 0(%esp)
2110 break;
2111 case TY_DOUBLE:
2112 o(0x50); /* push %eax */
2113 o(0x50); /* push %eax */
2114 o(0x241cdd); // fstpl 0(%esp)
2115 break;
2116 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002117 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002118 break;
2119 }
Jack Palevich8df46192009-07-07 14:48:51 -07002120 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002121 }
2122
Jack Palevich9eed7a22009-07-06 17:24:34 -07002123 virtual void storeR0ToTOS(Type* pPointerType) {
2124 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07002125 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002126 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002127 switch (pPointerType->pHead->tag) {
2128 case TY_INT:
2129 o(0x0189); /* movl %eax/%al, (%ecx) */
2130 break;
2131 case TY_CHAR:
2132 o(0x0188); /* movl %eax/%al, (%ecx) */
2133 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002134 case TY_FLOAT:
2135 o(0x19d9); /* fstps (%ecx) */
2136 break;
2137 case TY_DOUBLE:
2138 o(0x19dd); /* fstpl (%ecx) */
2139 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002140 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002141 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002142 break;
2143 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002144 }
2145
Jack Palevich9eed7a22009-07-06 17:24:34 -07002146 virtual void loadR0FromR0(Type* pPointerType) {
2147 assert(pPointerType->tag == TY_POINTER);
2148 switch (pPointerType->pHead->tag) {
2149 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002150 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002151 break;
2152 case TY_CHAR:
2153 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002154 ob(0); /* add zero in code */
2155 break;
2156 case TY_FLOAT:
2157 o2(0x00d9); // flds (%eax)
2158 break;
2159 case TY_DOUBLE:
2160 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002161 break;
2162 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002163 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002164 break;
2165 }
Jack Palevich8df46192009-07-07 14:48:51 -07002166 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002167 }
2168
Jack Palevich8df46192009-07-07 14:48:51 -07002169 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002170 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002171 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002172 }
2173
Jack Palevich9cbd2262009-07-08 16:48:41 -07002174 virtual void storeR0(int ea, Type* pType) {
2175 TypeTag tag = pType->tag;
2176 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002177 case TY_CHAR:
2178 if (ea < -LOCAL || ea > LOCAL) {
2179 oad(0xa2, ea); // movb %al,ea
2180 } else {
2181 oad(0x8588, ea); // movb %al,ea(%ebp)
2182 }
2183 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002184 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002185 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002186 gmov(6, ea); /* mov %eax, EA */
2187 break;
2188 case TY_FLOAT:
2189 if (ea < -LOCAL || ea > LOCAL) {
2190 oad(0x1dd9, ea); // fstps ea
2191 } else {
2192 oad(0x9dd9, ea); // fstps ea(%ebp)
2193 }
2194 break;
2195 case TY_DOUBLE:
2196 if (ea < -LOCAL || ea > LOCAL) {
2197 oad(0x1ddd, ea); // fstpl ea
2198 } else {
2199 oad(0x9ddd, ea); // fstpl ea(%ebp)
2200 }
2201 break;
2202 default:
2203 error("Unable to store to type %d", tag);
2204 break;
2205 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 }
2207
Jack Palevich8df46192009-07-07 14:48:51 -07002208 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002209 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002210 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002211 case TY_CHAR:
2212 if (ea < -LOCAL || ea > LOCAL) {
2213 oad(0x05BE0F, ea); // movsbl ea,%eax
2214 } else {
2215 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2216 }
2217 if (isIncDec) {
2218 error("inc/dec not implemented for char.");
2219 }
2220 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002221 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002222 case TY_POINTER:
2223 if (tag == TY_CHAR) {
2224 } else {
2225 gmov(8, ea); /* mov EA, %eax */
2226 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002227 if (isIncDec) {
2228 /* Implement post-increment or post decrement.
2229 */
2230 gmov(0, ea); /* 83 ADD */
2231 o(decodeOp(op));
2232 }
2233 break;
2234 case TY_FLOAT:
2235 if (ea < -LOCAL || ea > LOCAL) {
2236 oad(0x05d9, ea); // flds ea
2237 } else {
2238 oad(0x85d9, ea); // flds ea(%ebp)
2239 }
2240 if (isIncDec) {
2241 error("inc/dec not implemented for float.");
2242 }
2243 break;
2244 case TY_DOUBLE:
2245 if (ea < -LOCAL || ea > LOCAL) {
2246 oad(0x05dd, ea); // fldl ea
2247 } else {
2248 oad(0x85dd, ea); // fldl ea(%ebp)
2249 }
2250 if (isIncDec) {
2251 error("inc/dec not implemented for double.");
2252 }
2253 break;
2254 default:
2255 error("Unable to load type %d", tag);
2256 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002257 }
Jack Palevich8df46192009-07-07 14:48:51 -07002258 setR0Type(pType);
2259 }
2260
2261 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002262 Type* pR0Type = getR0Type();
2263 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002264 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002265 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002266 return;
2267 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002268 if (bitsSame(pType, pR0Type)) {
2269 // do nothing special
2270 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2271 // do nothing special, both held in same register on x87.
2272 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002273 TypeTag r0Tag = collapseType(pR0Type->tag);
2274 TypeTag destTag = collapseType(pType->tag);
2275 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2276 // Convert R0 from int to float
2277 o(0x50); // push %eax
2278 o(0x2404DB); // fildl 0(%esp)
2279 o(0x58); // pop %eax
2280 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2281 // Convert R0 from float to int. Complicated because
2282 // need to save and restore the rounding mode.
2283 o(0x50); // push %eax
2284 o(0x50); // push %eax
2285 o(0x02247cD9); // fnstcw 2(%esp)
2286 o(0x2444b70f); // movzwl 2(%esp), %eax
2287 o(0x02);
2288 o(0x0cb4); // movb $12, %ah
2289 o(0x24048966); // movw %ax, 0(%esp)
2290 o(0x242cd9); // fldcw 0(%esp)
2291 o(0x04245cdb); // fistpl 4(%esp)
2292 o(0x02246cd9); // fldcw 2(%esp)
2293 o(0x58); // pop %eax
2294 o(0x58); // pop %eax
2295 } else {
2296 error("Incompatible types old: %d new: %d",
2297 pR0Type->tag, pType->tag);
2298 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002299 }
2300 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002301 }
2302
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002303 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002304 return oad(0xec81, 0); /* sub $xxx, %esp */
2305 }
2306
Jack Palevich1a539db2009-07-08 13:04:41 -07002307 virtual size_t storeR0ToArg(int l) {
2308 Type* pR0Type = getR0Type();
2309 TypeTag r0ct = collapseType(pR0Type->tag);
2310 switch(r0ct) {
2311 case TY_INT:
2312 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2313 return 4;
2314 case TY_FLOAT:
2315 oad(0x249CD9, l); /* fstps xxx(%esp) */
2316 return 4;
2317 case TY_DOUBLE:
2318 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2319 return 8;
2320 default:
2321 assert(false);
2322 return 0;
2323 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002324 }
2325
Jack Palevichb7718b92009-07-09 22:00:24 -07002326 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002327 * (int*) a = l;
2328 }
2329
Jack Palevich8df46192009-07-07 14:48:51 -07002330 virtual int callForward(int symbol, Type* pFunc) {
2331 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002332 return psym(0xe8, symbol); /* call xxx */
2333 }
2334
Jack Palevich8df46192009-07-07 14:48:51 -07002335 virtual void callRelative(int t, Type* pFunc) {
2336 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002337 psym(0xe8, t); /* call xxx */
2338 }
2339
Jack Palevich8df46192009-07-07 14:48:51 -07002340 virtual void callIndirect(int l, Type* pFunc) {
2341 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002342 oad(0x2494ff, l); /* call *xxx(%esp) */
2343 }
2344
Jack Palevichb7718b92009-07-09 22:00:24 -07002345 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002346 if (isIndirect) {
2347 l += 4;
2348 }
-b master422972c2009-06-17 19:13:52 -07002349 if (l > 0) {
2350 oad(0xc481, l); /* add $xxx, %esp */
2351 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 }
2353
Jack Palevicha6535612009-05-13 16:24:17 -07002354 virtual int jumpOffset() {
2355 return 5;
2356 }
2357
2358 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002359 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002360 }
2361
Jack Paleviche7b59062009-05-19 17:12:17 -07002362 /* output a symbol and patch all calls to it */
2363 virtual void gsym(int t) {
2364 int n;
2365 int pc = getPC();
2366 while (t) {
2367 n = *(int *) t; /* next value */
2368 *(int *) t = pc - t - 4;
2369 t = n;
2370 }
2371 }
2372
Jack Palevich1cdef202009-05-22 12:06:27 -07002373 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002374 size_t pagesize = 4096;
2375 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2376 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2377 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2378 if (err) {
2379 error("mprotect() failed: %d", errno);
2380 }
2381 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002382 }
2383
Jack Palevich9eed7a22009-07-06 17:24:34 -07002384 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002385 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002386 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002387 virtual size_t alignmentOf(Type* pType){
2388 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002389 }
2390
2391 /**
2392 * Array element alignment (in bytes) for this type of data.
2393 */
2394 virtual size_t sizeOf(Type* pType){
2395 switch(pType->tag) {
2396 case TY_INT:
2397 return 4;
2398 case TY_CHAR:
2399 return 1;
2400 default:
2401 return 0;
2402 case TY_FLOAT:
2403 return 4;
2404 case TY_DOUBLE:
2405 return 8;
2406 case TY_POINTER:
2407 return 4;
2408 }
2409 }
2410
Jack Palevich9cbd2262009-07-08 16:48:41 -07002411 virtual size_t stackSizeOf(Type* pType) {
2412 switch(pType->tag) {
2413 case TY_DOUBLE:
2414 return 8;
2415 default:
2416 return 4;
2417 }
2418 }
2419
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002421
2422 /** Output 1 to 4 bytes.
2423 *
2424 */
2425 void o(int n) {
2426 /* cannot use unsigned, so we must do a hack */
2427 while (n && n != -1) {
2428 ob(n & 0xff);
2429 n = n >> 8;
2430 }
2431 }
2432
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002433 /* Output exactly 2 bytes
2434 */
2435 void o2(int n) {
2436 ob(n & 0xff);
2437 ob(0xff & (n >> 8));
2438 }
2439
Jack Paleviche7b59062009-05-19 17:12:17 -07002440 /* psym is used to put an instruction with a data field which is a
2441 reference to a symbol. It is in fact the same as oad ! */
2442 int psym(int n, int t) {
2443 return oad(n, t);
2444 }
2445
2446 /* instruction + address */
2447 int oad(int n, int t) {
2448 o(n);
2449 int result = getPC();
2450 o4(t);
2451 return result;
2452 }
2453
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002454 static const int operatorHelper[];
2455
2456 int decodeOp(int op) {
2457 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002458 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002459 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002460 }
2461 return operatorHelper[op];
2462 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002463
Jack Palevich546b2242009-05-13 15:10:04 -07002464 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002465 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002466 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002467 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002468
2469 void setupFloatOperands() {
2470 Type* pR0Type = getR0Type();
2471 Type* pTOSType = getTOSType();
2472 TypeTag tagR0 = pR0Type->tag;
2473 TypeTag tagTOS = pTOSType->tag;
2474 bool isFloatR0 = isFloatTag(tagR0);
2475 bool isFloatTOS = isFloatTag(tagTOS);
2476 if (! isFloatR0) {
2477 // Convert R0 from int to float
2478 o(0x50); // push %eax
2479 o(0x2404DB); // fildl 0(%esp)
2480 o(0x58); // pop %eax
2481 }
2482 if (! isFloatTOS){
2483 o(0x2404DB); // fildl 0(%esp);
2484 o(0x58); // pop %eax
2485 } else {
2486 if (tagTOS == TY_FLOAT) {
2487 o(0x2404d9); // flds (%esp)
2488 o(0x58); // pop %eax
2489 } else {
2490 o(0x2404dd); // fldl (%esp)
2491 o(0x58); // pop %eax
2492 o(0x58); // pop %eax
2493 }
2494 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002495 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002496 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002497 };
2498
Jack Paleviche7b59062009-05-19 17:12:17 -07002499#endif // PROVIDE_X86_CODEGEN
2500
Jack Palevichb67b18f2009-06-11 21:12:23 -07002501#ifdef PROVIDE_TRACE_CODEGEN
2502 class TraceCodeGenerator : public CodeGenerator {
2503 private:
2504 CodeGenerator* mpBase;
2505
2506 public:
2507 TraceCodeGenerator(CodeGenerator* pBase) {
2508 mpBase = pBase;
2509 }
2510
2511 virtual ~TraceCodeGenerator() {
2512 delete mpBase;
2513 }
2514
2515 virtual void init(CodeBuf* pCodeBuf) {
2516 mpBase->init(pCodeBuf);
2517 }
2518
2519 void setErrorSink(ErrorSink* pErrorSink) {
2520 mpBase->setErrorSink(pErrorSink);
2521 }
2522
2523 /* returns address to patch with local variable size
2524 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002525 virtual int functionEntry(Type* pDecl) {
2526 int result = mpBase->functionEntry(pDecl);
2527 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002528 return result;
2529 }
2530
Jack Palevichb7718b92009-07-09 22:00:24 -07002531 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2532 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2533 localVariableAddress, localVariableSize);
2534 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002535 }
2536
2537 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002538 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002539 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002540 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002541 }
2542
Jack Palevich1a539db2009-07-08 13:04:41 -07002543 virtual void loadFloat(int address, Type* pType) {
2544 fprintf(stderr, "loadFloat(%d, type)\n", address);
2545 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002546 }
2547
Jack Palevichb67b18f2009-06-11 21:12:23 -07002548 virtual int gjmp(int t) {
2549 int result = mpBase->gjmp(t);
2550 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2551 return result;
2552 }
2553
2554 /* l = 0: je, l == 1: jne */
2555 virtual int gtst(bool l, int t) {
2556 int result = mpBase->gtst(l, t);
2557 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2558 return result;
2559 }
2560
Jack Palevicha39749f2009-07-08 20:40:31 -07002561 virtual void gcmp(int op, Type* pResultType) {
2562 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2563 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002564 }
2565
2566 virtual void genOp(int op) {
2567 fprintf(stderr, "genOp(%d)\n", op);
2568 mpBase->genOp(op);
2569 }
2570
Jack Palevich9eed7a22009-07-06 17:24:34 -07002571
Jack Palevicha39749f2009-07-08 20:40:31 -07002572 virtual void gUnaryCmp(int op, Type* pResultType) {
2573 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2574 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002575 }
2576
2577 virtual void genUnaryOp(int op) {
2578 fprintf(stderr, "genUnaryOp(%d)\n", op);
2579 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002580 }
2581
2582 virtual void pushR0() {
2583 fprintf(stderr, "pushR0()\n");
2584 mpBase->pushR0();
2585 }
2586
Jack Palevich9eed7a22009-07-06 17:24:34 -07002587 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002588 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002589 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002590 }
2591
Jack Palevich9eed7a22009-07-06 17:24:34 -07002592 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002593 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002594 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002595 }
2596
Jack Palevich8df46192009-07-07 14:48:51 -07002597 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002598 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002599 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002600 }
2601
Jack Palevich9cbd2262009-07-08 16:48:41 -07002602 virtual void storeR0(int ea, Type* pType) {
2603 fprintf(stderr, "storeR0(%d, pType)\n", ea);
2604 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002605 }
2606
Jack Palevich8df46192009-07-07 14:48:51 -07002607 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002608 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002609 mpBase->loadR0(ea, isIncDec, op, pType);
2610 }
2611
2612 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002613 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002614 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002615 }
2616
2617 virtual int beginFunctionCallArguments() {
2618 int result = mpBase->beginFunctionCallArguments();
2619 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2620 return result;
2621 }
2622
Jack Palevich1a539db2009-07-08 13:04:41 -07002623 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002624 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07002625 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002626 }
2627
Jack Palevichb7718b92009-07-09 22:00:24 -07002628 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002629 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002630 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002631 }
2632
Jack Palevich8df46192009-07-07 14:48:51 -07002633 virtual int callForward(int symbol, Type* pFunc) {
2634 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002635 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2636 return result;
2637 }
2638
Jack Palevich8df46192009-07-07 14:48:51 -07002639 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002640 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002641 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002642 }
2643
Jack Palevich8df46192009-07-07 14:48:51 -07002644 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002645 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002646 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002647 }
2648
Jack Palevichb7718b92009-07-09 22:00:24 -07002649 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2650 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2651 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002652 }
2653
2654 virtual int jumpOffset() {
2655 return mpBase->jumpOffset();
2656 }
2657
2658 virtual int disassemble(FILE* out) {
2659 return mpBase->disassemble(out);
2660 }
2661
2662 /* output a symbol and patch all calls to it */
2663 virtual void gsym(int t) {
2664 fprintf(stderr, "gsym(%d)\n", t);
2665 mpBase->gsym(t);
2666 }
2667
2668 virtual int finishCompile() {
2669 int result = mpBase->finishCompile();
2670 fprintf(stderr, "finishCompile() = %d\n", result);
2671 return result;
2672 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002673
2674 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002675 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002676 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002677 virtual size_t alignmentOf(Type* pType){
2678 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002679 }
2680
2681 /**
2682 * Array element alignment (in bytes) for this type of data.
2683 */
2684 virtual size_t sizeOf(Type* pType){
2685 return mpBase->sizeOf(pType);
2686 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002687
Jack Palevich9cbd2262009-07-08 16:48:41 -07002688
2689 virtual size_t stackSizeOf(Type* pType) {
2690 return mpBase->stackSizeOf(pType);
2691 }
2692
2693
Jack Palevich1a539db2009-07-08 13:04:41 -07002694 virtual Type* getR0Type() {
2695 return mpBase->getR0Type();
2696 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002697 };
2698
2699#endif // PROVIDE_TRACE_CODEGEN
2700
Jack Palevich569f1352009-06-29 14:29:08 -07002701 class Arena {
2702 public:
2703 // Used to record a given allocation amount.
2704 // Used:
2705 // Mark mark = arena.mark();
2706 // ... lots of arena.allocate()
2707 // arena.free(mark);
2708
2709 struct Mark {
2710 size_t chunk;
2711 size_t offset;
2712 };
2713
2714 Arena() {
2715 mCurrentChunk = 0;
2716 Chunk start(CHUNK_SIZE);
2717 mData.push_back(start);
2718 }
2719
2720 ~Arena() {
2721 for(size_t i = 0; i < mData.size(); i++) {
2722 mData[i].free();
2723 }
2724 }
2725
2726 // Alloc using the standard alignment size safe for any variable
2727 void* alloc(size_t size) {
2728 return alloc(size, 8);
2729 }
2730
2731 Mark mark(){
2732 Mark result;
2733 result.chunk = mCurrentChunk;
2734 result.offset = mData[mCurrentChunk].mOffset;
2735 return result;
2736 }
2737
2738 void freeToMark(const Mark& mark) {
2739 mCurrentChunk = mark.chunk;
2740 mData[mCurrentChunk].mOffset = mark.offset;
2741 }
2742
2743 private:
2744 // Allocate memory aligned to a given size
2745 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2746 // Memory is not zero filled.
2747
2748 void* alloc(size_t size, size_t alignment) {
2749 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2750 if (mCurrentChunk + 1 < mData.size()) {
2751 mCurrentChunk++;
2752 } else {
2753 size_t allocSize = CHUNK_SIZE;
2754 if (allocSize < size + alignment - 1) {
2755 allocSize = size + alignment - 1;
2756 }
2757 Chunk chunk(allocSize);
2758 mData.push_back(chunk);
2759 mCurrentChunk++;
2760 }
2761 }
2762 return mData[mCurrentChunk].allocate(size, alignment);
2763 }
2764
2765 static const size_t CHUNK_SIZE = 128*1024;
2766 // Note: this class does not deallocate its
2767 // memory when it's destroyed. It depends upon
2768 // its parent to deallocate the memory.
2769 struct Chunk {
2770 Chunk() {
2771 mpData = 0;
2772 mSize = 0;
2773 mOffset = 0;
2774 }
2775
2776 Chunk(size_t size) {
2777 mSize = size;
2778 mpData = (char*) malloc(size);
2779 mOffset = 0;
2780 }
2781
2782 ~Chunk() {
2783 // Doesn't deallocate memory.
2784 }
2785
2786 void* allocate(size_t size, size_t alignment) {
2787 size_t alignedOffset = aligned(mOffset, alignment);
2788 void* result = mpData + alignedOffset;
2789 mOffset = alignedOffset + size;
2790 return result;
2791 }
2792
2793 void free() {
2794 if (mpData) {
2795 ::free(mpData);
2796 mpData = 0;
2797 }
2798 }
2799
2800 size_t remainingCapacity(size_t alignment) {
2801 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2802 }
2803
2804 // Assume alignment is a power of two
2805 inline size_t aligned(size_t v, size_t alignment) {
2806 size_t mask = alignment-1;
2807 return (v + mask) & ~mask;
2808 }
2809
2810 char* mpData;
2811 size_t mSize;
2812 size_t mOffset;
2813 };
2814
2815 size_t mCurrentChunk;
2816
2817 Vector<Chunk> mData;
2818 };
2819
Jack Palevich569f1352009-06-29 14:29:08 -07002820 struct VariableInfo;
2821
2822 struct Token {
2823 int hash;
2824 size_t length;
2825 char* pText;
2826 tokenid_t id;
2827
2828 // Current values for the token
2829 char* mpMacroDefinition;
2830 VariableInfo* mpVariableInfo;
2831 };
2832
2833 class TokenTable {
2834 public:
2835 // Don't use 0..0xff, allows characters and operators to be tokens too.
2836
2837 static const int TOKEN_BASE = 0x100;
2838 TokenTable() {
2839 mpMap = hashmapCreate(128, hashFn, equalsFn);
2840 }
2841
2842 ~TokenTable() {
2843 hashmapFree(mpMap);
2844 }
2845
2846 void setArena(Arena* pArena) {
2847 mpArena = pArena;
2848 }
2849
2850 // Returns a token for a given string of characters.
2851 tokenid_t intern(const char* pText, size_t length) {
2852 Token probe;
2853 int hash = hashmapHash((void*) pText, length);
2854 {
2855 Token probe;
2856 probe.hash = hash;
2857 probe.length = length;
2858 probe.pText = (char*) pText;
2859 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2860 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002861 return pValue->id;
2862 }
2863 }
2864
2865 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2866 memset(pToken, 0, sizeof(*pToken));
2867 pToken->hash = hash;
2868 pToken->length = length;
2869 pToken->pText = (char*) mpArena->alloc(length + 1);
2870 memcpy(pToken->pText, pText, length);
2871 pToken->pText[length] = 0;
2872 pToken->id = mTokens.size() + TOKEN_BASE;
2873 mTokens.push_back(pToken);
2874 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002875 return pToken->id;
2876 }
2877
2878 // Return the Token for a given tokenid.
2879 Token& operator[](tokenid_t id) {
2880 return *mTokens[id - TOKEN_BASE];
2881 }
2882
2883 inline size_t size() {
2884 return mTokens.size();
2885 }
2886
2887 private:
2888
2889 static int hashFn(void* pKey) {
2890 Token* pToken = (Token*) pKey;
2891 return pToken->hash;
2892 }
2893
2894 static bool equalsFn(void* keyA, void* keyB) {
2895 Token* pTokenA = (Token*) keyA;
2896 Token* pTokenB = (Token*) keyB;
2897 // Don't need to compare hash values, they should always be equal
2898 return pTokenA->length == pTokenB->length
2899 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2900 }
2901
2902 Hashmap* mpMap;
2903 Vector<Token*> mTokens;
2904 Arena* mpArena;
2905 };
2906
Jack Palevich1cdef202009-05-22 12:06:27 -07002907 class InputStream {
2908 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002909 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002910 int getChar() {
2911 if (bumpLine) {
2912 line++;
2913 bumpLine = false;
2914 }
2915 int ch = get();
2916 if (ch == '\n') {
2917 bumpLine = true;
2918 }
2919 return ch;
2920 }
2921 int getLine() {
2922 return line;
2923 }
2924 protected:
2925 InputStream() :
2926 line(1), bumpLine(false) {
2927 }
2928 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002929 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002930 int line;
2931 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002932 };
2933
2934 class FileInputStream : public InputStream {
2935 public:
2936 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002937 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002938 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002939 FILE* f;
2940 };
2941
2942 class TextInputStream : public InputStream {
2943 public:
2944 TextInputStream(const char* text, size_t textLength)
2945 : pText(text), mTextLength(textLength), mPosition(0) {
2946 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002947
2948 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002949 virtual int get() {
2950 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2951 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002952
Jack Palevich1cdef202009-05-22 12:06:27 -07002953 const char* pText;
2954 size_t mTextLength;
2955 size_t mPosition;
2956 };
2957
Jack Palevicheedf9d22009-06-04 16:23:40 -07002958 class String {
2959 public:
2960 String() {
2961 mpBase = 0;
2962 mUsed = 0;
2963 mSize = 0;
2964 }
2965
Jack Palevich303d8ff2009-06-11 19:06:24 -07002966 String(const char* item, int len, bool adopt) {
2967 if (len < 0) {
2968 len = strlen(item);
2969 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002970 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002971 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002972 mUsed = len;
2973 mSize = len + 1;
2974 } else {
2975 mpBase = 0;
2976 mUsed = 0;
2977 mSize = 0;
2978 appendBytes(item, len);
2979 }
2980 }
2981
Jack Palevich303d8ff2009-06-11 19:06:24 -07002982 String(const String& other) {
2983 mpBase = 0;
2984 mUsed = 0;
2985 mSize = 0;
2986 appendBytes(other.getUnwrapped(), other.len());
2987 }
2988
Jack Palevicheedf9d22009-06-04 16:23:40 -07002989 ~String() {
2990 if (mpBase) {
2991 free(mpBase);
2992 }
2993 }
2994
Jack Palevicha6baa232009-06-12 11:25:59 -07002995 String& operator=(const String& other) {
2996 clear();
2997 appendBytes(other.getUnwrapped(), other.len());
2998 return *this;
2999 }
3000
Jack Palevich303d8ff2009-06-11 19:06:24 -07003001 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003002 return mpBase;
3003 }
3004
Jack Palevich303d8ff2009-06-11 19:06:24 -07003005 void clear() {
3006 mUsed = 0;
3007 if (mSize > 0) {
3008 mpBase[0] = 0;
3009 }
3010 }
3011
Jack Palevicheedf9d22009-06-04 16:23:40 -07003012 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003013 appendBytes(s, strlen(s));
3014 }
3015
3016 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003017 memcpy(ensure(n), s, n + 1);
3018 }
3019
3020 void append(char c) {
3021 * ensure(1) = c;
3022 }
3023
Jack Palevich86351982009-06-30 18:09:56 -07003024 void append(String& other) {
3025 appendBytes(other.getUnwrapped(), other.len());
3026 }
3027
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003028 char* orphan() {
3029 char* result = mpBase;
3030 mpBase = 0;
3031 mUsed = 0;
3032 mSize = 0;
3033 return result;
3034 }
3035
Jack Palevicheedf9d22009-06-04 16:23:40 -07003036 void printf(const char* fmt,...) {
3037 va_list ap;
3038 va_start(ap, fmt);
3039 vprintf(fmt, ap);
3040 va_end(ap);
3041 }
3042
3043 void vprintf(const char* fmt, va_list ap) {
3044 char* temp;
3045 int numChars = vasprintf(&temp, fmt, ap);
3046 memcpy(ensure(numChars), temp, numChars+1);
3047 free(temp);
3048 }
3049
Jack Palevich303d8ff2009-06-11 19:06:24 -07003050 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003051 return mUsed;
3052 }
3053
3054 private:
3055 char* ensure(int n) {
3056 size_t newUsed = mUsed + n;
3057 if (newUsed > mSize) {
3058 size_t newSize = mSize * 2 + 10;
3059 if (newSize < newUsed) {
3060 newSize = newUsed;
3061 }
3062 mpBase = (char*) realloc(mpBase, newSize + 1);
3063 mSize = newSize;
3064 }
3065 mpBase[newUsed] = '\0';
3066 char* result = mpBase + mUsed;
3067 mUsed = newUsed;
3068 return result;
3069 }
3070
3071 char* mpBase;
3072 size_t mUsed;
3073 size_t mSize;
3074 };
3075
Jack Palevich569f1352009-06-29 14:29:08 -07003076 void internKeywords() {
3077 // Note: order has to match TOK_ constants
3078 static const char* keywords[] = {
3079 "int",
3080 "char",
3081 "void",
3082 "if",
3083 "else",
3084 "while",
3085 "break",
3086 "return",
3087 "for",
3088 "pragma",
3089 "define",
3090 "auto",
3091 "case",
3092 "const",
3093 "continue",
3094 "default",
3095 "do",
3096 "double",
3097 "enum",
3098 "extern",
3099 "float",
3100 "goto",
3101 "long",
3102 "register",
3103 "short",
3104 "signed",
3105 "sizeof",
3106 "static",
3107 "struct",
3108 "switch",
3109 "typedef",
3110 "union",
3111 "unsigned",
3112 "volatile",
3113 "_Bool",
3114 "_Complex",
3115 "_Imaginary",
3116 "inline",
3117 "restrict",
3118 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003119
Jack Palevich569f1352009-06-29 14:29:08 -07003120 for(int i = 0; keywords[i]; i++) {
3121 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003122 }
Jack Palevich569f1352009-06-29 14:29:08 -07003123 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003124
Jack Palevich36d94142009-06-08 15:55:32 -07003125 struct InputState {
3126 InputStream* pStream;
3127 int oldCh;
3128 };
3129
Jack Palevich2db168f2009-06-11 14:29:47 -07003130 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003131 void* pAddress;
3132 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003133 tokenid_t tok;
3134 size_t level;
3135 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003136 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003137 };
3138
Jack Palevich303d8ff2009-06-11 19:06:24 -07003139 class SymbolStack {
3140 public:
3141 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003142 mpArena = 0;
3143 mpTokenTable = 0;
3144 }
3145
3146 void setArena(Arena* pArena) {
3147 mpArena = pArena;
3148 }
3149
3150 void setTokenTable(TokenTable* pTokenTable) {
3151 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003152 }
3153
3154 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003155 Mark mark;
3156 mark.mArenaMark = mpArena->mark();
3157 mark.mSymbolHead = mStack.size();
3158 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003159 }
3160
3161 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003162 // Undo any shadowing that was done:
3163 Mark mark = mLevelStack.back();
3164 mLevelStack.pop_back();
3165 while (mStack.size() > mark.mSymbolHead) {
3166 VariableInfo* pV = mStack.back();
3167 mStack.pop_back();
3168 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003169 }
Jack Palevich569f1352009-06-29 14:29:08 -07003170 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003171 }
3172
Jack Palevich569f1352009-06-29 14:29:08 -07003173 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3174 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3175 return pV && pV->level == level();
3176 }
3177
3178 VariableInfo* add(tokenid_t tok) {
3179 Token& token = (*mpTokenTable)[tok];
3180 VariableInfo* pOldV = token.mpVariableInfo;
3181 VariableInfo* pNewV =
3182 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3183 memset(pNewV, 0, sizeof(VariableInfo));
3184 pNewV->tok = tok;
3185 pNewV->level = level();
3186 pNewV->pOldDefinition = pOldV;
3187 token.mpVariableInfo = pNewV;
3188 mStack.push_back(pNewV);
3189 return pNewV;
3190 }
3191
Jack Palevich86351982009-06-30 18:09:56 -07003192 VariableInfo* add(Type* pType) {
3193 VariableInfo* pVI = add(pType->id);
3194 pVI->pType = pType;
3195 return pVI;
3196 }
3197
Jack Palevich569f1352009-06-29 14:29:08 -07003198 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3199 for (size_t i = 0; i < mStack.size(); i++) {
3200 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003201 break;
3202 }
3203 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003204 }
3205
Jack Palevich303d8ff2009-06-11 19:06:24 -07003206 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003207 inline size_t level() {
3208 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003209 }
3210
Jack Palevich569f1352009-06-29 14:29:08 -07003211 struct Mark {
3212 Arena::Mark mArenaMark;
3213 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003214 };
3215
Jack Palevich569f1352009-06-29 14:29:08 -07003216 Arena* mpArena;
3217 TokenTable* mpTokenTable;
3218 Vector<VariableInfo*> mStack;
3219 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003220 };
Jack Palevich36d94142009-06-08 15:55:32 -07003221
3222 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003223 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003224 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003225 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003226 int tokl; // token operator level
3227 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003228 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003229 intptr_t loc; // local variable index
3230 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003231 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003232 char* dptr; // Macro state: Points to macro text during macro playback.
3233 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003234 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003235 ACCSymbolLookupFn mpSymbolLookupFn;
3236 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003237
3238 // Arena for the duration of the compile
3239 Arena mGlobalArena;
3240 // Arena for data that's only needed when compiling a single function
3241 Arena mLocalArena;
3242
3243 TokenTable mTokenTable;
3244 SymbolStack mGlobals;
3245 SymbolStack mLocals;
3246
Jack Palevich40600de2009-07-01 15:32:35 -07003247 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003248 Type* mkpInt; // int
3249 Type* mkpChar; // char
3250 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003251 Type* mkpFloat;
3252 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003253 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003254 Type* mkpIntPtr;
3255 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003256 Type* mkpFloatPtr;
3257 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003258 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003259
Jack Palevich36d94142009-06-08 15:55:32 -07003260 InputStream* file;
3261
3262 CodeBuf codeBuf;
3263 CodeGenerator* pGen;
3264
Jack Palevicheedf9d22009-06-04 16:23:40 -07003265 String mErrorBuf;
3266
Jack Palevicheedf9d22009-06-04 16:23:40 -07003267 String mPragmas;
3268 int mPragmaStringCount;
3269
Jack Palevich21a15a22009-05-11 14:49:29 -07003270 static const int ALLOC_SIZE = 99999;
3271
Jack Palevich303d8ff2009-06-11 19:06:24 -07003272 static const int TOK_DUMMY = 1;
3273 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003274 static const int TOK_NUM_FLOAT = 3;
3275 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003276
3277 // 3..255 are character and/or operators
3278
Jack Palevich2db168f2009-06-11 14:29:47 -07003279 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003280 // Order has to match string list in "internKeywords".
3281 enum {
3282 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3283 TOK_INT = TOK_KEYWORD,
3284 TOK_CHAR,
3285 TOK_VOID,
3286 TOK_IF,
3287 TOK_ELSE,
3288 TOK_WHILE,
3289 TOK_BREAK,
3290 TOK_RETURN,
3291 TOK_FOR,
3292 TOK_PRAGMA,
3293 TOK_DEFINE,
3294 TOK_AUTO,
3295 TOK_CASE,
3296 TOK_CONST,
3297 TOK_CONTINUE,
3298 TOK_DEFAULT,
3299 TOK_DO,
3300 TOK_DOUBLE,
3301 TOK_ENUM,
3302 TOK_EXTERN,
3303 TOK_FLOAT,
3304 TOK_GOTO,
3305 TOK_LONG,
3306 TOK_REGISTER,
3307 TOK_SHORT,
3308 TOK_SIGNED,
3309 TOK_SIZEOF,
3310 TOK_STATIC,
3311 TOK_STRUCT,
3312 TOK_SWITCH,
3313 TOK_TYPEDEF,
3314 TOK_UNION,
3315 TOK_UNSIGNED,
3316 TOK_VOLATILE,
3317 TOK__BOOL,
3318 TOK__COMPLEX,
3319 TOK__IMAGINARY,
3320 TOK_INLINE,
3321 TOK_RESTRICT,
3322 // Symbols start after tokens
3323 TOK_SYMBOL
3324 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003325
3326 static const int LOCAL = 0x200;
3327
3328 static const int SYM_FORWARD = 0;
3329 static const int SYM_DEFINE = 1;
3330
3331 /* tokens in string heap */
3332 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003333
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003334 static const int OP_INCREMENT = 0;
3335 static const int OP_DECREMENT = 1;
3336 static const int OP_MUL = 2;
3337 static const int OP_DIV = 3;
3338 static const int OP_MOD = 4;
3339 static const int OP_PLUS = 5;
3340 static const int OP_MINUS = 6;
3341 static const int OP_SHIFT_LEFT = 7;
3342 static const int OP_SHIFT_RIGHT = 8;
3343 static const int OP_LESS_EQUAL = 9;
3344 static const int OP_GREATER_EQUAL = 10;
3345 static const int OP_LESS = 11;
3346 static const int OP_GREATER = 12;
3347 static const int OP_EQUALS = 13;
3348 static const int OP_NOT_EQUALS = 14;
3349 static const int OP_LOGICAL_AND = 15;
3350 static const int OP_LOGICAL_OR = 16;
3351 static const int OP_BIT_AND = 17;
3352 static const int OP_BIT_XOR = 18;
3353 static const int OP_BIT_OR = 19;
3354 static const int OP_BIT_NOT = 20;
3355 static const int OP_LOGICAL_NOT = 21;
3356 static const int OP_COUNT = 22;
3357
3358 /* Operators are searched from front, the two-character operators appear
3359 * before the single-character operators with the same first character.
3360 * @ is used to pad out single-character operators.
3361 */
3362 static const char* operatorChars;
3363 static const char operatorLevel[];
3364
Jack Palevich569f1352009-06-29 14:29:08 -07003365 /* Called when we detect an internal problem. Does nothing in production.
3366 *
3367 */
3368 void internalError() {
3369 * (char*) 0 = 0;
3370 }
3371
Jack Palevich86351982009-06-30 18:09:56 -07003372 void assert(bool isTrue) {
3373 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003374 internalError();
3375 }
Jack Palevich86351982009-06-30 18:09:56 -07003376 }
3377
Jack Palevich40600de2009-07-01 15:32:35 -07003378 bool isSymbol(tokenid_t t) {
3379 return t >= TOK_SYMBOL &&
3380 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3381 }
3382
3383 bool isSymbolOrKeyword(tokenid_t t) {
3384 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003385 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003386 }
3387
Jack Palevich86351982009-06-30 18:09:56 -07003388 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003389 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003390 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3391 if (pV && pV->tok != t) {
3392 internalError();
3393 }
3394 return pV;
3395 }
3396
3397 inline bool isDefined(tokenid_t t) {
3398 return t >= TOK_SYMBOL && VI(t) != 0;
3399 }
3400
Jack Palevich40600de2009-07-01 15:32:35 -07003401 const char* nameof(tokenid_t t) {
3402 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003403 return mTokenTable[t].pText;
3404 }
3405
Jack Palevich21a15a22009-05-11 14:49:29 -07003406 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003407 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003408 }
3409
3410 void inp() {
3411 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003412 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003413 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003414 dptr = 0;
3415 ch = dch;
3416 }
3417 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003418 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003419#if 0
3420 printf("ch='%c' 0x%x\n", ch, ch);
3421#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003422 }
3423
3424 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003425 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003426 }
3427
Jack Palevichb4758ff2009-06-12 12:49:14 -07003428 /* read a character constant, advances ch to after end of constant */
3429 int getq() {
3430 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003431 if (ch == '\\') {
3432 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003433 if (isoctal(ch)) {
3434 // 1 to 3 octal characters.
3435 val = 0;
3436 for(int i = 0; i < 3; i++) {
3437 if (isoctal(ch)) {
3438 val = (val << 3) + ch - '0';
3439 inp();
3440 }
3441 }
3442 return val;
3443 } else if (ch == 'x' || ch == 'X') {
3444 // N hex chars
3445 inp();
3446 if (! isxdigit(ch)) {
3447 error("'x' character escape requires at least one digit.");
3448 } else {
3449 val = 0;
3450 while (isxdigit(ch)) {
3451 int d = ch;
3452 if (isdigit(d)) {
3453 d -= '0';
3454 } else if (d <= 'F') {
3455 d = d - 'A' + 10;
3456 } else {
3457 d = d - 'a' + 10;
3458 }
3459 val = (val << 4) + d;
3460 inp();
3461 }
3462 }
3463 } else {
3464 int val = ch;
3465 switch (ch) {
3466 case 'a':
3467 val = '\a';
3468 break;
3469 case 'b':
3470 val = '\b';
3471 break;
3472 case 'f':
3473 val = '\f';
3474 break;
3475 case 'n':
3476 val = '\n';
3477 break;
3478 case 'r':
3479 val = '\r';
3480 break;
3481 case 't':
3482 val = '\t';
3483 break;
3484 case 'v':
3485 val = '\v';
3486 break;
3487 case '\\':
3488 val = '\\';
3489 break;
3490 case '\'':
3491 val = '\'';
3492 break;
3493 case '"':
3494 val = '"';
3495 break;
3496 case '?':
3497 val = '?';
3498 break;
3499 default:
3500 error("Undefined character escape %c", ch);
3501 break;
3502 }
3503 inp();
3504 return val;
3505 }
3506 } else {
3507 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003508 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003509 return val;
3510 }
3511
3512 static bool isoctal(int ch) {
3513 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003514 }
3515
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003516 bool acceptCh(int c) {
3517 bool result = c == ch;
3518 if (result) {
3519 pdef(ch);
3520 inp();
3521 }
3522 return result;
3523 }
3524
3525 bool acceptDigitsCh() {
3526 bool result = false;
3527 while (isdigit(ch)) {
3528 result = true;
3529 pdef(ch);
3530 inp();
3531 }
3532 return result;
3533 }
3534
3535 void parseFloat() {
3536 tok = TOK_NUM_DOUBLE;
3537 // mTokenString already has the integral part of the number.
3538 acceptCh('.');
3539 acceptDigitsCh();
3540 bool doExp = true;
3541 if (acceptCh('e') || acceptCh('E')) {
3542 // Don't need to do any extra work
3543 } else if (ch == 'f' || ch == 'F') {
3544 pdef('e'); // So it can be parsed by strtof.
3545 inp();
3546 tok = TOK_NUM_FLOAT;
3547 } else {
3548 doExp = false;
3549 }
3550 if (doExp) {
3551 bool digitsRequired = acceptCh('-');
3552 bool digitsFound = acceptDigitsCh();
3553 if (digitsRequired && ! digitsFound) {
3554 error("malformed exponent");
3555 }
3556 }
3557 char* pText = mTokenString.getUnwrapped();
3558 if (tok == TOK_NUM_FLOAT) {
3559 tokd = strtof(pText, 0);
3560 } else {
3561 tokd = strtod(pText, 0);
3562 }
3563 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
3564 }
3565
Jack Palevich21a15a22009-05-11 14:49:29 -07003566 void next() {
3567 int l, a;
3568
Jack Palevich546b2242009-05-13 15:10:04 -07003569 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003570 if (ch == '#') {
3571 inp();
3572 next();
3573 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003574 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003575 } else if (tok == TOK_PRAGMA) {
3576 doPragma();
3577 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003578 error("Unsupported preprocessor directive \"%s\"",
3579 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003580 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003581 }
3582 inp();
3583 }
3584 tokl = 0;
3585 tok = ch;
3586 /* encode identifiers & numbers */
3587 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003588 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003589 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003590 pdef(ch);
3591 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003592 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003593 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003594 // Start of a numeric constant. Could be integer, float, or
3595 // double, won't know until we look further.
3596 if (ch == '.' || ch == 'e' || ch == 'e'
3597 || ch == 'f' || ch == 'F') {
3598 parseFloat();
3599 } else {
3600 // It's an integer constant
3601 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
3602 tok = TOK_NUM;
3603 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003604 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003605 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
3606 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003607 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07003608 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3609 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003610 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07003611 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003612 dch = ch;
3613 inp();
3614 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003615 }
3616 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003617 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003618 inp();
3619 if (tok == '\'') {
3620 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003621 tokc = getq();
3622 if (ch != '\'') {
3623 error("Expected a ' character, got %c", ch);
3624 } else {
3625 inp();
3626 }
Jack Palevich546b2242009-05-13 15:10:04 -07003627 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003628 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003629 while (ch && ch != EOF) {
3630 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003631 inp();
3632 inp();
3633 if (ch == '/')
3634 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003635 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003636 if (ch == EOF) {
3637 error("End of file inside comment.");
3638 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003639 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003640 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003641 } else if ((tok == '/') & (ch == '/')) {
3642 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003643 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003644 inp();
3645 }
3646 inp();
3647 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003648 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003649 const char* t = operatorChars;
3650 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003651 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003652 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003653 tokl = operatorLevel[opIndex];
3654 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003655 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003656#if 0
3657 printf("%c%c -> tokl=%d tokc=0x%x\n",
3658 l, a, tokl, tokc);
3659#endif
3660 if (a == ch) {
3661 inp();
3662 tok = TOK_DUMMY; /* dummy token for double tokens */
3663 }
3664 break;
3665 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003666 opIndex++;
3667 }
3668 if (l == 0) {
3669 tokl = 0;
3670 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003671 }
3672 }
3673 }
3674#if 0
3675 {
Jack Palevich569f1352009-06-29 14:29:08 -07003676 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003677 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003678 fprintf(stderr, "%s\n", buf.getUnwrapped());
3679 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003680#endif
3681 }
3682
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003683 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003684 next();
3685 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003686 String* pName = new String();
3687 while (isspace(ch)) {
3688 inp();
3689 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003690 if (ch == '(') {
3691 delete pName;
3692 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003693 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003694 }
3695 while (isspace(ch)) {
3696 inp();
3697 }
Jack Palevich569f1352009-06-29 14:29:08 -07003698 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003699 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003700 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003701 inp();
3702 }
Jack Palevich569f1352009-06-29 14:29:08 -07003703 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3704 memcpy(pDefn, value.getUnwrapped(), value.len());
3705 pDefn[value.len()] = 0;
3706 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003707 }
3708
Jack Palevicheedf9d22009-06-04 16:23:40 -07003709 void doPragma() {
3710 // # pragma name(val)
3711 int state = 0;
3712 while(ch != EOF && ch != '\n' && state < 10) {
3713 switch(state) {
3714 case 0:
3715 if (isspace(ch)) {
3716 inp();
3717 } else {
3718 state++;
3719 }
3720 break;
3721 case 1:
3722 if (isalnum(ch)) {
3723 mPragmas.append(ch);
3724 inp();
3725 } else if (ch == '(') {
3726 mPragmas.append(0);
3727 inp();
3728 state++;
3729 } else {
3730 state = 11;
3731 }
3732 break;
3733 case 2:
3734 if (isalnum(ch)) {
3735 mPragmas.append(ch);
3736 inp();
3737 } else if (ch == ')') {
3738 mPragmas.append(0);
3739 inp();
3740 state = 10;
3741 } else {
3742 state = 11;
3743 }
3744 break;
3745 }
3746 }
3747 if(state != 10) {
3748 error("Unexpected pragma syntax");
3749 }
3750 mPragmaStringCount += 2;
3751 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003752
Jack Palevichac0e95e2009-05-29 13:53:44 -07003753 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003754 mErrorBuf.printf("%ld: ", file->getLine());
3755 mErrorBuf.vprintf(fmt, ap);
3756 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003757 }
3758
Jack Palevich8b0624c2009-05-20 12:12:06 -07003759 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003760 if (tok != c) {
3761 error("'%c' expected", c);
3762 }
3763 next();
3764 }
3765
Jack Palevich86351982009-06-30 18:09:56 -07003766 bool accept(intptr_t c) {
3767 if (tok == c) {
3768 next();
3769 return true;
3770 }
3771 return false;
3772 }
3773
Jack Palevich40600de2009-07-01 15:32:35 -07003774 bool acceptStringLiteral() {
3775 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003776 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003777 // This while loop merges multiple adjacent string constants.
3778 while (tok == '"') {
3779 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003780 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003781 }
3782 if (ch != '"') {
3783 error("Unterminated string constant.");
3784 }
3785 inp();
3786 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003787 }
Jack Palevich40600de2009-07-01 15:32:35 -07003788 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003789 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003790 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003791 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003792
3793 return true;
3794 }
3795 return false;
3796 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003797
Jack Palevich40600de2009-07-01 15:32:35 -07003798 /* Parse and evaluate a unary expression.
3799 * allowAssignment is true if '=' parsing wanted (quick hack)
3800 */
3801 void unary(bool allowAssignment) {
3802 intptr_t n, t, a;
3803 t = 0;
3804 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3805 if (acceptStringLiteral()) {
3806 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003807 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003808 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003809 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003810 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003811 t = tok;
3812 next();
3813 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003814 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003815 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003816 // Align to 4-byte boundary
3817 glo = (char*) (((intptr_t) glo + 3) & -4);
3818 * (float*) glo = (float) ad;
3819 pGen->loadFloat((int) glo, mkpFloat);
3820 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003821 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003822 // Align to 8-byte boundary
3823 glo = (char*) (((intptr_t) glo + 7) & -8);
3824 * (double*) glo = ad;
3825 pGen->loadFloat((int) glo, mkpDouble);
3826 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003827 } else if (c == 2) {
3828 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003829 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003830 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003831 pGen->gUnaryCmp(a, mkpInt);
3832 else if (t == '+') {
3833 // ignore unary plus.
3834 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003835 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003836 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003837 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003838 // It's either a cast or an expression
3839 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3840 if (pCast) {
3841 skip(')');
3842 unary(false);
3843 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003844 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003845 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003846 skip(')');
3847 }
3848 } else if (t == '*') {
3849 /* This is a pointer dereference.
3850 */
3851 unary(false);
3852 Type* pR0Type = pGen->getR0Type();
3853 if (pR0Type->tag != TY_POINTER) {
3854 error("Expected a pointer type.");
3855 } else {
3856 if (pR0Type->pHead->tag == TY_FUNC) {
3857 t = 0;
3858 }
3859 if (accept('=')) {
3860 pGen->pushR0();
3861 expr();
3862 pGen->storeR0ToTOS(pR0Type);
3863 } else if (t) {
3864 pGen->loadR0FromR0(pR0Type);
3865 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003866 }
Jack Palevich3f226492009-07-02 14:46:19 -07003867 // Else we fall through to the function call below, with
3868 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003869 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003870 VariableInfo* pVI = VI(tok);
3871 pGen->leaR0((int) pVI->pAddress,
3872 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003873 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003874 } else if (t == EOF ) {
3875 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003876 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003877 // Don't have to do anything special here, the error
3878 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003879 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003880 if (!isDefined(t)) {
3881 mGlobals.add(t);
3882 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003883 }
Jack Palevich8df46192009-07-07 14:48:51 -07003884 VariableInfo* pVI = VI(t);
3885 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003886 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003887 if (!n) {
Jack Palevich8c246a92009-07-14 21:14:10 -07003888 if (mpSymbolLookupFn) {
3889 n = (intptr_t) mpSymbolLookupFn(
3890 mpSymbolLookupContext, nameof(t));
3891 }
Jack Palevich37c54bd2009-07-14 18:35:36 -07003892 if (pVI->pType == NULL) {
3893 if (tok == '(') {
3894 pVI->pType = mkpIntFn;
3895 } else {
3896 pVI->pType = mkpInt;
3897 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003898 }
Jack Palevich8df46192009-07-07 14:48:51 -07003899 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003900 }
Jack Palevich40600de2009-07-01 15:32:35 -07003901 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003902 /* assignment */
3903 next();
3904 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003905 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003906 } else if (tok != '(') {
3907 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003908 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003909 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003910 }
Jack Palevich8df46192009-07-07 14:48:51 -07003911 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003913 next();
3914 }
3915 }
3916 }
3917 }
3918
3919 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003920 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003921 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003922 VariableInfo* pVI = NULL;
3923 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003924 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003925 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003926 } else {
3927 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003928 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003929 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003930 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003931 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003932 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003933 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003934 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003935 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003936 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003937 if (! varArgs && !pArgList) {
3938 error ("Unexpected argument.");
3939 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003940 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003941 Type* pTargetType;
3942 if (pArgList) {
3943 pTargetType = pArgList->pHead;
3944 pArgList = pArgList->pTail;
3945 } else {
3946 pTargetType = pGen->getR0Type();
3947 if (pTargetType->tag == TY_FLOAT) {
3948 pTargetType = mkpDouble;
3949 }
3950 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003951 if (pTargetType->tag == TY_VOID) {
3952 error("Can't pass void value for argument %d",
3953 argCount + 1);
3954 } else {
3955 pGen->convertR0(pTargetType);
3956 l += pGen->storeR0ToArg(l);
3957 }
Jack Palevich95727a02009-07-06 12:07:15 -07003958 if (accept(',')) {
3959 // fine
3960 } else if ( tok != ')') {
3961 error("Expected ',' or ')'");
3962 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003963 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003964 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003965 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003966 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003967 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003968 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003969 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003970 if (!n) {
3971 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003972 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3973 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003974 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003975 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003976 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003977 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3978 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003979 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003980 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003981 }
3982 }
3983
Jack Palevich40600de2009-07-01 15:32:35 -07003984 /* Recursive descent parser for binary operations.
3985 */
3986 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07003987 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003988 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003989 if (level-- == 1)
3990 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003991 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003992 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003993 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003994 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003995 t = tokc;
3996 next();
3997
Jack Palevich40600de2009-07-01 15:32:35 -07003998 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003999 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004000 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004001 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004002 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004003 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004004
Jack Palevich40600de2009-07-01 15:32:35 -07004005 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004006 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004007 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004008 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004009 }
4010 }
4011 }
4012 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004013 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004014 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004015 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004016 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004017 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004018 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004019 }
4020 }
4021 }
4022
4023 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004024 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004025 }
4026
4027 int test_expr() {
4028 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004029 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004030 }
4031
Jack Palevicha6baa232009-06-12 11:25:59 -07004032 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004033 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004034
Jack Palevich95727a02009-07-06 12:07:15 -07004035 Type* pBaseType;
4036 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004037 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004038 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004039 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004040 next();
4041 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004042 a = test_expr();
4043 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004044 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004045 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004046 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004047 n = pGen->gjmp(0); /* jmp */
4048 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004049 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004050 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004051 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004052 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004053 }
Jack Palevich546b2242009-05-13 15:10:04 -07004054 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004055 t = tok;
4056 next();
4057 skip('(');
4058 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004059 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004060 a = test_expr();
4061 } else {
4062 if (tok != ';')
4063 expr();
4064 skip(';');
4065 n = codeBuf.getPC();
4066 a = 0;
4067 if (tok != ';')
4068 a = test_expr();
4069 skip(';');
4070 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004071 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004072 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004073 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004074 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 n = t + 4;
4076 }
4077 }
4078 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004079 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004080 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004081 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004082 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004083 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004084 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004085 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004086 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004087 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004088 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004089 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004090 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004091 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004092 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004093 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004094 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004095 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004096 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004097 if (pReturnType->tag == TY_VOID) {
4098 error("Must not return a value from a void function");
4099 } else {
4100 pGen->convertR0(pReturnType);
4101 }
4102 } else {
4103 if (pReturnType->tag != TY_VOID) {
4104 error("Must specify a value here");
4105 }
Jack Palevich8df46192009-07-07 14:48:51 -07004106 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004107 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004108 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004109 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004110 } else if (tok != ';')
4111 expr();
4112 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004113 }
4114 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004115
Jack Palevicha8f427f2009-07-13 18:40:08 -07004116 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004117 if (a == b) {
4118 return true;
4119 }
4120 if (a == NULL || b == NULL) {
4121 return false;
4122 }
4123 TypeTag at = a->tag;
4124 if (at != b->tag) {
4125 return false;
4126 }
4127 if (at == TY_POINTER) {
4128 return typeEqual(a->pHead, b->pHead);
4129 } else if (at == TY_FUNC || at == TY_PARAM) {
4130 return typeEqual(a->pHead, b->pHead)
4131 && typeEqual(a->pTail, b->pTail);
4132 }
4133 return true;
4134 }
4135
Jack Palevich86351982009-06-30 18:09:56 -07004136 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4137 assert(tag >= TY_INT && tag <= TY_PARAM);
4138 Type* pType = (Type*) arena.alloc(sizeof(Type));
4139 memset(pType, 0, sizeof(*pType));
4140 pType->tag = tag;
4141 pType->pHead = pHead;
4142 pType->pTail = pTail;
4143 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004144 }
4145
Jack Palevich3f226492009-07-02 14:46:19 -07004146 Type* createPtrType(Type* pType, Arena& arena) {
4147 return createType(TY_POINTER, pType, NULL, arena);
4148 }
4149
4150 /**
4151 * Try to print a type in declaration order
4152 */
Jack Palevich86351982009-06-30 18:09:56 -07004153 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004154 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004155 if (pType == NULL) {
4156 buffer.appendCStr("null");
4157 return;
4158 }
Jack Palevich3f226492009-07-02 14:46:19 -07004159 decodeTypeImp(buffer, pType);
4160 }
4161
4162 void decodeTypeImp(String& buffer, Type* pType) {
4163 decodeTypeImpPrefix(buffer, pType);
4164
Jack Palevich86351982009-06-30 18:09:56 -07004165 String temp;
4166 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004167 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004168 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004169 }
4170
4171 decodeTypeImpPostfix(buffer, pType);
4172 }
4173
4174 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4175 TypeTag tag = pType->tag;
4176
Jack Palevich37c54bd2009-07-14 18:35:36 -07004177 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004178 switch (tag) {
4179 case TY_INT:
4180 buffer.appendCStr("int");
4181 break;
4182 case TY_CHAR:
4183 buffer.appendCStr("char");
4184 break;
4185 case TY_VOID:
4186 buffer.appendCStr("void");
4187 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004188 case TY_FLOAT:
4189 buffer.appendCStr("float");
4190 break;
4191 case TY_DOUBLE:
4192 buffer.appendCStr("double");
4193 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004194 default:
4195 break;
4196 }
Jack Palevich86351982009-06-30 18:09:56 -07004197 buffer.append(' ');
4198 }
Jack Palevich3f226492009-07-02 14:46:19 -07004199
4200 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004201 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004202 break;
4203 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004204 break;
4205 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004206 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004207 case TY_FLOAT:
4208 break;
4209 case TY_DOUBLE:
4210 break;
Jack Palevich86351982009-06-30 18:09:56 -07004211 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004212 decodeTypeImpPrefix(buffer, pType->pHead);
4213 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4214 buffer.append('(');
4215 }
4216 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004217 break;
4218 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004219 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004220 break;
4221 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004222 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004223 break;
4224 default:
4225 String temp;
4226 temp.printf("Unknown tag %d", pType->tag);
4227 buffer.append(temp);
4228 break;
4229 }
Jack Palevich3f226492009-07-02 14:46:19 -07004230 }
4231
4232 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4233 TypeTag tag = pType->tag;
4234
4235 switch(tag) {
4236 case TY_POINTER:
4237 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4238 buffer.append(')');
4239 }
4240 decodeTypeImpPostfix(buffer, pType->pHead);
4241 break;
4242 case TY_FUNC:
4243 buffer.append('(');
4244 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4245 decodeTypeImp(buffer, pArg);
4246 if (pArg->pTail) {
4247 buffer.appendCStr(", ");
4248 }
4249 }
4250 buffer.append(')');
4251 break;
4252 default:
4253 break;
Jack Palevich86351982009-06-30 18:09:56 -07004254 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004255 }
4256
Jack Palevich86351982009-06-30 18:09:56 -07004257 void printType(Type* pType) {
4258 String buffer;
4259 decodeType(buffer, pType);
4260 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004261 }
4262
Jack Palevich86351982009-06-30 18:09:56 -07004263 Type* acceptPrimitiveType(Arena& arena) {
4264 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004265 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004266 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004267 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004268 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004269 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004270 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004271 } else if (tok == TOK_FLOAT) {
4272 pType = mkpFloat;
4273 } else if (tok == TOK_DOUBLE) {
4274 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004275 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004276 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004277 }
4278 next();
Jack Palevich86351982009-06-30 18:09:56 -07004279 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004280 }
4281
Jack Palevich3f226492009-07-02 14:46:19 -07004282 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4283 Arena& arena) {
4284 tokenid_t declName = 0;
4285 pType = acceptDecl2(pType, declName, nameAllowed,
4286 nameRequired, arena);
4287 if (declName) {
4288 // Clone the parent type so we can set a unique ID
4289 pType = createType(pType->tag, pType->pHead,
4290 pType->pTail, arena);
4291
Jack Palevich86351982009-06-30 18:09:56 -07004292 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004293 }
Jack Palevich3f226492009-07-02 14:46:19 -07004294 // fprintf(stderr, "Parsed a declaration: ");
4295 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004296 return pType;
4297 }
4298
Jack Palevich3f226492009-07-02 14:46:19 -07004299 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4300 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004301 if (! pType) {
4302 error("Expected a declaration");
4303 }
4304 return pType;
4305 }
4306
Jack Palevich3f226492009-07-02 14:46:19 -07004307 /* Used for accepting types that appear in casts */
4308 Type* acceptCastTypeDeclaration(Arena& arena) {
4309 Type* pType = acceptPrimitiveType(arena);
4310 if (pType) {
4311 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004312 }
Jack Palevich86351982009-06-30 18:09:56 -07004313 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004314 }
4315
Jack Palevich3f226492009-07-02 14:46:19 -07004316 Type* expectCastTypeDeclaration(Arena& arena) {
4317 Type* pType = acceptCastTypeDeclaration(arena);
4318 if (! pType) {
4319 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004320 }
Jack Palevich3f226492009-07-02 14:46:19 -07004321 return pType;
4322 }
4323
4324 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4325 bool nameAllowed, bool nameRequired, Arena& arena) {
4326 int ptrCounter = 0;
4327 while (accept('*')) {
4328 ptrCounter++;
4329 }
4330 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4331 while (ptrCounter-- > 0) {
4332 pType = createType(TY_POINTER, pType, NULL, arena);
4333 }
4334 return pType;
4335 }
4336
4337 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4338 bool nameAllowed, bool nameRequired, Arena& arena) {
4339 // direct-dcl :
4340 // name
4341 // (dcl)
4342 // direct-dcl()
4343 // direct-dcl[]
4344 Type* pNewHead = NULL;
4345 if (accept('(')) {
4346 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4347 nameRequired, arena);
4348 skip(')');
4349 } else if ((declName = acceptSymbol()) != 0) {
4350 if (nameAllowed == false && declName) {
4351 error("Symbol %s not allowed here", nameof(declName));
4352 } else if (nameRequired && ! declName) {
4353 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004354 decodeToken(temp, tok, true);
Jack Palevich3f226492009-07-02 14:46:19 -07004355 error("Expected symbol. Got %s", temp.getUnwrapped());
4356 }
4357 }
4358 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004359 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004360 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004361 pType = createType(TY_FUNC, pType, pTail, arena);
4362 skip(')');
4363 }
Jack Palevich3f226492009-07-02 14:46:19 -07004364
4365 if (pNewHead) {
4366 Type* pA = pNewHead;
4367 while (pA->pHead) {
4368 pA = pA->pHead;
4369 }
4370 pA->pHead = pType;
4371 pType = pNewHead;
4372 }
Jack Palevich86351982009-06-30 18:09:56 -07004373 return pType;
4374 }
4375
Jack Palevich3f226492009-07-02 14:46:19 -07004376 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004377 Type* pHead = NULL;
4378 Type* pTail = NULL;
4379 for(;;) {
4380 Type* pBaseArg = acceptPrimitiveType(arena);
4381 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004382 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4383 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004384 if (pArg) {
4385 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4386 if (!pHead) {
4387 pHead = pParam;
4388 pTail = pParam;
4389 } else {
4390 pTail->pTail = pParam;
4391 pTail = pParam;
4392 }
4393 }
4394 }
4395 if (! accept(',')) {
4396 break;
4397 }
4398 }
4399 return pHead;
4400 }
4401
4402 Type* expectPrimitiveType(Arena& arena) {
4403 Type* pType = acceptPrimitiveType(arena);
4404 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004405 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004406 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004407 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004408 }
Jack Palevich86351982009-06-30 18:09:56 -07004409 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004410 }
4411
Jack Palevich86351982009-06-30 18:09:56 -07004412 void addGlobalSymbol(Type* pDecl) {
4413 tokenid_t t = pDecl->id;
4414 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004415 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004416 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004417 }
Jack Palevich86351982009-06-30 18:09:56 -07004418 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004419 }
4420
Jack Palevich86351982009-06-30 18:09:56 -07004421 void reportDuplicate(tokenid_t t) {
4422 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004423 }
4424
Jack Palevich86351982009-06-30 18:09:56 -07004425 void addLocalSymbol(Type* pDecl) {
4426 tokenid_t t = pDecl->id;
4427 if (mLocals.isDefinedAtCurrentLevel(t)) {
4428 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004429 }
Jack Palevich86351982009-06-30 18:09:56 -07004430 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004431 }
4432
Jack Palevich95727a02009-07-06 12:07:15 -07004433 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004434 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004435
Jack Palevich95727a02009-07-06 12:07:15 -07004436 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004437 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004438 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4439 if (!pDecl) {
4440 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004441 }
Jack Palevich86351982009-06-30 18:09:56 -07004442 int variableAddress = 0;
4443 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004444 size_t alignment = pGen->alignmentOf(pDecl);
4445 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004446 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004447 variableAddress = -loc;
4448 VI(pDecl->id)->pAddress = (void*) variableAddress;
4449 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004450 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004451 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004452 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004453 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004454 if (tok == ',')
4455 next();
4456 }
4457 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004458 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004459 }
4460 }
4461
Jack Palevichf1728be2009-06-12 13:53:51 -07004462 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004463 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004464 }
4465
Jack Palevich37c54bd2009-07-14 18:35:36 -07004466 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004467 if (token == EOF ) {
4468 buffer.printf("EOF");
4469 } else if (token == TOK_NUM) {
4470 buffer.printf("numeric constant");
4471 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004472 if (token < 32) {
4473 buffer.printf("'\\x%02x'", token);
4474 } else {
4475 buffer.printf("'%c'", token);
4476 }
Jack Palevich569f1352009-06-29 14:29:08 -07004477 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004478 if (quote) {
4479 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4480 buffer.printf("keyword \"%s\"", nameof(token));
4481 } else {
4482 buffer.printf("symbol \"%s\"", nameof(token));
4483 }
4484 } else {
4485 buffer.printf("%s", nameof(token));
4486 }
Jack Palevich569f1352009-06-29 14:29:08 -07004487 }
4488 }
4489
Jack Palevich40600de2009-07-01 15:32:35 -07004490 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004491 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004492 if (!result) {
4493 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004494 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004495 error("Expected symbol. Got %s", temp.getUnwrapped());
4496 }
4497 return result;
4498 }
4499
Jack Palevich86351982009-06-30 18:09:56 -07004500 tokenid_t acceptSymbol() {
4501 tokenid_t result = 0;
4502 if (tok >= TOK_SYMBOL) {
4503 result = tok;
4504 next();
Jack Palevich86351982009-06-30 18:09:56 -07004505 }
4506 return result;
4507 }
4508
Jack Palevichb7c81e92009-06-04 19:56:13 -07004509 void globalDeclarations() {
4510 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004511 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4512 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004513 break;
4514 }
Jack Palevich86351982009-06-30 18:09:56 -07004515 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4516 if (!pDecl) {
4517 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004518 }
Jack Palevich86351982009-06-30 18:09:56 -07004519 if (! isDefined(pDecl->id)) {
4520 addGlobalSymbol(pDecl);
4521 }
4522 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004523 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004524 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004525 }
Jack Palevich86351982009-06-30 18:09:56 -07004526 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004527 // it's a variable declaration
4528 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004529 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004530 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004531 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004532 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004533 }
Jack Palevich86351982009-06-30 18:09:56 -07004534 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004535 if (tok == TOK_NUM) {
4536 if (name) {
4537 * (int*) name->pAddress = tokc;
4538 }
4539 next();
4540 } else {
4541 error("Expected an integer constant");
4542 }
4543 }
Jack Palevich86351982009-06-30 18:09:56 -07004544 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004545 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004546 }
Jack Palevich86351982009-06-30 18:09:56 -07004547 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4548 if (!pDecl) {
4549 break;
4550 }
4551 if (! isDefined(pDecl->id)) {
4552 addGlobalSymbol(pDecl);
4553 }
4554 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004555 }
4556 skip(';');
4557 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004558 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004559 if (accept(';')) {
4560 // forward declaration.
4561 } else {
4562 if (name) {
4563 /* patch forward references (XXX: does not work for function
4564 pointers) */
4565 pGen->gsym((int) name->pForward);
4566 /* put function address */
4567 name->pAddress = (void*) codeBuf.getPC();
4568 }
4569 // Calculate stack offsets for parameters
4570 mLocals.pushLevel();
4571 intptr_t a = 8;
4572 int argCount = 0;
4573 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4574 Type* pArg = pP->pHead;
4575 addLocalSymbol(pArg);
4576 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004577 size_t alignment = pGen->alignmentOf(pArg);
4578 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004579 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004580 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004581 argCount++;
4582 }
4583 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004584 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004585 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004586 block(0, true);
4587 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004588 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004589 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004590 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004591 }
4592 }
4593 }
4594
Jack Palevich9cbd2262009-07-08 16:48:41 -07004595 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4596 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4597 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004598 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004599 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004600 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004601 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004602 char* result = (char*) base;
4603 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004604 return result;
4605 }
4606
Jack Palevich21a15a22009-05-11 14:49:29 -07004607 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004608 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004609 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004610 pGlobalBase = 0;
4611 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004612 if (pGen) {
4613 delete pGen;
4614 pGen = 0;
4615 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004616 if (file) {
4617 delete file;
4618 file = 0;
4619 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004620 }
4621
Jack Palevich8c246a92009-07-14 21:14:10 -07004622 // One-time initialization, when class is constructed.
4623 void init() {
4624 mpSymbolLookupFn = 0;
4625 mpSymbolLookupContext = 0;
4626 }
4627
Jack Palevich21a15a22009-05-11 14:49:29 -07004628 void clear() {
4629 tok = 0;
4630 tokc = 0;
4631 tokl = 0;
4632 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004633 rsym = 0;
4634 loc = 0;
4635 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004636 dptr = 0;
4637 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004638 file = 0;
4639 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004640 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004641 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004642 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004643
Jack Palevich22305132009-05-13 10:58:45 -07004644 void setArchitecture(const char* architecture) {
4645 delete pGen;
4646 pGen = 0;
4647
4648 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004649#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004650 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004651 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004652 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004653#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004654#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004655 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004656 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004657 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004658#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004659 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004660 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004661 }
4662 }
4663
4664 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004665#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004666 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004667#elif defined(DEFAULT_X86_CODEGEN)
4668 pGen = new X86CodeGenerator();
4669#endif
4670 }
4671 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004672 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004673 } else {
4674 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004675 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004676 }
4677 }
4678
Jack Palevich77ae76e2009-05-10 19:59:24 -07004679public:
Jack Palevich22305132009-05-13 10:58:45 -07004680 struct args {
4681 args() {
4682 architecture = 0;
4683 }
4684 const char* architecture;
4685 };
4686
Jack Paleviche7b59062009-05-19 17:12:17 -07004687 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004688 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004689 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004690 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004691
Jack Paleviche7b59062009-05-19 17:12:17 -07004692 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004693 cleanup();
4694 }
4695
Jack Palevich8c246a92009-07-14 21:14:10 -07004696 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4697 mpSymbolLookupFn = pFn;
4698 mpSymbolLookupContext = pContext;
4699 }
4700
Jack Palevich1cdef202009-05-22 12:06:27 -07004701 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004702 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004703
Jack Palevicha8f427f2009-07-13 18:40:08 -07004704 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004705 cleanup();
4706 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004707 mTokenTable.setArena(&mGlobalArena);
4708 mGlobals.setArena(&mGlobalArena);
4709 mGlobals.setTokenTable(&mTokenTable);
4710 mLocals.setArena(&mLocalArena);
4711 mLocals.setTokenTable(&mTokenTable);
4712
4713 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004714 codeBuf.init(ALLOC_SIZE);
4715 setArchitecture(NULL);
4716 if (!pGen) {
4717 return -1;
4718 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004719#ifdef PROVIDE_TRACE_CODEGEN
4720 pGen = new TraceCodeGenerator(pGen);
4721#endif
4722 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004723 pGen->init(&codeBuf);
4724 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004725 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4726 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004727 inp();
4728 next();
4729 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004730 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004731 result = pGen->finishCompile();
4732 if (result == 0) {
4733 if (mErrorBuf.len()) {
4734 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004735 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004736 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004737 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004738 }
4739
Jack Palevich86351982009-06-30 18:09:56 -07004740 void createPrimitiveTypes() {
4741 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4742 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4743 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004744 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4745 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004746 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004747 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4748 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004749 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4750 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004751 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004752 }
4753
Jack Palevicha6baa232009-06-12 11:25:59 -07004754 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004755 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004756 }
4757
Jack Palevich569f1352009-06-29 14:29:08 -07004758 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004759 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004760 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004761 }
4762
Jack Palevich569f1352009-06-29 14:29:08 -07004763 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004764 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004765 error("Undefined forward reference: %s",
4766 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004767 }
4768 return true;
4769 }
4770
Jack Palevich21a15a22009-05-11 14:49:29 -07004771 int dump(FILE* out) {
4772 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4773 return 0;
4774 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004775
Jack Palevicha6535612009-05-13 16:24:17 -07004776 int disassemble(FILE* out) {
4777 return pGen->disassemble(out);
4778 }
4779
Jack Palevich1cdef202009-05-22 12:06:27 -07004780 /* Look through the symbol table to find a symbol.
4781 * If found, return its value.
4782 */
4783 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004784 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4785 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004786 if (pVariableInfo) {
4787 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004788 }
4789 return NULL;
4790 }
4791
Jack Palevicheedf9d22009-06-04 16:23:40 -07004792 void getPragmas(ACCsizei* actualStringCount,
4793 ACCsizei maxStringCount, ACCchar** strings) {
4794 int stringCount = mPragmaStringCount;
4795 if (actualStringCount) {
4796 *actualStringCount = stringCount;
4797 }
4798 if (stringCount > maxStringCount) {
4799 stringCount = maxStringCount;
4800 }
4801 if (strings) {
4802 char* pPragmas = mPragmas.getUnwrapped();
4803 while (stringCount-- > 0) {
4804 *strings++ = pPragmas;
4805 pPragmas += strlen(pPragmas) + 1;
4806 }
4807 }
4808 }
4809
Jack Palevichac0e95e2009-05-29 13:53:44 -07004810 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004811 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004812 }
4813
Jack Palevich77ae76e2009-05-10 19:59:24 -07004814};
4815
Jack Paleviche7b59062009-05-19 17:12:17 -07004816const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004817 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4818
Jack Paleviche7b59062009-05-19 17:12:17 -07004819const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004820 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4821 5, 5, /* ==, != */
4822 9, 10, /* &&, || */
4823 6, 7, 8, /* & ^ | */
4824 2, 2 /* ~ ! */
4825 };
4826
Jack Palevich8b0624c2009-05-20 12:12:06 -07004827#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004828FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004829#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004830
Jack Palevich8b0624c2009-05-20 12:12:06 -07004831#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004832const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004833 0x1, // ++
4834 0xff, // --
4835 0xc1af0f, // *
4836 0xf9f79991, // /
4837 0xf9f79991, // % (With manual assist to swap results)
4838 0xc801, // +
4839 0xd8f7c829, // -
4840 0xe0d391, // <<
4841 0xf8d391, // >>
4842 0xe, // <=
4843 0xd, // >=
4844 0xc, // <
4845 0xf, // >
4846 0x4, // ==
4847 0x5, // !=
4848 0x0, // &&
4849 0x1, // ||
4850 0xc821, // &
4851 0xc831, // ^
4852 0xc809, // |
4853 0xd0f7, // ~
4854 0x4 // !
4855};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004856#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004857
Jack Palevich1cdef202009-05-22 12:06:27 -07004858struct ACCscript {
4859 ACCscript() {
4860 text = 0;
4861 textLength = 0;
4862 accError = ACC_NO_ERROR;
4863 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004864
Jack Palevich1cdef202009-05-22 12:06:27 -07004865 ~ACCscript() {
4866 delete text;
4867 }
Jack Palevich546b2242009-05-13 15:10:04 -07004868
Jack Palevich8c246a92009-07-14 21:14:10 -07004869 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4870 compiler.registerSymbolCallback(pFn, pContext);
4871 }
4872
Jack Palevich1cdef202009-05-22 12:06:27 -07004873 void setError(ACCenum error) {
4874 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4875 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004876 }
4877 }
4878
Jack Palevich1cdef202009-05-22 12:06:27 -07004879 ACCenum getError() {
4880 ACCenum result = accError;
4881 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004882 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004883 }
4884
Jack Palevich1cdef202009-05-22 12:06:27 -07004885 Compiler compiler;
4886 char* text;
4887 int textLength;
4888 ACCenum accError;
4889};
4890
4891
4892extern "C"
4893ACCscript* accCreateScript() {
4894 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004895}
Jack Palevich1cdef202009-05-22 12:06:27 -07004896
4897extern "C"
4898ACCenum accGetError( ACCscript* script ) {
4899 return script->getError();
4900}
4901
4902extern "C"
4903void accDeleteScript(ACCscript* script) {
4904 delete script;
4905}
4906
4907extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004908void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4909 ACCvoid* pContext) {
4910 script->registerSymbolCallback(pFn, pContext);
4911}
4912
4913extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004914void accScriptSource(ACCscript* script,
4915 ACCsizei count,
4916 const ACCchar ** string,
4917 const ACCint * length) {
4918 int totalLength = 0;
4919 for(int i = 0; i < count; i++) {
4920 int len = -1;
4921 const ACCchar* s = string[i];
4922 if (length) {
4923 len = length[i];
4924 }
4925 if (len < 0) {
4926 len = strlen(s);
4927 }
4928 totalLength += len;
4929 }
4930 delete script->text;
4931 char* text = new char[totalLength + 1];
4932 script->text = text;
4933 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004934 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004935 for(int i = 0; i < count; i++) {
4936 int len = -1;
4937 const ACCchar* s = string[i];
4938 if (length) {
4939 len = length[i];
4940 }
4941 if (len < 0) {
4942 len = strlen(s);
4943 }
Jack Palevich09555c72009-05-27 12:25:55 -07004944 memcpy(dest, s, len);
4945 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004946 }
4947 text[totalLength] = '\0';
4948}
4949
4950extern "C"
4951void accCompileScript(ACCscript* script) {
4952 int result = script->compiler.compile(script->text, script->textLength);
4953 if (result) {
4954 script->setError(ACC_INVALID_OPERATION);
4955 }
4956}
4957
4958extern "C"
4959void accGetScriptiv(ACCscript* script,
4960 ACCenum pname,
4961 ACCint * params) {
4962 switch (pname) {
4963 case ACC_INFO_LOG_LENGTH:
4964 *params = 0;
4965 break;
4966 }
4967}
4968
4969extern "C"
4970void accGetScriptInfoLog(ACCscript* script,
4971 ACCsizei maxLength,
4972 ACCsizei * length,
4973 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004974 char* message = script->compiler.getErrorMessage();
4975 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004976 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004977 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004978 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004979 if (infoLog && maxLength > 0) {
4980 int trimmedLength = maxLength < messageLength ?
4981 maxLength : messageLength;
4982 memcpy(infoLog, message, trimmedLength);
4983 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004984 }
4985}
4986
4987extern "C"
4988void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4989 ACCvoid ** address) {
4990 void* value = script->compiler.lookup(name);
4991 if (value) {
4992 *address = value;
4993 } else {
4994 script->setError(ACC_INVALID_VALUE);
4995 }
4996}
4997
Jack Palevicheedf9d22009-06-04 16:23:40 -07004998extern "C"
4999void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5000 ACCsizei maxStringCount, ACCchar** strings){
5001 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5002}
5003
-b master422972c2009-06-17 19:13:52 -07005004extern "C"
5005void accDisassemble(ACCscript* script) {
5006 script->compiler.disassemble(stderr);
5007}
5008
Jack Palevicheedf9d22009-06-04 16:23:40 -07005009
Jack Palevich1cdef202009-05-22 12:06:27 -07005010} // namespace acc
5011