blob: a84bd91016171212fa2f1f39ac2544a0baac0454 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070041#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070042#endif
Jack Palevicha6535612009-05-13 16:24:17 -070043
Jack Palevich1cdef202009-05-22 12:06:27 -070044#include <acc/acc.h>
45
Jack Palevich09555c72009-05-27 12:25:55 -070046#define LOG_API(...) do {} while(0)
47// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070048
-b master422972c2009-06-17 19:13:52 -070049#define LOG_STACK(...) do {} while(0)
50// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
51
52// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070053// #define PROVIDE_TRACE_CODEGEN
54
Jack Palevichbbf8ab52009-05-11 11:54:30 -070055namespace acc {
56
Jack Palevich8df46192009-07-07 14:48:51 -070057// Subset of STL vector.
58template<class E> class Vector {
59 public:
60 Vector() {
61 mpBase = 0;
62 mUsed = 0;
63 mSize = 0;
64 }
65
66 ~Vector() {
67 if (mpBase) {
68 for(size_t i = 0; i < mUsed; i++) {
69 mpBase[mUsed].~E();
70 }
71 free(mpBase);
72 }
73 }
74
75 inline E& operator[](size_t i) {
76 return mpBase[i];
77 }
78
79 inline E& front() {
80 return mpBase[0];
81 }
82
83 inline E& back() {
84 return mpBase[mUsed - 1];
85 }
86
87 void pop_back() {
88 mUsed -= 1;
89 mpBase[mUsed].~E();
90 }
91
92 void push_back(const E& item) {
93 * ensure(1) = item;
94 }
95
96 size_t size() {
97 return mUsed;
98 }
99
100private:
101 E* ensure(int n) {
102 size_t newUsed = mUsed + n;
103 if (newUsed > mSize) {
104 size_t newSize = mSize * 2 + 10;
105 if (newSize < newUsed) {
106 newSize = newUsed;
107 }
108 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
109 mSize = newSize;
110 }
111 E* result = mpBase + mUsed;
112 mUsed = newUsed;
113 return result;
114 }
115
116 E* mpBase;
117 size_t mUsed;
118 size_t mSize;
119};
120
Jack Palevichac0e95e2009-05-29 13:53:44 -0700121class ErrorSink {
122public:
123 void error(const char *fmt, ...) {
124 va_list ap;
125 va_start(ap, fmt);
126 verror(fmt, ap);
127 va_end(ap);
128 }
129
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700130 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700131 virtual void verror(const char* fmt, va_list ap) = 0;
132};
133
134class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700135 typedef int tokenid_t;
136 enum TypeTag {
137 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
138 TY_POINTER, TY_FUNC, TY_PARAM
139 };
140
141 struct Type {
142 TypeTag tag;
143 tokenid_t id; // For function arguments
144 Type* pHead;
145 Type* pTail;
146 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700147
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700149 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700150 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700151 ErrorSink* mErrorSink;
152 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700153 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700154
Jack Palevich21a15a22009-05-11 14:49:29 -0700155 void release() {
156 if (pProgramBase != 0) {
157 free(pProgramBase);
158 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700159 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700160 }
161
Jack Palevich0a280a02009-06-11 10:53:51 -0700162 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700163 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700164 bool overflow = newSize > mSize;
165 if (overflow && !mOverflowed) {
166 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700167 if (mErrorSink) {
168 mErrorSink->error("Code too large: %d bytes", newSize);
169 }
170 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700171 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 }
173
Jack Palevich21a15a22009-05-11 14:49:29 -0700174 public:
175 CodeBuf() {
176 pProgramBase = 0;
177 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 mErrorSink = 0;
179 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700180 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 }
182
183 ~CodeBuf() {
184 release();
185 }
186
187 void init(int size) {
188 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 pProgramBase = (char*) calloc(1, size);
191 ind = pProgramBase;
192 }
193
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 void setErrorSink(ErrorSink* pErrorSink) {
195 mErrorSink = pErrorSink;
196 }
197
Jack Palevich546b2242009-05-13 15:10:04 -0700198 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700199 if(check(4)) {
200 return 0;
201 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700202 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700203 * (int*) ind = n;
204 ind += 4;
205 return result;
206 }
207
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 /*
209 * Output a byte. Handles all values, 0..ff.
210 */
211 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(1)) {
213 return;
214 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 *ind++ = n;
216 }
217
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 inline void* getBase() {
219 return (void*) pProgramBase;
220 }
221
Jack Palevich8b0624c2009-05-20 12:12:06 -0700222 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 return ind - pProgramBase;
224 }
225
Jack Palevich8b0624c2009-05-20 12:12:06 -0700226 intptr_t getPC() {
227 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 }
229 };
230
Jack Palevich1cdef202009-05-22 12:06:27 -0700231 /**
232 * A code generator creates an in-memory program, generating the code on
233 * the fly. There is one code generator implementation for each supported
234 * architecture.
235 *
236 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700237 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 * FP - a frame pointer for accessing function arguments and local
239 * variables.
240 * SP - a stack pointer for storing intermediate results while evaluating
241 * expressions. The stack pointer grows downwards.
242 *
243 * The function calling convention is that all arguments are placed on the
244 * stack such that the first argument has the lowest address.
245 * After the call, the result is in R0. The caller is responsible for
246 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700247 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700248 * FP and SP registers are saved.
249 */
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 class CodeGenerator {
252 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700253 CodeGenerator() {
254 mErrorSink = 0;
255 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700256 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700257 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 virtual ~CodeGenerator() {}
259
Jack Palevich22305132009-05-13 10:58:45 -0700260 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700262 pCodeBuf->setErrorSink(mErrorSink);
263 }
264
Jack Palevichb67b18f2009-06-11 21:12:23 -0700265 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 mErrorSink = pErrorSink;
267 if (pCodeBuf) {
268 pCodeBuf->setErrorSink(mErrorSink);
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 }
271
Jack Palevicha8f427f2009-07-13 18:40:08 -0700272 void setTypes(Type* pInt) {
273 mkpInt = pInt;
274 }
275
Jack Palevich1cdef202009-05-22 12:06:27 -0700276 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700277 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700278 * Save the old value of the FP.
279 * Set the new value of the FP.
280 * Convert from the native platform calling convention to
281 * our stack-based calling convention. This may require
282 * pushing arguments from registers to the stack.
283 * Allocate "N" bytes of stack space. N isn't known yet, so
284 * just emit the instructions for adjusting the stack, and return
285 * the address to patch up. The patching will be done in
286 * functionExit().
287 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700288 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700289 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700290
Jack Palevich1cdef202009-05-22 12:06:27 -0700291 /* Emit a function epilog.
292 * Restore the old SP and FP register values.
293 * Return to the calling function.
294 * argCount - the number of arguments to the function.
295 * localVariableAddress - returned from functionEntry()
296 * localVariableSize - the size in bytes of the local variables.
297 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700298 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700299 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700300
Jack Palevich1cdef202009-05-22 12:06:27 -0700301 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700302 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700303
Jack Palevich1a539db2009-07-08 13:04:41 -0700304 /* Load floating point value from global address. */
305 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700306
Jack Palevich1cdef202009-05-22 12:06:27 -0700307 /* Jump to a target, and return the address of the word that
308 * holds the target data, in case it needs to be fixed up later.
309 */
Jack Palevich22305132009-05-13 10:58:45 -0700310 virtual int gjmp(int t) = 0;
311
Jack Palevich1cdef202009-05-22 12:06:27 -0700312 /* Test R0 and jump to a target if the test succeeds.
313 * l = 0: je, l == 1: jne
314 * Return the address of the word that holds the targed data, in
315 * case it needs to be fixed up later.
316 */
Jack Palevich22305132009-05-13 10:58:45 -0700317 virtual int gtst(bool l, int t) = 0;
318
Jack Palevich9eed7a22009-07-06 17:24:34 -0700319 /* Compare TOS against R0, and store the boolean result in R0.
320 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700321 * op specifies the comparison.
322 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700323 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700324
Jack Palevich9eed7a22009-07-06 17:24:34 -0700325 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700326 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700327 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 */
Jack Palevich546b2242009-05-13 15:10:04 -0700329 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700330
Jack Palevich9eed7a22009-07-06 17:24:34 -0700331 /* Compare 0 against R0, and store the boolean result in R0.
332 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700333 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700334 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700335
336 /* Perform the arithmetic op specified by op. 0 is the
337 * left argument, R0 is the right argument.
338 */
339 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700340
Jack Palevich1cdef202009-05-22 12:06:27 -0700341 /* Push R0 onto the stack.
342 */
343 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700344
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 /* Store R0 to the address stored in TOS.
346 * The TOS is popped.
347 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700348 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700350
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700352 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700353 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700354 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700355
Jack Palevich1cdef202009-05-22 12:06:27 -0700356 /* Load the absolute address of a variable to R0.
357 * If ea <= LOCAL, then this is a local variable, or an
358 * argument, addressed relative to FP.
359 * else it is an absolute global address.
360 */
Jack Palevich8df46192009-07-07 14:48:51 -0700361 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 /* Store R0 to a variable.
364 * If ea <= LOCAL, then this is a local variable, or an
365 * argument, addressed relative to FP.
366 * else it is an absolute global address.
367 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700368 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700369
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 /* load R0 from a variable.
371 * If ea <= LOCAL, then this is a local variable, or an
372 * argument, addressed relative to FP.
373 * else it is an absolute global address.
374 * If isIncDec is true, then the stored variable's value
375 * should be post-incremented or post-decremented, based
376 * on the value of op.
377 */
Jack Palevich8df46192009-07-07 14:48:51 -0700378 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
379
380 /**
381 * Convert R0 to the given type.
382 */
383 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700384
Jack Palevich1cdef202009-05-22 12:06:27 -0700385 /* Emit code to adjust the stack for a function call. Return the
386 * label for the address of the instruction that adjusts the
387 * stack size. This will be passed as argument "a" to
388 * endFunctionCallArguments.
389 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700390 virtual int beginFunctionCallArguments() = 0;
391
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700393 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700394 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700395 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700396
Jack Palevich1cdef202009-05-22 12:06:27 -0700397 /* Patch the function call preamble.
398 * a is the address returned from beginFunctionCallArguments
399 * l is the number of bytes the arguments took on the stack.
400 * Typically you would also emit code to convert the argument
401 * list into whatever the native function calling convention is.
402 * On ARM for example you would pop the first 5 arguments into
403 * R0..R4
404 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700405 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700406
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 /* Emit a call to an unknown function. The argument "symbol" needs to
408 * be stored in the location where the address should go. It forms
409 * a chain. The address will be patched later.
410 * Return the address of the word that has to be patched.
411 */
Jack Palevich8df46192009-07-07 14:48:51 -0700412 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700413
Jack Palevich1cdef202009-05-22 12:06:27 -0700414 /* Call a function using PC-relative addressing. t is the PC-relative
415 * address of the function. It has already been adjusted for the
416 * architectural jump offset, so just store it as-is.
417 */
Jack Palevich8df46192009-07-07 14:48:51 -0700418 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 /* Call a function pointer. L is the number of bytes the arguments
421 * take on the stack. The address of the function is stored at
422 * location SP + l.
423 */
Jack Palevich8df46192009-07-07 14:48:51 -0700424 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700425
Jack Palevich1cdef202009-05-22 12:06:27 -0700426 /* Adjust SP after returning from a function call. l is the
427 * number of bytes of arguments stored on the stack. isIndirect
428 * is true if this was an indirect call. (In which case the
429 * address of the function is stored at location SP + l.)
430 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700431 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700432
Jack Palevich1cdef202009-05-22 12:06:27 -0700433 /* Print a disassembly of the assembled code to out. Return
434 * non-zero if there is an error.
435 */
Jack Palevicha6535612009-05-13 16:24:17 -0700436 virtual int disassemble(FILE* out) = 0;
437
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 /* Generate a symbol at the current PC. t is the head of a
439 * linked list of addresses to patch.
440 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700441 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700442
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 /*
444 * Do any cleanup work required at the end of a compile.
445 * For example, an instruction cache might need to be
446 * invalidated.
447 * Return non-zero if there is an error.
448 */
449 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700450
Jack Palevicha6535612009-05-13 16:24:17 -0700451 /**
452 * Adjust relative branches by this amount.
453 */
454 virtual int jumpOffset() = 0;
455
Jack Palevich9eed7a22009-07-06 17:24:34 -0700456 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700457 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700458 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700459 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700460
461 /**
462 * Array element alignment (in bytes) for this type of data.
463 */
464 virtual size_t sizeOf(Type* type) = 0;
465
Jack Palevich9cbd2262009-07-08 16:48:41 -0700466 /**
467 * Stack argument size of this data type.
468 */
469 virtual size_t stackSizeOf(Type* pType) = 0;
470
Jack Palevich1a539db2009-07-08 13:04:41 -0700471 virtual Type* getR0Type() {
472 return mExpressionStack.back();
473 }
474
Jack Palevich21a15a22009-05-11 14:49:29 -0700475 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700476 /*
477 * Output a byte. Handles all values, 0..ff.
478 */
479 void ob(int n) {
480 pCodeBuf->ob(n);
481 }
482
Jack Palevich8b0624c2009-05-20 12:12:06 -0700483 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700484 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700485 }
486
Jack Palevich8b0624c2009-05-20 12:12:06 -0700487 intptr_t getBase() {
488 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700489 }
490
Jack Palevich8b0624c2009-05-20 12:12:06 -0700491 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700492 return pCodeBuf->getPC();
493 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700494
495 intptr_t getSize() {
496 return pCodeBuf->getSize();
497 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700498
499 void error(const char* fmt,...) {
500 va_list ap;
501 va_start(ap, fmt);
502 mErrorSink->verror(fmt, ap);
503 va_end(ap);
504 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505
506 void assert(bool test) {
507 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700508 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700509 error("code generator assertion failed.");
510 }
511 }
Jack Palevich8df46192009-07-07 14:48:51 -0700512
513 void setR0Type(Type* pType) {
514 mExpressionStack.back() = pType;
515 }
516
Jack Palevich8df46192009-07-07 14:48:51 -0700517 Type* getTOSType() {
518 return mExpressionStack[mExpressionStack.size()-2];
519 }
520
521 void pushType() {
522 mExpressionStack.push_back(NULL);
523 }
524
525 void popType() {
526 mExpressionStack.pop_back();
527 }
528
529 bool bitsSame(Type* pA, Type* pB) {
530 return collapseType(pA->tag) == collapseType(pB->tag);
531 }
532
533 TypeTag collapseType(TypeTag tag) {
534 static const TypeTag collapsedTag[] = {
535 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
536 TY_VOID, TY_VOID};
537 return collapsedTag[tag];
538 }
539
Jack Palevich1a539db2009-07-08 13:04:41 -0700540 TypeTag collapseTypeR0() {
541 return collapseType(getR0Type()->tag);
542 }
543
544 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700545 return isFloatTag(pType->tag);
546 }
547
548 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700549 return tag == TY_FLOAT || tag == TY_DOUBLE;
550 }
551
Jack Palevicha8f427f2009-07-13 18:40:08 -0700552 Type* mkpInt;
553
Jack Palevich21a15a22009-05-11 14:49:29 -0700554 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700555 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700557 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700558 };
559
Jack Paleviche7b59062009-05-19 17:12:17 -0700560#ifdef PROVIDE_ARM_CODEGEN
561
Jack Palevich22305132009-05-13 10:58:45 -0700562 class ARMCodeGenerator : public CodeGenerator {
563 public:
564 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700565
Jack Palevich22305132009-05-13 10:58:45 -0700566 virtual ~ARMCodeGenerator() {}
567
568 /* returns address to patch with local variable size
569 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700570 virtual int functionEntry(Type* pDecl) {
571 LOG_API("functionEntry(%d);\n", pDecl);
-b master422972c2009-06-17 19:13:52 -0700572 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700573 // sp -> arg4 arg5 ...
574 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700575 int regArgCount = calcRegArgCount(pDecl);
576 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700577 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700578 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700579 }
580 // sp -> arg0 arg1 ...
581 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700582 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700583 // sp, fp -> oldfp, retadr, arg0 arg1 ....
584 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700585 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700586 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700587 // We don't know how many local variables we are going to use,
588 // but we will round the allocation up to a multiple of
589 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700590 }
591
Jack Palevichb7718b92009-07-09 22:00:24 -0700592 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700593 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700594 // Round local variable size up to a multiple of stack alignment
595 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
596 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700597 // Patch local variable allocation code:
598 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700599 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700600 }
Jack Palevich69796b62009-05-14 15:42:26 -0700601 *(char*) (localVariableAddress) = localVariableSize;
602
603 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
604 o4(0xE1A0E00B); // mov lr, fp
605 o4(0xE59BB000); // ldr fp, [fp]
606 o4(0xE28ED004); // add sp, lr, #4
607 // sp -> retadr, arg0, ...
608 o4(0xE8BD4000); // ldmfd sp!, {lr}
609 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700610
611 // We store the PC into the lr so we can adjust the sp before
612 // returning. We need to pull off the registers we pushed
613 // earlier. We don't need to actually store them anywhere,
614 // just adjust the stack.
615 int regArgCount = calcRegArgCount(pDecl);
616 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700617 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
618 }
619 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700620 }
621
622 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700623 virtual void li(int t, Type* pType) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700624 liReg(t, 0);
Jack Palevich8df46192009-07-07 14:48:51 -0700625 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700626 }
627
Jack Palevich1a539db2009-07-08 13:04:41 -0700628 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700629 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700630 // Global, absolute address
631 o4(0xE59F0000); // ldr r0, .L1
632 o4(0xEA000000); // b .L99
633 o4(address); // .L1: .word ea
634 // .L99:
635
636 switch (pType->tag) {
637 case TY_FLOAT:
638 o4(0xE5900000); // ldr r0, [r0]
639 break;
640 case TY_DOUBLE:
641 o4(0xE1C000D0); // ldrd r0, [r0]
642 break;
643 default:
644 assert(false);
645 break;
646 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700647 }
648
Jack Palevich22305132009-05-13 10:58:45 -0700649 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700650 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700651 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700652 }
653
654 /* l = 0: je, l == 1: jne */
655 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700656 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevichb7718b92009-07-09 22:00:24 -0700657 Type* pR0Type = getR0Type();
658 TypeTag tagR0 = pR0Type->tag;
659 switch(tagR0) {
660 case TY_FLOAT:
661 callRuntime((void*) runtime_is_non_zero_f);
662 break;
663 case TY_DOUBLE:
664 callRuntime((void*) runtime_is_non_zero_d);
665 break;
666 default:
667 break;
668 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700669 o4(0xE3500000); // cmp r0,#0
670 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
671 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700672 }
673
Jack Palevicha39749f2009-07-08 20:40:31 -0700674 virtual void gcmp(int op, Type* pResultType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700675 LOG_API("gcmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700676 Type* pR0Type = getR0Type();
677 Type* pTOSType = getTOSType();
678 TypeTag tagR0 = collapseType(pR0Type->tag);
679 TypeTag tagTOS = collapseType(pTOSType->tag);
680 if (tagR0 == TY_INT && tagTOS == TY_INT) {
681 o4(0xE8BD0002); // ldmfd sp!,{r1}
682 mStackUse -= 4;
683 o4(0xE1510000); // cmp r1, r1
684 switch(op) {
685 case OP_EQUALS:
686 o4(0x03A00001); // moveq r0,#1
687 o4(0x13A00000); // movne r0,#0
688 break;
689 case OP_NOT_EQUALS:
690 o4(0x03A00000); // moveq r0,#0
691 o4(0x13A00001); // movne r0,#1
692 break;
693 case OP_LESS_EQUAL:
694 o4(0xD3A00001); // movle r0,#1
695 o4(0xC3A00000); // movgt r0,#0
696 break;
697 case OP_GREATER:
698 o4(0xD3A00000); // movle r0,#0
699 o4(0xC3A00001); // movgt r0,#1
700 break;
701 case OP_GREATER_EQUAL:
702 o4(0xA3A00001); // movge r0,#1
703 o4(0xB3A00000); // movlt r0,#0
704 break;
705 case OP_LESS:
706 o4(0xA3A00000); // movge r0,#0
707 o4(0xB3A00001); // movlt r0,#1
708 break;
709 default:
710 error("Unknown comparison op %d", op);
711 break;
712 }
713 popType();
714 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
715 setupDoubleArgs();
716 switch(op) {
717 case OP_EQUALS:
718 callRuntime((void*) runtime_cmp_eq_dd);
719 break;
720 case OP_NOT_EQUALS:
721 callRuntime((void*) runtime_cmp_ne_dd);
722 break;
723 case OP_LESS_EQUAL:
724 callRuntime((void*) runtime_cmp_le_dd);
725 break;
726 case OP_GREATER:
727 callRuntime((void*) runtime_cmp_gt_dd);
728 break;
729 case OP_GREATER_EQUAL:
730 callRuntime((void*) runtime_cmp_ge_dd);
731 break;
732 case OP_LESS:
733 callRuntime((void*) runtime_cmp_lt_dd);
734 break;
735 default:
736 error("Unknown comparison op %d", op);
737 break;
738 }
739 } else {
740 setupFloatArgs();
741 switch(op) {
742 case OP_EQUALS:
743 callRuntime((void*) runtime_cmp_eq_ff);
744 break;
745 case OP_NOT_EQUALS:
746 callRuntime((void*) runtime_cmp_ne_ff);
747 break;
748 case OP_LESS_EQUAL:
749 callRuntime((void*) runtime_cmp_le_ff);
750 break;
751 case OP_GREATER:
752 callRuntime((void*) runtime_cmp_gt_ff);
753 break;
754 case OP_GREATER_EQUAL:
755 callRuntime((void*) runtime_cmp_ge_ff);
756 break;
757 case OP_LESS:
758 callRuntime((void*) runtime_cmp_lt_ff);
759 break;
760 default:
761 error("Unknown comparison op %d", op);
762 break;
763 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700764 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700765 setR0Type(pResultType);
Jack Palevich22305132009-05-13 10:58:45 -0700766 }
767
Jack Palevich546b2242009-05-13 15:10:04 -0700768 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700769 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700770 Type* pR0Type = getR0Type();
771 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700772 TypeTag tagR0 = pR0Type->tag;
773 TypeTag tagTOS = pTOSType->tag;
774 bool isFloatR0 = isFloatTag(tagR0);
775 bool isFloatTOS = isFloatTag(tagTOS);
776 if (!isFloatR0 && !isFloatTOS) {
777 bool isPtrR0 = tagR0 == TY_POINTER;
778 bool isPtrTOS = tagTOS == TY_POINTER;
779 if (isPtrR0 || isPtrTOS) {
780 if (isPtrR0 && isPtrTOS) {
781 if (op != OP_MINUS) {
782 error("Unsupported pointer-pointer operation %d.", op);
783 }
784 if (! typeEqual(pR0Type, pTOSType)) {
785 error("Incompatible pointer types for subtraction.");
786 }
787 o4(0xE8BD0002); // ldmfd sp!,{r1}
788 o4(0xE0410000); // sub r0,r1,r0
789 popType();
790 setR0Type(mkpInt);
791 int size = sizeOf(pR0Type->pHead);
792 if (size != 1) {
793 pushR0();
794 li(size, mkpInt);
795 // TODO: Optimize for power-of-two.
796 genOp(OP_DIV);
797 }
798 } else {
799 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
800 error("Unsupported pointer-scalar operation %d", op);
801 }
802 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
803 o4(0xE8BD0002); // ldmfd sp!,{r1}
804 int size = sizeOf(pPtrType->pHead);
805 if (size != 1) {
806 // TODO: Optimize for power-of-two.
807 liReg(size, 2);
808 if (isPtrR0) {
809 o4(0x0E0010192); // mul r1,r2,r1
810 } else {
811 o4(0x0E0000092); // mul r0,r2,r0
812 }
813 }
814 switch(op) {
815 case OP_PLUS:
816 o4(0xE0810000); // add r0,r1,r0
817 break;
818 case OP_MINUS:
819 o4(0xE0410000); // sub r0,r1,r0
820 break;
821 }
822 popType();
823 setR0Type(pPtrType);
824 }
825 } else {
826 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevichb7718b92009-07-09 22:00:24 -0700827 mStackUse -= 4;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700828 switch(op) {
829 case OP_MUL:
830 o4(0x0E0000091); // mul r0,r1,r0
831 break;
832 case OP_DIV:
833 callRuntime((void*) runtime_DIV);
834 break;
835 case OP_MOD:
836 callRuntime((void*) runtime_MOD);
837 break;
838 case OP_PLUS:
839 o4(0xE0810000); // add r0,r1,r0
840 break;
841 case OP_MINUS:
842 o4(0xE0410000); // sub r0,r1,r0
843 break;
844 case OP_SHIFT_LEFT:
845 o4(0xE1A00011); // lsl r0,r1,r0
846 break;
847 case OP_SHIFT_RIGHT:
848 o4(0xE1A00051); // asr r0,r1,r0
849 break;
850 case OP_BIT_AND:
851 o4(0xE0010000); // and r0,r1,r0
852 break;
853 case OP_BIT_XOR:
854 o4(0xE0210000); // eor r0,r1,r0
855 break;
856 case OP_BIT_OR:
857 o4(0xE1810000); // orr r0,r1,r0
858 break;
859 case OP_BIT_NOT:
860 o4(0xE1E00000); // mvn r0, r0
861 break;
862 default:
863 error("Unimplemented op %d\n", op);
864 break;
865 }
866 popType();
Jack Palevichb7718b92009-07-09 22:00:24 -0700867 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700868 } else {
869 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
870 if (pResultType->tag == TY_DOUBLE) {
871 setupDoubleArgs();
872 switch(op) {
873 case OP_MUL:
874 callRuntime((void*) runtime_op_mul_dd);
875 break;
876 case OP_DIV:
877 callRuntime((void*) runtime_op_div_dd);
878 break;
879 case OP_PLUS:
880 callRuntime((void*) runtime_op_add_dd);
881 break;
882 case OP_MINUS:
883 callRuntime((void*) runtime_op_sub_dd);
884 break;
885 default:
886 error("Unsupported binary floating operation %d\n", op);
887 break;
888 }
889 } else {
890 setupFloatArgs();
891 switch(op) {
892 case OP_MUL:
893 callRuntime((void*) runtime_op_mul_ff);
894 break;
895 case OP_DIV:
896 callRuntime((void*) runtime_op_div_ff);
897 break;
898 case OP_PLUS:
899 callRuntime((void*) runtime_op_add_ff);
900 break;
901 case OP_MINUS:
902 callRuntime((void*) runtime_op_sub_ff);
903 break;
904 default:
905 error("Unsupported binary floating operation %d\n", op);
906 break;
907 }
908 }
909 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700910 }
Jack Palevich22305132009-05-13 10:58:45 -0700911 }
912
Jack Palevicha39749f2009-07-08 20:40:31 -0700913 virtual void gUnaryCmp(int op, Type* pResultType) {
914 LOG_API("gUnaryCmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700915 if (op != OP_LOGICAL_NOT) {
916 error("Unknown unary cmp %d", op);
917 } else {
918 Type* pR0Type = getR0Type();
919 TypeTag tag = collapseType(pR0Type->tag);
920 switch(tag) {
921 case TY_INT:
922 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700923 o4(0xE1510000); // cmp r1, r0
924 o4(0x03A00001); // moveq r0,#1
925 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700926 break;
927 case TY_FLOAT:
928 callRuntime((void*) runtime_is_zero_f);
929 break;
930 case TY_DOUBLE:
931 callRuntime((void*) runtime_is_zero_d);
932 break;
933 default:
934 error("gUnaryCmp unsupported type");
935 break;
936 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700937 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700938 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700939 }
940
941 virtual void genUnaryOp(int op) {
942 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700943 Type* pR0Type = getR0Type();
944 TypeTag tag = collapseType(pR0Type->tag);
945 switch(tag) {
946 case TY_INT:
947 switch(op) {
948 case OP_MINUS:
949 o4(0xE3A01000); // mov r1, #0
950 o4(0xE0410000); // sub r0,r1,r0
951 break;
952 case OP_BIT_NOT:
953 o4(0xE1E00000); // mvn r0, r0
954 break;
955 default:
956 error("Unknown unary op %d\n", op);
957 break;
958 }
959 break;
960 case TY_FLOAT:
961 case TY_DOUBLE:
962 switch (op) {
963 case OP_MINUS:
964 if (tag == TY_FLOAT) {
965 callRuntime((void*) runtime_op_neg_f);
966 } else {
967 callRuntime((void*) runtime_op_neg_d);
968 }
969 break;
970 case OP_BIT_NOT:
971 error("Can't apply '~' operator to a float or double.");
972 break;
973 default:
974 error("Unknown unary op %d\n", op);
975 break;
976 }
977 break;
978 default:
979 error("genUnaryOp unsupported type");
980 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700981 }
Jack Palevich22305132009-05-13 10:58:45 -0700982 }
983
Jack Palevich1cdef202009-05-22 12:06:27 -0700984 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700985 LOG_API("pushR0();\n");
Jack Palevichb7718b92009-07-09 22:00:24 -0700986 Type* pR0Type = getR0Type();
987 TypeTag r0ct = collapseType(pR0Type->tag);
988 if (r0ct != TY_DOUBLE) {
989 o4(0xE92D0001); // stmfd sp!,{r0}
990 mStackUse += 4;
991 } else {
992 o4(0xE92D0003); // stmfd sp!,{r0,r1}
993 mStackUse += 8;
994 }
Jack Palevich8df46192009-07-07 14:48:51 -0700995 pushType();
-b master422972c2009-06-17 19:13:52 -0700996 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700997 }
998
Jack Palevich9eed7a22009-07-06 17:24:34 -0700999 virtual void storeR0ToTOS(Type* pPointerType) {
1000 LOG_API("storeR0ToTOS(%d);\n", isInt);
1001 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001002 o4(0xE8BD0004); // ldmfd sp!,{r2}
1003 popType();
-b master422972c2009-06-17 19:13:52 -07001004 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001005 switch (pPointerType->pHead->tag) {
1006 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001007 case TY_FLOAT:
1008 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001009 break;
1010 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001011 o4(0xE5C20000); // strb r0, [r2]
1012 break;
1013 case TY_DOUBLE:
1014 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001015 break;
1016 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001017 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001018 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001019 }
Jack Palevich22305132009-05-13 10:58:45 -07001020 }
1021
Jack Palevich9eed7a22009-07-06 17:24:34 -07001022 virtual void loadR0FromR0(Type* pPointerType) {
1023 LOG_API("loadR0FromR0(%d);\n", pPointerType);
1024 assert(pPointerType->tag == TY_POINTER);
1025 switch (pPointerType->pHead->tag) {
1026 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001027 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001028 o4(0xE5900000); // ldr r0, [r0]
1029 break;
1030 case TY_CHAR:
1031 o4(0xE5D00000); // ldrb r0, [r0]
1032 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001033 case TY_DOUBLE:
1034 o4(0xE1C000D0); // ldrd r0, [r0]
1035 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001036 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001037 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001038 break;
1039 }
Jack Palevich8df46192009-07-07 14:48:51 -07001040 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001041 }
1042
Jack Palevich8df46192009-07-07 14:48:51 -07001043 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001044 LOG_API("leaR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001046 // Local, fp relative
1047 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1048 error("Offset out of range: %08x", ea);
1049 }
1050 if (ea < 0) {
1051 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1052 } else {
1053 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1054 }
Jack Palevichbd894902009-05-14 19:35:31 -07001055 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001056 // Global, absolute.
1057 o4(0xE59F0000); // ldr r0, .L1
1058 o4(0xEA000000); // b .L99
1059 o4(ea); // .L1: .word 0
1060 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001061 }
Jack Palevich8df46192009-07-07 14:48:51 -07001062 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001063 }
1064
Jack Palevich9cbd2262009-07-08 16:48:41 -07001065 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001066 LOG_API("storeR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001067 TypeTag tag = pType->tag;
1068 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001069 case TY_CHAR:
1070 if (ea > -LOCAL && ea < LOCAL) {
1071 // Local, fp relative
1072 if (ea < -4095 || ea > 4095) {
1073 error("Offset out of range: %08x", ea);
1074 }
1075 if (ea < 0) {
1076 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1077 } else {
1078 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1079 }
1080 } else{
1081 // Global, absolute
1082 o4(0xE59F1000); // ldr r1, .L1
1083 o4(0xEA000000); // b .L99
1084 o4(ea); // .L1: .word 0
1085 o4(0xE5C10000); // .L99: strb r0, [r1]
1086 }
1087 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001088 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001089 case TY_INT:
1090 case TY_FLOAT:
1091 if (ea > -LOCAL && ea < LOCAL) {
1092 // Local, fp relative
1093 if (ea < -4095 || ea > 4095) {
1094 error("Offset out of range: %08x", ea);
1095 }
1096 if (ea < 0) {
1097 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1098 } else {
1099 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1100 }
1101 } else{
1102 // Global, absolute
1103 o4(0xE59F1000); // ldr r1, .L1
1104 o4(0xEA000000); // b .L99
1105 o4(ea); // .L1: .word 0
1106 o4(0xE5810000); // .L99: str r0, [r1]
1107 }
1108 break;
1109 case TY_DOUBLE:
1110 if ((ea & 0x7) != 0) {
1111 error("double address is not aligned: %d", ea);
1112 }
1113 if (ea > -LOCAL && ea < LOCAL) {
1114 // Local, fp relative
1115 if (ea < -4095 || ea > 4095) {
1116 error("Offset out of range: %08x", ea);
1117 }
1118 if (ea < 0) {
1119 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1120 o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4]
1121#if 0
1122 // strd doesn't seem to work. Is encoding wrong?
1123 } else if (ea < 0) {
1124 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1125 } else if (ea < 256) {
1126 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1127#endif
1128 } else {
1129 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1130 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1131 }
1132 } else{
1133 // Global, absolute
1134 o4(0xE59F2000); // ldr r2, .L1
1135 o4(0xEA000000); // b .L99
1136 o4(ea); // .L1: .word 0
1137 o4(0xE1C200F0); // .L99: strd r0, [r2]
1138 }
1139 break;
1140 default:
1141 error("Unable to store to type %d", tag);
1142 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001143 }
Jack Palevich22305132009-05-13 10:58:45 -07001144 }
1145
Jack Palevich8df46192009-07-07 14:48:51 -07001146 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001147 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich25c0cca2009-07-13 16:56:28 -07001148 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001150 case TY_CHAR:
1151 if (ea < LOCAL) {
1152 // Local, fp relative
1153 if (ea < -4095 || ea > 4095) {
1154 error("Offset out of range: %08x", ea);
1155 }
1156 if (ea < 0) {
1157 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1158 } else {
1159 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1160 }
1161 } else {
1162 // Global, absolute
1163 o4(0xE59F2000); // ldr r2, .L1
1164 o4(0xEA000000); // b .L99
1165 o4(ea); // .L1: .word ea
1166 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1167 }
1168
1169 if (isIncDec) {
1170 error("inc/dec not implemented for char.");
1171 }
1172 break;
1173 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001174 case TY_INT:
1175 case TY_FLOAT:
1176 if (ea < LOCAL) {
1177 // Local, fp relative
1178 if (ea < -4095 || ea > 4095) {
1179 error("Offset out of range: %08x", ea);
1180 }
1181 if (ea < 0) {
1182 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1183 } else {
1184 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1185 }
1186 } else {
1187 // Global, absolute
1188 o4(0xE59F2000); // ldr r2, .L1
1189 o4(0xEA000000); // b .L99
1190 o4(ea); // .L1: .word ea
1191 o4(0xE5920000); // .L99: ldr r0, [r2]
1192 }
Jack Palevich22305132009-05-13 10:58:45 -07001193
Jack Palevichb7718b92009-07-09 22:00:24 -07001194 if (isIncDec) {
1195 if (tag == TY_INT) {
1196 switch (op) {
1197 case OP_INCREMENT:
1198 o4(0xE2801001); // add r1, r0, #1
1199 break;
1200 case OP_DECREMENT:
1201 o4(0xE2401001); // sub r1, r0, #1
1202 break;
1203 default:
1204 error("unknown opcode: %d", op);
1205 }
1206 if (ea < LOCAL) {
1207 // Local, fp relative
1208 // Don't need range check, was already checked above
1209 if (ea < 0) {
1210 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1211 } else {
1212 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1213 }
1214 } else{
1215 // Global, absolute
1216 // r2 is already set up from before.
1217 o4(0xE5821000); // str r1, [r2]
1218 }
1219 }
1220 else {
1221 error("inc/dec not implemented for float.");
1222 }
1223 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001224 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001225 case TY_DOUBLE:
1226 if ((ea & 0x7) != 0) {
1227 error("double address is not aligned: %d", ea);
1228 }
1229 if (ea < LOCAL) {
1230 // Local, fp relative
1231 if (ea < -4095 || ea > 4095) {
1232 error("Offset out of range: %08x", ea);
1233 }
1234 if (ea < 0) {
1235 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1236 o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4]
1237 } else {
1238 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1239 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1240 }
1241 } else {
1242 // Global, absolute
1243 o4(0xE59F2000); // ldr r2, .L1
1244 o4(0xEA000000); // b .L99
1245 o4(ea); // .L1: .word ea
1246 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1247 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001248 break;
1249 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001250 error("Unable to load type %d", tag);
1251 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001252 }
Jack Palevich8df46192009-07-07 14:48:51 -07001253 setR0Type(pType);
1254 }
1255
1256 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001257 Type* pR0Type = getR0Type();
1258 if (bitsSame(pType, pR0Type)) {
1259 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001260 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001261 TypeTag r0Tag = collapseType(pR0Type->tag);
1262 TypeTag destTag = collapseType(pType->tag);
1263 if (r0Tag == TY_INT) {
1264 if (destTag == TY_FLOAT) {
1265 callRuntime((void*) runtime_int_to_float);
1266 } else {
1267 assert(destTag == TY_DOUBLE);
1268 callRuntime((void*) runtime_int_to_double);
1269 }
1270 } else if (r0Tag == TY_FLOAT) {
1271 if (destTag == TY_INT) {
1272 callRuntime((void*) runtime_float_to_int);
1273 } else {
1274 assert(destTag == TY_DOUBLE);
1275 callRuntime((void*) runtime_float_to_double);
1276 }
1277 } else {
1278 assert (r0Tag == TY_DOUBLE);
1279 if (destTag == TY_INT) {
1280 callRuntime((void*) runtime_double_to_int);
1281 } else {
1282 assert(destTag == TY_FLOAT);
1283 callRuntime((void*) runtime_double_to_float);
1284 }
1285 }
Jack Palevich8df46192009-07-07 14:48:51 -07001286 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001287 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001288 }
1289
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001290 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001291 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001292 return o4(0xE24DDF00); // Placeholder
1293 }
1294
Jack Palevich1a539db2009-07-08 13:04:41 -07001295 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001296 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevichb7718b92009-07-09 22:00:24 -07001297 Type* pR0Type = getR0Type();
1298 TypeTag r0ct = collapseType(pR0Type->tag);
1299 switch(r0ct) {
1300 case TY_INT:
1301 case TY_FLOAT:
1302 if (l < 0 || l > 4096-4) {
1303 error("l out of range for stack offset: 0x%08x", l);
1304 }
1305 o4(0xE58D0000 + l); // str r0, [sp, #l]
1306 return 4;
1307 case TY_DOUBLE: {
1308 // Align to 8 byte boundary
1309 int l2 = (l + 7) & ~7;
1310 if (l2 < 0 || l2 > 4096-8) {
1311 error("l out of range for stack offset: 0x%08x", l);
1312 }
1313 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1314 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1315 return (l2 - l) + 8;
1316 }
1317 default:
1318 assert(false);
1319 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001320 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001321 }
1322
Jack Palevichb7718b92009-07-09 22:00:24 -07001323 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001324 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001325 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001326 // Have to calculate register arg count from actual stack size,
1327 // in order to properly handle ... functions.
1328 int regArgCount = l >> 2;
1329 if (regArgCount > 4) {
1330 regArgCount = 4;
1331 }
1332 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001333 argumentStackUse -= regArgCount * 4;
1334 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1335 }
1336 mStackUse += argumentStackUse;
1337
1338 // Align stack.
1339 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1340 * STACK_ALIGNMENT);
1341 mStackAlignmentAdjustment = 0;
1342 if (missalignment > 0) {
1343 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1344 }
1345 l += mStackAlignmentAdjustment;
1346
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001347 if (l < 0 || l > 0x3FC) {
1348 error("L out of range for stack adjustment: 0x%08x", l);
1349 }
1350 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001351 mStackUse += mStackAlignmentAdjustment;
1352 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1353 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001354 }
1355
Jack Palevich8df46192009-07-07 14:48:51 -07001356 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001357 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001358 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001359 // Forward calls are always short (local)
1360 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001361 }
1362
Jack Palevich8df46192009-07-07 14:48:51 -07001363 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001364 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001365 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001366 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001367 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001368 if (t >= - (1 << 25) && t < (1 << 25)) {
1369 o4(0xEB000000 | encodeAddress(t));
1370 } else {
1371 // Long call.
1372 o4(0xE59FC000); // ldr r12, .L1
1373 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001374 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001375 o4(0xE08CC00F); // .L99: add r12,pc
1376 o4(0xE12FFF3C); // blx r12
1377 }
Jack Palevich22305132009-05-13 10:58:45 -07001378 }
1379
Jack Palevich8df46192009-07-07 14:48:51 -07001380 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001381 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001382 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001383 int argCount = l >> 2;
1384 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001385 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001386 if (adjustedL < 0 || adjustedL > 4096-4) {
1387 error("l out of range for stack offset: 0x%08x", l);
1388 }
1389 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1390 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001391 }
1392
Jack Palevichb7718b92009-07-09 22:00:24 -07001393 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001394 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001395 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001396 // Have to calculate register arg count from actual stack size,
1397 // in order to properly handle ... functions.
1398 int regArgCount = l >> 2;
1399 if (regArgCount > 4) {
1400 regArgCount = 4;
1401 }
1402 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001403 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1404 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001405 if (stackUse) {
1406 if (stackUse < 0 || stackUse > 255) {
1407 error("L out of range for stack adjustment: 0x%08x", l);
1408 }
1409 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001410 mStackUse -= stackUse * 4;
1411 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001412 }
Jack Palevich22305132009-05-13 10:58:45 -07001413 }
1414
Jack Palevicha6535612009-05-13 16:24:17 -07001415 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001416 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001417 }
1418
1419 /* output a symbol and patch all calls to it */
1420 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001421 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001422 int n;
1423 int base = getBase();
1424 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001425 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001426 while (t) {
1427 int data = * (int*) t;
1428 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1429 if (decodedOffset == 0) {
1430 n = 0;
1431 } else {
1432 n = base + decodedOffset; /* next value */
1433 }
1434 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1435 | encodeRelAddress(pc - t - 8);
1436 t = n;
1437 }
1438 }
1439
Jack Palevich1cdef202009-05-22 12:06:27 -07001440 virtual int finishCompile() {
1441#if defined(__arm__)
1442 const long base = long(getBase());
1443 const long curr = long(getPC());
1444 int err = cacheflush(base, curr, 0);
1445 return err;
1446#else
1447 return 0;
1448#endif
1449 }
1450
Jack Palevicha6535612009-05-13 16:24:17 -07001451 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001452#ifdef ENABLE_ARM_DISASSEMBLY
1453 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001454 disasm_interface_t di;
1455 di.di_readword = disassemble_readword;
1456 di.di_printaddr = disassemble_printaddr;
1457 di.di_printf = disassemble_printf;
1458
1459 int base = getBase();
1460 int pc = getPC();
1461 for(int i = base; i < pc; i += 4) {
1462 fprintf(out, "%08x: %08x ", i, *(int*) i);
1463 ::disasm(&di, i, 0);
1464 }
Jack Palevich09555c72009-05-27 12:25:55 -07001465#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001466 return 0;
1467 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001468
Jack Palevich9eed7a22009-07-06 17:24:34 -07001469 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001470 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001471 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001472 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001473 switch(pType->tag) {
1474 case TY_DOUBLE:
1475 return 8;
1476 default:
1477 return 4;
1478 }
1479 }
1480
1481 /**
1482 * Array element alignment (in bytes) for this type of data.
1483 */
1484 virtual size_t sizeOf(Type* pType){
1485 switch(pType->tag) {
1486 case TY_INT:
1487 return 4;
1488 case TY_CHAR:
1489 return 1;
1490 default:
1491 return 0;
1492 case TY_FLOAT:
1493 return 4;
1494 case TY_DOUBLE:
1495 return 8;
1496 case TY_POINTER:
1497 return 4;
1498 }
1499 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001500
1501 virtual size_t stackSizeOf(Type* pType) {
1502 switch(pType->tag) {
1503 case TY_DOUBLE:
1504 return 8;
1505 default:
1506 return 4;
1507 }
1508 }
1509
Jack Palevich22305132009-05-13 10:58:45 -07001510 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001511 static FILE* disasmOut;
1512
1513 static u_int
1514 disassemble_readword(u_int address)
1515 {
1516 return(*((u_int *)address));
1517 }
1518
1519 static void
1520 disassemble_printaddr(u_int address)
1521 {
1522 fprintf(disasmOut, "0x%08x", address);
1523 }
1524
1525 static void
1526 disassemble_printf(const char *fmt, ...) {
1527 va_list ap;
1528 va_start(ap, fmt);
1529 vfprintf(disasmOut, fmt, ap);
1530 va_end(ap);
1531 }
1532
1533 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1534
1535 /** Encode a relative address that might also be
1536 * a label.
1537 */
1538 int encodeAddress(int value) {
1539 int base = getBase();
1540 if (value >= base && value <= getPC() ) {
1541 // This is a label, encode it relative to the base.
1542 value = value - base;
1543 }
1544 return encodeRelAddress(value);
1545 }
1546
1547 int encodeRelAddress(int value) {
1548 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1549 }
Jack Palevich22305132009-05-13 10:58:45 -07001550
Jack Palevichb7718b92009-07-09 22:00:24 -07001551 int calcRegArgCount(Type* pDecl) {
1552 int reg = 0;
1553 Type* pArgs = pDecl->pTail;
1554 while (pArgs && reg < 4) {
1555 Type* pArg = pArgs->pHead;
1556 if ( pArg->tag == TY_DOUBLE) {
1557 int evenReg = (reg + 1) & ~1;
1558 if (evenReg >= 4) {
1559 break;
1560 }
1561 reg = evenReg + 2;
1562 } else {
1563 reg++;
1564 }
1565 pArgs = pArgs->pTail;
1566 }
1567 return reg;
1568 }
1569
1570 /* Pop TOS to R1
1571 * Make sure both R0 and TOS are floats. (Could be ints)
1572 * We know that at least one of R0 and TOS is already a float
1573 */
1574 void setupFloatArgs() {
1575 Type* pR0Type = getR0Type();
1576 Type* pTOSType = getTOSType();
1577 TypeTag tagR0 = collapseType(pR0Type->tag);
1578 TypeTag tagTOS = collapseType(pTOSType->tag);
1579 if (tagR0 != TY_FLOAT) {
1580 assert(tagR0 == TY_INT);
1581 callRuntime((void*) runtime_int_to_float);
1582 }
1583 if (tagTOS != TY_FLOAT) {
1584 assert(tagTOS == TY_INT);
1585 assert(tagR0 == TY_FLOAT);
1586 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1587 o4(0xE59D0004); // ldr r0, [sp, #4]
1588 callRuntime((void*) runtime_int_to_float);
1589 o4(0xE1A01000); // mov r1, r0
1590 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1591 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1592 } else {
1593 // Pop TOS
1594 o4(0xE8BD0002); // ldmfd sp!,{r1}
1595 }
1596 mStackUse -= 4;
1597 popType();
1598 }
1599
1600 /* Pop TOS into R2..R3
1601 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1602 * We know that at least one of R0 and TOS are already a double.
1603 */
1604
1605 void setupDoubleArgs() {
1606 Type* pR0Type = getR0Type();
1607 Type* pTOSType = getTOSType();
1608 TypeTag tagR0 = collapseType(pR0Type->tag);
1609 TypeTag tagTOS = collapseType(pTOSType->tag);
1610 if (tagR0 != TY_DOUBLE) {
1611 if (tagR0 == TY_INT) {
1612 callRuntime((void*) runtime_int_to_double);
1613 } else {
1614 assert(tagR0 == TY_FLOAT);
1615 callRuntime((void*) runtime_float_to_double);
1616 }
1617 }
1618 if (tagTOS != TY_DOUBLE) {
1619 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1620 o4(0xE59D0008); // ldr r0, [sp, #8]
1621 if (tagTOS == TY_INT) {
1622 callRuntime((void*) runtime_int_to_double);
1623 } else {
1624 assert(tagTOS == TY_FLOAT);
1625 callRuntime((void*) runtime_float_to_double);
1626 }
1627 o4(0xE1A02000); // mov r2, r0
1628 o4(0xE1A03001); // mov r3, r1
1629 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1630 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1631 mStackUse -= 4;
1632 } else {
1633 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1634 mStackUse -= 8;
1635 }
1636 popType();
1637 }
1638
Jack Palevicha8f427f2009-07-13 18:40:08 -07001639 void liReg(int t, int reg) {
1640 assert(reg >= 0 && reg < 16);
1641 int rN = (reg & 0xf) << 12;
1642 if (t >= 0 && t < 255) {
1643 o4((0xE3A00000 + t) | rN); // mov rN, #0
1644 } else if (t >= -256 && t < 0) {
1645 // mvn means move constant ^ ~0
1646 o4((0xE3E00001 - t) | rN); // mvn rN, #0
1647 } else {
1648 o4(0xE51F0000 | rN); // ldr rN, .L3
1649 o4(0xEA000000); // b .L99
1650 o4(t); // .L3: .word 0
1651 // .L99:
1652 }
1653 }
1654
Jack Palevichb7718b92009-07-09 22:00:24 -07001655 void callRuntime(void* fn) {
1656 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001657 o4(0xEA000000); // b .L99
1658 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001659 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001660 }
1661
Jack Palevichb7718b92009-07-09 22:00:24 -07001662 // Integer math:
1663
1664 static int runtime_DIV(int b, int a) {
1665 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001666 }
1667
Jack Palevichb7718b92009-07-09 22:00:24 -07001668 static int runtime_MOD(int b, int a) {
1669 return a % b;
1670 }
1671
1672 // Comparison to zero
1673
1674 static int runtime_is_non_zero_f(float a) {
1675 return a != 0;
1676 }
1677
1678 static int runtime_is_non_zero_d(double a) {
1679 return a != 0;
1680 }
1681
1682 // Comparison to zero
1683
1684 static int runtime_is_zero_f(float a) {
1685 return a == 0;
1686 }
1687
1688 static int runtime_is_zero_d(double a) {
1689 return a == 0;
1690 }
1691
1692 // Type conversion
1693
1694 static int runtime_float_to_int(float a) {
1695 return (int) a;
1696 }
1697
1698 static double runtime_float_to_double(float a) {
1699 return (double) a;
1700 }
1701
1702 static int runtime_double_to_int(double a) {
1703 return (int) a;
1704 }
1705
1706 static float runtime_double_to_float(double a) {
1707 return (float) a;
1708 }
1709
1710 static float runtime_int_to_float(int a) {
1711 return (float) a;
1712 }
1713
1714 static double runtime_int_to_double(int a) {
1715 return (double) a;
1716 }
1717
1718 // Comparisons float
1719
1720 static int runtime_cmp_eq_ff(float b, float a) {
1721 return a == b;
1722 }
1723
1724 static int runtime_cmp_ne_ff(float b, float a) {
1725 return a != b;
1726 }
1727
1728 static int runtime_cmp_lt_ff(float b, float a) {
1729 return a < b;
1730 }
1731
1732 static int runtime_cmp_le_ff(float b, float a) {
1733 return a <= b;
1734 }
1735
1736 static int runtime_cmp_ge_ff(float b, float a) {
1737 return a >= b;
1738 }
1739
1740 static int runtime_cmp_gt_ff(float b, float a) {
1741 return a > b;
1742 }
1743
1744 // Comparisons double
1745
1746 static int runtime_cmp_eq_dd(double b, double a) {
1747 return a == b;
1748 }
1749
1750 static int runtime_cmp_ne_dd(double b, double a) {
1751 return a != b;
1752 }
1753
1754 static int runtime_cmp_lt_dd(double b, double a) {
1755 return a < b;
1756 }
1757
1758 static int runtime_cmp_le_dd(double b, double a) {
1759 return a <= b;
1760 }
1761
1762 static int runtime_cmp_ge_dd(double b, double a) {
1763 return a >= b;
1764 }
1765
1766 static int runtime_cmp_gt_dd(double b, double a) {
1767 return a > b;
1768 }
1769
1770 // Math float
1771
1772 static float runtime_op_add_ff(float b, float a) {
1773 return a + b;
1774 }
1775
1776 static float runtime_op_sub_ff(float b, float a) {
1777 return a - b;
1778 }
1779
1780 static float runtime_op_mul_ff(float b, float a) {
1781 return a * b;
1782 }
1783
1784 static float runtime_op_div_ff(float b, float a) {
1785 return a / b;
1786 }
1787
1788 static float runtime_op_neg_f(float a) {
1789 return -a;
1790 }
1791
1792 // Math double
1793
1794 static double runtime_op_add_dd(double b, double a) {
1795 return a + b;
1796 }
1797
1798 static double runtime_op_sub_dd(double b, double a) {
1799 return a - b;
1800 }
1801
1802 static double runtime_op_mul_dd(double b, double a) {
1803 return a * b;
1804 }
1805
1806 static double runtime_op_div_dd(double b, double a) {
1807 return a / b;
1808 }
1809
1810 static double runtime_op_neg_d(double a) {
1811 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001812 }
-b master422972c2009-06-17 19:13:52 -07001813
1814 static const int STACK_ALIGNMENT = 8;
1815 int mStackUse;
1816 // This variable holds the amount we adjusted the stack in the most
1817 // recent endFunctionCallArguments call. It's examined by the
1818 // following adjustStackAfterCall call.
1819 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001820 };
1821
Jack Palevich09555c72009-05-27 12:25:55 -07001822#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001823
1824#ifdef PROVIDE_X86_CODEGEN
1825
Jack Palevich21a15a22009-05-11 14:49:29 -07001826 class X86CodeGenerator : public CodeGenerator {
1827 public:
1828 X86CodeGenerator() {}
1829 virtual ~X86CodeGenerator() {}
1830
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001831 /* returns address to patch with local variable size
1832 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001833 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001834 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1835 return oad(0xec81, 0); /* sub $xxx, %esp */
1836 }
1837
Jack Palevichb7718b92009-07-09 22:00:24 -07001838 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001839 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001840 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001841 }
1842
Jack Palevich21a15a22009-05-11 14:49:29 -07001843 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001844 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001845 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001846 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001847 }
1848
Jack Palevich1a539db2009-07-08 13:04:41 -07001849 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001850 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001851 switch (pType->tag) {
1852 case TY_FLOAT:
1853 oad(0x05D9, address); // flds
1854 break;
1855 case TY_DOUBLE:
1856 oad(0x05DD, address); // fldl
1857 break;
1858 default:
1859 assert(false);
1860 break;
1861 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001862 }
1863
Jack Palevich22305132009-05-13 10:58:45 -07001864 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001865 return psym(0xe9, t);
1866 }
1867
1868 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001869 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001870 Type* pR0Type = getR0Type();
1871 TypeTag tagR0 = pR0Type->tag;
1872 bool isFloatR0 = isFloatTag(tagR0);
1873 if (isFloatR0) {
1874 o(0xeed9); // fldz
1875 o(0xe9da); // fucompp
1876 o(0xe0df); // fnstsw %ax
1877 o(0x9e); // sahf
1878 } else {
1879 o(0xc085); // test %eax, %eax
1880 }
1881 // Use two output statements to generate one instruction.
1882 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001883 return psym(0x84 + l, t);
1884 }
1885
Jack Palevicha39749f2009-07-08 20:40:31 -07001886 virtual void gcmp(int op, Type* pResultType) {
1887 Type* pR0Type = getR0Type();
1888 Type* pTOSType = getTOSType();
1889 TypeTag tagR0 = pR0Type->tag;
1890 TypeTag tagTOS = pTOSType->tag;
1891 bool isFloatR0 = isFloatTag(tagR0);
1892 bool isFloatTOS = isFloatTag(tagTOS);
1893 if (!isFloatR0 && !isFloatTOS) {
1894 int t = decodeOp(op);
1895 o(0x59); /* pop %ecx */
1896 o(0xc139); /* cmp %eax,%ecx */
1897 li(0, NULL);
1898 o(0x0f); /* setxx %al */
1899 o(t + 0x90);
1900 o(0xc0);
1901 popType();
1902 } else {
1903 setupFloatOperands();
1904 switch (op) {
1905 case OP_EQUALS:
1906 o(0xe9da); // fucompp
1907 o(0xe0df); // fnstsw %ax
1908 o(0x9e); // sahf
1909 o(0xc0940f); // sete %al
1910 o(0xc29b0f); // setnp %dl
1911 o(0xd021); // andl %edx, %eax
1912 break;
1913 case OP_NOT_EQUALS:
1914 o(0xe9da); // fucompp
1915 o(0xe0df); // fnstsw %ax
1916 o(0x9e); // sahf
1917 o(0xc0950f); // setne %al
1918 o(0xc29a0f); // setp %dl
1919 o(0xd009); // orl %edx, %eax
1920 break;
1921 case OP_GREATER_EQUAL:
1922 o(0xe9da); // fucompp
1923 o(0xe0df); // fnstsw %ax
1924 o(0x05c4f6); // testb $5, %ah
1925 o(0xc0940f); // sete %al
1926 break;
1927 case OP_LESS:
1928 o(0xc9d9); // fxch %st(1)
1929 o(0xe9da); // fucompp
1930 o(0xe0df); // fnstsw %ax
1931 o(0x9e); // sahf
1932 o(0xc0970f); // seta %al
1933 break;
1934 case OP_LESS_EQUAL:
1935 o(0xc9d9); // fxch %st(1)
1936 o(0xe9da); // fucompp
1937 o(0xe0df); // fnstsw %ax
1938 o(0x9e); // sahf
1939 o(0xc0930f); // setea %al
1940 break;
1941 case OP_GREATER:
1942 o(0xe9da); // fucompp
1943 o(0xe0df); // fnstsw %ax
1944 o(0x45c4f6); // testb $69, %ah
1945 o(0xc0940f); // sete %al
1946 break;
1947 default:
1948 error("Unknown comparison op");
1949 }
1950 o(0xc0b60f); // movzbl %al, %eax
1951 }
1952 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001953 }
1954
Jack Palevich546b2242009-05-13 15:10:04 -07001955 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001956 Type* pR0Type = getR0Type();
1957 Type* pTOSType = getTOSType();
1958 TypeTag tagR0 = pR0Type->tag;
1959 TypeTag tagTOS = pTOSType->tag;
1960 bool isFloatR0 = isFloatTag(tagR0);
1961 bool isFloatTOS = isFloatTag(tagTOS);
1962 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001963 bool isPtrR0 = tagR0 == TY_POINTER;
1964 bool isPtrTOS = tagTOS == TY_POINTER;
1965 if (isPtrR0 || isPtrTOS) {
1966 if (isPtrR0 && isPtrTOS) {
1967 if (op != OP_MINUS) {
1968 error("Unsupported pointer-pointer operation %d.", op);
1969 }
1970 if (! typeEqual(pR0Type, pTOSType)) {
1971 error("Incompatible pointer types for subtraction.");
1972 }
1973 o(0x59); /* pop %ecx */
1974 o(decodeOp(op));
1975 popType();
1976 setR0Type(mkpInt);
1977 int size = sizeOf(pR0Type->pHead);
1978 if (size != 1) {
1979 pushR0();
1980 li(size, mkpInt);
1981 // TODO: Optimize for power-of-two.
1982 genOp(OP_DIV);
1983 }
1984 } else {
1985 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1986 error("Unsupported pointer-scalar operation %d", op);
1987 }
1988 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1989 o(0x59); /* pop %ecx */
1990 int size = sizeOf(pPtrType->pHead);
1991 if (size != 1) {
1992 // TODO: Optimize for power-of-two.
1993 if (isPtrR0) {
1994 oad(0xC969, size); // imull $size, %ecx
1995 } else {
1996 oad(0xC069, size); // mul $size, %eax
1997 }
1998 }
1999 o(decodeOp(op));
2000 popType();
2001 setR0Type(pPtrType);
2002 }
2003 } else {
2004 o(0x59); /* pop %ecx */
2005 o(decodeOp(op));
2006 if (op == OP_MOD)
2007 o(0x92); /* xchg %edx, %eax */
2008 popType();
2009 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002010 } else {
2011 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2012 setupFloatOperands();
2013 // Both float. x87 R0 == left hand, x87 R1 == right hand
2014 switch (op) {
2015 case OP_MUL:
2016 o(0xc9de); // fmulp
2017 break;
2018 case OP_DIV:
2019 o(0xf1de); // fdivp
2020 break;
2021 case OP_PLUS:
2022 o(0xc1de); // faddp
2023 break;
2024 case OP_MINUS:
2025 o(0xe1de); // fsubp
2026 break;
2027 default:
2028 error("Unsupported binary floating operation.");
2029 break;
2030 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002031 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002032 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002033 }
2034
Jack Palevicha39749f2009-07-08 20:40:31 -07002035 virtual void gUnaryCmp(int op, Type* pResultType) {
2036 if (op != OP_LOGICAL_NOT) {
2037 error("Unknown unary cmp %d", op);
2038 } else {
2039 Type* pR0Type = getR0Type();
2040 TypeTag tag = collapseType(pR0Type->tag);
2041 switch(tag) {
2042 case TY_INT: {
2043 oad(0xb9, 0); /* movl $0, %ecx */
2044 int t = decodeOp(op);
2045 o(0xc139); /* cmp %eax,%ecx */
2046 li(0, NULL);
2047 o(0x0f); /* setxx %al */
2048 o(t + 0x90);
2049 o(0xc0);
2050 }
2051 break;
2052 case TY_FLOAT:
2053 case TY_DOUBLE:
2054 o(0xeed9); // fldz
2055 o(0xe9da); // fucompp
2056 o(0xe0df); // fnstsw %ax
2057 o(0x9e); // sahf
2058 o(0xc0950f); // setne %al
2059 o(0xc29a0f); // setp %dl
2060 o(0xd009); // orl %edx, %eax
2061 o(0xc0b60f); // movzbl %al, %eax
2062 o(0x01f083); // xorl $1, %eax
2063 break;
2064 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002065 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002066 break;
2067 }
2068 }
2069 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002070 }
2071
2072 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002073 Type* pR0Type = getR0Type();
2074 TypeTag tag = collapseType(pR0Type->tag);
2075 switch(tag) {
2076 case TY_INT:
2077 oad(0xb9, 0); /* movl $0, %ecx */
2078 o(decodeOp(op));
2079 break;
2080 case TY_FLOAT:
2081 case TY_DOUBLE:
2082 switch (op) {
2083 case OP_MINUS:
2084 o(0xe0d9); // fchs
2085 break;
2086 case OP_BIT_NOT:
2087 error("Can't apply '~' operator to a float or double.");
2088 break;
2089 default:
2090 error("Unknown unary op %d\n", op);
2091 break;
2092 }
2093 break;
2094 default:
2095 error("genUnaryOp unsupported type");
2096 break;
2097 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002098 }
2099
Jack Palevich1cdef202009-05-22 12:06:27 -07002100 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002101 Type* pR0Type = getR0Type();
2102 TypeTag r0ct = collapseType(pR0Type->tag);
2103 switch(r0ct) {
2104 case TY_INT:
2105 o(0x50); /* push %eax */
2106 break;
2107 case TY_FLOAT:
2108 o(0x50); /* push %eax */
2109 o(0x241cd9); // fstps 0(%esp)
2110 break;
2111 case TY_DOUBLE:
2112 o(0x50); /* push %eax */
2113 o(0x50); /* push %eax */
2114 o(0x241cdd); // fstpl 0(%esp)
2115 break;
2116 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002117 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002118 break;
2119 }
Jack Palevich8df46192009-07-07 14:48:51 -07002120 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002121 }
2122
Jack Palevich9eed7a22009-07-06 17:24:34 -07002123 virtual void storeR0ToTOS(Type* pPointerType) {
2124 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07002125 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002126 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002127 switch (pPointerType->pHead->tag) {
2128 case TY_INT:
2129 o(0x0189); /* movl %eax/%al, (%ecx) */
2130 break;
2131 case TY_CHAR:
2132 o(0x0188); /* movl %eax/%al, (%ecx) */
2133 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002134 case TY_FLOAT:
2135 o(0x19d9); /* fstps (%ecx) */
2136 break;
2137 case TY_DOUBLE:
2138 o(0x19dd); /* fstpl (%ecx) */
2139 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002140 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002141 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002142 break;
2143 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002144 }
2145
Jack Palevich9eed7a22009-07-06 17:24:34 -07002146 virtual void loadR0FromR0(Type* pPointerType) {
2147 assert(pPointerType->tag == TY_POINTER);
2148 switch (pPointerType->pHead->tag) {
2149 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002150 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002151 break;
2152 case TY_CHAR:
2153 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002154 ob(0); /* add zero in code */
2155 break;
2156 case TY_FLOAT:
2157 o2(0x00d9); // flds (%eax)
2158 break;
2159 case TY_DOUBLE:
2160 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002161 break;
2162 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002163 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002164 break;
2165 }
Jack Palevich8df46192009-07-07 14:48:51 -07002166 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002167 }
2168
Jack Palevich8df46192009-07-07 14:48:51 -07002169 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002170 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002171 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002172 }
2173
Jack Palevich9cbd2262009-07-08 16:48:41 -07002174 virtual void storeR0(int ea, Type* pType) {
2175 TypeTag tag = pType->tag;
2176 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002177 case TY_CHAR:
2178 if (ea < -LOCAL || ea > LOCAL) {
2179 oad(0xa2, ea); // movb %al,ea
2180 } else {
2181 oad(0x8588, ea); // movb %al,ea(%ebp)
2182 }
2183 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002184 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002185 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002186 gmov(6, ea); /* mov %eax, EA */
2187 break;
2188 case TY_FLOAT:
2189 if (ea < -LOCAL || ea > LOCAL) {
2190 oad(0x1dd9, ea); // fstps ea
2191 } else {
2192 oad(0x9dd9, ea); // fstps ea(%ebp)
2193 }
2194 break;
2195 case TY_DOUBLE:
2196 if (ea < -LOCAL || ea > LOCAL) {
2197 oad(0x1ddd, ea); // fstpl ea
2198 } else {
2199 oad(0x9ddd, ea); // fstpl ea(%ebp)
2200 }
2201 break;
2202 default:
2203 error("Unable to store to type %d", tag);
2204 break;
2205 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 }
2207
Jack Palevich8df46192009-07-07 14:48:51 -07002208 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002209 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002210 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002211 case TY_CHAR:
2212 if (ea < -LOCAL || ea > LOCAL) {
2213 oad(0x05BE0F, ea); // movsbl ea,%eax
2214 } else {
2215 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2216 }
2217 if (isIncDec) {
2218 error("inc/dec not implemented for char.");
2219 }
2220 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002221 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002222 case TY_POINTER:
2223 if (tag == TY_CHAR) {
2224 } else {
2225 gmov(8, ea); /* mov EA, %eax */
2226 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002227 if (isIncDec) {
2228 /* Implement post-increment or post decrement.
2229 */
2230 gmov(0, ea); /* 83 ADD */
2231 o(decodeOp(op));
2232 }
2233 break;
2234 case TY_FLOAT:
2235 if (ea < -LOCAL || ea > LOCAL) {
2236 oad(0x05d9, ea); // flds ea
2237 } else {
2238 oad(0x85d9, ea); // flds ea(%ebp)
2239 }
2240 if (isIncDec) {
2241 error("inc/dec not implemented for float.");
2242 }
2243 break;
2244 case TY_DOUBLE:
2245 if (ea < -LOCAL || ea > LOCAL) {
2246 oad(0x05dd, ea); // fldl ea
2247 } else {
2248 oad(0x85dd, ea); // fldl ea(%ebp)
2249 }
2250 if (isIncDec) {
2251 error("inc/dec not implemented for double.");
2252 }
2253 break;
2254 default:
2255 error("Unable to load type %d", tag);
2256 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002257 }
Jack Palevich8df46192009-07-07 14:48:51 -07002258 setR0Type(pType);
2259 }
2260
2261 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002262 Type* pR0Type = getR0Type();
2263 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002264 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002265 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002266 return;
2267 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002268 if (bitsSame(pType, pR0Type)) {
2269 // do nothing special
2270 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2271 // do nothing special, both held in same register on x87.
2272 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002273 TypeTag r0Tag = collapseType(pR0Type->tag);
2274 TypeTag destTag = collapseType(pType->tag);
2275 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2276 // Convert R0 from int to float
2277 o(0x50); // push %eax
2278 o(0x2404DB); // fildl 0(%esp)
2279 o(0x58); // pop %eax
2280 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2281 // Convert R0 from float to int. Complicated because
2282 // need to save and restore the rounding mode.
2283 o(0x50); // push %eax
2284 o(0x50); // push %eax
2285 o(0x02247cD9); // fnstcw 2(%esp)
2286 o(0x2444b70f); // movzwl 2(%esp), %eax
2287 o(0x02);
2288 o(0x0cb4); // movb $12, %ah
2289 o(0x24048966); // movw %ax, 0(%esp)
2290 o(0x242cd9); // fldcw 0(%esp)
2291 o(0x04245cdb); // fistpl 4(%esp)
2292 o(0x02246cd9); // fldcw 2(%esp)
2293 o(0x58); // pop %eax
2294 o(0x58); // pop %eax
2295 } else {
2296 error("Incompatible types old: %d new: %d",
2297 pR0Type->tag, pType->tag);
2298 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002299 }
2300 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002301 }
2302
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002303 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002304 return oad(0xec81, 0); /* sub $xxx, %esp */
2305 }
2306
Jack Palevich1a539db2009-07-08 13:04:41 -07002307 virtual size_t storeR0ToArg(int l) {
2308 Type* pR0Type = getR0Type();
2309 TypeTag r0ct = collapseType(pR0Type->tag);
2310 switch(r0ct) {
2311 case TY_INT:
2312 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2313 return 4;
2314 case TY_FLOAT:
2315 oad(0x249CD9, l); /* fstps xxx(%esp) */
2316 return 4;
2317 case TY_DOUBLE:
2318 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2319 return 8;
2320 default:
2321 assert(false);
2322 return 0;
2323 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002324 }
2325
Jack Palevichb7718b92009-07-09 22:00:24 -07002326 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002327 * (int*) a = l;
2328 }
2329
Jack Palevich8df46192009-07-07 14:48:51 -07002330 virtual int callForward(int symbol, Type* pFunc) {
2331 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002332 return psym(0xe8, symbol); /* call xxx */
2333 }
2334
Jack Palevich8df46192009-07-07 14:48:51 -07002335 virtual void callRelative(int t, Type* pFunc) {
2336 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002337 psym(0xe8, t); /* call xxx */
2338 }
2339
Jack Palevich8df46192009-07-07 14:48:51 -07002340 virtual void callIndirect(int l, Type* pFunc) {
2341 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002342 oad(0x2494ff, l); /* call *xxx(%esp) */
2343 }
2344
Jack Palevichb7718b92009-07-09 22:00:24 -07002345 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002346 if (isIndirect) {
2347 l += 4;
2348 }
-b master422972c2009-06-17 19:13:52 -07002349 if (l > 0) {
2350 oad(0xc481, l); /* add $xxx, %esp */
2351 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 }
2353
Jack Palevicha6535612009-05-13 16:24:17 -07002354 virtual int jumpOffset() {
2355 return 5;
2356 }
2357
2358 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002359 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002360 }
2361
Jack Paleviche7b59062009-05-19 17:12:17 -07002362 /* output a symbol and patch all calls to it */
2363 virtual void gsym(int t) {
2364 int n;
2365 int pc = getPC();
2366 while (t) {
2367 n = *(int *) t; /* next value */
2368 *(int *) t = pc - t - 4;
2369 t = n;
2370 }
2371 }
2372
Jack Palevich1cdef202009-05-22 12:06:27 -07002373 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002374 size_t pagesize = 4096;
2375 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2376 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2377 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2378 if (err) {
2379 error("mprotect() failed: %d", errno);
2380 }
2381 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002382 }
2383
Jack Palevich9eed7a22009-07-06 17:24:34 -07002384 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002385 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002386 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002387 virtual size_t alignmentOf(Type* pType){
2388 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002389 }
2390
2391 /**
2392 * Array element alignment (in bytes) for this type of data.
2393 */
2394 virtual size_t sizeOf(Type* pType){
2395 switch(pType->tag) {
2396 case TY_INT:
2397 return 4;
2398 case TY_CHAR:
2399 return 1;
2400 default:
2401 return 0;
2402 case TY_FLOAT:
2403 return 4;
2404 case TY_DOUBLE:
2405 return 8;
2406 case TY_POINTER:
2407 return 4;
2408 }
2409 }
2410
Jack Palevich9cbd2262009-07-08 16:48:41 -07002411 virtual size_t stackSizeOf(Type* pType) {
2412 switch(pType->tag) {
2413 case TY_DOUBLE:
2414 return 8;
2415 default:
2416 return 4;
2417 }
2418 }
2419
Jack Palevich21a15a22009-05-11 14:49:29 -07002420 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002421
2422 /** Output 1 to 4 bytes.
2423 *
2424 */
2425 void o(int n) {
2426 /* cannot use unsigned, so we must do a hack */
2427 while (n && n != -1) {
2428 ob(n & 0xff);
2429 n = n >> 8;
2430 }
2431 }
2432
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002433 /* Output exactly 2 bytes
2434 */
2435 void o2(int n) {
2436 ob(n & 0xff);
2437 ob(0xff & (n >> 8));
2438 }
2439
Jack Paleviche7b59062009-05-19 17:12:17 -07002440 /* psym is used to put an instruction with a data field which is a
2441 reference to a symbol. It is in fact the same as oad ! */
2442 int psym(int n, int t) {
2443 return oad(n, t);
2444 }
2445
2446 /* instruction + address */
2447 int oad(int n, int t) {
2448 o(n);
2449 int result = getPC();
2450 o4(t);
2451 return result;
2452 }
2453
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002454 static const int operatorHelper[];
2455
2456 int decodeOp(int op) {
2457 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002458 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002459 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002460 }
2461 return operatorHelper[op];
2462 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002463
Jack Palevich546b2242009-05-13 15:10:04 -07002464 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002465 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002466 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002467 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002468
2469 void setupFloatOperands() {
2470 Type* pR0Type = getR0Type();
2471 Type* pTOSType = getTOSType();
2472 TypeTag tagR0 = pR0Type->tag;
2473 TypeTag tagTOS = pTOSType->tag;
2474 bool isFloatR0 = isFloatTag(tagR0);
2475 bool isFloatTOS = isFloatTag(tagTOS);
2476 if (! isFloatR0) {
2477 // Convert R0 from int to float
2478 o(0x50); // push %eax
2479 o(0x2404DB); // fildl 0(%esp)
2480 o(0x58); // pop %eax
2481 }
2482 if (! isFloatTOS){
2483 o(0x2404DB); // fildl 0(%esp);
2484 o(0x58); // pop %eax
2485 } else {
2486 if (tagTOS == TY_FLOAT) {
2487 o(0x2404d9); // flds (%esp)
2488 o(0x58); // pop %eax
2489 } else {
2490 o(0x2404dd); // fldl (%esp)
2491 o(0x58); // pop %eax
2492 o(0x58); // pop %eax
2493 }
2494 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002495 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002496 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002497 };
2498
Jack Paleviche7b59062009-05-19 17:12:17 -07002499#endif // PROVIDE_X86_CODEGEN
2500
Jack Palevichb67b18f2009-06-11 21:12:23 -07002501#ifdef PROVIDE_TRACE_CODEGEN
2502 class TraceCodeGenerator : public CodeGenerator {
2503 private:
2504 CodeGenerator* mpBase;
2505
2506 public:
2507 TraceCodeGenerator(CodeGenerator* pBase) {
2508 mpBase = pBase;
2509 }
2510
2511 virtual ~TraceCodeGenerator() {
2512 delete mpBase;
2513 }
2514
2515 virtual void init(CodeBuf* pCodeBuf) {
2516 mpBase->init(pCodeBuf);
2517 }
2518
2519 void setErrorSink(ErrorSink* pErrorSink) {
2520 mpBase->setErrorSink(pErrorSink);
2521 }
2522
2523 /* returns address to patch with local variable size
2524 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002525 virtual int functionEntry(Type* pDecl) {
2526 int result = mpBase->functionEntry(pDecl);
2527 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002528 return result;
2529 }
2530
Jack Palevichb7718b92009-07-09 22:00:24 -07002531 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2532 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2533 localVariableAddress, localVariableSize);
2534 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002535 }
2536
2537 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002538 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002539 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002540 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002541 }
2542
Jack Palevich1a539db2009-07-08 13:04:41 -07002543 virtual void loadFloat(int address, Type* pType) {
2544 fprintf(stderr, "loadFloat(%d, type)\n", address);
2545 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002546 }
2547
Jack Palevichb67b18f2009-06-11 21:12:23 -07002548 virtual int gjmp(int t) {
2549 int result = mpBase->gjmp(t);
2550 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2551 return result;
2552 }
2553
2554 /* l = 0: je, l == 1: jne */
2555 virtual int gtst(bool l, int t) {
2556 int result = mpBase->gtst(l, t);
2557 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2558 return result;
2559 }
2560
Jack Palevicha39749f2009-07-08 20:40:31 -07002561 virtual void gcmp(int op, Type* pResultType) {
2562 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2563 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002564 }
2565
2566 virtual void genOp(int op) {
2567 fprintf(stderr, "genOp(%d)\n", op);
2568 mpBase->genOp(op);
2569 }
2570
Jack Palevich9eed7a22009-07-06 17:24:34 -07002571
Jack Palevicha39749f2009-07-08 20:40:31 -07002572 virtual void gUnaryCmp(int op, Type* pResultType) {
2573 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2574 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002575 }
2576
2577 virtual void genUnaryOp(int op) {
2578 fprintf(stderr, "genUnaryOp(%d)\n", op);
2579 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002580 }
2581
2582 virtual void pushR0() {
2583 fprintf(stderr, "pushR0()\n");
2584 mpBase->pushR0();
2585 }
2586
Jack Palevich9eed7a22009-07-06 17:24:34 -07002587 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002588 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002589 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002590 }
2591
Jack Palevich9eed7a22009-07-06 17:24:34 -07002592 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002593 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002594 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002595 }
2596
Jack Palevich8df46192009-07-07 14:48:51 -07002597 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002598 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002599 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002600 }
2601
Jack Palevich9cbd2262009-07-08 16:48:41 -07002602 virtual void storeR0(int ea, Type* pType) {
2603 fprintf(stderr, "storeR0(%d, pType)\n", ea);
2604 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002605 }
2606
Jack Palevich8df46192009-07-07 14:48:51 -07002607 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002608 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002609 mpBase->loadR0(ea, isIncDec, op, pType);
2610 }
2611
2612 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002613 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002614 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002615 }
2616
2617 virtual int beginFunctionCallArguments() {
2618 int result = mpBase->beginFunctionCallArguments();
2619 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2620 return result;
2621 }
2622
Jack Palevich1a539db2009-07-08 13:04:41 -07002623 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002624 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07002625 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002626 }
2627
Jack Palevichb7718b92009-07-09 22:00:24 -07002628 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002629 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002630 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002631 }
2632
Jack Palevich8df46192009-07-07 14:48:51 -07002633 virtual int callForward(int symbol, Type* pFunc) {
2634 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002635 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2636 return result;
2637 }
2638
Jack Palevich8df46192009-07-07 14:48:51 -07002639 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002640 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002641 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002642 }
2643
Jack Palevich8df46192009-07-07 14:48:51 -07002644 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002645 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002646 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002647 }
2648
Jack Palevichb7718b92009-07-09 22:00:24 -07002649 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2650 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2651 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002652 }
2653
2654 virtual int jumpOffset() {
2655 return mpBase->jumpOffset();
2656 }
2657
2658 virtual int disassemble(FILE* out) {
2659 return mpBase->disassemble(out);
2660 }
2661
2662 /* output a symbol and patch all calls to it */
2663 virtual void gsym(int t) {
2664 fprintf(stderr, "gsym(%d)\n", t);
2665 mpBase->gsym(t);
2666 }
2667
2668 virtual int finishCompile() {
2669 int result = mpBase->finishCompile();
2670 fprintf(stderr, "finishCompile() = %d\n", result);
2671 return result;
2672 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002673
2674 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002675 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002676 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002677 virtual size_t alignmentOf(Type* pType){
2678 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002679 }
2680
2681 /**
2682 * Array element alignment (in bytes) for this type of data.
2683 */
2684 virtual size_t sizeOf(Type* pType){
2685 return mpBase->sizeOf(pType);
2686 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002687
Jack Palevich9cbd2262009-07-08 16:48:41 -07002688
2689 virtual size_t stackSizeOf(Type* pType) {
2690 return mpBase->stackSizeOf(pType);
2691 }
2692
2693
Jack Palevich1a539db2009-07-08 13:04:41 -07002694 virtual Type* getR0Type() {
2695 return mpBase->getR0Type();
2696 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002697 };
2698
2699#endif // PROVIDE_TRACE_CODEGEN
2700
Jack Palevich569f1352009-06-29 14:29:08 -07002701 class Arena {
2702 public:
2703 // Used to record a given allocation amount.
2704 // Used:
2705 // Mark mark = arena.mark();
2706 // ... lots of arena.allocate()
2707 // arena.free(mark);
2708
2709 struct Mark {
2710 size_t chunk;
2711 size_t offset;
2712 };
2713
2714 Arena() {
2715 mCurrentChunk = 0;
2716 Chunk start(CHUNK_SIZE);
2717 mData.push_back(start);
2718 }
2719
2720 ~Arena() {
2721 for(size_t i = 0; i < mData.size(); i++) {
2722 mData[i].free();
2723 }
2724 }
2725
2726 // Alloc using the standard alignment size safe for any variable
2727 void* alloc(size_t size) {
2728 return alloc(size, 8);
2729 }
2730
2731 Mark mark(){
2732 Mark result;
2733 result.chunk = mCurrentChunk;
2734 result.offset = mData[mCurrentChunk].mOffset;
2735 return result;
2736 }
2737
2738 void freeToMark(const Mark& mark) {
2739 mCurrentChunk = mark.chunk;
2740 mData[mCurrentChunk].mOffset = mark.offset;
2741 }
2742
2743 private:
2744 // Allocate memory aligned to a given size
2745 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2746 // Memory is not zero filled.
2747
2748 void* alloc(size_t size, size_t alignment) {
2749 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2750 if (mCurrentChunk + 1 < mData.size()) {
2751 mCurrentChunk++;
2752 } else {
2753 size_t allocSize = CHUNK_SIZE;
2754 if (allocSize < size + alignment - 1) {
2755 allocSize = size + alignment - 1;
2756 }
2757 Chunk chunk(allocSize);
2758 mData.push_back(chunk);
2759 mCurrentChunk++;
2760 }
2761 }
2762 return mData[mCurrentChunk].allocate(size, alignment);
2763 }
2764
2765 static const size_t CHUNK_SIZE = 128*1024;
2766 // Note: this class does not deallocate its
2767 // memory when it's destroyed. It depends upon
2768 // its parent to deallocate the memory.
2769 struct Chunk {
2770 Chunk() {
2771 mpData = 0;
2772 mSize = 0;
2773 mOffset = 0;
2774 }
2775
2776 Chunk(size_t size) {
2777 mSize = size;
2778 mpData = (char*) malloc(size);
2779 mOffset = 0;
2780 }
2781
2782 ~Chunk() {
2783 // Doesn't deallocate memory.
2784 }
2785
2786 void* allocate(size_t size, size_t alignment) {
2787 size_t alignedOffset = aligned(mOffset, alignment);
2788 void* result = mpData + alignedOffset;
2789 mOffset = alignedOffset + size;
2790 return result;
2791 }
2792
2793 void free() {
2794 if (mpData) {
2795 ::free(mpData);
2796 mpData = 0;
2797 }
2798 }
2799
2800 size_t remainingCapacity(size_t alignment) {
2801 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2802 }
2803
2804 // Assume alignment is a power of two
2805 inline size_t aligned(size_t v, size_t alignment) {
2806 size_t mask = alignment-1;
2807 return (v + mask) & ~mask;
2808 }
2809
2810 char* mpData;
2811 size_t mSize;
2812 size_t mOffset;
2813 };
2814
2815 size_t mCurrentChunk;
2816
2817 Vector<Chunk> mData;
2818 };
2819
Jack Palevich569f1352009-06-29 14:29:08 -07002820 struct VariableInfo;
2821
2822 struct Token {
2823 int hash;
2824 size_t length;
2825 char* pText;
2826 tokenid_t id;
2827
2828 // Current values for the token
2829 char* mpMacroDefinition;
2830 VariableInfo* mpVariableInfo;
2831 };
2832
2833 class TokenTable {
2834 public:
2835 // Don't use 0..0xff, allows characters and operators to be tokens too.
2836
2837 static const int TOKEN_BASE = 0x100;
2838 TokenTable() {
2839 mpMap = hashmapCreate(128, hashFn, equalsFn);
2840 }
2841
2842 ~TokenTable() {
2843 hashmapFree(mpMap);
2844 }
2845
2846 void setArena(Arena* pArena) {
2847 mpArena = pArena;
2848 }
2849
2850 // Returns a token for a given string of characters.
2851 tokenid_t intern(const char* pText, size_t length) {
2852 Token probe;
2853 int hash = hashmapHash((void*) pText, length);
2854 {
2855 Token probe;
2856 probe.hash = hash;
2857 probe.length = length;
2858 probe.pText = (char*) pText;
2859 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2860 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002861 return pValue->id;
2862 }
2863 }
2864
2865 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2866 memset(pToken, 0, sizeof(*pToken));
2867 pToken->hash = hash;
2868 pToken->length = length;
2869 pToken->pText = (char*) mpArena->alloc(length + 1);
2870 memcpy(pToken->pText, pText, length);
2871 pToken->pText[length] = 0;
2872 pToken->id = mTokens.size() + TOKEN_BASE;
2873 mTokens.push_back(pToken);
2874 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002875 return pToken->id;
2876 }
2877
2878 // Return the Token for a given tokenid.
2879 Token& operator[](tokenid_t id) {
2880 return *mTokens[id - TOKEN_BASE];
2881 }
2882
2883 inline size_t size() {
2884 return mTokens.size();
2885 }
2886
2887 private:
2888
2889 static int hashFn(void* pKey) {
2890 Token* pToken = (Token*) pKey;
2891 return pToken->hash;
2892 }
2893
2894 static bool equalsFn(void* keyA, void* keyB) {
2895 Token* pTokenA = (Token*) keyA;
2896 Token* pTokenB = (Token*) keyB;
2897 // Don't need to compare hash values, they should always be equal
2898 return pTokenA->length == pTokenB->length
2899 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2900 }
2901
2902 Hashmap* mpMap;
2903 Vector<Token*> mTokens;
2904 Arena* mpArena;
2905 };
2906
Jack Palevich1cdef202009-05-22 12:06:27 -07002907 class InputStream {
2908 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002909 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002910 int getChar() {
2911 if (bumpLine) {
2912 line++;
2913 bumpLine = false;
2914 }
2915 int ch = get();
2916 if (ch == '\n') {
2917 bumpLine = true;
2918 }
2919 return ch;
2920 }
2921 int getLine() {
2922 return line;
2923 }
2924 protected:
2925 InputStream() :
2926 line(1), bumpLine(false) {
2927 }
2928 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002929 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002930 int line;
2931 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002932 };
2933
2934 class FileInputStream : public InputStream {
2935 public:
2936 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002937 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002938 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002939 FILE* f;
2940 };
2941
2942 class TextInputStream : public InputStream {
2943 public:
2944 TextInputStream(const char* text, size_t textLength)
2945 : pText(text), mTextLength(textLength), mPosition(0) {
2946 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002947
2948 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002949 virtual int get() {
2950 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2951 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002952
Jack Palevich1cdef202009-05-22 12:06:27 -07002953 const char* pText;
2954 size_t mTextLength;
2955 size_t mPosition;
2956 };
2957
Jack Palevicheedf9d22009-06-04 16:23:40 -07002958 class String {
2959 public:
2960 String() {
2961 mpBase = 0;
2962 mUsed = 0;
2963 mSize = 0;
2964 }
2965
Jack Palevich303d8ff2009-06-11 19:06:24 -07002966 String(const char* item, int len, bool adopt) {
2967 if (len < 0) {
2968 len = strlen(item);
2969 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002970 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002971 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002972 mUsed = len;
2973 mSize = len + 1;
2974 } else {
2975 mpBase = 0;
2976 mUsed = 0;
2977 mSize = 0;
2978 appendBytes(item, len);
2979 }
2980 }
2981
Jack Palevich303d8ff2009-06-11 19:06:24 -07002982 String(const String& other) {
2983 mpBase = 0;
2984 mUsed = 0;
2985 mSize = 0;
2986 appendBytes(other.getUnwrapped(), other.len());
2987 }
2988
Jack Palevicheedf9d22009-06-04 16:23:40 -07002989 ~String() {
2990 if (mpBase) {
2991 free(mpBase);
2992 }
2993 }
2994
Jack Palevicha6baa232009-06-12 11:25:59 -07002995 String& operator=(const String& other) {
2996 clear();
2997 appendBytes(other.getUnwrapped(), other.len());
2998 return *this;
2999 }
3000
Jack Palevich303d8ff2009-06-11 19:06:24 -07003001 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003002 return mpBase;
3003 }
3004
Jack Palevich303d8ff2009-06-11 19:06:24 -07003005 void clear() {
3006 mUsed = 0;
3007 if (mSize > 0) {
3008 mpBase[0] = 0;
3009 }
3010 }
3011
Jack Palevicheedf9d22009-06-04 16:23:40 -07003012 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003013 appendBytes(s, strlen(s));
3014 }
3015
3016 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003017 memcpy(ensure(n), s, n + 1);
3018 }
3019
3020 void append(char c) {
3021 * ensure(1) = c;
3022 }
3023
Jack Palevich86351982009-06-30 18:09:56 -07003024 void append(String& other) {
3025 appendBytes(other.getUnwrapped(), other.len());
3026 }
3027
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003028 char* orphan() {
3029 char* result = mpBase;
3030 mpBase = 0;
3031 mUsed = 0;
3032 mSize = 0;
3033 return result;
3034 }
3035
Jack Palevicheedf9d22009-06-04 16:23:40 -07003036 void printf(const char* fmt,...) {
3037 va_list ap;
3038 va_start(ap, fmt);
3039 vprintf(fmt, ap);
3040 va_end(ap);
3041 }
3042
3043 void vprintf(const char* fmt, va_list ap) {
3044 char* temp;
3045 int numChars = vasprintf(&temp, fmt, ap);
3046 memcpy(ensure(numChars), temp, numChars+1);
3047 free(temp);
3048 }
3049
Jack Palevich303d8ff2009-06-11 19:06:24 -07003050 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003051 return mUsed;
3052 }
3053
3054 private:
3055 char* ensure(int n) {
3056 size_t newUsed = mUsed + n;
3057 if (newUsed > mSize) {
3058 size_t newSize = mSize * 2 + 10;
3059 if (newSize < newUsed) {
3060 newSize = newUsed;
3061 }
3062 mpBase = (char*) realloc(mpBase, newSize + 1);
3063 mSize = newSize;
3064 }
3065 mpBase[newUsed] = '\0';
3066 char* result = mpBase + mUsed;
3067 mUsed = newUsed;
3068 return result;
3069 }
3070
3071 char* mpBase;
3072 size_t mUsed;
3073 size_t mSize;
3074 };
3075
Jack Palevich569f1352009-06-29 14:29:08 -07003076 void internKeywords() {
3077 // Note: order has to match TOK_ constants
3078 static const char* keywords[] = {
3079 "int",
3080 "char",
3081 "void",
3082 "if",
3083 "else",
3084 "while",
3085 "break",
3086 "return",
3087 "for",
3088 "pragma",
3089 "define",
3090 "auto",
3091 "case",
3092 "const",
3093 "continue",
3094 "default",
3095 "do",
3096 "double",
3097 "enum",
3098 "extern",
3099 "float",
3100 "goto",
3101 "long",
3102 "register",
3103 "short",
3104 "signed",
3105 "sizeof",
3106 "static",
3107 "struct",
3108 "switch",
3109 "typedef",
3110 "union",
3111 "unsigned",
3112 "volatile",
3113 "_Bool",
3114 "_Complex",
3115 "_Imaginary",
3116 "inline",
3117 "restrict",
3118 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003119
Jack Palevich569f1352009-06-29 14:29:08 -07003120 for(int i = 0; keywords[i]; i++) {
3121 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003122 }
Jack Palevich569f1352009-06-29 14:29:08 -07003123 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003124
Jack Palevich36d94142009-06-08 15:55:32 -07003125 struct InputState {
3126 InputStream* pStream;
3127 int oldCh;
3128 };
3129
Jack Palevich2db168f2009-06-11 14:29:47 -07003130 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003131 void* pAddress;
3132 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003133 tokenid_t tok;
3134 size_t level;
3135 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003136 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003137 };
3138
Jack Palevich303d8ff2009-06-11 19:06:24 -07003139 class SymbolStack {
3140 public:
3141 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003142 mpArena = 0;
3143 mpTokenTable = 0;
3144 }
3145
3146 void setArena(Arena* pArena) {
3147 mpArena = pArena;
3148 }
3149
3150 void setTokenTable(TokenTable* pTokenTable) {
3151 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003152 }
3153
3154 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003155 Mark mark;
3156 mark.mArenaMark = mpArena->mark();
3157 mark.mSymbolHead = mStack.size();
3158 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003159 }
3160
3161 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003162 // Undo any shadowing that was done:
3163 Mark mark = mLevelStack.back();
3164 mLevelStack.pop_back();
3165 while (mStack.size() > mark.mSymbolHead) {
3166 VariableInfo* pV = mStack.back();
3167 mStack.pop_back();
3168 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003169 }
Jack Palevich569f1352009-06-29 14:29:08 -07003170 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003171 }
3172
Jack Palevich569f1352009-06-29 14:29:08 -07003173 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3174 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3175 return pV && pV->level == level();
3176 }
3177
3178 VariableInfo* add(tokenid_t tok) {
3179 Token& token = (*mpTokenTable)[tok];
3180 VariableInfo* pOldV = token.mpVariableInfo;
3181 VariableInfo* pNewV =
3182 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3183 memset(pNewV, 0, sizeof(VariableInfo));
3184 pNewV->tok = tok;
3185 pNewV->level = level();
3186 pNewV->pOldDefinition = pOldV;
3187 token.mpVariableInfo = pNewV;
3188 mStack.push_back(pNewV);
3189 return pNewV;
3190 }
3191
Jack Palevich86351982009-06-30 18:09:56 -07003192 VariableInfo* add(Type* pType) {
3193 VariableInfo* pVI = add(pType->id);
3194 pVI->pType = pType;
3195 return pVI;
3196 }
3197
Jack Palevich569f1352009-06-29 14:29:08 -07003198 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3199 for (size_t i = 0; i < mStack.size(); i++) {
3200 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003201 break;
3202 }
3203 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003204 }
3205
Jack Palevich303d8ff2009-06-11 19:06:24 -07003206 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003207 inline size_t level() {
3208 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003209 }
3210
Jack Palevich569f1352009-06-29 14:29:08 -07003211 struct Mark {
3212 Arena::Mark mArenaMark;
3213 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003214 };
3215
Jack Palevich569f1352009-06-29 14:29:08 -07003216 Arena* mpArena;
3217 TokenTable* mpTokenTable;
3218 Vector<VariableInfo*> mStack;
3219 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003220 };
Jack Palevich36d94142009-06-08 15:55:32 -07003221
3222 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003223 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003224 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003225 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003226 int tokl; // token operator level
3227 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003228 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003229 intptr_t loc; // local variable index
3230 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003231 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003232 char* dptr; // Macro state: Points to macro text during macro playback.
3233 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003234 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003235 ACCSymbolLookupFn mpSymbolLookupFn;
3236 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003237
3238 // Arena for the duration of the compile
3239 Arena mGlobalArena;
3240 // Arena for data that's only needed when compiling a single function
3241 Arena mLocalArena;
3242
3243 TokenTable mTokenTable;
3244 SymbolStack mGlobals;
3245 SymbolStack mLocals;
3246
Jack Palevich40600de2009-07-01 15:32:35 -07003247 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003248 Type* mkpInt; // int
3249 Type* mkpChar; // char
3250 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003251 Type* mkpFloat;
3252 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003253 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003254 Type* mkpIntPtr;
3255 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003256 Type* mkpFloatPtr;
3257 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003258 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003259
Jack Palevich36d94142009-06-08 15:55:32 -07003260 InputStream* file;
3261
3262 CodeBuf codeBuf;
3263 CodeGenerator* pGen;
3264
Jack Palevicheedf9d22009-06-04 16:23:40 -07003265 String mErrorBuf;
3266
Jack Palevicheedf9d22009-06-04 16:23:40 -07003267 String mPragmas;
3268 int mPragmaStringCount;
3269
Jack Palevich21a15a22009-05-11 14:49:29 -07003270 static const int ALLOC_SIZE = 99999;
3271
Jack Palevich303d8ff2009-06-11 19:06:24 -07003272 static const int TOK_DUMMY = 1;
3273 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003274 static const int TOK_NUM_FLOAT = 3;
3275 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003276
3277 // 3..255 are character and/or operators
3278
Jack Palevich2db168f2009-06-11 14:29:47 -07003279 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003280 // Order has to match string list in "internKeywords".
3281 enum {
3282 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3283 TOK_INT = TOK_KEYWORD,
3284 TOK_CHAR,
3285 TOK_VOID,
3286 TOK_IF,
3287 TOK_ELSE,
3288 TOK_WHILE,
3289 TOK_BREAK,
3290 TOK_RETURN,
3291 TOK_FOR,
3292 TOK_PRAGMA,
3293 TOK_DEFINE,
3294 TOK_AUTO,
3295 TOK_CASE,
3296 TOK_CONST,
3297 TOK_CONTINUE,
3298 TOK_DEFAULT,
3299 TOK_DO,
3300 TOK_DOUBLE,
3301 TOK_ENUM,
3302 TOK_EXTERN,
3303 TOK_FLOAT,
3304 TOK_GOTO,
3305 TOK_LONG,
3306 TOK_REGISTER,
3307 TOK_SHORT,
3308 TOK_SIGNED,
3309 TOK_SIZEOF,
3310 TOK_STATIC,
3311 TOK_STRUCT,
3312 TOK_SWITCH,
3313 TOK_TYPEDEF,
3314 TOK_UNION,
3315 TOK_UNSIGNED,
3316 TOK_VOLATILE,
3317 TOK__BOOL,
3318 TOK__COMPLEX,
3319 TOK__IMAGINARY,
3320 TOK_INLINE,
3321 TOK_RESTRICT,
3322 // Symbols start after tokens
3323 TOK_SYMBOL
3324 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003325
3326 static const int LOCAL = 0x200;
3327
3328 static const int SYM_FORWARD = 0;
3329 static const int SYM_DEFINE = 1;
3330
3331 /* tokens in string heap */
3332 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003333
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003334 static const int OP_INCREMENT = 0;
3335 static const int OP_DECREMENT = 1;
3336 static const int OP_MUL = 2;
3337 static const int OP_DIV = 3;
3338 static const int OP_MOD = 4;
3339 static const int OP_PLUS = 5;
3340 static const int OP_MINUS = 6;
3341 static const int OP_SHIFT_LEFT = 7;
3342 static const int OP_SHIFT_RIGHT = 8;
3343 static const int OP_LESS_EQUAL = 9;
3344 static const int OP_GREATER_EQUAL = 10;
3345 static const int OP_LESS = 11;
3346 static const int OP_GREATER = 12;
3347 static const int OP_EQUALS = 13;
3348 static const int OP_NOT_EQUALS = 14;
3349 static const int OP_LOGICAL_AND = 15;
3350 static const int OP_LOGICAL_OR = 16;
3351 static const int OP_BIT_AND = 17;
3352 static const int OP_BIT_XOR = 18;
3353 static const int OP_BIT_OR = 19;
3354 static const int OP_BIT_NOT = 20;
3355 static const int OP_LOGICAL_NOT = 21;
3356 static const int OP_COUNT = 22;
3357
3358 /* Operators are searched from front, the two-character operators appear
3359 * before the single-character operators with the same first character.
3360 * @ is used to pad out single-character operators.
3361 */
3362 static const char* operatorChars;
3363 static const char operatorLevel[];
3364
Jack Palevich569f1352009-06-29 14:29:08 -07003365 /* Called when we detect an internal problem. Does nothing in production.
3366 *
3367 */
3368 void internalError() {
3369 * (char*) 0 = 0;
3370 }
3371
Jack Palevich86351982009-06-30 18:09:56 -07003372 void assert(bool isTrue) {
3373 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003374 internalError();
3375 }
Jack Palevich86351982009-06-30 18:09:56 -07003376 }
3377
Jack Palevich40600de2009-07-01 15:32:35 -07003378 bool isSymbol(tokenid_t t) {
3379 return t >= TOK_SYMBOL &&
3380 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3381 }
3382
3383 bool isSymbolOrKeyword(tokenid_t t) {
3384 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003385 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003386 }
3387
Jack Palevich86351982009-06-30 18:09:56 -07003388 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003389 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003390 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3391 if (pV && pV->tok != t) {
3392 internalError();
3393 }
3394 return pV;
3395 }
3396
3397 inline bool isDefined(tokenid_t t) {
3398 return t >= TOK_SYMBOL && VI(t) != 0;
3399 }
3400
Jack Palevich40600de2009-07-01 15:32:35 -07003401 const char* nameof(tokenid_t t) {
3402 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003403 return mTokenTable[t].pText;
3404 }
3405
Jack Palevich21a15a22009-05-11 14:49:29 -07003406 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003407 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003408 }
3409
3410 void inp() {
3411 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003412 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003413 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003414 dptr = 0;
3415 ch = dch;
3416 }
3417 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003418 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003419#if 0
3420 printf("ch='%c' 0x%x\n", ch, ch);
3421#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003422 }
3423
3424 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003425 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003426 }
3427
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003428 int decodeHex(int c) {
3429 if (isdigit(c)) {
3430 c -= '0';
3431 } else if (c <= 'F') {
3432 c = c - 'A' + 10;
3433 } else {
3434 c =c - 'a' + 10;
3435 }
3436 return c;
3437 }
3438
Jack Palevichb4758ff2009-06-12 12:49:14 -07003439 /* read a character constant, advances ch to after end of constant */
3440 int getq() {
3441 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003442 if (ch == '\\') {
3443 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003444 if (isoctal(ch)) {
3445 // 1 to 3 octal characters.
3446 val = 0;
3447 for(int i = 0; i < 3; i++) {
3448 if (isoctal(ch)) {
3449 val = (val << 3) + ch - '0';
3450 inp();
3451 }
3452 }
3453 return val;
3454 } else if (ch == 'x' || ch == 'X') {
3455 // N hex chars
3456 inp();
3457 if (! isxdigit(ch)) {
3458 error("'x' character escape requires at least one digit.");
3459 } else {
3460 val = 0;
3461 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003462 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003463 inp();
3464 }
3465 }
3466 } else {
3467 int val = ch;
3468 switch (ch) {
3469 case 'a':
3470 val = '\a';
3471 break;
3472 case 'b':
3473 val = '\b';
3474 break;
3475 case 'f':
3476 val = '\f';
3477 break;
3478 case 'n':
3479 val = '\n';
3480 break;
3481 case 'r':
3482 val = '\r';
3483 break;
3484 case 't':
3485 val = '\t';
3486 break;
3487 case 'v':
3488 val = '\v';
3489 break;
3490 case '\\':
3491 val = '\\';
3492 break;
3493 case '\'':
3494 val = '\'';
3495 break;
3496 case '"':
3497 val = '"';
3498 break;
3499 case '?':
3500 val = '?';
3501 break;
3502 default:
3503 error("Undefined character escape %c", ch);
3504 break;
3505 }
3506 inp();
3507 return val;
3508 }
3509 } else {
3510 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003511 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003512 return val;
3513 }
3514
3515 static bool isoctal(int ch) {
3516 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003517 }
3518
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003519 bool acceptCh(int c) {
3520 bool result = c == ch;
3521 if (result) {
3522 pdef(ch);
3523 inp();
3524 }
3525 return result;
3526 }
3527
3528 bool acceptDigitsCh() {
3529 bool result = false;
3530 while (isdigit(ch)) {
3531 result = true;
3532 pdef(ch);
3533 inp();
3534 }
3535 return result;
3536 }
3537
3538 void parseFloat() {
3539 tok = TOK_NUM_DOUBLE;
3540 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003541 if(mTokenString.len() == 0) {
3542 mTokenString.append('0');
3543 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003544 acceptCh('.');
3545 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003546 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003547 acceptCh('-') || acceptCh('+');
3548 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003549 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003550 if (ch == 'f' || ch == 'F') {
3551 tok = TOK_NUM_FLOAT;
3552 inp();
3553 } else if (ch == 'l' || ch == 'L') {
3554 inp();
3555 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003556 }
3557 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003558 char* pEnd = pText + strlen(pText);
3559 char* pEndPtr = 0;
3560 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003561 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003562 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003563 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003564 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003565 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003566 if (errno || pEndPtr != pEnd) {
3567 error("Can't parse constant: %s", pText);
3568 }
3569 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003570 }
3571
Jack Palevich21a15a22009-05-11 14:49:29 -07003572 void next() {
3573 int l, a;
3574
Jack Palevich546b2242009-05-13 15:10:04 -07003575 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003576 if (ch == '#') {
3577 inp();
3578 next();
3579 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003580 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003581 } else if (tok == TOK_PRAGMA) {
3582 doPragma();
3583 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003584 error("Unsupported preprocessor directive \"%s\"",
3585 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003586 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003587 }
3588 inp();
3589 }
3590 tokl = 0;
3591 tok = ch;
3592 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003593 if (isdigit(ch) || ch == '.') {
3594 // Start of a numeric constant. Could be integer, float, or
3595 // double, won't know until we look further.
3596 mTokenString.clear();
3597 pdef(ch);
3598 inp();
3599 int base = 10;
3600 if (tok == '0') {
3601 if (ch == 'x' || ch == 'X') {
3602 base = 16;
3603 tok = TOK_NUM;
3604 tokc = 0;
3605 inp();
3606 while ( isxdigit(ch) ) {
3607 tokc = (tokc << 4) + decodeHex(ch);
3608 inp();
3609 }
3610 } else if (isoctal(ch)){
3611 base = 8;
3612 tok = TOK_NUM;
3613 tokc = 0;
3614 while ( isoctal(ch) ) {
3615 tokc = (tokc << 3) + (ch - '0');
3616 inp();
3617 }
3618 }
3619 } else if (isdigit(tok)){
3620 acceptDigitsCh();
3621 }
3622 if (base == 10) {
3623 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3624 parseFloat();
3625 } else {
3626 // It's an integer constant
3627 char* pText = mTokenString.getUnwrapped();
3628 char* pEnd = pText + strlen(pText);
3629 char* pEndPtr = 0;
3630 errno = 0;
3631 tokc = strtol(pText, &pEndPtr, base);
3632 if (errno || pEndPtr != pEnd) {
3633 error("Can't parse constant: %s %d %d", pText, base, errno);
3634 }
3635 tok = TOK_NUM;
3636 }
3637 }
3638 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003639 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003640 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003641 pdef(ch);
3642 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003643 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003644 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3645 // Is this a macro?
3646 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3647 if (pMacroDefinition) {
3648 // Yes, it is a macro
3649 dptr = pMacroDefinition;
3650 dch = ch;
3651 inp();
3652 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003653 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003654 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 inp();
3656 if (tok == '\'') {
3657 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003658 tokc = getq();
3659 if (ch != '\'') {
3660 error("Expected a ' character, got %c", ch);
3661 } else {
3662 inp();
3663 }
Jack Palevich546b2242009-05-13 15:10:04 -07003664 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003665 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003666 while (ch && ch != EOF) {
3667 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003668 inp();
3669 inp();
3670 if (ch == '/')
3671 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003672 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003673 if (ch == EOF) {
3674 error("End of file inside comment.");
3675 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003676 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003677 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003678 } else if ((tok == '/') & (ch == '/')) {
3679 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003680 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003681 inp();
3682 }
3683 inp();
3684 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003685 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003686 const char* t = operatorChars;
3687 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003688 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003689 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003690 tokl = operatorLevel[opIndex];
3691 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003692 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003693#if 0
3694 printf("%c%c -> tokl=%d tokc=0x%x\n",
3695 l, a, tokl, tokc);
3696#endif
3697 if (a == ch) {
3698 inp();
3699 tok = TOK_DUMMY; /* dummy token for double tokens */
3700 }
3701 break;
3702 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003703 opIndex++;
3704 }
3705 if (l == 0) {
3706 tokl = 0;
3707 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003708 }
3709 }
3710 }
3711#if 0
3712 {
Jack Palevich569f1352009-06-29 14:29:08 -07003713 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003714 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003715 fprintf(stderr, "%s\n", buf.getUnwrapped());
3716 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003717#endif
3718 }
3719
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003720 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003721 next();
3722 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003723 String* pName = new String();
3724 while (isspace(ch)) {
3725 inp();
3726 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003727 if (ch == '(') {
3728 delete pName;
3729 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003730 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003731 }
3732 while (isspace(ch)) {
3733 inp();
3734 }
Jack Palevich569f1352009-06-29 14:29:08 -07003735 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003736 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003737 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003738 inp();
3739 }
Jack Palevich569f1352009-06-29 14:29:08 -07003740 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3741 memcpy(pDefn, value.getUnwrapped(), value.len());
3742 pDefn[value.len()] = 0;
3743 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003744 }
3745
Jack Palevicheedf9d22009-06-04 16:23:40 -07003746 void doPragma() {
3747 // # pragma name(val)
3748 int state = 0;
3749 while(ch != EOF && ch != '\n' && state < 10) {
3750 switch(state) {
3751 case 0:
3752 if (isspace(ch)) {
3753 inp();
3754 } else {
3755 state++;
3756 }
3757 break;
3758 case 1:
3759 if (isalnum(ch)) {
3760 mPragmas.append(ch);
3761 inp();
3762 } else if (ch == '(') {
3763 mPragmas.append(0);
3764 inp();
3765 state++;
3766 } else {
3767 state = 11;
3768 }
3769 break;
3770 case 2:
3771 if (isalnum(ch)) {
3772 mPragmas.append(ch);
3773 inp();
3774 } else if (ch == ')') {
3775 mPragmas.append(0);
3776 inp();
3777 state = 10;
3778 } else {
3779 state = 11;
3780 }
3781 break;
3782 }
3783 }
3784 if(state != 10) {
3785 error("Unexpected pragma syntax");
3786 }
3787 mPragmaStringCount += 2;
3788 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003789
Jack Palevichac0e95e2009-05-29 13:53:44 -07003790 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003791 mErrorBuf.printf("%ld: ", file->getLine());
3792 mErrorBuf.vprintf(fmt, ap);
3793 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003794 }
3795
Jack Palevich8b0624c2009-05-20 12:12:06 -07003796 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003797 if (tok != c) {
3798 error("'%c' expected", c);
3799 }
3800 next();
3801 }
3802
Jack Palevich86351982009-06-30 18:09:56 -07003803 bool accept(intptr_t c) {
3804 if (tok == c) {
3805 next();
3806 return true;
3807 }
3808 return false;
3809 }
3810
Jack Palevich40600de2009-07-01 15:32:35 -07003811 bool acceptStringLiteral() {
3812 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003813 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003814 // This while loop merges multiple adjacent string constants.
3815 while (tok == '"') {
3816 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003817 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003818 }
3819 if (ch != '"') {
3820 error("Unterminated string constant.");
3821 }
3822 inp();
3823 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003824 }
Jack Palevich40600de2009-07-01 15:32:35 -07003825 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003826 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003827 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003828 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003829
3830 return true;
3831 }
3832 return false;
3833 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003834
Jack Palevich40600de2009-07-01 15:32:35 -07003835 /* Parse and evaluate a unary expression.
3836 * allowAssignment is true if '=' parsing wanted (quick hack)
3837 */
3838 void unary(bool allowAssignment) {
3839 intptr_t n, t, a;
3840 t = 0;
3841 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3842 if (acceptStringLiteral()) {
3843 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003844 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003845 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003846 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003847 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003848 t = tok;
3849 next();
3850 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003851 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003852 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003853 // Align to 4-byte boundary
3854 glo = (char*) (((intptr_t) glo + 3) & -4);
3855 * (float*) glo = (float) ad;
3856 pGen->loadFloat((int) glo, mkpFloat);
3857 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003858 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003859 // Align to 8-byte boundary
3860 glo = (char*) (((intptr_t) glo + 7) & -8);
3861 * (double*) glo = ad;
3862 pGen->loadFloat((int) glo, mkpDouble);
3863 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003864 } else if (c == 2) {
3865 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003866 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003867 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003868 pGen->gUnaryCmp(a, mkpInt);
3869 else if (t == '+') {
3870 // ignore unary plus.
3871 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003872 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003873 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003874 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003875 // It's either a cast or an expression
3876 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3877 if (pCast) {
3878 skip(')');
3879 unary(false);
3880 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003881 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003882 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003883 skip(')');
3884 }
3885 } else if (t == '*') {
3886 /* This is a pointer dereference.
3887 */
3888 unary(false);
3889 Type* pR0Type = pGen->getR0Type();
3890 if (pR0Type->tag != TY_POINTER) {
3891 error("Expected a pointer type.");
3892 } else {
3893 if (pR0Type->pHead->tag == TY_FUNC) {
3894 t = 0;
3895 }
3896 if (accept('=')) {
3897 pGen->pushR0();
3898 expr();
3899 pGen->storeR0ToTOS(pR0Type);
3900 } else if (t) {
3901 pGen->loadR0FromR0(pR0Type);
3902 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003903 }
Jack Palevich3f226492009-07-02 14:46:19 -07003904 // Else we fall through to the function call below, with
3905 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003906 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003907 VariableInfo* pVI = VI(tok);
3908 pGen->leaR0((int) pVI->pAddress,
3909 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003910 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003911 } else if (t == EOF ) {
3912 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003913 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003914 // Don't have to do anything special here, the error
3915 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003916 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003917 if (!isDefined(t)) {
3918 mGlobals.add(t);
3919 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003920 }
Jack Palevich8df46192009-07-07 14:48:51 -07003921 VariableInfo* pVI = VI(t);
3922 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003923 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003924 if (!n) {
Jack Palevich8c246a92009-07-14 21:14:10 -07003925 if (mpSymbolLookupFn) {
3926 n = (intptr_t) mpSymbolLookupFn(
3927 mpSymbolLookupContext, nameof(t));
3928 }
Jack Palevich37c54bd2009-07-14 18:35:36 -07003929 if (pVI->pType == NULL) {
3930 if (tok == '(') {
3931 pVI->pType = mkpIntFn;
3932 } else {
3933 pVI->pType = mkpInt;
3934 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003935 }
Jack Palevich8df46192009-07-07 14:48:51 -07003936 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003937 }
Jack Palevich40600de2009-07-01 15:32:35 -07003938 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003939 /* assignment */
3940 next();
3941 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003942 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003943 } else if (tok != '(') {
3944 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003945 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003946 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003947 }
Jack Palevich8df46192009-07-07 14:48:51 -07003948 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003949 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003950 next();
3951 }
3952 }
3953 }
3954 }
3955
3956 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003957 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003958 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003959 VariableInfo* pVI = NULL;
3960 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003961 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003962 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003963 } else {
3964 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003965 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003966 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003967 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003968 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003969 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003970 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003971 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003972 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003973 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003974 if (! varArgs && !pArgList) {
3975 error ("Unexpected argument.");
3976 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003977 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003978 Type* pTargetType;
3979 if (pArgList) {
3980 pTargetType = pArgList->pHead;
3981 pArgList = pArgList->pTail;
3982 } else {
3983 pTargetType = pGen->getR0Type();
3984 if (pTargetType->tag == TY_FLOAT) {
3985 pTargetType = mkpDouble;
3986 }
3987 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003988 if (pTargetType->tag == TY_VOID) {
3989 error("Can't pass void value for argument %d",
3990 argCount + 1);
3991 } else {
3992 pGen->convertR0(pTargetType);
3993 l += pGen->storeR0ToArg(l);
3994 }
Jack Palevich95727a02009-07-06 12:07:15 -07003995 if (accept(',')) {
3996 // fine
3997 } else if ( tok != ')') {
3998 error("Expected ',' or ')'");
3999 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004000 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004001 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004002 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004003 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004004 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004005 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004006 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004007 if (!n) {
4008 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004009 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4010 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004011 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004012 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004013 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004014 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4015 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004016 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004017 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004018 }
4019 }
4020
Jack Palevich40600de2009-07-01 15:32:35 -07004021 /* Recursive descent parser for binary operations.
4022 */
4023 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004024 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004025 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004026 if (level-- == 1)
4027 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004028 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004029 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004030 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004031 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004032 t = tokc;
4033 next();
4034
Jack Palevich40600de2009-07-01 15:32:35 -07004035 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004036 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004037 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004039 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004040 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004041
Jack Palevich40600de2009-07-01 15:32:35 -07004042 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004043 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004044 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004045 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004046 }
4047 }
4048 }
4049 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004050 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004051 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004052 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004053 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004054 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004055 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 }
4057 }
4058 }
4059
4060 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004061 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004062 }
4063
4064 int test_expr() {
4065 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004066 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004067 }
4068
Jack Palevicha6baa232009-06-12 11:25:59 -07004069 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004070 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004071
Jack Palevich95727a02009-07-06 12:07:15 -07004072 Type* pBaseType;
4073 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004074 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004075 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004076 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004077 next();
4078 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004079 a = test_expr();
4080 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004081 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004082 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004083 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004084 n = pGen->gjmp(0); /* jmp */
4085 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004086 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004087 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004088 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004089 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004090 }
Jack Palevich546b2242009-05-13 15:10:04 -07004091 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004092 t = tok;
4093 next();
4094 skip('(');
4095 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004096 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004097 a = test_expr();
4098 } else {
4099 if (tok != ';')
4100 expr();
4101 skip(';');
4102 n = codeBuf.getPC();
4103 a = 0;
4104 if (tok != ';')
4105 a = test_expr();
4106 skip(';');
4107 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004108 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004109 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004110 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004111 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004112 n = t + 4;
4113 }
4114 }
4115 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004116 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004117 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004118 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004119 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004120 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004121 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004122 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004123 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004124 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004125 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004126 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004127 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004128 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004129 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004130 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004131 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004132 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004134 if (pReturnType->tag == TY_VOID) {
4135 error("Must not return a value from a void function");
4136 } else {
4137 pGen->convertR0(pReturnType);
4138 }
4139 } else {
4140 if (pReturnType->tag != TY_VOID) {
4141 error("Must specify a value here");
4142 }
Jack Palevich8df46192009-07-07 14:48:51 -07004143 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004144 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004145 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004146 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004147 } else if (tok != ';')
4148 expr();
4149 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004150 }
4151 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004152
Jack Palevicha8f427f2009-07-13 18:40:08 -07004153 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004154 if (a == b) {
4155 return true;
4156 }
4157 if (a == NULL || b == NULL) {
4158 return false;
4159 }
4160 TypeTag at = a->tag;
4161 if (at != b->tag) {
4162 return false;
4163 }
4164 if (at == TY_POINTER) {
4165 return typeEqual(a->pHead, b->pHead);
4166 } else if (at == TY_FUNC || at == TY_PARAM) {
4167 return typeEqual(a->pHead, b->pHead)
4168 && typeEqual(a->pTail, b->pTail);
4169 }
4170 return true;
4171 }
4172
Jack Palevich86351982009-06-30 18:09:56 -07004173 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4174 assert(tag >= TY_INT && tag <= TY_PARAM);
4175 Type* pType = (Type*) arena.alloc(sizeof(Type));
4176 memset(pType, 0, sizeof(*pType));
4177 pType->tag = tag;
4178 pType->pHead = pHead;
4179 pType->pTail = pTail;
4180 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004181 }
4182
Jack Palevich3f226492009-07-02 14:46:19 -07004183 Type* createPtrType(Type* pType, Arena& arena) {
4184 return createType(TY_POINTER, pType, NULL, arena);
4185 }
4186
4187 /**
4188 * Try to print a type in declaration order
4189 */
Jack Palevich86351982009-06-30 18:09:56 -07004190 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004191 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004192 if (pType == NULL) {
4193 buffer.appendCStr("null");
4194 return;
4195 }
Jack Palevich3f226492009-07-02 14:46:19 -07004196 decodeTypeImp(buffer, pType);
4197 }
4198
4199 void decodeTypeImp(String& buffer, Type* pType) {
4200 decodeTypeImpPrefix(buffer, pType);
4201
Jack Palevich86351982009-06-30 18:09:56 -07004202 String temp;
4203 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004204 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004205 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004206 }
4207
4208 decodeTypeImpPostfix(buffer, pType);
4209 }
4210
4211 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4212 TypeTag tag = pType->tag;
4213
Jack Palevich37c54bd2009-07-14 18:35:36 -07004214 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004215 switch (tag) {
4216 case TY_INT:
4217 buffer.appendCStr("int");
4218 break;
4219 case TY_CHAR:
4220 buffer.appendCStr("char");
4221 break;
4222 case TY_VOID:
4223 buffer.appendCStr("void");
4224 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004225 case TY_FLOAT:
4226 buffer.appendCStr("float");
4227 break;
4228 case TY_DOUBLE:
4229 buffer.appendCStr("double");
4230 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004231 default:
4232 break;
4233 }
Jack Palevich86351982009-06-30 18:09:56 -07004234 buffer.append(' ');
4235 }
Jack Palevich3f226492009-07-02 14:46:19 -07004236
4237 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004238 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004239 break;
4240 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004241 break;
4242 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004243 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004244 case TY_FLOAT:
4245 break;
4246 case TY_DOUBLE:
4247 break;
Jack Palevich86351982009-06-30 18:09:56 -07004248 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004249 decodeTypeImpPrefix(buffer, pType->pHead);
4250 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4251 buffer.append('(');
4252 }
4253 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004254 break;
4255 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004256 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004257 break;
4258 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004259 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004260 break;
4261 default:
4262 String temp;
4263 temp.printf("Unknown tag %d", pType->tag);
4264 buffer.append(temp);
4265 break;
4266 }
Jack Palevich3f226492009-07-02 14:46:19 -07004267 }
4268
4269 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4270 TypeTag tag = pType->tag;
4271
4272 switch(tag) {
4273 case TY_POINTER:
4274 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4275 buffer.append(')');
4276 }
4277 decodeTypeImpPostfix(buffer, pType->pHead);
4278 break;
4279 case TY_FUNC:
4280 buffer.append('(');
4281 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4282 decodeTypeImp(buffer, pArg);
4283 if (pArg->pTail) {
4284 buffer.appendCStr(", ");
4285 }
4286 }
4287 buffer.append(')');
4288 break;
4289 default:
4290 break;
Jack Palevich86351982009-06-30 18:09:56 -07004291 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004292 }
4293
Jack Palevich86351982009-06-30 18:09:56 -07004294 void printType(Type* pType) {
4295 String buffer;
4296 decodeType(buffer, pType);
4297 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004298 }
4299
Jack Palevich86351982009-06-30 18:09:56 -07004300 Type* acceptPrimitiveType(Arena& arena) {
4301 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004302 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004303 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004304 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004305 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004306 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004307 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004308 } else if (tok == TOK_FLOAT) {
4309 pType = mkpFloat;
4310 } else if (tok == TOK_DOUBLE) {
4311 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004312 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004313 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004314 }
4315 next();
Jack Palevich86351982009-06-30 18:09:56 -07004316 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004317 }
4318
Jack Palevich3f226492009-07-02 14:46:19 -07004319 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4320 Arena& arena) {
4321 tokenid_t declName = 0;
4322 pType = acceptDecl2(pType, declName, nameAllowed,
4323 nameRequired, arena);
4324 if (declName) {
4325 // Clone the parent type so we can set a unique ID
4326 pType = createType(pType->tag, pType->pHead,
4327 pType->pTail, arena);
4328
Jack Palevich86351982009-06-30 18:09:56 -07004329 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004330 }
Jack Palevich3f226492009-07-02 14:46:19 -07004331 // fprintf(stderr, "Parsed a declaration: ");
4332 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004333 return pType;
4334 }
4335
Jack Palevich3f226492009-07-02 14:46:19 -07004336 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4337 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004338 if (! pType) {
4339 error("Expected a declaration");
4340 }
4341 return pType;
4342 }
4343
Jack Palevich3f226492009-07-02 14:46:19 -07004344 /* Used for accepting types that appear in casts */
4345 Type* acceptCastTypeDeclaration(Arena& arena) {
4346 Type* pType = acceptPrimitiveType(arena);
4347 if (pType) {
4348 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004349 }
Jack Palevich86351982009-06-30 18:09:56 -07004350 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004351 }
4352
Jack Palevich3f226492009-07-02 14:46:19 -07004353 Type* expectCastTypeDeclaration(Arena& arena) {
4354 Type* pType = acceptCastTypeDeclaration(arena);
4355 if (! pType) {
4356 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004357 }
Jack Palevich3f226492009-07-02 14:46:19 -07004358 return pType;
4359 }
4360
4361 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4362 bool nameAllowed, bool nameRequired, Arena& arena) {
4363 int ptrCounter = 0;
4364 while (accept('*')) {
4365 ptrCounter++;
4366 }
4367 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4368 while (ptrCounter-- > 0) {
4369 pType = createType(TY_POINTER, pType, NULL, arena);
4370 }
4371 return pType;
4372 }
4373
4374 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4375 bool nameAllowed, bool nameRequired, Arena& arena) {
4376 // direct-dcl :
4377 // name
4378 // (dcl)
4379 // direct-dcl()
4380 // direct-dcl[]
4381 Type* pNewHead = NULL;
4382 if (accept('(')) {
4383 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4384 nameRequired, arena);
4385 skip(')');
4386 } else if ((declName = acceptSymbol()) != 0) {
4387 if (nameAllowed == false && declName) {
4388 error("Symbol %s not allowed here", nameof(declName));
4389 } else if (nameRequired && ! declName) {
4390 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004391 decodeToken(temp, tok, true);
Jack Palevich3f226492009-07-02 14:46:19 -07004392 error("Expected symbol. Got %s", temp.getUnwrapped());
4393 }
4394 }
4395 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004396 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004397 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004398 pType = createType(TY_FUNC, pType, pTail, arena);
4399 skip(')');
4400 }
Jack Palevich3f226492009-07-02 14:46:19 -07004401
4402 if (pNewHead) {
4403 Type* pA = pNewHead;
4404 while (pA->pHead) {
4405 pA = pA->pHead;
4406 }
4407 pA->pHead = pType;
4408 pType = pNewHead;
4409 }
Jack Palevich86351982009-06-30 18:09:56 -07004410 return pType;
4411 }
4412
Jack Palevich3f226492009-07-02 14:46:19 -07004413 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004414 Type* pHead = NULL;
4415 Type* pTail = NULL;
4416 for(;;) {
4417 Type* pBaseArg = acceptPrimitiveType(arena);
4418 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004419 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4420 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004421 if (pArg) {
4422 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4423 if (!pHead) {
4424 pHead = pParam;
4425 pTail = pParam;
4426 } else {
4427 pTail->pTail = pParam;
4428 pTail = pParam;
4429 }
4430 }
4431 }
4432 if (! accept(',')) {
4433 break;
4434 }
4435 }
4436 return pHead;
4437 }
4438
4439 Type* expectPrimitiveType(Arena& arena) {
4440 Type* pType = acceptPrimitiveType(arena);
4441 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004442 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004443 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004444 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004445 }
Jack Palevich86351982009-06-30 18:09:56 -07004446 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004447 }
4448
Jack Palevich86351982009-06-30 18:09:56 -07004449 void addGlobalSymbol(Type* pDecl) {
4450 tokenid_t t = pDecl->id;
4451 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004452 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004453 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004454 }
Jack Palevich86351982009-06-30 18:09:56 -07004455 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004456 }
4457
Jack Palevich86351982009-06-30 18:09:56 -07004458 void reportDuplicate(tokenid_t t) {
4459 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004460 }
4461
Jack Palevich86351982009-06-30 18:09:56 -07004462 void addLocalSymbol(Type* pDecl) {
4463 tokenid_t t = pDecl->id;
4464 if (mLocals.isDefinedAtCurrentLevel(t)) {
4465 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004466 }
Jack Palevich86351982009-06-30 18:09:56 -07004467 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004468 }
4469
Jack Palevich95727a02009-07-06 12:07:15 -07004470 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004471 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004472
Jack Palevich95727a02009-07-06 12:07:15 -07004473 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004474 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004475 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4476 if (!pDecl) {
4477 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004478 }
Jack Palevich86351982009-06-30 18:09:56 -07004479 int variableAddress = 0;
4480 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004481 size_t alignment = pGen->alignmentOf(pDecl);
4482 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004483 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004484 variableAddress = -loc;
4485 VI(pDecl->id)->pAddress = (void*) variableAddress;
4486 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004487 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004488 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004489 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004490 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004491 if (tok == ',')
4492 next();
4493 }
4494 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004495 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004496 }
4497 }
4498
Jack Palevichf1728be2009-06-12 13:53:51 -07004499 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004500 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004501 }
4502
Jack Palevich37c54bd2009-07-14 18:35:36 -07004503 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004504 if (token == EOF ) {
4505 buffer.printf("EOF");
4506 } else if (token == TOK_NUM) {
4507 buffer.printf("numeric constant");
4508 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004509 if (token < 32) {
4510 buffer.printf("'\\x%02x'", token);
4511 } else {
4512 buffer.printf("'%c'", token);
4513 }
Jack Palevich569f1352009-06-29 14:29:08 -07004514 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004515 if (quote) {
4516 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4517 buffer.printf("keyword \"%s\"", nameof(token));
4518 } else {
4519 buffer.printf("symbol \"%s\"", nameof(token));
4520 }
4521 } else {
4522 buffer.printf("%s", nameof(token));
4523 }
Jack Palevich569f1352009-06-29 14:29:08 -07004524 }
4525 }
4526
Jack Palevich40600de2009-07-01 15:32:35 -07004527 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004528 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004529 if (!result) {
4530 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004531 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004532 error("Expected symbol. Got %s", temp.getUnwrapped());
4533 }
4534 return result;
4535 }
4536
Jack Palevich86351982009-06-30 18:09:56 -07004537 tokenid_t acceptSymbol() {
4538 tokenid_t result = 0;
4539 if (tok >= TOK_SYMBOL) {
4540 result = tok;
4541 next();
Jack Palevich86351982009-06-30 18:09:56 -07004542 }
4543 return result;
4544 }
4545
Jack Palevichb7c81e92009-06-04 19:56:13 -07004546 void globalDeclarations() {
4547 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004548 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4549 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004550 break;
4551 }
Jack Palevich86351982009-06-30 18:09:56 -07004552 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4553 if (!pDecl) {
4554 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004555 }
Jack Palevich86351982009-06-30 18:09:56 -07004556 if (! isDefined(pDecl->id)) {
4557 addGlobalSymbol(pDecl);
4558 }
4559 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004560 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004561 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004562 }
Jack Palevich86351982009-06-30 18:09:56 -07004563 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004564 // it's a variable declaration
4565 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004566 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004567 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004568 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004569 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004570 }
Jack Palevich86351982009-06-30 18:09:56 -07004571 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004572 if (tok == TOK_NUM) {
4573 if (name) {
4574 * (int*) name->pAddress = tokc;
4575 }
4576 next();
4577 } else {
4578 error("Expected an integer constant");
4579 }
4580 }
Jack Palevich86351982009-06-30 18:09:56 -07004581 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004582 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004583 }
Jack Palevich86351982009-06-30 18:09:56 -07004584 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4585 if (!pDecl) {
4586 break;
4587 }
4588 if (! isDefined(pDecl->id)) {
4589 addGlobalSymbol(pDecl);
4590 }
4591 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004592 }
4593 skip(';');
4594 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004595 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004596 if (accept(';')) {
4597 // forward declaration.
4598 } else {
4599 if (name) {
4600 /* patch forward references (XXX: does not work for function
4601 pointers) */
4602 pGen->gsym((int) name->pForward);
4603 /* put function address */
4604 name->pAddress = (void*) codeBuf.getPC();
4605 }
4606 // Calculate stack offsets for parameters
4607 mLocals.pushLevel();
4608 intptr_t a = 8;
4609 int argCount = 0;
4610 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4611 Type* pArg = pP->pHead;
4612 addLocalSymbol(pArg);
4613 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004614 size_t alignment = pGen->alignmentOf(pArg);
4615 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004616 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004617 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004618 argCount++;
4619 }
4620 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004621 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004622 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004623 block(0, true);
4624 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004625 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004626 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004627 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004628 }
4629 }
4630 }
4631
Jack Palevich9cbd2262009-07-08 16:48:41 -07004632 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4633 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4634 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004635 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004636 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004637 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004638 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004639 char* result = (char*) base;
4640 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004641 return result;
4642 }
4643
Jack Palevich21a15a22009-05-11 14:49:29 -07004644 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004645 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004646 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004647 pGlobalBase = 0;
4648 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004649 if (pGen) {
4650 delete pGen;
4651 pGen = 0;
4652 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004653 if (file) {
4654 delete file;
4655 file = 0;
4656 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004657 }
4658
Jack Palevich8c246a92009-07-14 21:14:10 -07004659 // One-time initialization, when class is constructed.
4660 void init() {
4661 mpSymbolLookupFn = 0;
4662 mpSymbolLookupContext = 0;
4663 }
4664
Jack Palevich21a15a22009-05-11 14:49:29 -07004665 void clear() {
4666 tok = 0;
4667 tokc = 0;
4668 tokl = 0;
4669 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004670 rsym = 0;
4671 loc = 0;
4672 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004673 dptr = 0;
4674 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004675 file = 0;
4676 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004677 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004678 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004679 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004680
Jack Palevich22305132009-05-13 10:58:45 -07004681 void setArchitecture(const char* architecture) {
4682 delete pGen;
4683 pGen = 0;
4684
4685 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004686#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004687 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004688 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004689 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004690#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004691#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004692 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004693 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004694 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004695#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004696 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004697 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004698 }
4699 }
4700
4701 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004702#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004703 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004704#elif defined(DEFAULT_X86_CODEGEN)
4705 pGen = new X86CodeGenerator();
4706#endif
4707 }
4708 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004709 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004710 } else {
4711 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004712 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004713 }
4714 }
4715
Jack Palevich77ae76e2009-05-10 19:59:24 -07004716public:
Jack Palevich22305132009-05-13 10:58:45 -07004717 struct args {
4718 args() {
4719 architecture = 0;
4720 }
4721 const char* architecture;
4722 };
4723
Jack Paleviche7b59062009-05-19 17:12:17 -07004724 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004725 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004726 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004727 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004728
Jack Paleviche7b59062009-05-19 17:12:17 -07004729 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004730 cleanup();
4731 }
4732
Jack Palevich8c246a92009-07-14 21:14:10 -07004733 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4734 mpSymbolLookupFn = pFn;
4735 mpSymbolLookupContext = pContext;
4736 }
4737
Jack Palevich1cdef202009-05-22 12:06:27 -07004738 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004739 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004740
Jack Palevicha8f427f2009-07-13 18:40:08 -07004741 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004742 cleanup();
4743 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004744 mTokenTable.setArena(&mGlobalArena);
4745 mGlobals.setArena(&mGlobalArena);
4746 mGlobals.setTokenTable(&mTokenTable);
4747 mLocals.setArena(&mLocalArena);
4748 mLocals.setTokenTable(&mTokenTable);
4749
4750 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004751 codeBuf.init(ALLOC_SIZE);
4752 setArchitecture(NULL);
4753 if (!pGen) {
4754 return -1;
4755 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004756#ifdef PROVIDE_TRACE_CODEGEN
4757 pGen = new TraceCodeGenerator(pGen);
4758#endif
4759 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004760 pGen->init(&codeBuf);
4761 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004762 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4763 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004764 inp();
4765 next();
4766 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004767 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004768 result = pGen->finishCompile();
4769 if (result == 0) {
4770 if (mErrorBuf.len()) {
4771 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004772 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004773 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004774 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004775 }
4776
Jack Palevich86351982009-06-30 18:09:56 -07004777 void createPrimitiveTypes() {
4778 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4779 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4780 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004781 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4782 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004783 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004784 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4785 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004786 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4787 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004788 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004789 }
4790
Jack Palevicha6baa232009-06-12 11:25:59 -07004791 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004792 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004793 }
4794
Jack Palevich569f1352009-06-29 14:29:08 -07004795 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004796 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004797 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004798 }
4799
Jack Palevich569f1352009-06-29 14:29:08 -07004800 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004801 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004802 error("Undefined forward reference: %s",
4803 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004804 }
4805 return true;
4806 }
4807
Jack Palevich21a15a22009-05-11 14:49:29 -07004808 int dump(FILE* out) {
4809 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4810 return 0;
4811 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004812
Jack Palevicha6535612009-05-13 16:24:17 -07004813 int disassemble(FILE* out) {
4814 return pGen->disassemble(out);
4815 }
4816
Jack Palevich1cdef202009-05-22 12:06:27 -07004817 /* Look through the symbol table to find a symbol.
4818 * If found, return its value.
4819 */
4820 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004821 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4822 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004823 if (pVariableInfo) {
4824 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004825 }
4826 return NULL;
4827 }
4828
Jack Palevicheedf9d22009-06-04 16:23:40 -07004829 void getPragmas(ACCsizei* actualStringCount,
4830 ACCsizei maxStringCount, ACCchar** strings) {
4831 int stringCount = mPragmaStringCount;
4832 if (actualStringCount) {
4833 *actualStringCount = stringCount;
4834 }
4835 if (stringCount > maxStringCount) {
4836 stringCount = maxStringCount;
4837 }
4838 if (strings) {
4839 char* pPragmas = mPragmas.getUnwrapped();
4840 while (stringCount-- > 0) {
4841 *strings++ = pPragmas;
4842 pPragmas += strlen(pPragmas) + 1;
4843 }
4844 }
4845 }
4846
Jack Palevichac0e95e2009-05-29 13:53:44 -07004847 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004848 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004849 }
4850
Jack Palevich77ae76e2009-05-10 19:59:24 -07004851};
4852
Jack Paleviche7b59062009-05-19 17:12:17 -07004853const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004854 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4855
Jack Paleviche7b59062009-05-19 17:12:17 -07004856const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004857 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4858 5, 5, /* ==, != */
4859 9, 10, /* &&, || */
4860 6, 7, 8, /* & ^ | */
4861 2, 2 /* ~ ! */
4862 };
4863
Jack Palevich8b0624c2009-05-20 12:12:06 -07004864#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004865FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004866#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004867
Jack Palevich8b0624c2009-05-20 12:12:06 -07004868#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004869const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004870 0x1, // ++
4871 0xff, // --
4872 0xc1af0f, // *
4873 0xf9f79991, // /
4874 0xf9f79991, // % (With manual assist to swap results)
4875 0xc801, // +
4876 0xd8f7c829, // -
4877 0xe0d391, // <<
4878 0xf8d391, // >>
4879 0xe, // <=
4880 0xd, // >=
4881 0xc, // <
4882 0xf, // >
4883 0x4, // ==
4884 0x5, // !=
4885 0x0, // &&
4886 0x1, // ||
4887 0xc821, // &
4888 0xc831, // ^
4889 0xc809, // |
4890 0xd0f7, // ~
4891 0x4 // !
4892};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004893#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004894
Jack Palevich1cdef202009-05-22 12:06:27 -07004895struct ACCscript {
4896 ACCscript() {
4897 text = 0;
4898 textLength = 0;
4899 accError = ACC_NO_ERROR;
4900 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004901
Jack Palevich1cdef202009-05-22 12:06:27 -07004902 ~ACCscript() {
4903 delete text;
4904 }
Jack Palevich546b2242009-05-13 15:10:04 -07004905
Jack Palevich8c246a92009-07-14 21:14:10 -07004906 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4907 compiler.registerSymbolCallback(pFn, pContext);
4908 }
4909
Jack Palevich1cdef202009-05-22 12:06:27 -07004910 void setError(ACCenum error) {
4911 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4912 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004913 }
4914 }
4915
Jack Palevich1cdef202009-05-22 12:06:27 -07004916 ACCenum getError() {
4917 ACCenum result = accError;
4918 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004919 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004920 }
4921
Jack Palevich1cdef202009-05-22 12:06:27 -07004922 Compiler compiler;
4923 char* text;
4924 int textLength;
4925 ACCenum accError;
4926};
4927
4928
4929extern "C"
4930ACCscript* accCreateScript() {
4931 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004932}
Jack Palevich1cdef202009-05-22 12:06:27 -07004933
4934extern "C"
4935ACCenum accGetError( ACCscript* script ) {
4936 return script->getError();
4937}
4938
4939extern "C"
4940void accDeleteScript(ACCscript* script) {
4941 delete script;
4942}
4943
4944extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004945void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4946 ACCvoid* pContext) {
4947 script->registerSymbolCallback(pFn, pContext);
4948}
4949
4950extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004951void accScriptSource(ACCscript* script,
4952 ACCsizei count,
4953 const ACCchar ** string,
4954 const ACCint * length) {
4955 int totalLength = 0;
4956 for(int i = 0; i < count; i++) {
4957 int len = -1;
4958 const ACCchar* s = string[i];
4959 if (length) {
4960 len = length[i];
4961 }
4962 if (len < 0) {
4963 len = strlen(s);
4964 }
4965 totalLength += len;
4966 }
4967 delete script->text;
4968 char* text = new char[totalLength + 1];
4969 script->text = text;
4970 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004971 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004972 for(int i = 0; i < count; i++) {
4973 int len = -1;
4974 const ACCchar* s = string[i];
4975 if (length) {
4976 len = length[i];
4977 }
4978 if (len < 0) {
4979 len = strlen(s);
4980 }
Jack Palevich09555c72009-05-27 12:25:55 -07004981 memcpy(dest, s, len);
4982 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004983 }
4984 text[totalLength] = '\0';
4985}
4986
4987extern "C"
4988void accCompileScript(ACCscript* script) {
4989 int result = script->compiler.compile(script->text, script->textLength);
4990 if (result) {
4991 script->setError(ACC_INVALID_OPERATION);
4992 }
4993}
4994
4995extern "C"
4996void accGetScriptiv(ACCscript* script,
4997 ACCenum pname,
4998 ACCint * params) {
4999 switch (pname) {
5000 case ACC_INFO_LOG_LENGTH:
5001 *params = 0;
5002 break;
5003 }
5004}
5005
5006extern "C"
5007void accGetScriptInfoLog(ACCscript* script,
5008 ACCsizei maxLength,
5009 ACCsizei * length,
5010 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005011 char* message = script->compiler.getErrorMessage();
5012 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005013 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005014 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005015 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005016 if (infoLog && maxLength > 0) {
5017 int trimmedLength = maxLength < messageLength ?
5018 maxLength : messageLength;
5019 memcpy(infoLog, message, trimmedLength);
5020 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005021 }
5022}
5023
5024extern "C"
5025void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5026 ACCvoid ** address) {
5027 void* value = script->compiler.lookup(name);
5028 if (value) {
5029 *address = value;
5030 } else {
5031 script->setError(ACC_INVALID_VALUE);
5032 }
5033}
5034
Jack Palevicheedf9d22009-06-04 16:23:40 -07005035extern "C"
5036void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5037 ACCsizei maxStringCount, ACCchar** strings){
5038 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5039}
5040
-b master422972c2009-06-17 19:13:52 -07005041extern "C"
5042void accDisassemble(ACCscript* script) {
5043 script->compiler.disassemble(stderr);
5044}
5045
Jack Palevicheedf9d22009-06-04 16:23:40 -07005046
Jack Palevich1cdef202009-05-22 12:06:27 -07005047} // namespace acc
5048