blob: 219a436909da101982790108474ad67ad40ff4d7 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
12#include <dlfcn.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000013#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070019#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070020
Jack Palevich8dc662e2009-06-09 22:53:47 +000021#if defined(__i386__)
22#include <sys/mman.h>
23#endif
24
Jack Palevich546b2242009-05-13 15:10:04 -070025#if defined(__arm__)
26#include <unistd.h>
27#endif
28
Jack Paleviche7b59062009-05-19 17:12:17 -070029#if defined(__arm__)
30#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#elif defined(__i386__)
33#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__x86_64__)
36#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
39
Jack Paleviche7b59062009-05-19 17:12:17 -070040#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070041#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070042#endif
Jack Palevicha6535612009-05-13 16:24:17 -070043
Jack Palevich1cdef202009-05-22 12:06:27 -070044#include <acc/acc.h>
45
Jack Palevich09555c72009-05-27 12:25:55 -070046#define LOG_API(...) do {} while(0)
47// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070048
-b master422972c2009-06-17 19:13:52 -070049#define LOG_STACK(...) do {} while(0)
50// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
51
52// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070053// #define PROVIDE_TRACE_CODEGEN
54
Jack Palevichbbf8ab52009-05-11 11:54:30 -070055namespace acc {
56
Jack Palevich8df46192009-07-07 14:48:51 -070057// Subset of STL vector.
58template<class E> class Vector {
59 public:
60 Vector() {
61 mpBase = 0;
62 mUsed = 0;
63 mSize = 0;
64 }
65
66 ~Vector() {
67 if (mpBase) {
68 for(size_t i = 0; i < mUsed; i++) {
69 mpBase[mUsed].~E();
70 }
71 free(mpBase);
72 }
73 }
74
75 inline E& operator[](size_t i) {
76 return mpBase[i];
77 }
78
79 inline E& front() {
80 return mpBase[0];
81 }
82
83 inline E& back() {
84 return mpBase[mUsed - 1];
85 }
86
87 void pop_back() {
88 mUsed -= 1;
89 mpBase[mUsed].~E();
90 }
91
92 void push_back(const E& item) {
93 * ensure(1) = item;
94 }
95
96 size_t size() {
97 return mUsed;
98 }
99
100private:
101 E* ensure(int n) {
102 size_t newUsed = mUsed + n;
103 if (newUsed > mSize) {
104 size_t newSize = mSize * 2 + 10;
105 if (newSize < newUsed) {
106 newSize = newUsed;
107 }
108 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
109 mSize = newSize;
110 }
111 E* result = mpBase + mUsed;
112 mUsed = newUsed;
113 return result;
114 }
115
116 E* mpBase;
117 size_t mUsed;
118 size_t mSize;
119};
120
Jack Palevichac0e95e2009-05-29 13:53:44 -0700121class ErrorSink {
122public:
123 void error(const char *fmt, ...) {
124 va_list ap;
125 va_start(ap, fmt);
126 verror(fmt, ap);
127 va_end(ap);
128 }
129
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700130 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700131 virtual void verror(const char* fmt, va_list ap) = 0;
132};
133
134class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700135 typedef int tokenid_t;
136 enum TypeTag {
137 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
138 TY_POINTER, TY_FUNC, TY_PARAM
139 };
140
141 struct Type {
142 TypeTag tag;
143 tokenid_t id; // For function arguments
144 Type* pHead;
145 Type* pTail;
146 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700147
Jack Palevich21a15a22009-05-11 14:49:29 -0700148 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700149 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700150 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700151 ErrorSink* mErrorSink;
152 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700153 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700154
Jack Palevich21a15a22009-05-11 14:49:29 -0700155 void release() {
156 if (pProgramBase != 0) {
157 free(pProgramBase);
158 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700159 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700160 }
161
Jack Palevich0a280a02009-06-11 10:53:51 -0700162 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700163 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700164 bool overflow = newSize > mSize;
165 if (overflow && !mOverflowed) {
166 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700167 if (mErrorSink) {
168 mErrorSink->error("Code too large: %d bytes", newSize);
169 }
170 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700171 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700172 }
173
Jack Palevich21a15a22009-05-11 14:49:29 -0700174 public:
175 CodeBuf() {
176 pProgramBase = 0;
177 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700178 mErrorSink = 0;
179 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700180 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700181 }
182
183 ~CodeBuf() {
184 release();
185 }
186
187 void init(int size) {
188 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700190 pProgramBase = (char*) calloc(1, size);
191 ind = pProgramBase;
192 }
193
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 void setErrorSink(ErrorSink* pErrorSink) {
195 mErrorSink = pErrorSink;
196 }
197
Jack Palevich546b2242009-05-13 15:10:04 -0700198 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700199 if(check(4)) {
200 return 0;
201 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700202 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700203 * (int*) ind = n;
204 ind += 4;
205 return result;
206 }
207
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 /*
209 * Output a byte. Handles all values, 0..ff.
210 */
211 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(1)) {
213 return;
214 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 *ind++ = n;
216 }
217
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 inline void* getBase() {
219 return (void*) pProgramBase;
220 }
221
Jack Palevich8b0624c2009-05-20 12:12:06 -0700222 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 return ind - pProgramBase;
224 }
225
Jack Palevich8b0624c2009-05-20 12:12:06 -0700226 intptr_t getPC() {
227 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 }
229 };
230
Jack Palevich1cdef202009-05-22 12:06:27 -0700231 /**
232 * A code generator creates an in-memory program, generating the code on
233 * the fly. There is one code generator implementation for each supported
234 * architecture.
235 *
236 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700237 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 * FP - a frame pointer for accessing function arguments and local
239 * variables.
240 * SP - a stack pointer for storing intermediate results while evaluating
241 * expressions. The stack pointer grows downwards.
242 *
243 * The function calling convention is that all arguments are placed on the
244 * stack such that the first argument has the lowest address.
245 * After the call, the result is in R0. The caller is responsible for
246 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700247 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700248 * FP and SP registers are saved.
249 */
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 class CodeGenerator {
252 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700253 CodeGenerator() {
254 mErrorSink = 0;
255 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700256 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700257 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 virtual ~CodeGenerator() {}
259
Jack Palevich22305132009-05-13 10:58:45 -0700260 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700262 pCodeBuf->setErrorSink(mErrorSink);
263 }
264
Jack Palevichb67b18f2009-06-11 21:12:23 -0700265 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 mErrorSink = pErrorSink;
267 if (pCodeBuf) {
268 pCodeBuf->setErrorSink(mErrorSink);
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 }
271
Jack Palevich1cdef202009-05-22 12:06:27 -0700272 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700273 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700274 * Save the old value of the FP.
275 * Set the new value of the FP.
276 * Convert from the native platform calling convention to
277 * our stack-based calling convention. This may require
278 * pushing arguments from registers to the stack.
279 * Allocate "N" bytes of stack space. N isn't known yet, so
280 * just emit the instructions for adjusting the stack, and return
281 * the address to patch up. The patching will be done in
282 * functionExit().
283 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700284 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700285 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700286
Jack Palevich1cdef202009-05-22 12:06:27 -0700287 /* Emit a function epilog.
288 * Restore the old SP and FP register values.
289 * Return to the calling function.
290 * argCount - the number of arguments to the function.
291 * localVariableAddress - returned from functionEntry()
292 * localVariableSize - the size in bytes of the local variables.
293 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700294 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700295 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700298 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700299
Jack Palevich1a539db2009-07-08 13:04:41 -0700300 /* Load floating point value from global address. */
301 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Jump to a target, and return the address of the word that
304 * holds the target data, in case it needs to be fixed up later.
305 */
Jack Palevich22305132009-05-13 10:58:45 -0700306 virtual int gjmp(int t) = 0;
307
Jack Palevich1cdef202009-05-22 12:06:27 -0700308 /* Test R0 and jump to a target if the test succeeds.
309 * l = 0: je, l == 1: jne
310 * Return the address of the word that holds the targed data, in
311 * case it needs to be fixed up later.
312 */
Jack Palevich22305132009-05-13 10:58:45 -0700313 virtual int gtst(bool l, int t) = 0;
314
Jack Palevich9eed7a22009-07-06 17:24:34 -0700315 /* Compare TOS against R0, and store the boolean result in R0.
316 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 * op specifies the comparison.
318 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700319 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700320
Jack Palevich9eed7a22009-07-06 17:24:34 -0700321 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700322 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700323 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 */
Jack Palevich546b2242009-05-13 15:10:04 -0700325 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700326
Jack Palevich9eed7a22009-07-06 17:24:34 -0700327 /* Compare 0 against R0, and store the boolean result in R0.
328 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700330 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700331
332 /* Perform the arithmetic op specified by op. 0 is the
333 * left argument, R0 is the right argument.
334 */
335 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700336
Jack Palevich1cdef202009-05-22 12:06:27 -0700337 /* Push R0 onto the stack.
338 */
339 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700340
Jack Palevich9eed7a22009-07-06 17:24:34 -0700341 /* Store R0 to the address stored in TOS.
342 * The TOS is popped.
343 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700346
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700350 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700351
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 /* Load the absolute address of a variable to R0.
353 * If ea <= LOCAL, then this is a local variable, or an
354 * argument, addressed relative to FP.
355 * else it is an absolute global address.
356 */
Jack Palevich8df46192009-07-07 14:48:51 -0700357 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevich1cdef202009-05-22 12:06:27 -0700359 /* Store R0 to a variable.
360 * If ea <= LOCAL, then this is a local variable, or an
361 * argument, addressed relative to FP.
362 * else it is an absolute global address.
363 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700364 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700365
Jack Palevich1cdef202009-05-22 12:06:27 -0700366 /* load R0 from a variable.
367 * If ea <= LOCAL, then this is a local variable, or an
368 * argument, addressed relative to FP.
369 * else it is an absolute global address.
370 * If isIncDec is true, then the stored variable's value
371 * should be post-incremented or post-decremented, based
372 * on the value of op.
373 */
Jack Palevich8df46192009-07-07 14:48:51 -0700374 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
375
376 /**
377 * Convert R0 to the given type.
378 */
379 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700380
Jack Palevich1cdef202009-05-22 12:06:27 -0700381 /* Emit code to adjust the stack for a function call. Return the
382 * label for the address of the instruction that adjusts the
383 * stack size. This will be passed as argument "a" to
384 * endFunctionCallArguments.
385 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700386 virtual int beginFunctionCallArguments() = 0;
387
Jack Palevich1cdef202009-05-22 12:06:27 -0700388 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700389 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700391 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700392
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 /* Patch the function call preamble.
394 * a is the address returned from beginFunctionCallArguments
395 * l is the number of bytes the arguments took on the stack.
396 * Typically you would also emit code to convert the argument
397 * list into whatever the native function calling convention is.
398 * On ARM for example you would pop the first 5 arguments into
399 * R0..R4
400 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700401 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700402
Jack Palevich1cdef202009-05-22 12:06:27 -0700403 /* Emit a call to an unknown function. The argument "symbol" needs to
404 * be stored in the location where the address should go. It forms
405 * a chain. The address will be patched later.
406 * Return the address of the word that has to be patched.
407 */
Jack Palevich8df46192009-07-07 14:48:51 -0700408 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Call a function using PC-relative addressing. t is the PC-relative
411 * address of the function. It has already been adjusted for the
412 * architectural jump offset, so just store it as-is.
413 */
Jack Palevich8df46192009-07-07 14:48:51 -0700414 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700415
Jack Palevich1cdef202009-05-22 12:06:27 -0700416 /* Call a function pointer. L is the number of bytes the arguments
417 * take on the stack. The address of the function is stored at
418 * location SP + l.
419 */
Jack Palevich8df46192009-07-07 14:48:51 -0700420 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700421
Jack Palevich1cdef202009-05-22 12:06:27 -0700422 /* Adjust SP after returning from a function call. l is the
423 * number of bytes of arguments stored on the stack. isIndirect
424 * is true if this was an indirect call. (In which case the
425 * address of the function is stored at location SP + l.)
426 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700427 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700428
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 /* Print a disassembly of the assembled code to out. Return
430 * non-zero if there is an error.
431 */
Jack Palevicha6535612009-05-13 16:24:17 -0700432 virtual int disassemble(FILE* out) = 0;
433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Generate a symbol at the current PC. t is the head of a
435 * linked list of addresses to patch.
436 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700437 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700438
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 /*
440 * Do any cleanup work required at the end of a compile.
441 * For example, an instruction cache might need to be
442 * invalidated.
443 * Return non-zero if there is an error.
444 */
445 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700446
Jack Palevicha6535612009-05-13 16:24:17 -0700447 /**
448 * Adjust relative branches by this amount.
449 */
450 virtual int jumpOffset() = 0;
451
Jack Palevich9eed7a22009-07-06 17:24:34 -0700452 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700453 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700454 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700455 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700456
457 /**
458 * Array element alignment (in bytes) for this type of data.
459 */
460 virtual size_t sizeOf(Type* type) = 0;
461
Jack Palevich9cbd2262009-07-08 16:48:41 -0700462 /**
463 * Stack argument size of this data type.
464 */
465 virtual size_t stackSizeOf(Type* pType) = 0;
466
Jack Palevich1a539db2009-07-08 13:04:41 -0700467 virtual Type* getR0Type() {
468 return mExpressionStack.back();
469 }
470
Jack Palevich21a15a22009-05-11 14:49:29 -0700471 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700472 /*
473 * Output a byte. Handles all values, 0..ff.
474 */
475 void ob(int n) {
476 pCodeBuf->ob(n);
477 }
478
Jack Palevich8b0624c2009-05-20 12:12:06 -0700479 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700480 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700481 }
482
Jack Palevich8b0624c2009-05-20 12:12:06 -0700483 intptr_t getBase() {
484 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700485 }
486
Jack Palevich8b0624c2009-05-20 12:12:06 -0700487 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700488 return pCodeBuf->getPC();
489 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700490
491 intptr_t getSize() {
492 return pCodeBuf->getSize();
493 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700494
495 void error(const char* fmt,...) {
496 va_list ap;
497 va_start(ap, fmt);
498 mErrorSink->verror(fmt, ap);
499 va_end(ap);
500 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700501
502 void assert(bool test) {
503 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700504 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505 error("code generator assertion failed.");
506 }
507 }
Jack Palevich8df46192009-07-07 14:48:51 -0700508
509 void setR0Type(Type* pType) {
510 mExpressionStack.back() = pType;
511 }
512
Jack Palevich8df46192009-07-07 14:48:51 -0700513 Type* getTOSType() {
514 return mExpressionStack[mExpressionStack.size()-2];
515 }
516
517 void pushType() {
518 mExpressionStack.push_back(NULL);
519 }
520
521 void popType() {
522 mExpressionStack.pop_back();
523 }
524
525 bool bitsSame(Type* pA, Type* pB) {
526 return collapseType(pA->tag) == collapseType(pB->tag);
527 }
528
529 TypeTag collapseType(TypeTag tag) {
530 static const TypeTag collapsedTag[] = {
531 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
532 TY_VOID, TY_VOID};
533 return collapsedTag[tag];
534 }
535
Jack Palevich1a539db2009-07-08 13:04:41 -0700536 TypeTag collapseTypeR0() {
537 return collapseType(getR0Type()->tag);
538 }
539
540 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700541 return isFloatTag(pType->tag);
542 }
543
544 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700545 return tag == TY_FLOAT || tag == TY_DOUBLE;
546 }
547
Jack Palevich21a15a22009-05-11 14:49:29 -0700548 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700549 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700550 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700551 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700552 };
553
Jack Paleviche7b59062009-05-19 17:12:17 -0700554#ifdef PROVIDE_ARM_CODEGEN
555
Jack Palevich22305132009-05-13 10:58:45 -0700556 class ARMCodeGenerator : public CodeGenerator {
557 public:
558 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700559
Jack Palevich22305132009-05-13 10:58:45 -0700560 virtual ~ARMCodeGenerator() {}
561
562 /* returns address to patch with local variable size
563 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700564 virtual int functionEntry(Type* pDecl) {
565 LOG_API("functionEntry(%d);\n", pDecl);
-b master422972c2009-06-17 19:13:52 -0700566 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700567 // sp -> arg4 arg5 ...
568 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700569 int regArgCount = calcRegArgCount(pDecl);
570 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700571 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700572 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700573 }
574 // sp -> arg0 arg1 ...
575 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700576 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700577 // sp, fp -> oldfp, retadr, arg0 arg1 ....
578 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700579 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700580 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700581 // We don't know how many local variables we are going to use,
582 // but we will round the allocation up to a multiple of
583 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700584 }
585
Jack Palevichb7718b92009-07-09 22:00:24 -0700586 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700587 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700588 // Round local variable size up to a multiple of stack alignment
589 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
590 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700591 // Patch local variable allocation code:
592 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700593 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700594 }
Jack Palevich69796b62009-05-14 15:42:26 -0700595 *(char*) (localVariableAddress) = localVariableSize;
596
597 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
598 o4(0xE1A0E00B); // mov lr, fp
599 o4(0xE59BB000); // ldr fp, [fp]
600 o4(0xE28ED004); // add sp, lr, #4
601 // sp -> retadr, arg0, ...
602 o4(0xE8BD4000); // ldmfd sp!, {lr}
603 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700604
605 // We store the PC into the lr so we can adjust the sp before
606 // returning. We need to pull off the registers we pushed
607 // earlier. We don't need to actually store them anywhere,
608 // just adjust the stack.
609 int regArgCount = calcRegArgCount(pDecl);
610 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700611 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
612 }
613 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700614 }
615
616 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700617 virtual void li(int t, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700618 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700619 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700620 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700621 } else if (t >= -256 && t < 0) {
622 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700623 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700624 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700625 o4(0xE51F0000); // ldr r0, .L3
626 o4(0xEA000000); // b .L99
627 o4(t); // .L3: .word 0
628 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700629 }
Jack Palevich8df46192009-07-07 14:48:51 -0700630 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700631 }
632
Jack Palevich1a539db2009-07-08 13:04:41 -0700633 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700634 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700635 // Global, absolute address
636 o4(0xE59F0000); // ldr r0, .L1
637 o4(0xEA000000); // b .L99
638 o4(address); // .L1: .word ea
639 // .L99:
640
641 switch (pType->tag) {
642 case TY_FLOAT:
643 o4(0xE5900000); // ldr r0, [r0]
644 break;
645 case TY_DOUBLE:
646 o4(0xE1C000D0); // ldrd r0, [r0]
647 break;
648 default:
649 assert(false);
650 break;
651 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700652 }
653
Jack Palevich22305132009-05-13 10:58:45 -0700654 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700655 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700656 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700657 }
658
659 /* l = 0: je, l == 1: jne */
660 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700661 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevichb7718b92009-07-09 22:00:24 -0700662 Type* pR0Type = getR0Type();
663 TypeTag tagR0 = pR0Type->tag;
664 switch(tagR0) {
665 case TY_FLOAT:
666 callRuntime((void*) runtime_is_non_zero_f);
667 break;
668 case TY_DOUBLE:
669 callRuntime((void*) runtime_is_non_zero_d);
670 break;
671 default:
672 break;
673 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700674 o4(0xE3500000); // cmp r0,#0
675 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
676 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700677 }
678
Jack Palevicha39749f2009-07-08 20:40:31 -0700679 virtual void gcmp(int op, Type* pResultType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700680 LOG_API("gcmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700681 Type* pR0Type = getR0Type();
682 Type* pTOSType = getTOSType();
683 TypeTag tagR0 = collapseType(pR0Type->tag);
684 TypeTag tagTOS = collapseType(pTOSType->tag);
685 if (tagR0 == TY_INT && tagTOS == TY_INT) {
686 o4(0xE8BD0002); // ldmfd sp!,{r1}
687 mStackUse -= 4;
688 o4(0xE1510000); // cmp r1, r1
689 switch(op) {
690 case OP_EQUALS:
691 o4(0x03A00001); // moveq r0,#1
692 o4(0x13A00000); // movne r0,#0
693 break;
694 case OP_NOT_EQUALS:
695 o4(0x03A00000); // moveq r0,#0
696 o4(0x13A00001); // movne r0,#1
697 break;
698 case OP_LESS_EQUAL:
699 o4(0xD3A00001); // movle r0,#1
700 o4(0xC3A00000); // movgt r0,#0
701 break;
702 case OP_GREATER:
703 o4(0xD3A00000); // movle r0,#0
704 o4(0xC3A00001); // movgt r0,#1
705 break;
706 case OP_GREATER_EQUAL:
707 o4(0xA3A00001); // movge r0,#1
708 o4(0xB3A00000); // movlt r0,#0
709 break;
710 case OP_LESS:
711 o4(0xA3A00000); // movge r0,#0
712 o4(0xB3A00001); // movlt r0,#1
713 break;
714 default:
715 error("Unknown comparison op %d", op);
716 break;
717 }
718 popType();
719 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
720 setupDoubleArgs();
721 switch(op) {
722 case OP_EQUALS:
723 callRuntime((void*) runtime_cmp_eq_dd);
724 break;
725 case OP_NOT_EQUALS:
726 callRuntime((void*) runtime_cmp_ne_dd);
727 break;
728 case OP_LESS_EQUAL:
729 callRuntime((void*) runtime_cmp_le_dd);
730 break;
731 case OP_GREATER:
732 callRuntime((void*) runtime_cmp_gt_dd);
733 break;
734 case OP_GREATER_EQUAL:
735 callRuntime((void*) runtime_cmp_ge_dd);
736 break;
737 case OP_LESS:
738 callRuntime((void*) runtime_cmp_lt_dd);
739 break;
740 default:
741 error("Unknown comparison op %d", op);
742 break;
743 }
744 } else {
745 setupFloatArgs();
746 switch(op) {
747 case OP_EQUALS:
748 callRuntime((void*) runtime_cmp_eq_ff);
749 break;
750 case OP_NOT_EQUALS:
751 callRuntime((void*) runtime_cmp_ne_ff);
752 break;
753 case OP_LESS_EQUAL:
754 callRuntime((void*) runtime_cmp_le_ff);
755 break;
756 case OP_GREATER:
757 callRuntime((void*) runtime_cmp_gt_ff);
758 break;
759 case OP_GREATER_EQUAL:
760 callRuntime((void*) runtime_cmp_ge_ff);
761 break;
762 case OP_LESS:
763 callRuntime((void*) runtime_cmp_lt_ff);
764 break;
765 default:
766 error("Unknown comparison op %d", op);
767 break;
768 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700769 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700770 setR0Type(pResultType);
Jack Palevich22305132009-05-13 10:58:45 -0700771 }
772
Jack Palevich546b2242009-05-13 15:10:04 -0700773 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700774 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700775 Type* pR0Type = getR0Type();
776 Type* pTOSType = getTOSType();
777 TypeTag tagR0 = collapseType(pR0Type->tag);
778 TypeTag tagTOS = collapseType(pTOSType->tag);
779 if (tagR0 == TY_INT && tagTOS == TY_INT) {
780 o4(0xE8BD0002); // ldmfd sp!,{r1}
781 mStackUse -= 4;
782 switch(op) {
783 case OP_MUL:
784 o4(0x0E0000091); // mul r0,r1,r0
785 break;
786 case OP_DIV:
787 callRuntime((void*) runtime_DIV);
788 break;
789 case OP_MOD:
790 callRuntime((void*) runtime_MOD);
791 break;
792 case OP_PLUS:
793 o4(0xE0810000); // add r0,r1,r0
794 break;
795 case OP_MINUS:
796 o4(0xE0410000); // sub r0,r1,r0
797 break;
798 case OP_SHIFT_LEFT:
799 o4(0xE1A00011); // lsl r0,r1,r0
800 break;
801 case OP_SHIFT_RIGHT:
802 o4(0xE1A00051); // asr r0,r1,r0
803 break;
804 case OP_BIT_AND:
805 o4(0xE0010000); // and r0,r1,r0
806 break;
807 case OP_BIT_XOR:
808 o4(0xE0210000); // eor r0,r1,r0
809 break;
810 case OP_BIT_OR:
811 o4(0xE1810000); // orr r0,r1,r0
812 break;
813 case OP_BIT_NOT:
814 o4(0xE1E00000); // mvn r0, r0
815 break;
816 default:
817 error("Unimplemented op %d\n", op);
818 break;
819 }
820 popType();
821 } else {
822 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
823 if (pResultType->tag == TY_DOUBLE) {
824 setupDoubleArgs();
825 switch(op) {
826 case OP_MUL:
827 callRuntime((void*) runtime_op_mul_dd);
828 break;
829 case OP_DIV:
830 callRuntime((void*) runtime_op_div_dd);
831 break;
832 case OP_PLUS:
833 callRuntime((void*) runtime_op_add_dd);
834 break;
835 case OP_MINUS:
836 callRuntime((void*) runtime_op_sub_dd);
837 break;
838 default:
839 error("Unsupported binary floating operation %d\n", op);
840 break;
841 }
842 } else {
843 setupFloatArgs();
844 switch(op) {
845 case OP_MUL:
846 callRuntime((void*) runtime_op_mul_ff);
847 break;
848 case OP_DIV:
849 callRuntime((void*) runtime_op_div_ff);
850 break;
851 case OP_PLUS:
852 callRuntime((void*) runtime_op_add_ff);
853 break;
854 case OP_MINUS:
855 callRuntime((void*) runtime_op_sub_ff);
856 break;
857 default:
858 error("Unsupported binary floating operation %d\n", op);
859 break;
860 }
861 }
862 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700863 }
Jack Palevich22305132009-05-13 10:58:45 -0700864 }
865
Jack Palevicha39749f2009-07-08 20:40:31 -0700866 virtual void gUnaryCmp(int op, Type* pResultType) {
867 LOG_API("gUnaryCmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700868 if (op != OP_LOGICAL_NOT) {
869 error("Unknown unary cmp %d", op);
870 } else {
871 Type* pR0Type = getR0Type();
872 TypeTag tag = collapseType(pR0Type->tag);
873 switch(tag) {
874 case TY_INT:
875 o4(0xE3A01000); // mov r1, #0
876 o4(0xE1510000); // cmp r1, r1
877 o4(0x03A00000); // moveq r0,#0
878 o4(0x13A00001); // movne r0,#1
879 break;
880 case TY_FLOAT:
881 callRuntime((void*) runtime_is_zero_f);
882 break;
883 case TY_DOUBLE:
884 callRuntime((void*) runtime_is_zero_d);
885 break;
886 default:
887 error("gUnaryCmp unsupported type");
888 break;
889 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700890 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700891 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700892 }
893
894 virtual void genUnaryOp(int op) {
895 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700896 Type* pR0Type = getR0Type();
897 TypeTag tag = collapseType(pR0Type->tag);
898 switch(tag) {
899 case TY_INT:
900 switch(op) {
901 case OP_MINUS:
902 o4(0xE3A01000); // mov r1, #0
903 o4(0xE0410000); // sub r0,r1,r0
904 break;
905 case OP_BIT_NOT:
906 o4(0xE1E00000); // mvn r0, r0
907 break;
908 default:
909 error("Unknown unary op %d\n", op);
910 break;
911 }
912 break;
913 case TY_FLOAT:
914 case TY_DOUBLE:
915 switch (op) {
916 case OP_MINUS:
917 if (tag == TY_FLOAT) {
918 callRuntime((void*) runtime_op_neg_f);
919 } else {
920 callRuntime((void*) runtime_op_neg_d);
921 }
922 break;
923 case OP_BIT_NOT:
924 error("Can't apply '~' operator to a float or double.");
925 break;
926 default:
927 error("Unknown unary op %d\n", op);
928 break;
929 }
930 break;
931 default:
932 error("genUnaryOp unsupported type");
933 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700934 }
Jack Palevich22305132009-05-13 10:58:45 -0700935 }
936
Jack Palevich1cdef202009-05-22 12:06:27 -0700937 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700938 LOG_API("pushR0();\n");
Jack Palevichb7718b92009-07-09 22:00:24 -0700939 Type* pR0Type = getR0Type();
940 TypeTag r0ct = collapseType(pR0Type->tag);
941 if (r0ct != TY_DOUBLE) {
942 o4(0xE92D0001); // stmfd sp!,{r0}
943 mStackUse += 4;
944 } else {
945 o4(0xE92D0003); // stmfd sp!,{r0,r1}
946 mStackUse += 8;
947 }
Jack Palevich8df46192009-07-07 14:48:51 -0700948 pushType();
-b master422972c2009-06-17 19:13:52 -0700949 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700950 }
951
Jack Palevich9eed7a22009-07-06 17:24:34 -0700952 virtual void storeR0ToTOS(Type* pPointerType) {
953 LOG_API("storeR0ToTOS(%d);\n", isInt);
954 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -0700955 o4(0xE8BD0004); // ldmfd sp!,{r2}
956 popType();
-b master422972c2009-06-17 19:13:52 -0700957 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700958 switch (pPointerType->pHead->tag) {
959 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -0700960 case TY_FLOAT:
961 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -0700962 break;
963 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -0700964 o4(0xE5C20000); // strb r0, [r2]
965 break;
966 case TY_DOUBLE:
967 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -0700968 break;
969 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700970 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700971 break;
Jack Palevichbd894902009-05-14 19:35:31 -0700972 }
Jack Palevich22305132009-05-13 10:58:45 -0700973 }
974
Jack Palevich9eed7a22009-07-06 17:24:34 -0700975 virtual void loadR0FromR0(Type* pPointerType) {
976 LOG_API("loadR0FromR0(%d);\n", pPointerType);
977 assert(pPointerType->tag == TY_POINTER);
978 switch (pPointerType->pHead->tag) {
979 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -0700980 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700981 o4(0xE5900000); // ldr r0, [r0]
982 break;
983 case TY_CHAR:
984 o4(0xE5D00000); // ldrb r0, [r0]
985 break;
Jack Palevichb7718b92009-07-09 22:00:24 -0700986 case TY_DOUBLE:
987 o4(0xE1C000D0); // ldrd r0, [r0]
988 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700989 default:
Jack Palevich8df46192009-07-07 14:48:51 -0700990 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -0700991 break;
992 }
Jack Palevich8df46192009-07-07 14:48:51 -0700993 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -0700994 }
995
Jack Palevich8df46192009-07-07 14:48:51 -0700996 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700997 LOG_API("leaR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -0700998 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -0700999 // Local, fp relative
1000 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1001 error("Offset out of range: %08x", ea);
1002 }
1003 if (ea < 0) {
1004 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1005 } else {
1006 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1007 }
Jack Palevichbd894902009-05-14 19:35:31 -07001008 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001009 // Global, absolute.
1010 o4(0xE59F0000); // ldr r0, .L1
1011 o4(0xEA000000); // b .L99
1012 o4(ea); // .L1: .word 0
1013 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001014 }
Jack Palevich8df46192009-07-07 14:48:51 -07001015 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001016 }
1017
Jack Palevich9cbd2262009-07-08 16:48:41 -07001018 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001019 LOG_API("storeR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001020 TypeTag tag = pType->tag;
1021 switch (tag) {
1022 case TY_INT:
1023 case TY_FLOAT:
1024 if (ea > -LOCAL && ea < LOCAL) {
1025 // Local, fp relative
1026 if (ea < -4095 || ea > 4095) {
1027 error("Offset out of range: %08x", ea);
1028 }
1029 if (ea < 0) {
1030 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1031 } else {
1032 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1033 }
1034 } else{
1035 // Global, absolute
1036 o4(0xE59F1000); // ldr r1, .L1
1037 o4(0xEA000000); // b .L99
1038 o4(ea); // .L1: .word 0
1039 o4(0xE5810000); // .L99: str r0, [r1]
1040 }
1041 break;
1042 case TY_DOUBLE:
1043 if ((ea & 0x7) != 0) {
1044 error("double address is not aligned: %d", ea);
1045 }
1046 if (ea > -LOCAL && ea < LOCAL) {
1047 // Local, fp relative
1048 if (ea < -4095 || ea > 4095) {
1049 error("Offset out of range: %08x", ea);
1050 }
1051 if (ea < 0) {
1052 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1053 o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4]
1054#if 0
1055 // strd doesn't seem to work. Is encoding wrong?
1056 } else if (ea < 0) {
1057 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1058 } else if (ea < 256) {
1059 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1060#endif
1061 } else {
1062 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1063 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1064 }
1065 } else{
1066 // Global, absolute
1067 o4(0xE59F2000); // ldr r2, .L1
1068 o4(0xEA000000); // b .L99
1069 o4(ea); // .L1: .word 0
1070 o4(0xE1C200F0); // .L99: strd r0, [r2]
1071 }
1072 break;
1073 default:
1074 error("Unable to store to type %d", tag);
1075 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001076 }
Jack Palevich22305132009-05-13 10:58:45 -07001077 }
1078
Jack Palevich8df46192009-07-07 14:48:51 -07001079 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001080 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001081 TypeTag tag = collapseType(pType->tag);
1082 switch (tag) {
1083 case TY_INT:
1084 case TY_FLOAT:
1085 if (ea < LOCAL) {
1086 // Local, fp relative
1087 if (ea < -4095 || ea > 4095) {
1088 error("Offset out of range: %08x", ea);
1089 }
1090 if (ea < 0) {
1091 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1092 } else {
1093 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1094 }
1095 } else {
1096 // Global, absolute
1097 o4(0xE59F2000); // ldr r2, .L1
1098 o4(0xEA000000); // b .L99
1099 o4(ea); // .L1: .word ea
1100 o4(0xE5920000); // .L99: ldr r0, [r2]
1101 }
Jack Palevich22305132009-05-13 10:58:45 -07001102
Jack Palevichb7718b92009-07-09 22:00:24 -07001103 if (isIncDec) {
1104 if (tag == TY_INT) {
1105 switch (op) {
1106 case OP_INCREMENT:
1107 o4(0xE2801001); // add r1, r0, #1
1108 break;
1109 case OP_DECREMENT:
1110 o4(0xE2401001); // sub r1, r0, #1
1111 break;
1112 default:
1113 error("unknown opcode: %d", op);
1114 }
1115 if (ea < LOCAL) {
1116 // Local, fp relative
1117 // Don't need range check, was already checked above
1118 if (ea < 0) {
1119 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1120 } else {
1121 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1122 }
1123 } else{
1124 // Global, absolute
1125 // r2 is already set up from before.
1126 o4(0xE5821000); // str r1, [r2]
1127 }
1128 }
1129 else {
1130 error("inc/dec not implemented for float.");
1131 }
1132 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001133 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001134 case TY_DOUBLE:
1135 if ((ea & 0x7) != 0) {
1136 error("double address is not aligned: %d", ea);
1137 }
1138 if (ea < LOCAL) {
1139 // Local, fp relative
1140 if (ea < -4095 || ea > 4095) {
1141 error("Offset out of range: %08x", ea);
1142 }
1143 if (ea < 0) {
1144 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1145 o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4]
1146 } else {
1147 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1148 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1149 }
1150 } else {
1151 // Global, absolute
1152 o4(0xE59F2000); // ldr r2, .L1
1153 o4(0xEA000000); // b .L99
1154 o4(ea); // .L1: .word ea
1155 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1156 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001157 break;
1158 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001159 error("Unable to load type %d", tag);
1160 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001161 }
Jack Palevich8df46192009-07-07 14:48:51 -07001162 setR0Type(pType);
1163 }
1164
1165 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001166 Type* pR0Type = getR0Type();
1167 if (bitsSame(pType, pR0Type)) {
1168 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001169 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001170 TypeTag r0Tag = collapseType(pR0Type->tag);
1171 TypeTag destTag = collapseType(pType->tag);
1172 if (r0Tag == TY_INT) {
1173 if (destTag == TY_FLOAT) {
1174 callRuntime((void*) runtime_int_to_float);
1175 } else {
1176 assert(destTag == TY_DOUBLE);
1177 callRuntime((void*) runtime_int_to_double);
1178 }
1179 } else if (r0Tag == TY_FLOAT) {
1180 if (destTag == TY_INT) {
1181 callRuntime((void*) runtime_float_to_int);
1182 } else {
1183 assert(destTag == TY_DOUBLE);
1184 callRuntime((void*) runtime_float_to_double);
1185 }
1186 } else {
1187 assert (r0Tag == TY_DOUBLE);
1188 if (destTag == TY_INT) {
1189 callRuntime((void*) runtime_double_to_int);
1190 } else {
1191 assert(destTag == TY_FLOAT);
1192 callRuntime((void*) runtime_double_to_float);
1193 }
1194 }
Jack Palevich8df46192009-07-07 14:48:51 -07001195 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001196 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001197 }
1198
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001199 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001200 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001201 return o4(0xE24DDF00); // Placeholder
1202 }
1203
Jack Palevich1a539db2009-07-08 13:04:41 -07001204 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001205 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevichb7718b92009-07-09 22:00:24 -07001206 Type* pR0Type = getR0Type();
1207 TypeTag r0ct = collapseType(pR0Type->tag);
1208 switch(r0ct) {
1209 case TY_INT:
1210 case TY_FLOAT:
1211 if (l < 0 || l > 4096-4) {
1212 error("l out of range for stack offset: 0x%08x", l);
1213 }
1214 o4(0xE58D0000 + l); // str r0, [sp, #l]
1215 return 4;
1216 case TY_DOUBLE: {
1217 // Align to 8 byte boundary
1218 int l2 = (l + 7) & ~7;
1219 if (l2 < 0 || l2 > 4096-8) {
1220 error("l out of range for stack offset: 0x%08x", l);
1221 }
1222 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1223 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1224 return (l2 - l) + 8;
1225 }
1226 default:
1227 assert(false);
1228 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001229 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001230 }
1231
Jack Palevichb7718b92009-07-09 22:00:24 -07001232 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001233 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001234 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001235 // Have to calculate register arg count from actual stack size,
1236 // in order to properly handle ... functions.
1237 int regArgCount = l >> 2;
1238 if (regArgCount > 4) {
1239 regArgCount = 4;
1240 }
1241 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001242 argumentStackUse -= regArgCount * 4;
1243 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1244 }
1245 mStackUse += argumentStackUse;
1246
1247 // Align stack.
1248 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1249 * STACK_ALIGNMENT);
1250 mStackAlignmentAdjustment = 0;
1251 if (missalignment > 0) {
1252 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1253 }
1254 l += mStackAlignmentAdjustment;
1255
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001256 if (l < 0 || l > 0x3FC) {
1257 error("L out of range for stack adjustment: 0x%08x", l);
1258 }
1259 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001260 mStackUse += mStackAlignmentAdjustment;
1261 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1262 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001263 }
1264
Jack Palevich8df46192009-07-07 14:48:51 -07001265 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001266 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001267 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001268 // Forward calls are always short (local)
1269 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001270 }
1271
Jack Palevich8df46192009-07-07 14:48:51 -07001272 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001273 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001274 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001275 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001276 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001277 if (t >= - (1 << 25) && t < (1 << 25)) {
1278 o4(0xEB000000 | encodeAddress(t));
1279 } else {
1280 // Long call.
1281 o4(0xE59FC000); // ldr r12, .L1
1282 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001283 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001284 o4(0xE08CC00F); // .L99: add r12,pc
1285 o4(0xE12FFF3C); // blx r12
1286 }
Jack Palevich22305132009-05-13 10:58:45 -07001287 }
1288
Jack Palevich8df46192009-07-07 14:48:51 -07001289 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001290 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001291 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001292 int argCount = l >> 2;
1293 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001294 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001295 if (adjustedL < 0 || adjustedL > 4096-4) {
1296 error("l out of range for stack offset: 0x%08x", l);
1297 }
1298 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1299 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001300 }
1301
Jack Palevichb7718b92009-07-09 22:00:24 -07001302 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001303 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001304 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001305 // Have to calculate register arg count from actual stack size,
1306 // in order to properly handle ... functions.
1307 int regArgCount = l >> 2;
1308 if (regArgCount > 4) {
1309 regArgCount = 4;
1310 }
1311 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001312 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1313 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001314 if (stackUse) {
1315 if (stackUse < 0 || stackUse > 255) {
1316 error("L out of range for stack adjustment: 0x%08x", l);
1317 }
1318 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001319 mStackUse -= stackUse * 4;
1320 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001321 }
Jack Palevich22305132009-05-13 10:58:45 -07001322 }
1323
Jack Palevicha6535612009-05-13 16:24:17 -07001324 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001325 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001326 }
1327
1328 /* output a symbol and patch all calls to it */
1329 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001330 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001331 int n;
1332 int base = getBase();
1333 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001334 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001335 while (t) {
1336 int data = * (int*) t;
1337 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1338 if (decodedOffset == 0) {
1339 n = 0;
1340 } else {
1341 n = base + decodedOffset; /* next value */
1342 }
1343 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1344 | encodeRelAddress(pc - t - 8);
1345 t = n;
1346 }
1347 }
1348
Jack Palevich1cdef202009-05-22 12:06:27 -07001349 virtual int finishCompile() {
1350#if defined(__arm__)
1351 const long base = long(getBase());
1352 const long curr = long(getPC());
1353 int err = cacheflush(base, curr, 0);
1354 return err;
1355#else
1356 return 0;
1357#endif
1358 }
1359
Jack Palevicha6535612009-05-13 16:24:17 -07001360 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001361#ifdef ENABLE_ARM_DISASSEMBLY
1362 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001363 disasm_interface_t di;
1364 di.di_readword = disassemble_readword;
1365 di.di_printaddr = disassemble_printaddr;
1366 di.di_printf = disassemble_printf;
1367
1368 int base = getBase();
1369 int pc = getPC();
1370 for(int i = base; i < pc; i += 4) {
1371 fprintf(out, "%08x: %08x ", i, *(int*) i);
1372 ::disasm(&di, i, 0);
1373 }
Jack Palevich09555c72009-05-27 12:25:55 -07001374#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001375 return 0;
1376 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001377
Jack Palevich9eed7a22009-07-06 17:24:34 -07001378 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001379 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001380 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001381 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001382 switch(pType->tag) {
1383 case TY_DOUBLE:
1384 return 8;
1385 default:
1386 return 4;
1387 }
1388 }
1389
1390 /**
1391 * Array element alignment (in bytes) for this type of data.
1392 */
1393 virtual size_t sizeOf(Type* pType){
1394 switch(pType->tag) {
1395 case TY_INT:
1396 return 4;
1397 case TY_CHAR:
1398 return 1;
1399 default:
1400 return 0;
1401 case TY_FLOAT:
1402 return 4;
1403 case TY_DOUBLE:
1404 return 8;
1405 case TY_POINTER:
1406 return 4;
1407 }
1408 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001409
1410 virtual size_t stackSizeOf(Type* pType) {
1411 switch(pType->tag) {
1412 case TY_DOUBLE:
1413 return 8;
1414 default:
1415 return 4;
1416 }
1417 }
1418
Jack Palevich22305132009-05-13 10:58:45 -07001419 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001420 static FILE* disasmOut;
1421
1422 static u_int
1423 disassemble_readword(u_int address)
1424 {
1425 return(*((u_int *)address));
1426 }
1427
1428 static void
1429 disassemble_printaddr(u_int address)
1430 {
1431 fprintf(disasmOut, "0x%08x", address);
1432 }
1433
1434 static void
1435 disassemble_printf(const char *fmt, ...) {
1436 va_list ap;
1437 va_start(ap, fmt);
1438 vfprintf(disasmOut, fmt, ap);
1439 va_end(ap);
1440 }
1441
1442 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1443
1444 /** Encode a relative address that might also be
1445 * a label.
1446 */
1447 int encodeAddress(int value) {
1448 int base = getBase();
1449 if (value >= base && value <= getPC() ) {
1450 // This is a label, encode it relative to the base.
1451 value = value - base;
1452 }
1453 return encodeRelAddress(value);
1454 }
1455
1456 int encodeRelAddress(int value) {
1457 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1458 }
Jack Palevich22305132009-05-13 10:58:45 -07001459
Jack Palevichb7718b92009-07-09 22:00:24 -07001460 int calcRegArgCount(Type* pDecl) {
1461 int reg = 0;
1462 Type* pArgs = pDecl->pTail;
1463 while (pArgs && reg < 4) {
1464 Type* pArg = pArgs->pHead;
1465 if ( pArg->tag == TY_DOUBLE) {
1466 int evenReg = (reg + 1) & ~1;
1467 if (evenReg >= 4) {
1468 break;
1469 }
1470 reg = evenReg + 2;
1471 } else {
1472 reg++;
1473 }
1474 pArgs = pArgs->pTail;
1475 }
1476 return reg;
1477 }
1478
1479 /* Pop TOS to R1
1480 * Make sure both R0 and TOS are floats. (Could be ints)
1481 * We know that at least one of R0 and TOS is already a float
1482 */
1483 void setupFloatArgs() {
1484 Type* pR0Type = getR0Type();
1485 Type* pTOSType = getTOSType();
1486 TypeTag tagR0 = collapseType(pR0Type->tag);
1487 TypeTag tagTOS = collapseType(pTOSType->tag);
1488 if (tagR0 != TY_FLOAT) {
1489 assert(tagR0 == TY_INT);
1490 callRuntime((void*) runtime_int_to_float);
1491 }
1492 if (tagTOS != TY_FLOAT) {
1493 assert(tagTOS == TY_INT);
1494 assert(tagR0 == TY_FLOAT);
1495 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1496 o4(0xE59D0004); // ldr r0, [sp, #4]
1497 callRuntime((void*) runtime_int_to_float);
1498 o4(0xE1A01000); // mov r1, r0
1499 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1500 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1501 } else {
1502 // Pop TOS
1503 o4(0xE8BD0002); // ldmfd sp!,{r1}
1504 }
1505 mStackUse -= 4;
1506 popType();
1507 }
1508
1509 /* Pop TOS into R2..R3
1510 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1511 * We know that at least one of R0 and TOS are already a double.
1512 */
1513
1514 void setupDoubleArgs() {
1515 Type* pR0Type = getR0Type();
1516 Type* pTOSType = getTOSType();
1517 TypeTag tagR0 = collapseType(pR0Type->tag);
1518 TypeTag tagTOS = collapseType(pTOSType->tag);
1519 if (tagR0 != TY_DOUBLE) {
1520 if (tagR0 == TY_INT) {
1521 callRuntime((void*) runtime_int_to_double);
1522 } else {
1523 assert(tagR0 == TY_FLOAT);
1524 callRuntime((void*) runtime_float_to_double);
1525 }
1526 }
1527 if (tagTOS != TY_DOUBLE) {
1528 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1529 o4(0xE59D0008); // ldr r0, [sp, #8]
1530 if (tagTOS == TY_INT) {
1531 callRuntime((void*) runtime_int_to_double);
1532 } else {
1533 assert(tagTOS == TY_FLOAT);
1534 callRuntime((void*) runtime_float_to_double);
1535 }
1536 o4(0xE1A02000); // mov r2, r0
1537 o4(0xE1A03001); // mov r3, r1
1538 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1539 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1540 mStackUse -= 4;
1541 } else {
1542 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1543 mStackUse -= 8;
1544 }
1545 popType();
1546 }
1547
1548 void callRuntime(void* fn) {
1549 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001550 o4(0xEA000000); // b .L99
1551 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001552 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001553 }
1554
Jack Palevichb7718b92009-07-09 22:00:24 -07001555 // Integer math:
1556
1557 static int runtime_DIV(int b, int a) {
1558 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001559 }
1560
Jack Palevichb7718b92009-07-09 22:00:24 -07001561 static int runtime_MOD(int b, int a) {
1562 return a % b;
1563 }
1564
1565 // Comparison to zero
1566
1567 static int runtime_is_non_zero_f(float a) {
1568 return a != 0;
1569 }
1570
1571 static int runtime_is_non_zero_d(double a) {
1572 return a != 0;
1573 }
1574
1575 // Comparison to zero
1576
1577 static int runtime_is_zero_f(float a) {
1578 return a == 0;
1579 }
1580
1581 static int runtime_is_zero_d(double a) {
1582 return a == 0;
1583 }
1584
1585 // Type conversion
1586
1587 static int runtime_float_to_int(float a) {
1588 return (int) a;
1589 }
1590
1591 static double runtime_float_to_double(float a) {
1592 return (double) a;
1593 }
1594
1595 static int runtime_double_to_int(double a) {
1596 return (int) a;
1597 }
1598
1599 static float runtime_double_to_float(double a) {
1600 return (float) a;
1601 }
1602
1603 static float runtime_int_to_float(int a) {
1604 return (float) a;
1605 }
1606
1607 static double runtime_int_to_double(int a) {
1608 return (double) a;
1609 }
1610
1611 // Comparisons float
1612
1613 static int runtime_cmp_eq_ff(float b, float a) {
1614 return a == b;
1615 }
1616
1617 static int runtime_cmp_ne_ff(float b, float a) {
1618 return a != b;
1619 }
1620
1621 static int runtime_cmp_lt_ff(float b, float a) {
1622 return a < b;
1623 }
1624
1625 static int runtime_cmp_le_ff(float b, float a) {
1626 return a <= b;
1627 }
1628
1629 static int runtime_cmp_ge_ff(float b, float a) {
1630 return a >= b;
1631 }
1632
1633 static int runtime_cmp_gt_ff(float b, float a) {
1634 return a > b;
1635 }
1636
1637 // Comparisons double
1638
1639 static int runtime_cmp_eq_dd(double b, double a) {
1640 return a == b;
1641 }
1642
1643 static int runtime_cmp_ne_dd(double b, double a) {
1644 return a != b;
1645 }
1646
1647 static int runtime_cmp_lt_dd(double b, double a) {
1648 return a < b;
1649 }
1650
1651 static int runtime_cmp_le_dd(double b, double a) {
1652 return a <= b;
1653 }
1654
1655 static int runtime_cmp_ge_dd(double b, double a) {
1656 return a >= b;
1657 }
1658
1659 static int runtime_cmp_gt_dd(double b, double a) {
1660 return a > b;
1661 }
1662
1663 // Math float
1664
1665 static float runtime_op_add_ff(float b, float a) {
1666 return a + b;
1667 }
1668
1669 static float runtime_op_sub_ff(float b, float a) {
1670 return a - b;
1671 }
1672
1673 static float runtime_op_mul_ff(float b, float a) {
1674 return a * b;
1675 }
1676
1677 static float runtime_op_div_ff(float b, float a) {
1678 return a / b;
1679 }
1680
1681 static float runtime_op_neg_f(float a) {
1682 return -a;
1683 }
1684
1685 // Math double
1686
1687 static double runtime_op_add_dd(double b, double a) {
1688 return a + b;
1689 }
1690
1691 static double runtime_op_sub_dd(double b, double a) {
1692 return a - b;
1693 }
1694
1695 static double runtime_op_mul_dd(double b, double a) {
1696 return a * b;
1697 }
1698
1699 static double runtime_op_div_dd(double b, double a) {
1700 return a / b;
1701 }
1702
1703 static double runtime_op_neg_d(double a) {
1704 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001705 }
-b master422972c2009-06-17 19:13:52 -07001706
1707 static const int STACK_ALIGNMENT = 8;
1708 int mStackUse;
1709 // This variable holds the amount we adjusted the stack in the most
1710 // recent endFunctionCallArguments call. It's examined by the
1711 // following adjustStackAfterCall call.
1712 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001713 };
1714
Jack Palevich09555c72009-05-27 12:25:55 -07001715#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001716
1717#ifdef PROVIDE_X86_CODEGEN
1718
Jack Palevich21a15a22009-05-11 14:49:29 -07001719 class X86CodeGenerator : public CodeGenerator {
1720 public:
1721 X86CodeGenerator() {}
1722 virtual ~X86CodeGenerator() {}
1723
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001724 /* returns address to patch with local variable size
1725 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001726 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001727 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1728 return oad(0xec81, 0); /* sub $xxx, %esp */
1729 }
1730
Jack Palevichb7718b92009-07-09 22:00:24 -07001731 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001732 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001733 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001734 }
1735
Jack Palevich21a15a22009-05-11 14:49:29 -07001736 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001737 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001738 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001739 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001740 }
1741
Jack Palevich1a539db2009-07-08 13:04:41 -07001742 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001743 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001744 switch (pType->tag) {
1745 case TY_FLOAT:
1746 oad(0x05D9, address); // flds
1747 break;
1748 case TY_DOUBLE:
1749 oad(0x05DD, address); // fldl
1750 break;
1751 default:
1752 assert(false);
1753 break;
1754 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001755 }
1756
Jack Palevich22305132009-05-13 10:58:45 -07001757 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001758 return psym(0xe9, t);
1759 }
1760
1761 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001762 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001763 Type* pR0Type = getR0Type();
1764 TypeTag tagR0 = pR0Type->tag;
1765 bool isFloatR0 = isFloatTag(tagR0);
1766 if (isFloatR0) {
1767 o(0xeed9); // fldz
1768 o(0xe9da); // fucompp
1769 o(0xe0df); // fnstsw %ax
1770 o(0x9e); // sahf
1771 } else {
1772 o(0xc085); // test %eax, %eax
1773 }
1774 // Use two output statements to generate one instruction.
1775 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001776 return psym(0x84 + l, t);
1777 }
1778
Jack Palevicha39749f2009-07-08 20:40:31 -07001779 virtual void gcmp(int op, Type* pResultType) {
1780 Type* pR0Type = getR0Type();
1781 Type* pTOSType = getTOSType();
1782 TypeTag tagR0 = pR0Type->tag;
1783 TypeTag tagTOS = pTOSType->tag;
1784 bool isFloatR0 = isFloatTag(tagR0);
1785 bool isFloatTOS = isFloatTag(tagTOS);
1786 if (!isFloatR0 && !isFloatTOS) {
1787 int t = decodeOp(op);
1788 o(0x59); /* pop %ecx */
1789 o(0xc139); /* cmp %eax,%ecx */
1790 li(0, NULL);
1791 o(0x0f); /* setxx %al */
1792 o(t + 0x90);
1793 o(0xc0);
1794 popType();
1795 } else {
1796 setupFloatOperands();
1797 switch (op) {
1798 case OP_EQUALS:
1799 o(0xe9da); // fucompp
1800 o(0xe0df); // fnstsw %ax
1801 o(0x9e); // sahf
1802 o(0xc0940f); // sete %al
1803 o(0xc29b0f); // setnp %dl
1804 o(0xd021); // andl %edx, %eax
1805 break;
1806 case OP_NOT_EQUALS:
1807 o(0xe9da); // fucompp
1808 o(0xe0df); // fnstsw %ax
1809 o(0x9e); // sahf
1810 o(0xc0950f); // setne %al
1811 o(0xc29a0f); // setp %dl
1812 o(0xd009); // orl %edx, %eax
1813 break;
1814 case OP_GREATER_EQUAL:
1815 o(0xe9da); // fucompp
1816 o(0xe0df); // fnstsw %ax
1817 o(0x05c4f6); // testb $5, %ah
1818 o(0xc0940f); // sete %al
1819 break;
1820 case OP_LESS:
1821 o(0xc9d9); // fxch %st(1)
1822 o(0xe9da); // fucompp
1823 o(0xe0df); // fnstsw %ax
1824 o(0x9e); // sahf
1825 o(0xc0970f); // seta %al
1826 break;
1827 case OP_LESS_EQUAL:
1828 o(0xc9d9); // fxch %st(1)
1829 o(0xe9da); // fucompp
1830 o(0xe0df); // fnstsw %ax
1831 o(0x9e); // sahf
1832 o(0xc0930f); // setea %al
1833 break;
1834 case OP_GREATER:
1835 o(0xe9da); // fucompp
1836 o(0xe0df); // fnstsw %ax
1837 o(0x45c4f6); // testb $69, %ah
1838 o(0xc0940f); // sete %al
1839 break;
1840 default:
1841 error("Unknown comparison op");
1842 }
1843 o(0xc0b60f); // movzbl %al, %eax
1844 }
1845 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001846 }
1847
Jack Palevich546b2242009-05-13 15:10:04 -07001848 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001849 Type* pR0Type = getR0Type();
1850 Type* pTOSType = getTOSType();
1851 TypeTag tagR0 = pR0Type->tag;
1852 TypeTag tagTOS = pTOSType->tag;
1853 bool isFloatR0 = isFloatTag(tagR0);
1854 bool isFloatTOS = isFloatTag(tagTOS);
1855 if (!isFloatR0 && !isFloatTOS) {
1856 // TODO: Deal with pointer arithmetic
1857 o(0x59); /* pop %ecx */
1858 o(decodeOp(op));
1859 if (op == OP_MOD)
1860 o(0x92); /* xchg %edx, %eax */
1861 popType();
1862 } else {
1863 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1864 setupFloatOperands();
1865 // Both float. x87 R0 == left hand, x87 R1 == right hand
1866 switch (op) {
1867 case OP_MUL:
1868 o(0xc9de); // fmulp
1869 break;
1870 case OP_DIV:
1871 o(0xf1de); // fdivp
1872 break;
1873 case OP_PLUS:
1874 o(0xc1de); // faddp
1875 break;
1876 case OP_MINUS:
1877 o(0xe1de); // fsubp
1878 break;
1879 default:
1880 error("Unsupported binary floating operation.");
1881 break;
1882 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001883 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001884 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001885 }
1886
Jack Palevicha39749f2009-07-08 20:40:31 -07001887 virtual void gUnaryCmp(int op, Type* pResultType) {
1888 if (op != OP_LOGICAL_NOT) {
1889 error("Unknown unary cmp %d", op);
1890 } else {
1891 Type* pR0Type = getR0Type();
1892 TypeTag tag = collapseType(pR0Type->tag);
1893 switch(tag) {
1894 case TY_INT: {
1895 oad(0xb9, 0); /* movl $0, %ecx */
1896 int t = decodeOp(op);
1897 o(0xc139); /* cmp %eax,%ecx */
1898 li(0, NULL);
1899 o(0x0f); /* setxx %al */
1900 o(t + 0x90);
1901 o(0xc0);
1902 }
1903 break;
1904 case TY_FLOAT:
1905 case TY_DOUBLE:
1906 o(0xeed9); // fldz
1907 o(0xe9da); // fucompp
1908 o(0xe0df); // fnstsw %ax
1909 o(0x9e); // sahf
1910 o(0xc0950f); // setne %al
1911 o(0xc29a0f); // setp %dl
1912 o(0xd009); // orl %edx, %eax
1913 o(0xc0b60f); // movzbl %al, %eax
1914 o(0x01f083); // xorl $1, %eax
1915 break;
1916 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001917 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07001918 break;
1919 }
1920 }
1921 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001922 }
1923
1924 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001925 Type* pR0Type = getR0Type();
1926 TypeTag tag = collapseType(pR0Type->tag);
1927 switch(tag) {
1928 case TY_INT:
1929 oad(0xb9, 0); /* movl $0, %ecx */
1930 o(decodeOp(op));
1931 break;
1932 case TY_FLOAT:
1933 case TY_DOUBLE:
1934 switch (op) {
1935 case OP_MINUS:
1936 o(0xe0d9); // fchs
1937 break;
1938 case OP_BIT_NOT:
1939 error("Can't apply '~' operator to a float or double.");
1940 break;
1941 default:
1942 error("Unknown unary op %d\n", op);
1943 break;
1944 }
1945 break;
1946 default:
1947 error("genUnaryOp unsupported type");
1948 break;
1949 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001950 }
1951
Jack Palevich1cdef202009-05-22 12:06:27 -07001952 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001953 Type* pR0Type = getR0Type();
1954 TypeTag r0ct = collapseType(pR0Type->tag);
1955 switch(r0ct) {
1956 case TY_INT:
1957 o(0x50); /* push %eax */
1958 break;
1959 case TY_FLOAT:
1960 o(0x50); /* push %eax */
1961 o(0x241cd9); // fstps 0(%esp)
1962 break;
1963 case TY_DOUBLE:
1964 o(0x50); /* push %eax */
1965 o(0x50); /* push %eax */
1966 o(0x241cdd); // fstpl 0(%esp)
1967 break;
1968 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001969 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07001970 break;
1971 }
Jack Palevich8df46192009-07-07 14:48:51 -07001972 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001973 }
1974
Jack Palevich9eed7a22009-07-06 17:24:34 -07001975 virtual void storeR0ToTOS(Type* pPointerType) {
1976 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001977 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001978 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001979 switch (pPointerType->pHead->tag) {
1980 case TY_INT:
1981 o(0x0189); /* movl %eax/%al, (%ecx) */
1982 break;
1983 case TY_CHAR:
1984 o(0x0188); /* movl %eax/%al, (%ecx) */
1985 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001986 case TY_FLOAT:
1987 o(0x19d9); /* fstps (%ecx) */
1988 break;
1989 case TY_DOUBLE:
1990 o(0x19dd); /* fstpl (%ecx) */
1991 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001992 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001993 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001994 break;
1995 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001996 }
1997
Jack Palevich9eed7a22009-07-06 17:24:34 -07001998 virtual void loadR0FromR0(Type* pPointerType) {
1999 assert(pPointerType->tag == TY_POINTER);
2000 switch (pPointerType->pHead->tag) {
2001 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002002 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002003 break;
2004 case TY_CHAR:
2005 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002006 ob(0); /* add zero in code */
2007 break;
2008 case TY_FLOAT:
2009 o2(0x00d9); // flds (%eax)
2010 break;
2011 case TY_DOUBLE:
2012 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002013 break;
2014 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002015 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002016 break;
2017 }
Jack Palevich8df46192009-07-07 14:48:51 -07002018 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002019 }
2020
Jack Palevich8df46192009-07-07 14:48:51 -07002021 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002022 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002023 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002024 }
2025
Jack Palevich9cbd2262009-07-08 16:48:41 -07002026 virtual void storeR0(int ea, Type* pType) {
2027 TypeTag tag = pType->tag;
2028 switch (tag) {
2029 case TY_INT:
2030 gmov(6, ea); /* mov %eax, EA */
2031 break;
2032 case TY_FLOAT:
2033 if (ea < -LOCAL || ea > LOCAL) {
2034 oad(0x1dd9, ea); // fstps ea
2035 } else {
2036 oad(0x9dd9, ea); // fstps ea(%ebp)
2037 }
2038 break;
2039 case TY_DOUBLE:
2040 if (ea < -LOCAL || ea > LOCAL) {
2041 oad(0x1ddd, ea); // fstpl ea
2042 } else {
2043 oad(0x9ddd, ea); // fstpl ea(%ebp)
2044 }
2045 break;
2046 default:
2047 error("Unable to store to type %d", tag);
2048 break;
2049 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002050 }
2051
Jack Palevich8df46192009-07-07 14:48:51 -07002052 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002053 TypeTag tag = collapseType(pType->tag);
2054 switch (tag) {
2055 case TY_INT:
2056 gmov(8, ea); /* mov EA, %eax */
2057 if (isIncDec) {
2058 /* Implement post-increment or post decrement.
2059 */
2060 gmov(0, ea); /* 83 ADD */
2061 o(decodeOp(op));
2062 }
2063 break;
2064 case TY_FLOAT:
2065 if (ea < -LOCAL || ea > LOCAL) {
2066 oad(0x05d9, ea); // flds ea
2067 } else {
2068 oad(0x85d9, ea); // flds ea(%ebp)
2069 }
2070 if (isIncDec) {
2071 error("inc/dec not implemented for float.");
2072 }
2073 break;
2074 case TY_DOUBLE:
2075 if (ea < -LOCAL || ea > LOCAL) {
2076 oad(0x05dd, ea); // fldl ea
2077 } else {
2078 oad(0x85dd, ea); // fldl ea(%ebp)
2079 }
2080 if (isIncDec) {
2081 error("inc/dec not implemented for double.");
2082 }
2083 break;
2084 default:
2085 error("Unable to load type %d", tag);
2086 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002087 }
Jack Palevich8df46192009-07-07 14:48:51 -07002088 setR0Type(pType);
2089 }
2090
2091 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002092 Type* pR0Type = getR0Type();
2093 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002094 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002095 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002096 return;
2097 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002098 if (bitsSame(pType, pR0Type)) {
2099 // do nothing special
2100 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2101 // do nothing special, both held in same register on x87.
2102 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002103 TypeTag r0Tag = collapseType(pR0Type->tag);
2104 TypeTag destTag = collapseType(pType->tag);
2105 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2106 // Convert R0 from int to float
2107 o(0x50); // push %eax
2108 o(0x2404DB); // fildl 0(%esp)
2109 o(0x58); // pop %eax
2110 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2111 // Convert R0 from float to int. Complicated because
2112 // need to save and restore the rounding mode.
2113 o(0x50); // push %eax
2114 o(0x50); // push %eax
2115 o(0x02247cD9); // fnstcw 2(%esp)
2116 o(0x2444b70f); // movzwl 2(%esp), %eax
2117 o(0x02);
2118 o(0x0cb4); // movb $12, %ah
2119 o(0x24048966); // movw %ax, 0(%esp)
2120 o(0x242cd9); // fldcw 0(%esp)
2121 o(0x04245cdb); // fistpl 4(%esp)
2122 o(0x02246cd9); // fldcw 2(%esp)
2123 o(0x58); // pop %eax
2124 o(0x58); // pop %eax
2125 } else {
2126 error("Incompatible types old: %d new: %d",
2127 pR0Type->tag, pType->tag);
2128 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002129 }
2130 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002131 }
2132
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002133 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002134 return oad(0xec81, 0); /* sub $xxx, %esp */
2135 }
2136
Jack Palevich1a539db2009-07-08 13:04:41 -07002137 virtual size_t storeR0ToArg(int l) {
2138 Type* pR0Type = getR0Type();
2139 TypeTag r0ct = collapseType(pR0Type->tag);
2140 switch(r0ct) {
2141 case TY_INT:
2142 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2143 return 4;
2144 case TY_FLOAT:
2145 oad(0x249CD9, l); /* fstps xxx(%esp) */
2146 return 4;
2147 case TY_DOUBLE:
2148 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2149 return 8;
2150 default:
2151 assert(false);
2152 return 0;
2153 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002154 }
2155
Jack Palevichb7718b92009-07-09 22:00:24 -07002156 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002157 * (int*) a = l;
2158 }
2159
Jack Palevich8df46192009-07-07 14:48:51 -07002160 virtual int callForward(int symbol, Type* pFunc) {
2161 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002162 return psym(0xe8, symbol); /* call xxx */
2163 }
2164
Jack Palevich8df46192009-07-07 14:48:51 -07002165 virtual void callRelative(int t, Type* pFunc) {
2166 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002167 psym(0xe8, t); /* call xxx */
2168 }
2169
Jack Palevich8df46192009-07-07 14:48:51 -07002170 virtual void callIndirect(int l, Type* pFunc) {
2171 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002172 oad(0x2494ff, l); /* call *xxx(%esp) */
2173 }
2174
Jack Palevichb7718b92009-07-09 22:00:24 -07002175 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002176 if (isIndirect) {
2177 l += 4;
2178 }
-b master422972c2009-06-17 19:13:52 -07002179 if (l > 0) {
2180 oad(0xc481, l); /* add $xxx, %esp */
2181 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002182 }
2183
Jack Palevicha6535612009-05-13 16:24:17 -07002184 virtual int jumpOffset() {
2185 return 5;
2186 }
2187
2188 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002189 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002190 }
2191
Jack Paleviche7b59062009-05-19 17:12:17 -07002192 /* output a symbol and patch all calls to it */
2193 virtual void gsym(int t) {
2194 int n;
2195 int pc = getPC();
2196 while (t) {
2197 n = *(int *) t; /* next value */
2198 *(int *) t = pc - t - 4;
2199 t = n;
2200 }
2201 }
2202
Jack Palevich1cdef202009-05-22 12:06:27 -07002203 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002204 size_t pagesize = 4096;
2205 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2206 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2207 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2208 if (err) {
2209 error("mprotect() failed: %d", errno);
2210 }
2211 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002212 }
2213
Jack Palevich9eed7a22009-07-06 17:24:34 -07002214 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002215 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002216 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002217 virtual size_t alignmentOf(Type* pType){
2218 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002219 }
2220
2221 /**
2222 * Array element alignment (in bytes) for this type of data.
2223 */
2224 virtual size_t sizeOf(Type* pType){
2225 switch(pType->tag) {
2226 case TY_INT:
2227 return 4;
2228 case TY_CHAR:
2229 return 1;
2230 default:
2231 return 0;
2232 case TY_FLOAT:
2233 return 4;
2234 case TY_DOUBLE:
2235 return 8;
2236 case TY_POINTER:
2237 return 4;
2238 }
2239 }
2240
Jack Palevich9cbd2262009-07-08 16:48:41 -07002241 virtual size_t stackSizeOf(Type* pType) {
2242 switch(pType->tag) {
2243 case TY_DOUBLE:
2244 return 8;
2245 default:
2246 return 4;
2247 }
2248 }
2249
Jack Palevich21a15a22009-05-11 14:49:29 -07002250 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002251
2252 /** Output 1 to 4 bytes.
2253 *
2254 */
2255 void o(int n) {
2256 /* cannot use unsigned, so we must do a hack */
2257 while (n && n != -1) {
2258 ob(n & 0xff);
2259 n = n >> 8;
2260 }
2261 }
2262
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002263 /* Output exactly 2 bytes
2264 */
2265 void o2(int n) {
2266 ob(n & 0xff);
2267 ob(0xff & (n >> 8));
2268 }
2269
Jack Paleviche7b59062009-05-19 17:12:17 -07002270 /* psym is used to put an instruction with a data field which is a
2271 reference to a symbol. It is in fact the same as oad ! */
2272 int psym(int n, int t) {
2273 return oad(n, t);
2274 }
2275
2276 /* instruction + address */
2277 int oad(int n, int t) {
2278 o(n);
2279 int result = getPC();
2280 o4(t);
2281 return result;
2282 }
2283
2284
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002285 static const int operatorHelper[];
2286
2287 int decodeOp(int op) {
2288 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002289 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002290 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002291 }
2292 return operatorHelper[op];
2293 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002294
Jack Palevich546b2242009-05-13 15:10:04 -07002295 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002296 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002297 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002298 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002299
2300 void setupFloatOperands() {
2301 Type* pR0Type = getR0Type();
2302 Type* pTOSType = getTOSType();
2303 TypeTag tagR0 = pR0Type->tag;
2304 TypeTag tagTOS = pTOSType->tag;
2305 bool isFloatR0 = isFloatTag(tagR0);
2306 bool isFloatTOS = isFloatTag(tagTOS);
2307 if (! isFloatR0) {
2308 // Convert R0 from int to float
2309 o(0x50); // push %eax
2310 o(0x2404DB); // fildl 0(%esp)
2311 o(0x58); // pop %eax
2312 }
2313 if (! isFloatTOS){
2314 o(0x2404DB); // fildl 0(%esp);
2315 o(0x58); // pop %eax
2316 } else {
2317 if (tagTOS == TY_FLOAT) {
2318 o(0x2404d9); // flds (%esp)
2319 o(0x58); // pop %eax
2320 } else {
2321 o(0x2404dd); // fldl (%esp)
2322 o(0x58); // pop %eax
2323 o(0x58); // pop %eax
2324 }
2325 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002326 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002327 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002328 };
2329
Jack Paleviche7b59062009-05-19 17:12:17 -07002330#endif // PROVIDE_X86_CODEGEN
2331
Jack Palevichb67b18f2009-06-11 21:12:23 -07002332#ifdef PROVIDE_TRACE_CODEGEN
2333 class TraceCodeGenerator : public CodeGenerator {
2334 private:
2335 CodeGenerator* mpBase;
2336
2337 public:
2338 TraceCodeGenerator(CodeGenerator* pBase) {
2339 mpBase = pBase;
2340 }
2341
2342 virtual ~TraceCodeGenerator() {
2343 delete mpBase;
2344 }
2345
2346 virtual void init(CodeBuf* pCodeBuf) {
2347 mpBase->init(pCodeBuf);
2348 }
2349
2350 void setErrorSink(ErrorSink* pErrorSink) {
2351 mpBase->setErrorSink(pErrorSink);
2352 }
2353
2354 /* returns address to patch with local variable size
2355 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002356 virtual int functionEntry(Type* pDecl) {
2357 int result = mpBase->functionEntry(pDecl);
2358 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002359 return result;
2360 }
2361
Jack Palevichb7718b92009-07-09 22:00:24 -07002362 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2363 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2364 localVariableAddress, localVariableSize);
2365 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002366 }
2367
2368 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002369 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002370 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002371 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002372 }
2373
Jack Palevich1a539db2009-07-08 13:04:41 -07002374 virtual void loadFloat(int address, Type* pType) {
2375 fprintf(stderr, "loadFloat(%d, type)\n", address);
2376 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002377 }
2378
Jack Palevichb67b18f2009-06-11 21:12:23 -07002379 virtual int gjmp(int t) {
2380 int result = mpBase->gjmp(t);
2381 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2382 return result;
2383 }
2384
2385 /* l = 0: je, l == 1: jne */
2386 virtual int gtst(bool l, int t) {
2387 int result = mpBase->gtst(l, t);
2388 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2389 return result;
2390 }
2391
Jack Palevicha39749f2009-07-08 20:40:31 -07002392 virtual void gcmp(int op, Type* pResultType) {
2393 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2394 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002395 }
2396
2397 virtual void genOp(int op) {
2398 fprintf(stderr, "genOp(%d)\n", op);
2399 mpBase->genOp(op);
2400 }
2401
Jack Palevich9eed7a22009-07-06 17:24:34 -07002402
Jack Palevicha39749f2009-07-08 20:40:31 -07002403 virtual void gUnaryCmp(int op, Type* pResultType) {
2404 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2405 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002406 }
2407
2408 virtual void genUnaryOp(int op) {
2409 fprintf(stderr, "genUnaryOp(%d)\n", op);
2410 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002411 }
2412
2413 virtual void pushR0() {
2414 fprintf(stderr, "pushR0()\n");
2415 mpBase->pushR0();
2416 }
2417
Jack Palevich9eed7a22009-07-06 17:24:34 -07002418 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002419 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002420 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002421 }
2422
Jack Palevich9eed7a22009-07-06 17:24:34 -07002423 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002424 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002425 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002426 }
2427
Jack Palevich8df46192009-07-07 14:48:51 -07002428 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002429 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002430 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002431 }
2432
Jack Palevich9cbd2262009-07-08 16:48:41 -07002433 virtual void storeR0(int ea, Type* pType) {
2434 fprintf(stderr, "storeR0(%d, pType)\n", ea);
2435 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002436 }
2437
Jack Palevich8df46192009-07-07 14:48:51 -07002438 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002439 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002440 mpBase->loadR0(ea, isIncDec, op, pType);
2441 }
2442
2443 virtual void convertR0(Type* pType){
2444 fprintf(stderr, "convertR0(pType)\n");
2445 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002446 }
2447
2448 virtual int beginFunctionCallArguments() {
2449 int result = mpBase->beginFunctionCallArguments();
2450 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2451 return result;
2452 }
2453
Jack Palevich1a539db2009-07-08 13:04:41 -07002454 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002455 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07002456 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002457 }
2458
Jack Palevichb7718b92009-07-09 22:00:24 -07002459 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002460 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002461 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002462 }
2463
Jack Palevich8df46192009-07-07 14:48:51 -07002464 virtual int callForward(int symbol, Type* pFunc) {
2465 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002466 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2467 return result;
2468 }
2469
Jack Palevich8df46192009-07-07 14:48:51 -07002470 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002471 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002472 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002473 }
2474
Jack Palevich8df46192009-07-07 14:48:51 -07002475 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002476 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002477 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002478 }
2479
Jack Palevichb7718b92009-07-09 22:00:24 -07002480 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2481 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2482 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002483 }
2484
2485 virtual int jumpOffset() {
2486 return mpBase->jumpOffset();
2487 }
2488
2489 virtual int disassemble(FILE* out) {
2490 return mpBase->disassemble(out);
2491 }
2492
2493 /* output a symbol and patch all calls to it */
2494 virtual void gsym(int t) {
2495 fprintf(stderr, "gsym(%d)\n", t);
2496 mpBase->gsym(t);
2497 }
2498
2499 virtual int finishCompile() {
2500 int result = mpBase->finishCompile();
2501 fprintf(stderr, "finishCompile() = %d\n", result);
2502 return result;
2503 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002504
2505 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002506 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002507 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002508 virtual size_t alignmentOf(Type* pType){
2509 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002510 }
2511
2512 /**
2513 * Array element alignment (in bytes) for this type of data.
2514 */
2515 virtual size_t sizeOf(Type* pType){
2516 return mpBase->sizeOf(pType);
2517 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002518
Jack Palevich9cbd2262009-07-08 16:48:41 -07002519
2520 virtual size_t stackSizeOf(Type* pType) {
2521 return mpBase->stackSizeOf(pType);
2522 }
2523
2524
Jack Palevich1a539db2009-07-08 13:04:41 -07002525 virtual Type* getR0Type() {
2526 return mpBase->getR0Type();
2527 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002528 };
2529
2530#endif // PROVIDE_TRACE_CODEGEN
2531
Jack Palevich569f1352009-06-29 14:29:08 -07002532 class Arena {
2533 public:
2534 // Used to record a given allocation amount.
2535 // Used:
2536 // Mark mark = arena.mark();
2537 // ... lots of arena.allocate()
2538 // arena.free(mark);
2539
2540 struct Mark {
2541 size_t chunk;
2542 size_t offset;
2543 };
2544
2545 Arena() {
2546 mCurrentChunk = 0;
2547 Chunk start(CHUNK_SIZE);
2548 mData.push_back(start);
2549 }
2550
2551 ~Arena() {
2552 for(size_t i = 0; i < mData.size(); i++) {
2553 mData[i].free();
2554 }
2555 }
2556
2557 // Alloc using the standard alignment size safe for any variable
2558 void* alloc(size_t size) {
2559 return alloc(size, 8);
2560 }
2561
2562 Mark mark(){
2563 Mark result;
2564 result.chunk = mCurrentChunk;
2565 result.offset = mData[mCurrentChunk].mOffset;
2566 return result;
2567 }
2568
2569 void freeToMark(const Mark& mark) {
2570 mCurrentChunk = mark.chunk;
2571 mData[mCurrentChunk].mOffset = mark.offset;
2572 }
2573
2574 private:
2575 // Allocate memory aligned to a given size
2576 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2577 // Memory is not zero filled.
2578
2579 void* alloc(size_t size, size_t alignment) {
2580 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2581 if (mCurrentChunk + 1 < mData.size()) {
2582 mCurrentChunk++;
2583 } else {
2584 size_t allocSize = CHUNK_SIZE;
2585 if (allocSize < size + alignment - 1) {
2586 allocSize = size + alignment - 1;
2587 }
2588 Chunk chunk(allocSize);
2589 mData.push_back(chunk);
2590 mCurrentChunk++;
2591 }
2592 }
2593 return mData[mCurrentChunk].allocate(size, alignment);
2594 }
2595
2596 static const size_t CHUNK_SIZE = 128*1024;
2597 // Note: this class does not deallocate its
2598 // memory when it's destroyed. It depends upon
2599 // its parent to deallocate the memory.
2600 struct Chunk {
2601 Chunk() {
2602 mpData = 0;
2603 mSize = 0;
2604 mOffset = 0;
2605 }
2606
2607 Chunk(size_t size) {
2608 mSize = size;
2609 mpData = (char*) malloc(size);
2610 mOffset = 0;
2611 }
2612
2613 ~Chunk() {
2614 // Doesn't deallocate memory.
2615 }
2616
2617 void* allocate(size_t size, size_t alignment) {
2618 size_t alignedOffset = aligned(mOffset, alignment);
2619 void* result = mpData + alignedOffset;
2620 mOffset = alignedOffset + size;
2621 return result;
2622 }
2623
2624 void free() {
2625 if (mpData) {
2626 ::free(mpData);
2627 mpData = 0;
2628 }
2629 }
2630
2631 size_t remainingCapacity(size_t alignment) {
2632 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2633 }
2634
2635 // Assume alignment is a power of two
2636 inline size_t aligned(size_t v, size_t alignment) {
2637 size_t mask = alignment-1;
2638 return (v + mask) & ~mask;
2639 }
2640
2641 char* mpData;
2642 size_t mSize;
2643 size_t mOffset;
2644 };
2645
2646 size_t mCurrentChunk;
2647
2648 Vector<Chunk> mData;
2649 };
2650
Jack Palevich569f1352009-06-29 14:29:08 -07002651 struct VariableInfo;
2652
2653 struct Token {
2654 int hash;
2655 size_t length;
2656 char* pText;
2657 tokenid_t id;
2658
2659 // Current values for the token
2660 char* mpMacroDefinition;
2661 VariableInfo* mpVariableInfo;
2662 };
2663
2664 class TokenTable {
2665 public:
2666 // Don't use 0..0xff, allows characters and operators to be tokens too.
2667
2668 static const int TOKEN_BASE = 0x100;
2669 TokenTable() {
2670 mpMap = hashmapCreate(128, hashFn, equalsFn);
2671 }
2672
2673 ~TokenTable() {
2674 hashmapFree(mpMap);
2675 }
2676
2677 void setArena(Arena* pArena) {
2678 mpArena = pArena;
2679 }
2680
2681 // Returns a token for a given string of characters.
2682 tokenid_t intern(const char* pText, size_t length) {
2683 Token probe;
2684 int hash = hashmapHash((void*) pText, length);
2685 {
2686 Token probe;
2687 probe.hash = hash;
2688 probe.length = length;
2689 probe.pText = (char*) pText;
2690 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2691 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002692 return pValue->id;
2693 }
2694 }
2695
2696 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2697 memset(pToken, 0, sizeof(*pToken));
2698 pToken->hash = hash;
2699 pToken->length = length;
2700 pToken->pText = (char*) mpArena->alloc(length + 1);
2701 memcpy(pToken->pText, pText, length);
2702 pToken->pText[length] = 0;
2703 pToken->id = mTokens.size() + TOKEN_BASE;
2704 mTokens.push_back(pToken);
2705 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002706 return pToken->id;
2707 }
2708
2709 // Return the Token for a given tokenid.
2710 Token& operator[](tokenid_t id) {
2711 return *mTokens[id - TOKEN_BASE];
2712 }
2713
2714 inline size_t size() {
2715 return mTokens.size();
2716 }
2717
2718 private:
2719
2720 static int hashFn(void* pKey) {
2721 Token* pToken = (Token*) pKey;
2722 return pToken->hash;
2723 }
2724
2725 static bool equalsFn(void* keyA, void* keyB) {
2726 Token* pTokenA = (Token*) keyA;
2727 Token* pTokenB = (Token*) keyB;
2728 // Don't need to compare hash values, they should always be equal
2729 return pTokenA->length == pTokenB->length
2730 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2731 }
2732
2733 Hashmap* mpMap;
2734 Vector<Token*> mTokens;
2735 Arena* mpArena;
2736 };
2737
Jack Palevich1cdef202009-05-22 12:06:27 -07002738 class InputStream {
2739 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002740 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002741 int getChar() {
2742 if (bumpLine) {
2743 line++;
2744 bumpLine = false;
2745 }
2746 int ch = get();
2747 if (ch == '\n') {
2748 bumpLine = true;
2749 }
2750 return ch;
2751 }
2752 int getLine() {
2753 return line;
2754 }
2755 protected:
2756 InputStream() :
2757 line(1), bumpLine(false) {
2758 }
2759 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002760 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002761 int line;
2762 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002763 };
2764
2765 class FileInputStream : public InputStream {
2766 public:
2767 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002768 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002769 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002770 FILE* f;
2771 };
2772
2773 class TextInputStream : public InputStream {
2774 public:
2775 TextInputStream(const char* text, size_t textLength)
2776 : pText(text), mTextLength(textLength), mPosition(0) {
2777 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002778
2779 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002780 virtual int get() {
2781 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2782 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002783
Jack Palevich1cdef202009-05-22 12:06:27 -07002784 const char* pText;
2785 size_t mTextLength;
2786 size_t mPosition;
2787 };
2788
Jack Palevicheedf9d22009-06-04 16:23:40 -07002789 class String {
2790 public:
2791 String() {
2792 mpBase = 0;
2793 mUsed = 0;
2794 mSize = 0;
2795 }
2796
Jack Palevich303d8ff2009-06-11 19:06:24 -07002797 String(const char* item, int len, bool adopt) {
2798 if (len < 0) {
2799 len = strlen(item);
2800 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002801 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002802 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002803 mUsed = len;
2804 mSize = len + 1;
2805 } else {
2806 mpBase = 0;
2807 mUsed = 0;
2808 mSize = 0;
2809 appendBytes(item, len);
2810 }
2811 }
2812
Jack Palevich303d8ff2009-06-11 19:06:24 -07002813 String(const String& other) {
2814 mpBase = 0;
2815 mUsed = 0;
2816 mSize = 0;
2817 appendBytes(other.getUnwrapped(), other.len());
2818 }
2819
Jack Palevicheedf9d22009-06-04 16:23:40 -07002820 ~String() {
2821 if (mpBase) {
2822 free(mpBase);
2823 }
2824 }
2825
Jack Palevicha6baa232009-06-12 11:25:59 -07002826 String& operator=(const String& other) {
2827 clear();
2828 appendBytes(other.getUnwrapped(), other.len());
2829 return *this;
2830 }
2831
Jack Palevich303d8ff2009-06-11 19:06:24 -07002832 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002833 return mpBase;
2834 }
2835
Jack Palevich303d8ff2009-06-11 19:06:24 -07002836 void clear() {
2837 mUsed = 0;
2838 if (mSize > 0) {
2839 mpBase[0] = 0;
2840 }
2841 }
2842
Jack Palevicheedf9d22009-06-04 16:23:40 -07002843 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002844 appendBytes(s, strlen(s));
2845 }
2846
2847 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002848 memcpy(ensure(n), s, n + 1);
2849 }
2850
2851 void append(char c) {
2852 * ensure(1) = c;
2853 }
2854
Jack Palevich86351982009-06-30 18:09:56 -07002855 void append(String& other) {
2856 appendBytes(other.getUnwrapped(), other.len());
2857 }
2858
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002859 char* orphan() {
2860 char* result = mpBase;
2861 mpBase = 0;
2862 mUsed = 0;
2863 mSize = 0;
2864 return result;
2865 }
2866
Jack Palevicheedf9d22009-06-04 16:23:40 -07002867 void printf(const char* fmt,...) {
2868 va_list ap;
2869 va_start(ap, fmt);
2870 vprintf(fmt, ap);
2871 va_end(ap);
2872 }
2873
2874 void vprintf(const char* fmt, va_list ap) {
2875 char* temp;
2876 int numChars = vasprintf(&temp, fmt, ap);
2877 memcpy(ensure(numChars), temp, numChars+1);
2878 free(temp);
2879 }
2880
Jack Palevich303d8ff2009-06-11 19:06:24 -07002881 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002882 return mUsed;
2883 }
2884
2885 private:
2886 char* ensure(int n) {
2887 size_t newUsed = mUsed + n;
2888 if (newUsed > mSize) {
2889 size_t newSize = mSize * 2 + 10;
2890 if (newSize < newUsed) {
2891 newSize = newUsed;
2892 }
2893 mpBase = (char*) realloc(mpBase, newSize + 1);
2894 mSize = newSize;
2895 }
2896 mpBase[newUsed] = '\0';
2897 char* result = mpBase + mUsed;
2898 mUsed = newUsed;
2899 return result;
2900 }
2901
2902 char* mpBase;
2903 size_t mUsed;
2904 size_t mSize;
2905 };
2906
Jack Palevich569f1352009-06-29 14:29:08 -07002907 void internKeywords() {
2908 // Note: order has to match TOK_ constants
2909 static const char* keywords[] = {
2910 "int",
2911 "char",
2912 "void",
2913 "if",
2914 "else",
2915 "while",
2916 "break",
2917 "return",
2918 "for",
2919 "pragma",
2920 "define",
2921 "auto",
2922 "case",
2923 "const",
2924 "continue",
2925 "default",
2926 "do",
2927 "double",
2928 "enum",
2929 "extern",
2930 "float",
2931 "goto",
2932 "long",
2933 "register",
2934 "short",
2935 "signed",
2936 "sizeof",
2937 "static",
2938 "struct",
2939 "switch",
2940 "typedef",
2941 "union",
2942 "unsigned",
2943 "volatile",
2944 "_Bool",
2945 "_Complex",
2946 "_Imaginary",
2947 "inline",
2948 "restrict",
2949 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002950
Jack Palevich569f1352009-06-29 14:29:08 -07002951 for(int i = 0; keywords[i]; i++) {
2952 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002953 }
Jack Palevich569f1352009-06-29 14:29:08 -07002954 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002955
Jack Palevich36d94142009-06-08 15:55:32 -07002956 struct InputState {
2957 InputStream* pStream;
2958 int oldCh;
2959 };
2960
Jack Palevich2db168f2009-06-11 14:29:47 -07002961 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002962 void* pAddress;
2963 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002964 tokenid_t tok;
2965 size_t level;
2966 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002967 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002968 };
2969
Jack Palevich303d8ff2009-06-11 19:06:24 -07002970 class SymbolStack {
2971 public:
2972 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002973 mpArena = 0;
2974 mpTokenTable = 0;
2975 }
2976
2977 void setArena(Arena* pArena) {
2978 mpArena = pArena;
2979 }
2980
2981 void setTokenTable(TokenTable* pTokenTable) {
2982 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002983 }
2984
2985 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002986 Mark mark;
2987 mark.mArenaMark = mpArena->mark();
2988 mark.mSymbolHead = mStack.size();
2989 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002990 }
2991
2992 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002993 // Undo any shadowing that was done:
2994 Mark mark = mLevelStack.back();
2995 mLevelStack.pop_back();
2996 while (mStack.size() > mark.mSymbolHead) {
2997 VariableInfo* pV = mStack.back();
2998 mStack.pop_back();
2999 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003000 }
Jack Palevich569f1352009-06-29 14:29:08 -07003001 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003002 }
3003
Jack Palevich569f1352009-06-29 14:29:08 -07003004 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3005 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3006 return pV && pV->level == level();
3007 }
3008
3009 VariableInfo* add(tokenid_t tok) {
3010 Token& token = (*mpTokenTable)[tok];
3011 VariableInfo* pOldV = token.mpVariableInfo;
3012 VariableInfo* pNewV =
3013 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3014 memset(pNewV, 0, sizeof(VariableInfo));
3015 pNewV->tok = tok;
3016 pNewV->level = level();
3017 pNewV->pOldDefinition = pOldV;
3018 token.mpVariableInfo = pNewV;
3019 mStack.push_back(pNewV);
3020 return pNewV;
3021 }
3022
Jack Palevich86351982009-06-30 18:09:56 -07003023 VariableInfo* add(Type* pType) {
3024 VariableInfo* pVI = add(pType->id);
3025 pVI->pType = pType;
3026 return pVI;
3027 }
3028
Jack Palevich569f1352009-06-29 14:29:08 -07003029 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3030 for (size_t i = 0; i < mStack.size(); i++) {
3031 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003032 break;
3033 }
3034 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003035 }
3036
Jack Palevich303d8ff2009-06-11 19:06:24 -07003037 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003038 inline size_t level() {
3039 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003040 }
3041
Jack Palevich569f1352009-06-29 14:29:08 -07003042 struct Mark {
3043 Arena::Mark mArenaMark;
3044 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003045 };
3046
Jack Palevich569f1352009-06-29 14:29:08 -07003047 Arena* mpArena;
3048 TokenTable* mpTokenTable;
3049 Vector<VariableInfo*> mStack;
3050 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003051 };
Jack Palevich36d94142009-06-08 15:55:32 -07003052
3053 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003054 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003055 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003056 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003057 int tokl; // token operator level
3058 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003059 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003060 intptr_t loc; // local variable index
3061 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003062 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003063 char* dptr; // Macro state: Points to macro text during macro playback.
3064 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003065 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07003066
3067 // Arena for the duration of the compile
3068 Arena mGlobalArena;
3069 // Arena for data that's only needed when compiling a single function
3070 Arena mLocalArena;
3071
3072 TokenTable mTokenTable;
3073 SymbolStack mGlobals;
3074 SymbolStack mLocals;
3075
Jack Palevich40600de2009-07-01 15:32:35 -07003076 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003077 Type* mkpInt; // int
3078 Type* mkpChar; // char
3079 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003080 Type* mkpFloat;
3081 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003082 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003083 Type* mkpIntPtr;
3084 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003085 Type* mkpFloatPtr;
3086 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003087 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003088
Jack Palevich36d94142009-06-08 15:55:32 -07003089 InputStream* file;
3090
3091 CodeBuf codeBuf;
3092 CodeGenerator* pGen;
3093
Jack Palevicheedf9d22009-06-04 16:23:40 -07003094 String mErrorBuf;
3095
Jack Palevicheedf9d22009-06-04 16:23:40 -07003096 String mPragmas;
3097 int mPragmaStringCount;
3098
Jack Palevich21a15a22009-05-11 14:49:29 -07003099 static const int ALLOC_SIZE = 99999;
3100
Jack Palevich303d8ff2009-06-11 19:06:24 -07003101 static const int TOK_DUMMY = 1;
3102 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003103 static const int TOK_NUM_FLOAT = 3;
3104 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003105
3106 // 3..255 are character and/or operators
3107
Jack Palevich2db168f2009-06-11 14:29:47 -07003108 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003109 // Order has to match string list in "internKeywords".
3110 enum {
3111 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3112 TOK_INT = TOK_KEYWORD,
3113 TOK_CHAR,
3114 TOK_VOID,
3115 TOK_IF,
3116 TOK_ELSE,
3117 TOK_WHILE,
3118 TOK_BREAK,
3119 TOK_RETURN,
3120 TOK_FOR,
3121 TOK_PRAGMA,
3122 TOK_DEFINE,
3123 TOK_AUTO,
3124 TOK_CASE,
3125 TOK_CONST,
3126 TOK_CONTINUE,
3127 TOK_DEFAULT,
3128 TOK_DO,
3129 TOK_DOUBLE,
3130 TOK_ENUM,
3131 TOK_EXTERN,
3132 TOK_FLOAT,
3133 TOK_GOTO,
3134 TOK_LONG,
3135 TOK_REGISTER,
3136 TOK_SHORT,
3137 TOK_SIGNED,
3138 TOK_SIZEOF,
3139 TOK_STATIC,
3140 TOK_STRUCT,
3141 TOK_SWITCH,
3142 TOK_TYPEDEF,
3143 TOK_UNION,
3144 TOK_UNSIGNED,
3145 TOK_VOLATILE,
3146 TOK__BOOL,
3147 TOK__COMPLEX,
3148 TOK__IMAGINARY,
3149 TOK_INLINE,
3150 TOK_RESTRICT,
3151 // Symbols start after tokens
3152 TOK_SYMBOL
3153 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003154
3155 static const int LOCAL = 0x200;
3156
3157 static const int SYM_FORWARD = 0;
3158 static const int SYM_DEFINE = 1;
3159
3160 /* tokens in string heap */
3161 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003162
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003163 static const int OP_INCREMENT = 0;
3164 static const int OP_DECREMENT = 1;
3165 static const int OP_MUL = 2;
3166 static const int OP_DIV = 3;
3167 static const int OP_MOD = 4;
3168 static const int OP_PLUS = 5;
3169 static const int OP_MINUS = 6;
3170 static const int OP_SHIFT_LEFT = 7;
3171 static const int OP_SHIFT_RIGHT = 8;
3172 static const int OP_LESS_EQUAL = 9;
3173 static const int OP_GREATER_EQUAL = 10;
3174 static const int OP_LESS = 11;
3175 static const int OP_GREATER = 12;
3176 static const int OP_EQUALS = 13;
3177 static const int OP_NOT_EQUALS = 14;
3178 static const int OP_LOGICAL_AND = 15;
3179 static const int OP_LOGICAL_OR = 16;
3180 static const int OP_BIT_AND = 17;
3181 static const int OP_BIT_XOR = 18;
3182 static const int OP_BIT_OR = 19;
3183 static const int OP_BIT_NOT = 20;
3184 static const int OP_LOGICAL_NOT = 21;
3185 static const int OP_COUNT = 22;
3186
3187 /* Operators are searched from front, the two-character operators appear
3188 * before the single-character operators with the same first character.
3189 * @ is used to pad out single-character operators.
3190 */
3191 static const char* operatorChars;
3192 static const char operatorLevel[];
3193
Jack Palevich569f1352009-06-29 14:29:08 -07003194 /* Called when we detect an internal problem. Does nothing in production.
3195 *
3196 */
3197 void internalError() {
3198 * (char*) 0 = 0;
3199 }
3200
Jack Palevich86351982009-06-30 18:09:56 -07003201 void assert(bool isTrue) {
3202 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003203 internalError();
3204 }
Jack Palevich86351982009-06-30 18:09:56 -07003205 }
3206
Jack Palevich40600de2009-07-01 15:32:35 -07003207 bool isSymbol(tokenid_t t) {
3208 return t >= TOK_SYMBOL &&
3209 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3210 }
3211
3212 bool isSymbolOrKeyword(tokenid_t t) {
3213 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003214 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003215 }
3216
Jack Palevich86351982009-06-30 18:09:56 -07003217 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003218 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003219 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3220 if (pV && pV->tok != t) {
3221 internalError();
3222 }
3223 return pV;
3224 }
3225
3226 inline bool isDefined(tokenid_t t) {
3227 return t >= TOK_SYMBOL && VI(t) != 0;
3228 }
3229
Jack Palevich40600de2009-07-01 15:32:35 -07003230 const char* nameof(tokenid_t t) {
3231 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003232 return mTokenTable[t].pText;
3233 }
3234
Jack Palevich21a15a22009-05-11 14:49:29 -07003235 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003236 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003237 }
3238
3239 void inp() {
3240 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003241 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003242 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003243 dptr = 0;
3244 ch = dch;
3245 }
3246 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003247 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003248#if 0
3249 printf("ch='%c' 0x%x\n", ch, ch);
3250#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003251 }
3252
3253 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003254 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003255 }
3256
Jack Palevichb4758ff2009-06-12 12:49:14 -07003257 /* read a character constant, advances ch to after end of constant */
3258 int getq() {
3259 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003260 if (ch == '\\') {
3261 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003262 if (isoctal(ch)) {
3263 // 1 to 3 octal characters.
3264 val = 0;
3265 for(int i = 0; i < 3; i++) {
3266 if (isoctal(ch)) {
3267 val = (val << 3) + ch - '0';
3268 inp();
3269 }
3270 }
3271 return val;
3272 } else if (ch == 'x' || ch == 'X') {
3273 // N hex chars
3274 inp();
3275 if (! isxdigit(ch)) {
3276 error("'x' character escape requires at least one digit.");
3277 } else {
3278 val = 0;
3279 while (isxdigit(ch)) {
3280 int d = ch;
3281 if (isdigit(d)) {
3282 d -= '0';
3283 } else if (d <= 'F') {
3284 d = d - 'A' + 10;
3285 } else {
3286 d = d - 'a' + 10;
3287 }
3288 val = (val << 4) + d;
3289 inp();
3290 }
3291 }
3292 } else {
3293 int val = ch;
3294 switch (ch) {
3295 case 'a':
3296 val = '\a';
3297 break;
3298 case 'b':
3299 val = '\b';
3300 break;
3301 case 'f':
3302 val = '\f';
3303 break;
3304 case 'n':
3305 val = '\n';
3306 break;
3307 case 'r':
3308 val = '\r';
3309 break;
3310 case 't':
3311 val = '\t';
3312 break;
3313 case 'v':
3314 val = '\v';
3315 break;
3316 case '\\':
3317 val = '\\';
3318 break;
3319 case '\'':
3320 val = '\'';
3321 break;
3322 case '"':
3323 val = '"';
3324 break;
3325 case '?':
3326 val = '?';
3327 break;
3328 default:
3329 error("Undefined character escape %c", ch);
3330 break;
3331 }
3332 inp();
3333 return val;
3334 }
3335 } else {
3336 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003337 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003338 return val;
3339 }
3340
3341 static bool isoctal(int ch) {
3342 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003343 }
3344
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003345 bool acceptCh(int c) {
3346 bool result = c == ch;
3347 if (result) {
3348 pdef(ch);
3349 inp();
3350 }
3351 return result;
3352 }
3353
3354 bool acceptDigitsCh() {
3355 bool result = false;
3356 while (isdigit(ch)) {
3357 result = true;
3358 pdef(ch);
3359 inp();
3360 }
3361 return result;
3362 }
3363
3364 void parseFloat() {
3365 tok = TOK_NUM_DOUBLE;
3366 // mTokenString already has the integral part of the number.
3367 acceptCh('.');
3368 acceptDigitsCh();
3369 bool doExp = true;
3370 if (acceptCh('e') || acceptCh('E')) {
3371 // Don't need to do any extra work
3372 } else if (ch == 'f' || ch == 'F') {
3373 pdef('e'); // So it can be parsed by strtof.
3374 inp();
3375 tok = TOK_NUM_FLOAT;
3376 } else {
3377 doExp = false;
3378 }
3379 if (doExp) {
3380 bool digitsRequired = acceptCh('-');
3381 bool digitsFound = acceptDigitsCh();
3382 if (digitsRequired && ! digitsFound) {
3383 error("malformed exponent");
3384 }
3385 }
3386 char* pText = mTokenString.getUnwrapped();
3387 if (tok == TOK_NUM_FLOAT) {
3388 tokd = strtof(pText, 0);
3389 } else {
3390 tokd = strtod(pText, 0);
3391 }
3392 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
3393 }
3394
Jack Palevich21a15a22009-05-11 14:49:29 -07003395 void next() {
3396 int l, a;
3397
Jack Palevich546b2242009-05-13 15:10:04 -07003398 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003399 if (ch == '#') {
3400 inp();
3401 next();
3402 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003403 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003404 } else if (tok == TOK_PRAGMA) {
3405 doPragma();
3406 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003407 error("Unsupported preprocessor directive \"%s\"",
3408 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003409 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003410 }
3411 inp();
3412 }
3413 tokl = 0;
3414 tok = ch;
3415 /* encode identifiers & numbers */
3416 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003417 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003418 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003419 pdef(ch);
3420 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003421 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003422 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003423 // Start of a numeric constant. Could be integer, float, or
3424 // double, won't know until we look further.
3425 if (ch == '.' || ch == 'e' || ch == 'e'
3426 || ch == 'f' || ch == 'F') {
3427 parseFloat();
3428 } else {
3429 // It's an integer constant
3430 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
3431 tok = TOK_NUM;
3432 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003433 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003434 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
3435 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003436 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07003437 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3438 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003439 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07003440 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003441 dch = ch;
3442 inp();
3443 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003444 }
3445 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003446 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003447 inp();
3448 if (tok == '\'') {
3449 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003450 tokc = getq();
3451 if (ch != '\'') {
3452 error("Expected a ' character, got %c", ch);
3453 } else {
3454 inp();
3455 }
Jack Palevich546b2242009-05-13 15:10:04 -07003456 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003457 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003458 while (ch && ch != EOF) {
3459 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003460 inp();
3461 inp();
3462 if (ch == '/')
3463 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003464 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003465 if (ch == EOF) {
3466 error("End of file inside comment.");
3467 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003468 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003469 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003470 } else if ((tok == '/') & (ch == '/')) {
3471 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003472 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003473 inp();
3474 }
3475 inp();
3476 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003477 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003478 const char* t = operatorChars;
3479 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003480 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003481 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003482 tokl = operatorLevel[opIndex];
3483 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003484 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003485#if 0
3486 printf("%c%c -> tokl=%d tokc=0x%x\n",
3487 l, a, tokl, tokc);
3488#endif
3489 if (a == ch) {
3490 inp();
3491 tok = TOK_DUMMY; /* dummy token for double tokens */
3492 }
3493 break;
3494 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003495 opIndex++;
3496 }
3497 if (l == 0) {
3498 tokl = 0;
3499 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003500 }
3501 }
3502 }
3503#if 0
3504 {
Jack Palevich569f1352009-06-29 14:29:08 -07003505 String buf;
3506 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07003507 fprintf(stderr, "%s\n", buf.getUnwrapped());
3508 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003509#endif
3510 }
3511
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003512 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003513 next();
3514 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003515 String* pName = new String();
3516 while (isspace(ch)) {
3517 inp();
3518 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003519 if (ch == '(') {
3520 delete pName;
3521 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003522 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003523 }
3524 while (isspace(ch)) {
3525 inp();
3526 }
Jack Palevich569f1352009-06-29 14:29:08 -07003527 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003528 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003529 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003530 inp();
3531 }
Jack Palevich569f1352009-06-29 14:29:08 -07003532 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3533 memcpy(pDefn, value.getUnwrapped(), value.len());
3534 pDefn[value.len()] = 0;
3535 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003536 }
3537
Jack Palevicheedf9d22009-06-04 16:23:40 -07003538 void doPragma() {
3539 // # pragma name(val)
3540 int state = 0;
3541 while(ch != EOF && ch != '\n' && state < 10) {
3542 switch(state) {
3543 case 0:
3544 if (isspace(ch)) {
3545 inp();
3546 } else {
3547 state++;
3548 }
3549 break;
3550 case 1:
3551 if (isalnum(ch)) {
3552 mPragmas.append(ch);
3553 inp();
3554 } else if (ch == '(') {
3555 mPragmas.append(0);
3556 inp();
3557 state++;
3558 } else {
3559 state = 11;
3560 }
3561 break;
3562 case 2:
3563 if (isalnum(ch)) {
3564 mPragmas.append(ch);
3565 inp();
3566 } else if (ch == ')') {
3567 mPragmas.append(0);
3568 inp();
3569 state = 10;
3570 } else {
3571 state = 11;
3572 }
3573 break;
3574 }
3575 }
3576 if(state != 10) {
3577 error("Unexpected pragma syntax");
3578 }
3579 mPragmaStringCount += 2;
3580 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003581
Jack Palevichac0e95e2009-05-29 13:53:44 -07003582 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003583 mErrorBuf.printf("%ld: ", file->getLine());
3584 mErrorBuf.vprintf(fmt, ap);
3585 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003586 }
3587
Jack Palevich8b0624c2009-05-20 12:12:06 -07003588 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003589 if (tok != c) {
3590 error("'%c' expected", c);
3591 }
3592 next();
3593 }
3594
Jack Palevich86351982009-06-30 18:09:56 -07003595 bool accept(intptr_t c) {
3596 if (tok == c) {
3597 next();
3598 return true;
3599 }
3600 return false;
3601 }
3602
Jack Palevich40600de2009-07-01 15:32:35 -07003603 bool acceptStringLiteral() {
3604 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003605 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003606 // This while loop merges multiple adjacent string constants.
3607 while (tok == '"') {
3608 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003609 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003610 }
3611 if (ch != '"') {
3612 error("Unterminated string constant.");
3613 }
3614 inp();
3615 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003616 }
Jack Palevich40600de2009-07-01 15:32:35 -07003617 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003618 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003619 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003620 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003621
3622 return true;
3623 }
3624 return false;
3625 }
3626 /* Parse and evaluate a unary expression.
3627 * allowAssignment is true if '=' parsing wanted (quick hack)
3628 */
3629 void unary(bool allowAssignment) {
3630 intptr_t n, t, a;
3631 t = 0;
3632 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3633 if (acceptStringLiteral()) {
3634 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003635 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003636 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003637 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003638 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003639 t = tok;
3640 next();
3641 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003642 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003643 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003644 // Align to 4-byte boundary
3645 glo = (char*) (((intptr_t) glo + 3) & -4);
3646 * (float*) glo = (float) ad;
3647 pGen->loadFloat((int) glo, mkpFloat);
3648 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003649 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003650 // Align to 8-byte boundary
3651 glo = (char*) (((intptr_t) glo + 7) & -8);
3652 * (double*) glo = ad;
3653 pGen->loadFloat((int) glo, mkpDouble);
3654 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 } else if (c == 2) {
3656 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003657 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003658 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003659 pGen->gUnaryCmp(a, mkpInt);
3660 else if (t == '+') {
3661 // ignore unary plus.
3662 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003663 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003664 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003665 } else if (t == '(') {
3666 expr();
3667 skip(')');
3668 } else if (t == '*') {
Jack Palevich3f226492009-07-02 14:46:19 -07003669 /* This is a pointer dereference, but we currently only
3670 * support a pointer dereference if it's immediately
3671 * in front of a cast. So parse the cast right here.
3672 */
Jack Palevich21a15a22009-05-11 14:49:29 -07003673 skip('(');
Jack Palevich3f226492009-07-02 14:46:19 -07003674 Type* pCast = expectCastTypeDeclaration(mLocalArena);
3675 // We currently only handle 3 types of cast:
3676 // (int*), (char*) , (int (*)())
3677 if(typeEqual(pCast, mkpIntPtr)) {
3678 t = TOK_INT;
3679 } else if (typeEqual(pCast, mkpCharPtr)) {
3680 t = TOK_CHAR;
Jack Palevich9cbd2262009-07-08 16:48:41 -07003681 } else if (typeEqual(pCast, mkpFloatPtr)) {
3682 t = TOK_FLOAT;
3683 } else if (typeEqual(pCast, mkpDoublePtr)) {
3684 t = TOK_DOUBLE;
Jack Palevich3f226492009-07-02 14:46:19 -07003685 } else if (typeEqual(pCast, mkpPtrIntFn)){
Jack Palevich21a15a22009-05-11 14:49:29 -07003686 t = 0;
Jack Palevich3f226492009-07-02 14:46:19 -07003687 } else {
3688 String buffer;
3689 decodeType(buffer, pCast);
3690 error("Unsupported cast type %s", buffer.getUnwrapped());
3691 decodeType(buffer, mkpPtrIntFn);
Jack Palevich21a15a22009-05-11 14:49:29 -07003692 }
3693 skip(')');
Jack Palevich40600de2009-07-01 15:32:35 -07003694 unary(false);
Jack Palevich95727a02009-07-06 12:07:15 -07003695 if (accept('=')) {
Jack Palevich1cdef202009-05-22 12:06:27 -07003696 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003697 expr();
Jack Palevich9eed7a22009-07-06 17:24:34 -07003698 pGen->storeR0ToTOS(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003699 } else if (t) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003700 pGen->loadR0FromR0(pCast);
Jack Palevich21a15a22009-05-11 14:49:29 -07003701 }
Jack Palevich3f226492009-07-02 14:46:19 -07003702 // Else we fall through to the function call below, with
3703 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003704 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003705 VariableInfo* pVI = VI(tok);
3706 pGen->leaR0((int) pVI->pAddress,
3707 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003708 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003709 } else if (t == EOF ) {
3710 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003711 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003712 // Don't have to do anything special here, the error
3713 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003714 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003715 if (!isDefined(t)) {
3716 mGlobals.add(t);
3717 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003718 }
Jack Palevich8df46192009-07-07 14:48:51 -07003719 VariableInfo* pVI = VI(t);
3720 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003721 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003722 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003723 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003724 if (tok == '(') {
3725 pVI->pType = mkpIntFn;
3726 } else {
3727 pVI->pType = mkpInt;
3728 }
Jack Palevich8df46192009-07-07 14:48:51 -07003729 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003730 }
Jack Palevich40600de2009-07-01 15:32:35 -07003731 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003732 /* assignment */
3733 next();
3734 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003735 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003736 } else if (tok != '(') {
3737 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003738 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003739 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003740 }
Jack Palevich8df46192009-07-07 14:48:51 -07003741 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003742 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003743 next();
3744 }
3745 }
3746 }
3747 }
3748
3749 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003750 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003751 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003752 VariableInfo* pVI = NULL;
3753 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003754 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003755 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003756 } else {
3757 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003758 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003759 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003760 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003761 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003762 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003763 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003764 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003765 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003766 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003767 if (! varArgs && !pArgList) {
3768 error ("Unexpected argument.");
3769 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003770 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003771 Type* pTargetType;
3772 if (pArgList) {
3773 pTargetType = pArgList->pHead;
3774 pArgList = pArgList->pTail;
3775 } else {
3776 pTargetType = pGen->getR0Type();
3777 if (pTargetType->tag == TY_FLOAT) {
3778 pTargetType = mkpDouble;
3779 }
3780 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003781 if (pTargetType->tag == TY_VOID) {
3782 error("Can't pass void value for argument %d",
3783 argCount + 1);
3784 } else {
3785 pGen->convertR0(pTargetType);
3786 l += pGen->storeR0ToArg(l);
3787 }
Jack Palevich95727a02009-07-06 12:07:15 -07003788 if (accept(',')) {
3789 // fine
3790 } else if ( tok != ')') {
3791 error("Expected ',' or ')'");
3792 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003793 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003794 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003795 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003796 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003797 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003798 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003799 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003800 if (!n) {
3801 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003802 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3803 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003804 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003805 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003806 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003807 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3808 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003809 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003810 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003811 }
3812 }
3813
Jack Palevich40600de2009-07-01 15:32:35 -07003814 /* Recursive descent parser for binary operations.
3815 */
3816 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003817 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003818 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003819 if (level-- == 1)
3820 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003821 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003822 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003823 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003824 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003825 n = tok;
3826 t = tokc;
3827 next();
3828
Jack Palevich40600de2009-07-01 15:32:35 -07003829 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003830 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003831 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003832 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003833 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003834 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003835
Jack Palevich40600de2009-07-01 15:32:35 -07003836 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003837 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003838 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003839 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003840 }
3841 }
3842 }
3843 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003844 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003845 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003846 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003847 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003848 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003849 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003850 }
3851 }
3852 }
3853
3854 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003855 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003856 }
3857
3858 int test_expr() {
3859 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003860 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003861 }
3862
Jack Palevicha6baa232009-06-12 11:25:59 -07003863 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003864 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003865
Jack Palevich95727a02009-07-06 12:07:15 -07003866 Type* pBaseType;
3867 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003868 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003869 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003870 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003871 next();
3872 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003873 a = test_expr();
3874 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003875 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003876 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003877 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003878 n = pGen->gjmp(0); /* jmp */
3879 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003880 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003881 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003882 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003883 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003884 }
Jack Palevich546b2242009-05-13 15:10:04 -07003885 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 t = tok;
3887 next();
3888 skip('(');
3889 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003890 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 a = test_expr();
3892 } else {
3893 if (tok != ';')
3894 expr();
3895 skip(';');
3896 n = codeBuf.getPC();
3897 a = 0;
3898 if (tok != ';')
3899 a = test_expr();
3900 skip(';');
3901 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003902 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003903 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003904 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003905 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003906 n = t + 4;
3907 }
3908 }
3909 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003910 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003911 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003912 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003913 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003914 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003915 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003916 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003917 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003918 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003919 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003920 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003921 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003922 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003923 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003924 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003925 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003926 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003927 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003928 if (pReturnType->tag == TY_VOID) {
3929 error("Must not return a value from a void function");
3930 } else {
3931 pGen->convertR0(pReturnType);
3932 }
3933 } else {
3934 if (pReturnType->tag != TY_VOID) {
3935 error("Must specify a value here");
3936 }
Jack Palevich8df46192009-07-07 14:48:51 -07003937 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003938 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003939 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003940 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003941 } else if (tok != ';')
3942 expr();
3943 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003944 }
3945 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003946
Jack Palevich3f226492009-07-02 14:46:19 -07003947 bool typeEqual(Type* a, Type* b) {
3948 if (a == b) {
3949 return true;
3950 }
3951 if (a == NULL || b == NULL) {
3952 return false;
3953 }
3954 TypeTag at = a->tag;
3955 if (at != b->tag) {
3956 return false;
3957 }
3958 if (at == TY_POINTER) {
3959 return typeEqual(a->pHead, b->pHead);
3960 } else if (at == TY_FUNC || at == TY_PARAM) {
3961 return typeEqual(a->pHead, b->pHead)
3962 && typeEqual(a->pTail, b->pTail);
3963 }
3964 return true;
3965 }
3966
Jack Palevich86351982009-06-30 18:09:56 -07003967 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3968 assert(tag >= TY_INT && tag <= TY_PARAM);
3969 Type* pType = (Type*) arena.alloc(sizeof(Type));
3970 memset(pType, 0, sizeof(*pType));
3971 pType->tag = tag;
3972 pType->pHead = pHead;
3973 pType->pTail = pTail;
3974 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003975 }
3976
Jack Palevich3f226492009-07-02 14:46:19 -07003977 Type* createPtrType(Type* pType, Arena& arena) {
3978 return createType(TY_POINTER, pType, NULL, arena);
3979 }
3980
3981 /**
3982 * Try to print a type in declaration order
3983 */
Jack Palevich86351982009-06-30 18:09:56 -07003984 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003985 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003986 if (pType == NULL) {
3987 buffer.appendCStr("null");
3988 return;
3989 }
Jack Palevich3f226492009-07-02 14:46:19 -07003990 decodeTypeImp(buffer, pType);
3991 }
3992
3993 void decodeTypeImp(String& buffer, Type* pType) {
3994 decodeTypeImpPrefix(buffer, pType);
3995
Jack Palevich86351982009-06-30 18:09:56 -07003996 String temp;
3997 if (pType->id != 0) {
3998 decodeToken(temp, pType->id);
3999 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004000 }
4001
4002 decodeTypeImpPostfix(buffer, pType);
4003 }
4004
4005 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4006 TypeTag tag = pType->tag;
4007
4008 if (tag >= TY_INT && tag <= TY_VOID) {
4009 switch (tag) {
4010 case TY_INT:
4011 buffer.appendCStr("int");
4012 break;
4013 case TY_CHAR:
4014 buffer.appendCStr("char");
4015 break;
4016 case TY_VOID:
4017 buffer.appendCStr("void");
4018 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004019 case TY_FLOAT:
4020 buffer.appendCStr("float");
4021 break;
4022 case TY_DOUBLE:
4023 buffer.appendCStr("double");
4024 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004025 default:
4026 break;
4027 }
Jack Palevich86351982009-06-30 18:09:56 -07004028 buffer.append(' ');
4029 }
Jack Palevich3f226492009-07-02 14:46:19 -07004030
4031 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004032 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004033 break;
4034 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004035 break;
4036 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004037 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004038 case TY_FLOAT:
4039 break;
4040 case TY_DOUBLE:
4041 break;
Jack Palevich86351982009-06-30 18:09:56 -07004042 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004043 decodeTypeImpPrefix(buffer, pType->pHead);
4044 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4045 buffer.append('(');
4046 }
4047 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004048 break;
4049 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004050 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004051 break;
4052 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004053 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004054 break;
4055 default:
4056 String temp;
4057 temp.printf("Unknown tag %d", pType->tag);
4058 buffer.append(temp);
4059 break;
4060 }
Jack Palevich3f226492009-07-02 14:46:19 -07004061 }
4062
4063 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4064 TypeTag tag = pType->tag;
4065
4066 switch(tag) {
4067 case TY_POINTER:
4068 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4069 buffer.append(')');
4070 }
4071 decodeTypeImpPostfix(buffer, pType->pHead);
4072 break;
4073 case TY_FUNC:
4074 buffer.append('(');
4075 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4076 decodeTypeImp(buffer, pArg);
4077 if (pArg->pTail) {
4078 buffer.appendCStr(", ");
4079 }
4080 }
4081 buffer.append(')');
4082 break;
4083 default:
4084 break;
Jack Palevich86351982009-06-30 18:09:56 -07004085 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004086 }
4087
Jack Palevich86351982009-06-30 18:09:56 -07004088 void printType(Type* pType) {
4089 String buffer;
4090 decodeType(buffer, pType);
4091 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004092 }
4093
Jack Palevich86351982009-06-30 18:09:56 -07004094 Type* acceptPrimitiveType(Arena& arena) {
4095 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004096 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004097 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004098 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004099 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004100 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004101 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004102 } else if (tok == TOK_FLOAT) {
4103 pType = mkpFloat;
4104 } else if (tok == TOK_DOUBLE) {
4105 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004106 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004107 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004108 }
4109 next();
Jack Palevich86351982009-06-30 18:09:56 -07004110 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004111 }
4112
Jack Palevich3f226492009-07-02 14:46:19 -07004113 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4114 Arena& arena) {
4115 tokenid_t declName = 0;
4116 pType = acceptDecl2(pType, declName, nameAllowed,
4117 nameRequired, arena);
4118 if (declName) {
4119 // Clone the parent type so we can set a unique ID
4120 pType = createType(pType->tag, pType->pHead,
4121 pType->pTail, arena);
4122
Jack Palevich86351982009-06-30 18:09:56 -07004123 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004124 }
Jack Palevich3f226492009-07-02 14:46:19 -07004125 // fprintf(stderr, "Parsed a declaration: ");
4126 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004127 return pType;
4128 }
4129
Jack Palevich3f226492009-07-02 14:46:19 -07004130 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4131 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004132 if (! pType) {
4133 error("Expected a declaration");
4134 }
4135 return pType;
4136 }
4137
Jack Palevich3f226492009-07-02 14:46:19 -07004138 /* Used for accepting types that appear in casts */
4139 Type* acceptCastTypeDeclaration(Arena& arena) {
4140 Type* pType = acceptPrimitiveType(arena);
4141 if (pType) {
4142 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004143 }
Jack Palevich86351982009-06-30 18:09:56 -07004144 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004145 }
4146
Jack Palevich3f226492009-07-02 14:46:19 -07004147 Type* expectCastTypeDeclaration(Arena& arena) {
4148 Type* pType = acceptCastTypeDeclaration(arena);
4149 if (! pType) {
4150 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004151 }
Jack Palevich3f226492009-07-02 14:46:19 -07004152 return pType;
4153 }
4154
4155 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4156 bool nameAllowed, bool nameRequired, Arena& arena) {
4157 int ptrCounter = 0;
4158 while (accept('*')) {
4159 ptrCounter++;
4160 }
4161 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4162 while (ptrCounter-- > 0) {
4163 pType = createType(TY_POINTER, pType, NULL, arena);
4164 }
4165 return pType;
4166 }
4167
4168 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4169 bool nameAllowed, bool nameRequired, Arena& arena) {
4170 // direct-dcl :
4171 // name
4172 // (dcl)
4173 // direct-dcl()
4174 // direct-dcl[]
4175 Type* pNewHead = NULL;
4176 if (accept('(')) {
4177 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4178 nameRequired, arena);
4179 skip(')');
4180 } else if ((declName = acceptSymbol()) != 0) {
4181 if (nameAllowed == false && declName) {
4182 error("Symbol %s not allowed here", nameof(declName));
4183 } else if (nameRequired && ! declName) {
4184 String temp;
4185 decodeToken(temp, tok);
4186 error("Expected symbol. Got %s", temp.getUnwrapped());
4187 }
4188 }
4189 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004190 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004191 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004192 pType = createType(TY_FUNC, pType, pTail, arena);
4193 skip(')');
4194 }
Jack Palevich3f226492009-07-02 14:46:19 -07004195
4196 if (pNewHead) {
4197 Type* pA = pNewHead;
4198 while (pA->pHead) {
4199 pA = pA->pHead;
4200 }
4201 pA->pHead = pType;
4202 pType = pNewHead;
4203 }
Jack Palevich86351982009-06-30 18:09:56 -07004204 return pType;
4205 }
4206
Jack Palevich3f226492009-07-02 14:46:19 -07004207 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004208 Type* pHead = NULL;
4209 Type* pTail = NULL;
4210 for(;;) {
4211 Type* pBaseArg = acceptPrimitiveType(arena);
4212 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004213 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4214 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004215 if (pArg) {
4216 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4217 if (!pHead) {
4218 pHead = pParam;
4219 pTail = pParam;
4220 } else {
4221 pTail->pTail = pParam;
4222 pTail = pParam;
4223 }
4224 }
4225 }
4226 if (! accept(',')) {
4227 break;
4228 }
4229 }
4230 return pHead;
4231 }
4232
4233 Type* expectPrimitiveType(Arena& arena) {
4234 Type* pType = acceptPrimitiveType(arena);
4235 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004236 String buf;
4237 decodeToken(buf, tok);
4238 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004239 }
Jack Palevich86351982009-06-30 18:09:56 -07004240 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004241 }
4242
Jack Palevich86351982009-06-30 18:09:56 -07004243 void addGlobalSymbol(Type* pDecl) {
4244 tokenid_t t = pDecl->id;
4245 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004246 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004247 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004248 }
Jack Palevich86351982009-06-30 18:09:56 -07004249 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004250 }
4251
Jack Palevich86351982009-06-30 18:09:56 -07004252 void reportDuplicate(tokenid_t t) {
4253 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004254 }
4255
Jack Palevich86351982009-06-30 18:09:56 -07004256 void addLocalSymbol(Type* pDecl) {
4257 tokenid_t t = pDecl->id;
4258 if (mLocals.isDefinedAtCurrentLevel(t)) {
4259 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004260 }
Jack Palevich86351982009-06-30 18:09:56 -07004261 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004262 }
4263
Jack Palevich95727a02009-07-06 12:07:15 -07004264 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004265 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004266
Jack Palevich95727a02009-07-06 12:07:15 -07004267 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004268 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004269 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4270 if (!pDecl) {
4271 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004272 }
Jack Palevich86351982009-06-30 18:09:56 -07004273 int variableAddress = 0;
4274 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004275 size_t alignment = pGen->alignmentOf(pDecl);
4276 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004277 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004278 variableAddress = -loc;
4279 VI(pDecl->id)->pAddress = (void*) variableAddress;
4280 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004281 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004282 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004283 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004284 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004285 if (tok == ',')
4286 next();
4287 }
4288 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004289 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004290 }
4291 }
4292
Jack Palevichf1728be2009-06-12 13:53:51 -07004293 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004294 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004295 }
4296
Jack Palevich569f1352009-06-29 14:29:08 -07004297 void decodeToken(String& buffer, tokenid_t token) {
4298 if (token == EOF ) {
4299 buffer.printf("EOF");
4300 } else if (token == TOK_NUM) {
4301 buffer.printf("numeric constant");
4302 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004303 if (token < 32) {
4304 buffer.printf("'\\x%02x'", token);
4305 } else {
4306 buffer.printf("'%c'", token);
4307 }
Jack Palevich569f1352009-06-29 14:29:08 -07004308 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4309 buffer.printf("keyword \"%s\"", nameof(token));
4310 } else {
4311 buffer.printf("symbol \"%s\"", nameof(token));
4312 }
4313 }
4314
Jack Palevich40600de2009-07-01 15:32:35 -07004315 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004316 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004317 if (!result) {
4318 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07004319 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07004320 error("Expected symbol. Got %s", temp.getUnwrapped());
4321 }
4322 return result;
4323 }
4324
Jack Palevich86351982009-06-30 18:09:56 -07004325 tokenid_t acceptSymbol() {
4326 tokenid_t result = 0;
4327 if (tok >= TOK_SYMBOL) {
4328 result = tok;
4329 next();
Jack Palevich86351982009-06-30 18:09:56 -07004330 }
4331 return result;
4332 }
4333
Jack Palevichb7c81e92009-06-04 19:56:13 -07004334 void globalDeclarations() {
4335 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004336 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4337 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004338 break;
4339 }
Jack Palevich86351982009-06-30 18:09:56 -07004340 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4341 if (!pDecl) {
4342 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004343 }
Jack Palevich86351982009-06-30 18:09:56 -07004344 if (! isDefined(pDecl->id)) {
4345 addGlobalSymbol(pDecl);
4346 }
4347 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004348 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004349 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004350 }
Jack Palevich86351982009-06-30 18:09:56 -07004351 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004352 // it's a variable declaration
4353 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004354 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004355 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004356 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004357 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004358 }
Jack Palevich86351982009-06-30 18:09:56 -07004359 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004360 if (tok == TOK_NUM) {
4361 if (name) {
4362 * (int*) name->pAddress = tokc;
4363 }
4364 next();
4365 } else {
4366 error("Expected an integer constant");
4367 }
4368 }
Jack Palevich86351982009-06-30 18:09:56 -07004369 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004370 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004371 }
Jack Palevich86351982009-06-30 18:09:56 -07004372 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4373 if (!pDecl) {
4374 break;
4375 }
4376 if (! isDefined(pDecl->id)) {
4377 addGlobalSymbol(pDecl);
4378 }
4379 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004380 }
4381 skip(';');
4382 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004383 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004384 if (accept(';')) {
4385 // forward declaration.
4386 } else {
4387 if (name) {
4388 /* patch forward references (XXX: does not work for function
4389 pointers) */
4390 pGen->gsym((int) name->pForward);
4391 /* put function address */
4392 name->pAddress = (void*) codeBuf.getPC();
4393 }
4394 // Calculate stack offsets for parameters
4395 mLocals.pushLevel();
4396 intptr_t a = 8;
4397 int argCount = 0;
4398 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4399 Type* pArg = pP->pHead;
4400 addLocalSymbol(pArg);
4401 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004402 size_t alignment = pGen->alignmentOf(pArg);
4403 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004404 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004405 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004406 argCount++;
4407 }
4408 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004409 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004410 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004411 block(0, true);
4412 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004413 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004414 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004415 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004416 }
4417 }
4418 }
4419
Jack Palevich9cbd2262009-07-08 16:48:41 -07004420 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4421 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4422 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004423 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004424 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004425 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004426 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004427 char* result = (char*) base;
4428 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004429 return result;
4430 }
4431
Jack Palevich21a15a22009-05-11 14:49:29 -07004432 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004433 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004434 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004435 pGlobalBase = 0;
4436 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004437 if (pGen) {
4438 delete pGen;
4439 pGen = 0;
4440 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004441 if (file) {
4442 delete file;
4443 file = 0;
4444 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004445 }
4446
4447 void clear() {
4448 tok = 0;
4449 tokc = 0;
4450 tokl = 0;
4451 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004452 rsym = 0;
4453 loc = 0;
4454 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004455 dptr = 0;
4456 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004457 file = 0;
4458 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004459 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004460 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004461 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004462
Jack Palevich22305132009-05-13 10:58:45 -07004463 void setArchitecture(const char* architecture) {
4464 delete pGen;
4465 pGen = 0;
4466
4467 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004468#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004469 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004470 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004471 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004472#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004473#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004474 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004475 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004476 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004477#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004478 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004479 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004480 }
4481 }
4482
4483 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004484#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004485 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004486#elif defined(DEFAULT_X86_CODEGEN)
4487 pGen = new X86CodeGenerator();
4488#endif
4489 }
4490 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004491 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004492 } else {
4493 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07004494 }
4495 }
4496
Jack Palevich77ae76e2009-05-10 19:59:24 -07004497public:
Jack Palevich22305132009-05-13 10:58:45 -07004498 struct args {
4499 args() {
4500 architecture = 0;
4501 }
4502 const char* architecture;
4503 };
4504
Jack Paleviche7b59062009-05-19 17:12:17 -07004505 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004506 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004507 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004508
Jack Paleviche7b59062009-05-19 17:12:17 -07004509 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004510 cleanup();
4511 }
4512
Jack Palevich1cdef202009-05-22 12:06:27 -07004513 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004514 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004515
4516 cleanup();
4517 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004518 mTokenTable.setArena(&mGlobalArena);
4519 mGlobals.setArena(&mGlobalArena);
4520 mGlobals.setTokenTable(&mTokenTable);
4521 mLocals.setArena(&mLocalArena);
4522 mLocals.setTokenTable(&mTokenTable);
4523
4524 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07004525 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004526 codeBuf.init(ALLOC_SIZE);
4527 setArchitecture(NULL);
4528 if (!pGen) {
4529 return -1;
4530 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004531#ifdef PROVIDE_TRACE_CODEGEN
4532 pGen = new TraceCodeGenerator(pGen);
4533#endif
4534 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004535 pGen->init(&codeBuf);
4536 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004537 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4538 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004539 inp();
4540 next();
4541 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004542 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004543 result = pGen->finishCompile();
4544 if (result == 0) {
4545 if (mErrorBuf.len()) {
4546 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004547 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004548 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004549 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004550 }
4551
Jack Palevich86351982009-06-30 18:09:56 -07004552 void createPrimitiveTypes() {
4553 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4554 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4555 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004556 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4557 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004558 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004559 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4560 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004561 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4562 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004563 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004564 }
4565
Jack Palevicha6baa232009-06-12 11:25:59 -07004566 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004567 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004568 }
4569
Jack Palevich569f1352009-06-29 14:29:08 -07004570 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004571 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004572 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004573 }
4574
Jack Palevich569f1352009-06-29 14:29:08 -07004575 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004576 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004577 error("Undefined forward reference: %s",
4578 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004579 }
4580 return true;
4581 }
4582
Jack Palevich21a15a22009-05-11 14:49:29 -07004583 int dump(FILE* out) {
4584 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4585 return 0;
4586 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004587
Jack Palevicha6535612009-05-13 16:24:17 -07004588 int disassemble(FILE* out) {
4589 return pGen->disassemble(out);
4590 }
4591
Jack Palevich1cdef202009-05-22 12:06:27 -07004592 /* Look through the symbol table to find a symbol.
4593 * If found, return its value.
4594 */
4595 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004596 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4597 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004598 if (pVariableInfo) {
4599 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004600 }
4601 return NULL;
4602 }
4603
Jack Palevicheedf9d22009-06-04 16:23:40 -07004604 void getPragmas(ACCsizei* actualStringCount,
4605 ACCsizei maxStringCount, ACCchar** strings) {
4606 int stringCount = mPragmaStringCount;
4607 if (actualStringCount) {
4608 *actualStringCount = stringCount;
4609 }
4610 if (stringCount > maxStringCount) {
4611 stringCount = maxStringCount;
4612 }
4613 if (strings) {
4614 char* pPragmas = mPragmas.getUnwrapped();
4615 while (stringCount-- > 0) {
4616 *strings++ = pPragmas;
4617 pPragmas += strlen(pPragmas) + 1;
4618 }
4619 }
4620 }
4621
Jack Palevichac0e95e2009-05-29 13:53:44 -07004622 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004623 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004624 }
4625
Jack Palevich77ae76e2009-05-10 19:59:24 -07004626};
4627
Jack Paleviche7b59062009-05-19 17:12:17 -07004628const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004629 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4630
Jack Paleviche7b59062009-05-19 17:12:17 -07004631const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004632 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4633 5, 5, /* ==, != */
4634 9, 10, /* &&, || */
4635 6, 7, 8, /* & ^ | */
4636 2, 2 /* ~ ! */
4637 };
4638
Jack Palevich8b0624c2009-05-20 12:12:06 -07004639#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004640FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004641#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004642
Jack Palevich8b0624c2009-05-20 12:12:06 -07004643#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004644const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004645 0x1, // ++
4646 0xff, // --
4647 0xc1af0f, // *
4648 0xf9f79991, // /
4649 0xf9f79991, // % (With manual assist to swap results)
4650 0xc801, // +
4651 0xd8f7c829, // -
4652 0xe0d391, // <<
4653 0xf8d391, // >>
4654 0xe, // <=
4655 0xd, // >=
4656 0xc, // <
4657 0xf, // >
4658 0x4, // ==
4659 0x5, // !=
4660 0x0, // &&
4661 0x1, // ||
4662 0xc821, // &
4663 0xc831, // ^
4664 0xc809, // |
4665 0xd0f7, // ~
4666 0x4 // !
4667};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004668#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004669
Jack Palevich1cdef202009-05-22 12:06:27 -07004670struct ACCscript {
4671 ACCscript() {
4672 text = 0;
4673 textLength = 0;
4674 accError = ACC_NO_ERROR;
4675 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004676
Jack Palevich1cdef202009-05-22 12:06:27 -07004677 ~ACCscript() {
4678 delete text;
4679 }
Jack Palevich546b2242009-05-13 15:10:04 -07004680
Jack Palevich1cdef202009-05-22 12:06:27 -07004681 void setError(ACCenum error) {
4682 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4683 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004684 }
4685 }
4686
Jack Palevich1cdef202009-05-22 12:06:27 -07004687 ACCenum getError() {
4688 ACCenum result = accError;
4689 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004690 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004691 }
4692
Jack Palevich1cdef202009-05-22 12:06:27 -07004693 Compiler compiler;
4694 char* text;
4695 int textLength;
4696 ACCenum accError;
4697};
4698
4699
4700extern "C"
4701ACCscript* accCreateScript() {
4702 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004703}
Jack Palevich1cdef202009-05-22 12:06:27 -07004704
4705extern "C"
4706ACCenum accGetError( ACCscript* script ) {
4707 return script->getError();
4708}
4709
4710extern "C"
4711void accDeleteScript(ACCscript* script) {
4712 delete script;
4713}
4714
4715extern "C"
4716void accScriptSource(ACCscript* script,
4717 ACCsizei count,
4718 const ACCchar ** string,
4719 const ACCint * length) {
4720 int totalLength = 0;
4721 for(int i = 0; i < count; i++) {
4722 int len = -1;
4723 const ACCchar* s = string[i];
4724 if (length) {
4725 len = length[i];
4726 }
4727 if (len < 0) {
4728 len = strlen(s);
4729 }
4730 totalLength += len;
4731 }
4732 delete script->text;
4733 char* text = new char[totalLength + 1];
4734 script->text = text;
4735 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004736 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004737 for(int i = 0; i < count; i++) {
4738 int len = -1;
4739 const ACCchar* s = string[i];
4740 if (length) {
4741 len = length[i];
4742 }
4743 if (len < 0) {
4744 len = strlen(s);
4745 }
Jack Palevich09555c72009-05-27 12:25:55 -07004746 memcpy(dest, s, len);
4747 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004748 }
4749 text[totalLength] = '\0';
4750}
4751
4752extern "C"
4753void accCompileScript(ACCscript* script) {
4754 int result = script->compiler.compile(script->text, script->textLength);
4755 if (result) {
4756 script->setError(ACC_INVALID_OPERATION);
4757 }
4758}
4759
4760extern "C"
4761void accGetScriptiv(ACCscript* script,
4762 ACCenum pname,
4763 ACCint * params) {
4764 switch (pname) {
4765 case ACC_INFO_LOG_LENGTH:
4766 *params = 0;
4767 break;
4768 }
4769}
4770
4771extern "C"
4772void accGetScriptInfoLog(ACCscript* script,
4773 ACCsizei maxLength,
4774 ACCsizei * length,
4775 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004776 char* message = script->compiler.getErrorMessage();
4777 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004778 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004779 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004780 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004781 if (infoLog && maxLength > 0) {
4782 int trimmedLength = maxLength < messageLength ?
4783 maxLength : messageLength;
4784 memcpy(infoLog, message, trimmedLength);
4785 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004786 }
4787}
4788
4789extern "C"
4790void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4791 ACCvoid ** address) {
4792 void* value = script->compiler.lookup(name);
4793 if (value) {
4794 *address = value;
4795 } else {
4796 script->setError(ACC_INVALID_VALUE);
4797 }
4798}
4799
Jack Palevicheedf9d22009-06-04 16:23:40 -07004800extern "C"
4801void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4802 ACCsizei maxStringCount, ACCchar** strings){
4803 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4804}
4805
-b master422972c2009-06-17 19:13:52 -07004806extern "C"
4807void accDisassemble(ACCscript* script) {
4808 script->compiler.disassemble(stderr);
4809}
4810
Jack Palevicheedf9d22009-06-04 16:23:40 -07004811
Jack Palevich1cdef202009-05-22 12:06:27 -07004812} // namespace acc
4813