blob: 78f33069f09470613e04a6083601359fd628037d [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){
2613 fprintf(stderr, "convertR0(pType)\n");
2614 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 Palevich569f1352009-06-29 14:29:08 -07003235
3236 // Arena for the duration of the compile
3237 Arena mGlobalArena;
3238 // Arena for data that's only needed when compiling a single function
3239 Arena mLocalArena;
3240
3241 TokenTable mTokenTable;
3242 SymbolStack mGlobals;
3243 SymbolStack mLocals;
3244
Jack Palevich40600de2009-07-01 15:32:35 -07003245 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003246 Type* mkpInt; // int
3247 Type* mkpChar; // char
3248 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003249 Type* mkpFloat;
3250 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003251 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003252 Type* mkpIntPtr;
3253 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003254 Type* mkpFloatPtr;
3255 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003256 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003257
Jack Palevich36d94142009-06-08 15:55:32 -07003258 InputStream* file;
3259
3260 CodeBuf codeBuf;
3261 CodeGenerator* pGen;
3262
Jack Palevicheedf9d22009-06-04 16:23:40 -07003263 String mErrorBuf;
3264
Jack Palevicheedf9d22009-06-04 16:23:40 -07003265 String mPragmas;
3266 int mPragmaStringCount;
3267
Jack Palevich21a15a22009-05-11 14:49:29 -07003268 static const int ALLOC_SIZE = 99999;
3269
Jack Palevich303d8ff2009-06-11 19:06:24 -07003270 static const int TOK_DUMMY = 1;
3271 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003272 static const int TOK_NUM_FLOAT = 3;
3273 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003274
3275 // 3..255 are character and/or operators
3276
Jack Palevich2db168f2009-06-11 14:29:47 -07003277 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003278 // Order has to match string list in "internKeywords".
3279 enum {
3280 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3281 TOK_INT = TOK_KEYWORD,
3282 TOK_CHAR,
3283 TOK_VOID,
3284 TOK_IF,
3285 TOK_ELSE,
3286 TOK_WHILE,
3287 TOK_BREAK,
3288 TOK_RETURN,
3289 TOK_FOR,
3290 TOK_PRAGMA,
3291 TOK_DEFINE,
3292 TOK_AUTO,
3293 TOK_CASE,
3294 TOK_CONST,
3295 TOK_CONTINUE,
3296 TOK_DEFAULT,
3297 TOK_DO,
3298 TOK_DOUBLE,
3299 TOK_ENUM,
3300 TOK_EXTERN,
3301 TOK_FLOAT,
3302 TOK_GOTO,
3303 TOK_LONG,
3304 TOK_REGISTER,
3305 TOK_SHORT,
3306 TOK_SIGNED,
3307 TOK_SIZEOF,
3308 TOK_STATIC,
3309 TOK_STRUCT,
3310 TOK_SWITCH,
3311 TOK_TYPEDEF,
3312 TOK_UNION,
3313 TOK_UNSIGNED,
3314 TOK_VOLATILE,
3315 TOK__BOOL,
3316 TOK__COMPLEX,
3317 TOK__IMAGINARY,
3318 TOK_INLINE,
3319 TOK_RESTRICT,
3320 // Symbols start after tokens
3321 TOK_SYMBOL
3322 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003323
3324 static const int LOCAL = 0x200;
3325
3326 static const int SYM_FORWARD = 0;
3327 static const int SYM_DEFINE = 1;
3328
3329 /* tokens in string heap */
3330 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003331
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003332 static const int OP_INCREMENT = 0;
3333 static const int OP_DECREMENT = 1;
3334 static const int OP_MUL = 2;
3335 static const int OP_DIV = 3;
3336 static const int OP_MOD = 4;
3337 static const int OP_PLUS = 5;
3338 static const int OP_MINUS = 6;
3339 static const int OP_SHIFT_LEFT = 7;
3340 static const int OP_SHIFT_RIGHT = 8;
3341 static const int OP_LESS_EQUAL = 9;
3342 static const int OP_GREATER_EQUAL = 10;
3343 static const int OP_LESS = 11;
3344 static const int OP_GREATER = 12;
3345 static const int OP_EQUALS = 13;
3346 static const int OP_NOT_EQUALS = 14;
3347 static const int OP_LOGICAL_AND = 15;
3348 static const int OP_LOGICAL_OR = 16;
3349 static const int OP_BIT_AND = 17;
3350 static const int OP_BIT_XOR = 18;
3351 static const int OP_BIT_OR = 19;
3352 static const int OP_BIT_NOT = 20;
3353 static const int OP_LOGICAL_NOT = 21;
3354 static const int OP_COUNT = 22;
3355
3356 /* Operators are searched from front, the two-character operators appear
3357 * before the single-character operators with the same first character.
3358 * @ is used to pad out single-character operators.
3359 */
3360 static const char* operatorChars;
3361 static const char operatorLevel[];
3362
Jack Palevich569f1352009-06-29 14:29:08 -07003363 /* Called when we detect an internal problem. Does nothing in production.
3364 *
3365 */
3366 void internalError() {
3367 * (char*) 0 = 0;
3368 }
3369
Jack Palevich86351982009-06-30 18:09:56 -07003370 void assert(bool isTrue) {
3371 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003372 internalError();
3373 }
Jack Palevich86351982009-06-30 18:09:56 -07003374 }
3375
Jack Palevich40600de2009-07-01 15:32:35 -07003376 bool isSymbol(tokenid_t t) {
3377 return t >= TOK_SYMBOL &&
3378 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3379 }
3380
3381 bool isSymbolOrKeyword(tokenid_t t) {
3382 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003383 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003384 }
3385
Jack Palevich86351982009-06-30 18:09:56 -07003386 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003387 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003388 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3389 if (pV && pV->tok != t) {
3390 internalError();
3391 }
3392 return pV;
3393 }
3394
3395 inline bool isDefined(tokenid_t t) {
3396 return t >= TOK_SYMBOL && VI(t) != 0;
3397 }
3398
Jack Palevich40600de2009-07-01 15:32:35 -07003399 const char* nameof(tokenid_t t) {
3400 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003401 return mTokenTable[t].pText;
3402 }
3403
Jack Palevich21a15a22009-05-11 14:49:29 -07003404 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003405 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003406 }
3407
3408 void inp() {
3409 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003410 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003411 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003412 dptr = 0;
3413 ch = dch;
3414 }
3415 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003416 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003417#if 0
3418 printf("ch='%c' 0x%x\n", ch, ch);
3419#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003420 }
3421
3422 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003423 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003424 }
3425
Jack Palevichb4758ff2009-06-12 12:49:14 -07003426 /* read a character constant, advances ch to after end of constant */
3427 int getq() {
3428 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003429 if (ch == '\\') {
3430 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003431 if (isoctal(ch)) {
3432 // 1 to 3 octal characters.
3433 val = 0;
3434 for(int i = 0; i < 3; i++) {
3435 if (isoctal(ch)) {
3436 val = (val << 3) + ch - '0';
3437 inp();
3438 }
3439 }
3440 return val;
3441 } else if (ch == 'x' || ch == 'X') {
3442 // N hex chars
3443 inp();
3444 if (! isxdigit(ch)) {
3445 error("'x' character escape requires at least one digit.");
3446 } else {
3447 val = 0;
3448 while (isxdigit(ch)) {
3449 int d = ch;
3450 if (isdigit(d)) {
3451 d -= '0';
3452 } else if (d <= 'F') {
3453 d = d - 'A' + 10;
3454 } else {
3455 d = d - 'a' + 10;
3456 }
3457 val = (val << 4) + d;
3458 inp();
3459 }
3460 }
3461 } else {
3462 int val = ch;
3463 switch (ch) {
3464 case 'a':
3465 val = '\a';
3466 break;
3467 case 'b':
3468 val = '\b';
3469 break;
3470 case 'f':
3471 val = '\f';
3472 break;
3473 case 'n':
3474 val = '\n';
3475 break;
3476 case 'r':
3477 val = '\r';
3478 break;
3479 case 't':
3480 val = '\t';
3481 break;
3482 case 'v':
3483 val = '\v';
3484 break;
3485 case '\\':
3486 val = '\\';
3487 break;
3488 case '\'':
3489 val = '\'';
3490 break;
3491 case '"':
3492 val = '"';
3493 break;
3494 case '?':
3495 val = '?';
3496 break;
3497 default:
3498 error("Undefined character escape %c", ch);
3499 break;
3500 }
3501 inp();
3502 return val;
3503 }
3504 } else {
3505 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003506 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003507 return val;
3508 }
3509
3510 static bool isoctal(int ch) {
3511 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003512 }
3513
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003514 bool acceptCh(int c) {
3515 bool result = c == ch;
3516 if (result) {
3517 pdef(ch);
3518 inp();
3519 }
3520 return result;
3521 }
3522
3523 bool acceptDigitsCh() {
3524 bool result = false;
3525 while (isdigit(ch)) {
3526 result = true;
3527 pdef(ch);
3528 inp();
3529 }
3530 return result;
3531 }
3532
3533 void parseFloat() {
3534 tok = TOK_NUM_DOUBLE;
3535 // mTokenString already has the integral part of the number.
3536 acceptCh('.');
3537 acceptDigitsCh();
3538 bool doExp = true;
3539 if (acceptCh('e') || acceptCh('E')) {
3540 // Don't need to do any extra work
3541 } else if (ch == 'f' || ch == 'F') {
3542 pdef('e'); // So it can be parsed by strtof.
3543 inp();
3544 tok = TOK_NUM_FLOAT;
3545 } else {
3546 doExp = false;
3547 }
3548 if (doExp) {
3549 bool digitsRequired = acceptCh('-');
3550 bool digitsFound = acceptDigitsCh();
3551 if (digitsRequired && ! digitsFound) {
3552 error("malformed exponent");
3553 }
3554 }
3555 char* pText = mTokenString.getUnwrapped();
3556 if (tok == TOK_NUM_FLOAT) {
3557 tokd = strtof(pText, 0);
3558 } else {
3559 tokd = strtod(pText, 0);
3560 }
3561 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
3562 }
3563
Jack Palevich21a15a22009-05-11 14:49:29 -07003564 void next() {
3565 int l, a;
3566
Jack Palevich546b2242009-05-13 15:10:04 -07003567 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003568 if (ch == '#') {
3569 inp();
3570 next();
3571 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003572 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003573 } else if (tok == TOK_PRAGMA) {
3574 doPragma();
3575 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003576 error("Unsupported preprocessor directive \"%s\"",
3577 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003578 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003579 }
3580 inp();
3581 }
3582 tokl = 0;
3583 tok = ch;
3584 /* encode identifiers & numbers */
3585 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003586 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003587 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003588 pdef(ch);
3589 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003590 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003591 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003592 // Start of a numeric constant. Could be integer, float, or
3593 // double, won't know until we look further.
3594 if (ch == '.' || ch == 'e' || ch == 'e'
3595 || ch == 'f' || ch == 'F') {
3596 parseFloat();
3597 } else {
3598 // It's an integer constant
3599 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
3600 tok = TOK_NUM;
3601 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003602 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003603 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
3604 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003605 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07003606 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3607 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003608 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07003609 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003610 dch = ch;
3611 inp();
3612 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003613 }
3614 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003615 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003616 inp();
3617 if (tok == '\'') {
3618 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003619 tokc = getq();
3620 if (ch != '\'') {
3621 error("Expected a ' character, got %c", ch);
3622 } else {
3623 inp();
3624 }
Jack Palevich546b2242009-05-13 15:10:04 -07003625 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003626 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003627 while (ch && ch != EOF) {
3628 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003629 inp();
3630 inp();
3631 if (ch == '/')
3632 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003633 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003634 if (ch == EOF) {
3635 error("End of file inside comment.");
3636 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003637 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003638 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003639 } else if ((tok == '/') & (ch == '/')) {
3640 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003641 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003642 inp();
3643 }
3644 inp();
3645 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003646 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003647 const char* t = operatorChars;
3648 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003649 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003650 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003651 tokl = operatorLevel[opIndex];
3652 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003653 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003654#if 0
3655 printf("%c%c -> tokl=%d tokc=0x%x\n",
3656 l, a, tokl, tokc);
3657#endif
3658 if (a == ch) {
3659 inp();
3660 tok = TOK_DUMMY; /* dummy token for double tokens */
3661 }
3662 break;
3663 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003664 opIndex++;
3665 }
3666 if (l == 0) {
3667 tokl = 0;
3668 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003669 }
3670 }
3671 }
3672#if 0
3673 {
Jack Palevich569f1352009-06-29 14:29:08 -07003674 String buf;
3675 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07003676 fprintf(stderr, "%s\n", buf.getUnwrapped());
3677 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003678#endif
3679 }
3680
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003681 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003682 next();
3683 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003684 String* pName = new String();
3685 while (isspace(ch)) {
3686 inp();
3687 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003688 if (ch == '(') {
3689 delete pName;
3690 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003691 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003692 }
3693 while (isspace(ch)) {
3694 inp();
3695 }
Jack Palevich569f1352009-06-29 14:29:08 -07003696 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003697 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003698 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003699 inp();
3700 }
Jack Palevich569f1352009-06-29 14:29:08 -07003701 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3702 memcpy(pDefn, value.getUnwrapped(), value.len());
3703 pDefn[value.len()] = 0;
3704 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003705 }
3706
Jack Palevicheedf9d22009-06-04 16:23:40 -07003707 void doPragma() {
3708 // # pragma name(val)
3709 int state = 0;
3710 while(ch != EOF && ch != '\n' && state < 10) {
3711 switch(state) {
3712 case 0:
3713 if (isspace(ch)) {
3714 inp();
3715 } else {
3716 state++;
3717 }
3718 break;
3719 case 1:
3720 if (isalnum(ch)) {
3721 mPragmas.append(ch);
3722 inp();
3723 } else if (ch == '(') {
3724 mPragmas.append(0);
3725 inp();
3726 state++;
3727 } else {
3728 state = 11;
3729 }
3730 break;
3731 case 2:
3732 if (isalnum(ch)) {
3733 mPragmas.append(ch);
3734 inp();
3735 } else if (ch == ')') {
3736 mPragmas.append(0);
3737 inp();
3738 state = 10;
3739 } else {
3740 state = 11;
3741 }
3742 break;
3743 }
3744 }
3745 if(state != 10) {
3746 error("Unexpected pragma syntax");
3747 }
3748 mPragmaStringCount += 2;
3749 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003750
Jack Palevichac0e95e2009-05-29 13:53:44 -07003751 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003752 mErrorBuf.printf("%ld: ", file->getLine());
3753 mErrorBuf.vprintf(fmt, ap);
3754 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003755 }
3756
Jack Palevich8b0624c2009-05-20 12:12:06 -07003757 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003758 if (tok != c) {
3759 error("'%c' expected", c);
3760 }
3761 next();
3762 }
3763
Jack Palevich86351982009-06-30 18:09:56 -07003764 bool accept(intptr_t c) {
3765 if (tok == c) {
3766 next();
3767 return true;
3768 }
3769 return false;
3770 }
3771
Jack Palevich40600de2009-07-01 15:32:35 -07003772 bool acceptStringLiteral() {
3773 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003774 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003775 // This while loop merges multiple adjacent string constants.
3776 while (tok == '"') {
3777 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003778 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003779 }
3780 if (ch != '"') {
3781 error("Unterminated string constant.");
3782 }
3783 inp();
3784 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003785 }
Jack Palevich40600de2009-07-01 15:32:35 -07003786 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003787 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003788 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003789 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003790
3791 return true;
3792 }
3793 return false;
3794 }
3795 /* Parse and evaluate a unary expression.
3796 * allowAssignment is true if '=' parsing wanted (quick hack)
3797 */
3798 void unary(bool allowAssignment) {
3799 intptr_t n, t, a;
3800 t = 0;
3801 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3802 if (acceptStringLiteral()) {
3803 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003804 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003805 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003806 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003807 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003808 t = tok;
3809 next();
3810 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003811 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003812 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003813 // Align to 4-byte boundary
3814 glo = (char*) (((intptr_t) glo + 3) & -4);
3815 * (float*) glo = (float) ad;
3816 pGen->loadFloat((int) glo, mkpFloat);
3817 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003818 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003819 // Align to 8-byte boundary
3820 glo = (char*) (((intptr_t) glo + 7) & -8);
3821 * (double*) glo = ad;
3822 pGen->loadFloat((int) glo, mkpDouble);
3823 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003824 } else if (c == 2) {
3825 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003826 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003827 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003828 pGen->gUnaryCmp(a, mkpInt);
3829 else if (t == '+') {
3830 // ignore unary plus.
3831 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003832 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003833 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003834 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003835 // It's either a cast or an expression
3836 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3837 if (pCast) {
3838 skip(')');
3839 unary(false);
3840 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003841 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003842 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003843 skip(')');
3844 }
3845 } else if (t == '*') {
3846 /* This is a pointer dereference.
3847 */
3848 unary(false);
3849 Type* pR0Type = pGen->getR0Type();
3850 if (pR0Type->tag != TY_POINTER) {
3851 error("Expected a pointer type.");
3852 } else {
3853 if (pR0Type->pHead->tag == TY_FUNC) {
3854 t = 0;
3855 }
3856 if (accept('=')) {
3857 pGen->pushR0();
3858 expr();
3859 pGen->storeR0ToTOS(pR0Type);
3860 } else if (t) {
3861 pGen->loadR0FromR0(pR0Type);
3862 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003863 }
Jack Palevich3f226492009-07-02 14:46:19 -07003864 // Else we fall through to the function call below, with
3865 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003866 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003867 VariableInfo* pVI = VI(tok);
3868 pGen->leaR0((int) pVI->pAddress,
3869 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003870 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003871 } else if (t == EOF ) {
3872 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003873 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003874 // Don't have to do anything special here, the error
3875 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003876 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003877 if (!isDefined(t)) {
3878 mGlobals.add(t);
3879 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003880 }
Jack Palevich8df46192009-07-07 14:48:51 -07003881 VariableInfo* pVI = VI(t);
3882 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003883 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003884 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003885 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003886 if (tok == '(') {
3887 pVI->pType = mkpIntFn;
3888 } else {
3889 pVI->pType = mkpInt;
3890 }
Jack Palevich8df46192009-07-07 14:48:51 -07003891 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003892 }
Jack Palevich40600de2009-07-01 15:32:35 -07003893 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003894 /* assignment */
3895 next();
3896 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003897 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003898 } else if (tok != '(') {
3899 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003900 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003901 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003902 }
Jack Palevich8df46192009-07-07 14:48:51 -07003903 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003904 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003905 next();
3906 }
3907 }
3908 }
3909 }
3910
3911 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003912 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003913 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003914 VariableInfo* pVI = NULL;
3915 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003916 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003917 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003918 } else {
3919 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003920 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003921 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003922 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003923 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003924 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003925 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003926 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003927 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003928 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003929 if (! varArgs && !pArgList) {
3930 error ("Unexpected argument.");
3931 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003932 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003933 Type* pTargetType;
3934 if (pArgList) {
3935 pTargetType = pArgList->pHead;
3936 pArgList = pArgList->pTail;
3937 } else {
3938 pTargetType = pGen->getR0Type();
3939 if (pTargetType->tag == TY_FLOAT) {
3940 pTargetType = mkpDouble;
3941 }
3942 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003943 if (pTargetType->tag == TY_VOID) {
3944 error("Can't pass void value for argument %d",
3945 argCount + 1);
3946 } else {
3947 pGen->convertR0(pTargetType);
3948 l += pGen->storeR0ToArg(l);
3949 }
Jack Palevich95727a02009-07-06 12:07:15 -07003950 if (accept(',')) {
3951 // fine
3952 } else if ( tok != ')') {
3953 error("Expected ',' or ')'");
3954 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003955 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003956 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003957 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003958 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003959 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003960 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003961 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003962 if (!n) {
3963 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003964 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3965 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003966 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003967 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003968 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003969 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3970 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003971 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003972 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003973 }
3974 }
3975
Jack Palevich40600de2009-07-01 15:32:35 -07003976 /* Recursive descent parser for binary operations.
3977 */
3978 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003979 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003980 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003981 if (level-- == 1)
3982 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003983 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003984 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003985 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003986 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003987 n = tok;
3988 t = tokc;
3989 next();
3990
Jack Palevich40600de2009-07-01 15:32:35 -07003991 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003992 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003993 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003995 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003996 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003997
Jack Palevich40600de2009-07-01 15:32:35 -07003998 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003999 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004000 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004001 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004002 }
4003 }
4004 }
4005 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004006 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004007 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004008 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004009 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004010 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004011 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004012 }
4013 }
4014 }
4015
4016 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004017 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004018 }
4019
4020 int test_expr() {
4021 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004022 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004023 }
4024
Jack Palevicha6baa232009-06-12 11:25:59 -07004025 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004026 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004027
Jack Palevich95727a02009-07-06 12:07:15 -07004028 Type* pBaseType;
4029 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004030 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004031 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004032 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004033 next();
4034 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 a = test_expr();
4036 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004037 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004039 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004040 n = pGen->gjmp(0); /* jmp */
4041 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004042 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004043 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004044 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004045 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004046 }
Jack Palevich546b2242009-05-13 15:10:04 -07004047 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004048 t = tok;
4049 next();
4050 skip('(');
4051 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004052 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004053 a = test_expr();
4054 } else {
4055 if (tok != ';')
4056 expr();
4057 skip(';');
4058 n = codeBuf.getPC();
4059 a = 0;
4060 if (tok != ';')
4061 a = test_expr();
4062 skip(';');
4063 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004064 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004065 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004066 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004067 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004068 n = t + 4;
4069 }
4070 }
4071 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004072 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004073 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004074 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004076 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004077 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004078 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004079 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004080 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004081 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004082 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004083 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004084 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004085 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004086 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004087 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004088 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004089 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004090 if (pReturnType->tag == TY_VOID) {
4091 error("Must not return a value from a void function");
4092 } else {
4093 pGen->convertR0(pReturnType);
4094 }
4095 } else {
4096 if (pReturnType->tag != TY_VOID) {
4097 error("Must specify a value here");
4098 }
Jack Palevich8df46192009-07-07 14:48:51 -07004099 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004100 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004101 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004102 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004103 } else if (tok != ';')
4104 expr();
4105 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004106 }
4107 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004108
Jack Palevicha8f427f2009-07-13 18:40:08 -07004109 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004110 if (a == b) {
4111 return true;
4112 }
4113 if (a == NULL || b == NULL) {
4114 return false;
4115 }
4116 TypeTag at = a->tag;
4117 if (at != b->tag) {
4118 return false;
4119 }
4120 if (at == TY_POINTER) {
4121 return typeEqual(a->pHead, b->pHead);
4122 } else if (at == TY_FUNC || at == TY_PARAM) {
4123 return typeEqual(a->pHead, b->pHead)
4124 && typeEqual(a->pTail, b->pTail);
4125 }
4126 return true;
4127 }
4128
Jack Palevich86351982009-06-30 18:09:56 -07004129 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4130 assert(tag >= TY_INT && tag <= TY_PARAM);
4131 Type* pType = (Type*) arena.alloc(sizeof(Type));
4132 memset(pType, 0, sizeof(*pType));
4133 pType->tag = tag;
4134 pType->pHead = pHead;
4135 pType->pTail = pTail;
4136 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004137 }
4138
Jack Palevich3f226492009-07-02 14:46:19 -07004139 Type* createPtrType(Type* pType, Arena& arena) {
4140 return createType(TY_POINTER, pType, NULL, arena);
4141 }
4142
4143 /**
4144 * Try to print a type in declaration order
4145 */
Jack Palevich86351982009-06-30 18:09:56 -07004146 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004147 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004148 if (pType == NULL) {
4149 buffer.appendCStr("null");
4150 return;
4151 }
Jack Palevich3f226492009-07-02 14:46:19 -07004152 decodeTypeImp(buffer, pType);
4153 }
4154
4155 void decodeTypeImp(String& buffer, Type* pType) {
4156 decodeTypeImpPrefix(buffer, pType);
4157
Jack Palevich86351982009-06-30 18:09:56 -07004158 String temp;
4159 if (pType->id != 0) {
4160 decodeToken(temp, pType->id);
4161 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004162 }
4163
4164 decodeTypeImpPostfix(buffer, pType);
4165 }
4166
4167 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4168 TypeTag tag = pType->tag;
4169
4170 if (tag >= TY_INT && tag <= TY_VOID) {
4171 switch (tag) {
4172 case TY_INT:
4173 buffer.appendCStr("int");
4174 break;
4175 case TY_CHAR:
4176 buffer.appendCStr("char");
4177 break;
4178 case TY_VOID:
4179 buffer.appendCStr("void");
4180 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004181 case TY_FLOAT:
4182 buffer.appendCStr("float");
4183 break;
4184 case TY_DOUBLE:
4185 buffer.appendCStr("double");
4186 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004187 default:
4188 break;
4189 }
Jack Palevich86351982009-06-30 18:09:56 -07004190 buffer.append(' ');
4191 }
Jack Palevich3f226492009-07-02 14:46:19 -07004192
4193 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004194 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004195 break;
4196 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004197 break;
4198 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004199 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004200 case TY_FLOAT:
4201 break;
4202 case TY_DOUBLE:
4203 break;
Jack Palevich86351982009-06-30 18:09:56 -07004204 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004205 decodeTypeImpPrefix(buffer, pType->pHead);
4206 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4207 buffer.append('(');
4208 }
4209 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004210 break;
4211 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004212 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004213 break;
4214 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004215 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004216 break;
4217 default:
4218 String temp;
4219 temp.printf("Unknown tag %d", pType->tag);
4220 buffer.append(temp);
4221 break;
4222 }
Jack Palevich3f226492009-07-02 14:46:19 -07004223 }
4224
4225 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4226 TypeTag tag = pType->tag;
4227
4228 switch(tag) {
4229 case TY_POINTER:
4230 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4231 buffer.append(')');
4232 }
4233 decodeTypeImpPostfix(buffer, pType->pHead);
4234 break;
4235 case TY_FUNC:
4236 buffer.append('(');
4237 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4238 decodeTypeImp(buffer, pArg);
4239 if (pArg->pTail) {
4240 buffer.appendCStr(", ");
4241 }
4242 }
4243 buffer.append(')');
4244 break;
4245 default:
4246 break;
Jack Palevich86351982009-06-30 18:09:56 -07004247 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004248 }
4249
Jack Palevich86351982009-06-30 18:09:56 -07004250 void printType(Type* pType) {
4251 String buffer;
4252 decodeType(buffer, pType);
4253 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004254 }
4255
Jack Palevich86351982009-06-30 18:09:56 -07004256 Type* acceptPrimitiveType(Arena& arena) {
4257 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004258 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004259 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004260 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004261 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004262 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004263 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004264 } else if (tok == TOK_FLOAT) {
4265 pType = mkpFloat;
4266 } else if (tok == TOK_DOUBLE) {
4267 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004268 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004269 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004270 }
4271 next();
Jack Palevich86351982009-06-30 18:09:56 -07004272 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004273 }
4274
Jack Palevich3f226492009-07-02 14:46:19 -07004275 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4276 Arena& arena) {
4277 tokenid_t declName = 0;
4278 pType = acceptDecl2(pType, declName, nameAllowed,
4279 nameRequired, arena);
4280 if (declName) {
4281 // Clone the parent type so we can set a unique ID
4282 pType = createType(pType->tag, pType->pHead,
4283 pType->pTail, arena);
4284
Jack Palevich86351982009-06-30 18:09:56 -07004285 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004286 }
Jack Palevich3f226492009-07-02 14:46:19 -07004287 // fprintf(stderr, "Parsed a declaration: ");
4288 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004289 return pType;
4290 }
4291
Jack Palevich3f226492009-07-02 14:46:19 -07004292 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4293 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004294 if (! pType) {
4295 error("Expected a declaration");
4296 }
4297 return pType;
4298 }
4299
Jack Palevich3f226492009-07-02 14:46:19 -07004300 /* Used for accepting types that appear in casts */
4301 Type* acceptCastTypeDeclaration(Arena& arena) {
4302 Type* pType = acceptPrimitiveType(arena);
4303 if (pType) {
4304 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004305 }
Jack Palevich86351982009-06-30 18:09:56 -07004306 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004307 }
4308
Jack Palevich3f226492009-07-02 14:46:19 -07004309 Type* expectCastTypeDeclaration(Arena& arena) {
4310 Type* pType = acceptCastTypeDeclaration(arena);
4311 if (! pType) {
4312 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004313 }
Jack Palevich3f226492009-07-02 14:46:19 -07004314 return pType;
4315 }
4316
4317 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4318 bool nameAllowed, bool nameRequired, Arena& arena) {
4319 int ptrCounter = 0;
4320 while (accept('*')) {
4321 ptrCounter++;
4322 }
4323 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4324 while (ptrCounter-- > 0) {
4325 pType = createType(TY_POINTER, pType, NULL, arena);
4326 }
4327 return pType;
4328 }
4329
4330 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4331 bool nameAllowed, bool nameRequired, Arena& arena) {
4332 // direct-dcl :
4333 // name
4334 // (dcl)
4335 // direct-dcl()
4336 // direct-dcl[]
4337 Type* pNewHead = NULL;
4338 if (accept('(')) {
4339 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4340 nameRequired, arena);
4341 skip(')');
4342 } else if ((declName = acceptSymbol()) != 0) {
4343 if (nameAllowed == false && declName) {
4344 error("Symbol %s not allowed here", nameof(declName));
4345 } else if (nameRequired && ! declName) {
4346 String temp;
4347 decodeToken(temp, tok);
4348 error("Expected symbol. Got %s", temp.getUnwrapped());
4349 }
4350 }
4351 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004352 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004353 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004354 pType = createType(TY_FUNC, pType, pTail, arena);
4355 skip(')');
4356 }
Jack Palevich3f226492009-07-02 14:46:19 -07004357
4358 if (pNewHead) {
4359 Type* pA = pNewHead;
4360 while (pA->pHead) {
4361 pA = pA->pHead;
4362 }
4363 pA->pHead = pType;
4364 pType = pNewHead;
4365 }
Jack Palevich86351982009-06-30 18:09:56 -07004366 return pType;
4367 }
4368
Jack Palevich3f226492009-07-02 14:46:19 -07004369 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004370 Type* pHead = NULL;
4371 Type* pTail = NULL;
4372 for(;;) {
4373 Type* pBaseArg = acceptPrimitiveType(arena);
4374 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004375 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4376 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004377 if (pArg) {
4378 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4379 if (!pHead) {
4380 pHead = pParam;
4381 pTail = pParam;
4382 } else {
4383 pTail->pTail = pParam;
4384 pTail = pParam;
4385 }
4386 }
4387 }
4388 if (! accept(',')) {
4389 break;
4390 }
4391 }
4392 return pHead;
4393 }
4394
4395 Type* expectPrimitiveType(Arena& arena) {
4396 Type* pType = acceptPrimitiveType(arena);
4397 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004398 String buf;
4399 decodeToken(buf, tok);
4400 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004401 }
Jack Palevich86351982009-06-30 18:09:56 -07004402 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004403 }
4404
Jack Palevich86351982009-06-30 18:09:56 -07004405 void addGlobalSymbol(Type* pDecl) {
4406 tokenid_t t = pDecl->id;
4407 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004408 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004409 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004410 }
Jack Palevich86351982009-06-30 18:09:56 -07004411 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004412 }
4413
Jack Palevich86351982009-06-30 18:09:56 -07004414 void reportDuplicate(tokenid_t t) {
4415 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004416 }
4417
Jack Palevich86351982009-06-30 18:09:56 -07004418 void addLocalSymbol(Type* pDecl) {
4419 tokenid_t t = pDecl->id;
4420 if (mLocals.isDefinedAtCurrentLevel(t)) {
4421 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004422 }
Jack Palevich86351982009-06-30 18:09:56 -07004423 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004424 }
4425
Jack Palevich95727a02009-07-06 12:07:15 -07004426 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004427 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004428
Jack Palevich95727a02009-07-06 12:07:15 -07004429 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004430 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004431 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4432 if (!pDecl) {
4433 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004434 }
Jack Palevich86351982009-06-30 18:09:56 -07004435 int variableAddress = 0;
4436 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004437 size_t alignment = pGen->alignmentOf(pDecl);
4438 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004439 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004440 variableAddress = -loc;
4441 VI(pDecl->id)->pAddress = (void*) variableAddress;
4442 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004443 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004444 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004445 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004446 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004447 if (tok == ',')
4448 next();
4449 }
4450 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004451 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004452 }
4453 }
4454
Jack Palevichf1728be2009-06-12 13:53:51 -07004455 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004456 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004457 }
4458
Jack Palevich569f1352009-06-29 14:29:08 -07004459 void decodeToken(String& buffer, tokenid_t token) {
4460 if (token == EOF ) {
4461 buffer.printf("EOF");
4462 } else if (token == TOK_NUM) {
4463 buffer.printf("numeric constant");
4464 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004465 if (token < 32) {
4466 buffer.printf("'\\x%02x'", token);
4467 } else {
4468 buffer.printf("'%c'", token);
4469 }
Jack Palevich569f1352009-06-29 14:29:08 -07004470 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4471 buffer.printf("keyword \"%s\"", nameof(token));
4472 } else {
4473 buffer.printf("symbol \"%s\"", nameof(token));
4474 }
4475 }
4476
Jack Palevich40600de2009-07-01 15:32:35 -07004477 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004478 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004479 if (!result) {
4480 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07004481 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07004482 error("Expected symbol. Got %s", temp.getUnwrapped());
4483 }
4484 return result;
4485 }
4486
Jack Palevich86351982009-06-30 18:09:56 -07004487 tokenid_t acceptSymbol() {
4488 tokenid_t result = 0;
4489 if (tok >= TOK_SYMBOL) {
4490 result = tok;
4491 next();
Jack Palevich86351982009-06-30 18:09:56 -07004492 }
4493 return result;
4494 }
4495
Jack Palevichb7c81e92009-06-04 19:56:13 -07004496 void globalDeclarations() {
4497 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004498 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4499 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004500 break;
4501 }
Jack Palevich86351982009-06-30 18:09:56 -07004502 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4503 if (!pDecl) {
4504 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004505 }
Jack Palevich86351982009-06-30 18:09:56 -07004506 if (! isDefined(pDecl->id)) {
4507 addGlobalSymbol(pDecl);
4508 }
4509 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004510 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004511 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004512 }
Jack Palevich86351982009-06-30 18:09:56 -07004513 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004514 // it's a variable declaration
4515 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004516 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004517 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004518 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004519 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004520 }
Jack Palevich86351982009-06-30 18:09:56 -07004521 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004522 if (tok == TOK_NUM) {
4523 if (name) {
4524 * (int*) name->pAddress = tokc;
4525 }
4526 next();
4527 } else {
4528 error("Expected an integer constant");
4529 }
4530 }
Jack Palevich86351982009-06-30 18:09:56 -07004531 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004532 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004533 }
Jack Palevich86351982009-06-30 18:09:56 -07004534 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4535 if (!pDecl) {
4536 break;
4537 }
4538 if (! isDefined(pDecl->id)) {
4539 addGlobalSymbol(pDecl);
4540 }
4541 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004542 }
4543 skip(';');
4544 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004545 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004546 if (accept(';')) {
4547 // forward declaration.
4548 } else {
4549 if (name) {
4550 /* patch forward references (XXX: does not work for function
4551 pointers) */
4552 pGen->gsym((int) name->pForward);
4553 /* put function address */
4554 name->pAddress = (void*) codeBuf.getPC();
4555 }
4556 // Calculate stack offsets for parameters
4557 mLocals.pushLevel();
4558 intptr_t a = 8;
4559 int argCount = 0;
4560 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4561 Type* pArg = pP->pHead;
4562 addLocalSymbol(pArg);
4563 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004564 size_t alignment = pGen->alignmentOf(pArg);
4565 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004566 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004567 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004568 argCount++;
4569 }
4570 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004571 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004572 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004573 block(0, true);
4574 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004575 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004576 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004577 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004578 }
4579 }
4580 }
4581
Jack Palevich9cbd2262009-07-08 16:48:41 -07004582 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4583 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4584 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004585 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004586 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004587 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004588 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004589 char* result = (char*) base;
4590 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004591 return result;
4592 }
4593
Jack Palevich21a15a22009-05-11 14:49:29 -07004594 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004595 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004596 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004597 pGlobalBase = 0;
4598 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004599 if (pGen) {
4600 delete pGen;
4601 pGen = 0;
4602 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004603 if (file) {
4604 delete file;
4605 file = 0;
4606 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004607 }
4608
4609 void clear() {
4610 tok = 0;
4611 tokc = 0;
4612 tokl = 0;
4613 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004614 rsym = 0;
4615 loc = 0;
4616 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004617 dptr = 0;
4618 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004619 file = 0;
4620 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004621 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004622 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004623 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004624
Jack Palevich22305132009-05-13 10:58:45 -07004625 void setArchitecture(const char* architecture) {
4626 delete pGen;
4627 pGen = 0;
4628
4629 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004630#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004631 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004632 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004633 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004634#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004635#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004636 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004637 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004638 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004639#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004640 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004641 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004642 }
4643 }
4644
4645 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004646#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004647 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004648#elif defined(DEFAULT_X86_CODEGEN)
4649 pGen = new X86CodeGenerator();
4650#endif
4651 }
4652 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004653 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004654 } else {
4655 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004656 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004657 }
4658 }
4659
Jack Palevich77ae76e2009-05-10 19:59:24 -07004660public:
Jack Palevich22305132009-05-13 10:58:45 -07004661 struct args {
4662 args() {
4663 architecture = 0;
4664 }
4665 const char* architecture;
4666 };
4667
Jack Paleviche7b59062009-05-19 17:12:17 -07004668 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004669 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004670 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004671
Jack Paleviche7b59062009-05-19 17:12:17 -07004672 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004673 cleanup();
4674 }
4675
Jack Palevich1cdef202009-05-22 12:06:27 -07004676 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004677 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004678
Jack Palevicha8f427f2009-07-13 18:40:08 -07004679 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004680 cleanup();
4681 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004682 mTokenTable.setArena(&mGlobalArena);
4683 mGlobals.setArena(&mGlobalArena);
4684 mGlobals.setTokenTable(&mTokenTable);
4685 mLocals.setArena(&mLocalArena);
4686 mLocals.setTokenTable(&mTokenTable);
4687
4688 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004689 codeBuf.init(ALLOC_SIZE);
4690 setArchitecture(NULL);
4691 if (!pGen) {
4692 return -1;
4693 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004694#ifdef PROVIDE_TRACE_CODEGEN
4695 pGen = new TraceCodeGenerator(pGen);
4696#endif
4697 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004698 pGen->init(&codeBuf);
4699 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004700 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4701 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004702 inp();
4703 next();
4704 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004705 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004706 result = pGen->finishCompile();
4707 if (result == 0) {
4708 if (mErrorBuf.len()) {
4709 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004710 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004711 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004712 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004713 }
4714
Jack Palevich86351982009-06-30 18:09:56 -07004715 void createPrimitiveTypes() {
4716 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4717 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4718 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004719 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4720 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004721 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004722 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4723 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004724 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4725 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004726 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004727 }
4728
Jack Palevicha6baa232009-06-12 11:25:59 -07004729 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004730 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004731 }
4732
Jack Palevich569f1352009-06-29 14:29:08 -07004733 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004734 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004735 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004736 }
4737
Jack Palevich569f1352009-06-29 14:29:08 -07004738 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004739 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004740 error("Undefined forward reference: %s",
4741 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004742 }
4743 return true;
4744 }
4745
Jack Palevich21a15a22009-05-11 14:49:29 -07004746 int dump(FILE* out) {
4747 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4748 return 0;
4749 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004750
Jack Palevicha6535612009-05-13 16:24:17 -07004751 int disassemble(FILE* out) {
4752 return pGen->disassemble(out);
4753 }
4754
Jack Palevich1cdef202009-05-22 12:06:27 -07004755 /* Look through the symbol table to find a symbol.
4756 * If found, return its value.
4757 */
4758 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004759 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4760 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004761 if (pVariableInfo) {
4762 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004763 }
4764 return NULL;
4765 }
4766
Jack Palevicheedf9d22009-06-04 16:23:40 -07004767 void getPragmas(ACCsizei* actualStringCount,
4768 ACCsizei maxStringCount, ACCchar** strings) {
4769 int stringCount = mPragmaStringCount;
4770 if (actualStringCount) {
4771 *actualStringCount = stringCount;
4772 }
4773 if (stringCount > maxStringCount) {
4774 stringCount = maxStringCount;
4775 }
4776 if (strings) {
4777 char* pPragmas = mPragmas.getUnwrapped();
4778 while (stringCount-- > 0) {
4779 *strings++ = pPragmas;
4780 pPragmas += strlen(pPragmas) + 1;
4781 }
4782 }
4783 }
4784
Jack Palevichac0e95e2009-05-29 13:53:44 -07004785 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004786 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004787 }
4788
Jack Palevich77ae76e2009-05-10 19:59:24 -07004789};
4790
Jack Paleviche7b59062009-05-19 17:12:17 -07004791const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004792 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4793
Jack Paleviche7b59062009-05-19 17:12:17 -07004794const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004795 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4796 5, 5, /* ==, != */
4797 9, 10, /* &&, || */
4798 6, 7, 8, /* & ^ | */
4799 2, 2 /* ~ ! */
4800 };
4801
Jack Palevich8b0624c2009-05-20 12:12:06 -07004802#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004803FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004804#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004805
Jack Palevich8b0624c2009-05-20 12:12:06 -07004806#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004807const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004808 0x1, // ++
4809 0xff, // --
4810 0xc1af0f, // *
4811 0xf9f79991, // /
4812 0xf9f79991, // % (With manual assist to swap results)
4813 0xc801, // +
4814 0xd8f7c829, // -
4815 0xe0d391, // <<
4816 0xf8d391, // >>
4817 0xe, // <=
4818 0xd, // >=
4819 0xc, // <
4820 0xf, // >
4821 0x4, // ==
4822 0x5, // !=
4823 0x0, // &&
4824 0x1, // ||
4825 0xc821, // &
4826 0xc831, // ^
4827 0xc809, // |
4828 0xd0f7, // ~
4829 0x4 // !
4830};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004831#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004832
Jack Palevich1cdef202009-05-22 12:06:27 -07004833struct ACCscript {
4834 ACCscript() {
4835 text = 0;
4836 textLength = 0;
4837 accError = ACC_NO_ERROR;
4838 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004839
Jack Palevich1cdef202009-05-22 12:06:27 -07004840 ~ACCscript() {
4841 delete text;
4842 }
Jack Palevich546b2242009-05-13 15:10:04 -07004843
Jack Palevich1cdef202009-05-22 12:06:27 -07004844 void setError(ACCenum error) {
4845 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4846 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004847 }
4848 }
4849
Jack Palevich1cdef202009-05-22 12:06:27 -07004850 ACCenum getError() {
4851 ACCenum result = accError;
4852 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004853 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004854 }
4855
Jack Palevich1cdef202009-05-22 12:06:27 -07004856 Compiler compiler;
4857 char* text;
4858 int textLength;
4859 ACCenum accError;
4860};
4861
4862
4863extern "C"
4864ACCscript* accCreateScript() {
4865 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004866}
Jack Palevich1cdef202009-05-22 12:06:27 -07004867
4868extern "C"
4869ACCenum accGetError( ACCscript* script ) {
4870 return script->getError();
4871}
4872
4873extern "C"
4874void accDeleteScript(ACCscript* script) {
4875 delete script;
4876}
4877
4878extern "C"
4879void accScriptSource(ACCscript* script,
4880 ACCsizei count,
4881 const ACCchar ** string,
4882 const ACCint * length) {
4883 int totalLength = 0;
4884 for(int i = 0; i < count; i++) {
4885 int len = -1;
4886 const ACCchar* s = string[i];
4887 if (length) {
4888 len = length[i];
4889 }
4890 if (len < 0) {
4891 len = strlen(s);
4892 }
4893 totalLength += len;
4894 }
4895 delete script->text;
4896 char* text = new char[totalLength + 1];
4897 script->text = text;
4898 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004899 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004900 for(int i = 0; i < count; i++) {
4901 int len = -1;
4902 const ACCchar* s = string[i];
4903 if (length) {
4904 len = length[i];
4905 }
4906 if (len < 0) {
4907 len = strlen(s);
4908 }
Jack Palevich09555c72009-05-27 12:25:55 -07004909 memcpy(dest, s, len);
4910 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004911 }
4912 text[totalLength] = '\0';
4913}
4914
4915extern "C"
4916void accCompileScript(ACCscript* script) {
4917 int result = script->compiler.compile(script->text, script->textLength);
4918 if (result) {
4919 script->setError(ACC_INVALID_OPERATION);
4920 }
4921}
4922
4923extern "C"
4924void accGetScriptiv(ACCscript* script,
4925 ACCenum pname,
4926 ACCint * params) {
4927 switch (pname) {
4928 case ACC_INFO_LOG_LENGTH:
4929 *params = 0;
4930 break;
4931 }
4932}
4933
4934extern "C"
4935void accGetScriptInfoLog(ACCscript* script,
4936 ACCsizei maxLength,
4937 ACCsizei * length,
4938 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004939 char* message = script->compiler.getErrorMessage();
4940 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004941 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004942 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004943 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004944 if (infoLog && maxLength > 0) {
4945 int trimmedLength = maxLength < messageLength ?
4946 maxLength : messageLength;
4947 memcpy(infoLog, message, trimmedLength);
4948 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004949 }
4950}
4951
4952extern "C"
4953void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4954 ACCvoid ** address) {
4955 void* value = script->compiler.lookup(name);
4956 if (value) {
4957 *address = value;
4958 } else {
4959 script->setError(ACC_INVALID_VALUE);
4960 }
4961}
4962
Jack Palevicheedf9d22009-06-04 16:23:40 -07004963extern "C"
4964void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4965 ACCsizei maxStringCount, ACCchar** strings){
4966 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4967}
4968
-b master422972c2009-06-17 19:13:52 -07004969extern "C"
4970void accDisassemble(ACCscript* script) {
4971 script->compiler.disassemble(stderr);
4972}
4973
Jack Palevicheedf9d22009-06-04 16:23:40 -07004974
Jack Palevich1cdef202009-05-22 12:06:27 -07004975} // namespace acc
4976