blob: fb7ec80bcb5b7e1d2b0b9608e9d6c53db93d3861 [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) {
Jack Palevich45431bc2009-07-13 15:57:26 -07001022 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001023 case TY_INT:
1024 case TY_FLOAT:
1025 if (ea > -LOCAL && ea < LOCAL) {
1026 // Local, fp relative
1027 if (ea < -4095 || ea > 4095) {
1028 error("Offset out of range: %08x", ea);
1029 }
1030 if (ea < 0) {
1031 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1032 } else {
1033 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1034 }
1035 } else{
1036 // Global, absolute
1037 o4(0xE59F1000); // ldr r1, .L1
1038 o4(0xEA000000); // b .L99
1039 o4(ea); // .L1: .word 0
1040 o4(0xE5810000); // .L99: str r0, [r1]
1041 }
1042 break;
1043 case TY_DOUBLE:
1044 if ((ea & 0x7) != 0) {
1045 error("double address is not aligned: %d", ea);
1046 }
1047 if (ea > -LOCAL && ea < LOCAL) {
1048 // Local, fp relative
1049 if (ea < -4095 || ea > 4095) {
1050 error("Offset out of range: %08x", ea);
1051 }
1052 if (ea < 0) {
1053 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1054 o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4]
1055#if 0
1056 // strd doesn't seem to work. Is encoding wrong?
1057 } else if (ea < 0) {
1058 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1059 } else if (ea < 256) {
1060 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1061#endif
1062 } else {
1063 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1064 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1065 }
1066 } else{
1067 // Global, absolute
1068 o4(0xE59F2000); // ldr r2, .L1
1069 o4(0xEA000000); // b .L99
1070 o4(ea); // .L1: .word 0
1071 o4(0xE1C200F0); // .L99: strd r0, [r2]
1072 }
1073 break;
1074 default:
1075 error("Unable to store to type %d", tag);
1076 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001077 }
Jack Palevich22305132009-05-13 10:58:45 -07001078 }
1079
Jack Palevich8df46192009-07-07 14:48:51 -07001080 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001081 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001082 TypeTag tag = collapseType(pType->tag);
1083 switch (tag) {
1084 case TY_INT:
1085 case TY_FLOAT:
1086 if (ea < LOCAL) {
1087 // Local, fp relative
1088 if (ea < -4095 || ea > 4095) {
1089 error("Offset out of range: %08x", ea);
1090 }
1091 if (ea < 0) {
1092 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1093 } else {
1094 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1095 }
1096 } else {
1097 // Global, absolute
1098 o4(0xE59F2000); // ldr r2, .L1
1099 o4(0xEA000000); // b .L99
1100 o4(ea); // .L1: .word ea
1101 o4(0xE5920000); // .L99: ldr r0, [r2]
1102 }
Jack Palevich22305132009-05-13 10:58:45 -07001103
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 if (isIncDec) {
1105 if (tag == TY_INT) {
1106 switch (op) {
1107 case OP_INCREMENT:
1108 o4(0xE2801001); // add r1, r0, #1
1109 break;
1110 case OP_DECREMENT:
1111 o4(0xE2401001); // sub r1, r0, #1
1112 break;
1113 default:
1114 error("unknown opcode: %d", op);
1115 }
1116 if (ea < LOCAL) {
1117 // Local, fp relative
1118 // Don't need range check, was already checked above
1119 if (ea < 0) {
1120 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1121 } else {
1122 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1123 }
1124 } else{
1125 // Global, absolute
1126 // r2 is already set up from before.
1127 o4(0xE5821000); // str r1, [r2]
1128 }
1129 }
1130 else {
1131 error("inc/dec not implemented for float.");
1132 }
1133 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001134 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001135 case TY_DOUBLE:
1136 if ((ea & 0x7) != 0) {
1137 error("double address is not aligned: %d", ea);
1138 }
1139 if (ea < LOCAL) {
1140 // Local, fp relative
1141 if (ea < -4095 || ea > 4095) {
1142 error("Offset out of range: %08x", ea);
1143 }
1144 if (ea < 0) {
1145 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1146 o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4]
1147 } else {
1148 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1149 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1150 }
1151 } else {
1152 // Global, absolute
1153 o4(0xE59F2000); // ldr r2, .L1
1154 o4(0xEA000000); // b .L99
1155 o4(ea); // .L1: .word ea
1156 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1157 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001158 break;
1159 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001160 error("Unable to load type %d", tag);
1161 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001162 }
Jack Palevich8df46192009-07-07 14:48:51 -07001163 setR0Type(pType);
1164 }
1165
1166 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001167 Type* pR0Type = getR0Type();
1168 if (bitsSame(pType, pR0Type)) {
1169 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001170 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001171 TypeTag r0Tag = collapseType(pR0Type->tag);
1172 TypeTag destTag = collapseType(pType->tag);
1173 if (r0Tag == TY_INT) {
1174 if (destTag == TY_FLOAT) {
1175 callRuntime((void*) runtime_int_to_float);
1176 } else {
1177 assert(destTag == TY_DOUBLE);
1178 callRuntime((void*) runtime_int_to_double);
1179 }
1180 } else if (r0Tag == TY_FLOAT) {
1181 if (destTag == TY_INT) {
1182 callRuntime((void*) runtime_float_to_int);
1183 } else {
1184 assert(destTag == TY_DOUBLE);
1185 callRuntime((void*) runtime_float_to_double);
1186 }
1187 } else {
1188 assert (r0Tag == TY_DOUBLE);
1189 if (destTag == TY_INT) {
1190 callRuntime((void*) runtime_double_to_int);
1191 } else {
1192 assert(destTag == TY_FLOAT);
1193 callRuntime((void*) runtime_double_to_float);
1194 }
1195 }
Jack Palevich8df46192009-07-07 14:48:51 -07001196 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001197 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001198 }
1199
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001200 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001201 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001202 return o4(0xE24DDF00); // Placeholder
1203 }
1204
Jack Palevich1a539db2009-07-08 13:04:41 -07001205 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001206 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevichb7718b92009-07-09 22:00:24 -07001207 Type* pR0Type = getR0Type();
1208 TypeTag r0ct = collapseType(pR0Type->tag);
1209 switch(r0ct) {
1210 case TY_INT:
1211 case TY_FLOAT:
1212 if (l < 0 || l > 4096-4) {
1213 error("l out of range for stack offset: 0x%08x", l);
1214 }
1215 o4(0xE58D0000 + l); // str r0, [sp, #l]
1216 return 4;
1217 case TY_DOUBLE: {
1218 // Align to 8 byte boundary
1219 int l2 = (l + 7) & ~7;
1220 if (l2 < 0 || l2 > 4096-8) {
1221 error("l out of range for stack offset: 0x%08x", l);
1222 }
1223 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1224 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1225 return (l2 - l) + 8;
1226 }
1227 default:
1228 assert(false);
1229 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001230 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001231 }
1232
Jack Palevichb7718b92009-07-09 22:00:24 -07001233 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001234 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001235 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001236 // Have to calculate register arg count from actual stack size,
1237 // in order to properly handle ... functions.
1238 int regArgCount = l >> 2;
1239 if (regArgCount > 4) {
1240 regArgCount = 4;
1241 }
1242 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001243 argumentStackUse -= regArgCount * 4;
1244 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1245 }
1246 mStackUse += argumentStackUse;
1247
1248 // Align stack.
1249 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1250 * STACK_ALIGNMENT);
1251 mStackAlignmentAdjustment = 0;
1252 if (missalignment > 0) {
1253 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1254 }
1255 l += mStackAlignmentAdjustment;
1256
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001257 if (l < 0 || l > 0x3FC) {
1258 error("L out of range for stack adjustment: 0x%08x", l);
1259 }
1260 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001261 mStackUse += mStackAlignmentAdjustment;
1262 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1263 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001264 }
1265
Jack Palevich8df46192009-07-07 14:48:51 -07001266 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001267 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001268 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001269 // Forward calls are always short (local)
1270 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001271 }
1272
Jack Palevich8df46192009-07-07 14:48:51 -07001273 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001274 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001275 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001276 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001277 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001278 if (t >= - (1 << 25) && t < (1 << 25)) {
1279 o4(0xEB000000 | encodeAddress(t));
1280 } else {
1281 // Long call.
1282 o4(0xE59FC000); // ldr r12, .L1
1283 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001284 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001285 o4(0xE08CC00F); // .L99: add r12,pc
1286 o4(0xE12FFF3C); // blx r12
1287 }
Jack Palevich22305132009-05-13 10:58:45 -07001288 }
1289
Jack Palevich8df46192009-07-07 14:48:51 -07001290 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001291 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001292 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001293 int argCount = l >> 2;
1294 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001295 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001296 if (adjustedL < 0 || adjustedL > 4096-4) {
1297 error("l out of range for stack offset: 0x%08x", l);
1298 }
1299 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1300 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001301 }
1302
Jack Palevichb7718b92009-07-09 22:00:24 -07001303 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001304 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001305 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001306 // Have to calculate register arg count from actual stack size,
1307 // in order to properly handle ... functions.
1308 int regArgCount = l >> 2;
1309 if (regArgCount > 4) {
1310 regArgCount = 4;
1311 }
1312 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001313 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1314 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001315 if (stackUse) {
1316 if (stackUse < 0 || stackUse > 255) {
1317 error("L out of range for stack adjustment: 0x%08x", l);
1318 }
1319 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001320 mStackUse -= stackUse * 4;
1321 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001322 }
Jack Palevich22305132009-05-13 10:58:45 -07001323 }
1324
Jack Palevicha6535612009-05-13 16:24:17 -07001325 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001326 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001327 }
1328
1329 /* output a symbol and patch all calls to it */
1330 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001331 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001332 int n;
1333 int base = getBase();
1334 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001335 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001336 while (t) {
1337 int data = * (int*) t;
1338 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1339 if (decodedOffset == 0) {
1340 n = 0;
1341 } else {
1342 n = base + decodedOffset; /* next value */
1343 }
1344 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1345 | encodeRelAddress(pc - t - 8);
1346 t = n;
1347 }
1348 }
1349
Jack Palevich1cdef202009-05-22 12:06:27 -07001350 virtual int finishCompile() {
1351#if defined(__arm__)
1352 const long base = long(getBase());
1353 const long curr = long(getPC());
1354 int err = cacheflush(base, curr, 0);
1355 return err;
1356#else
1357 return 0;
1358#endif
1359 }
1360
Jack Palevicha6535612009-05-13 16:24:17 -07001361 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001362#ifdef ENABLE_ARM_DISASSEMBLY
1363 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001364 disasm_interface_t di;
1365 di.di_readword = disassemble_readword;
1366 di.di_printaddr = disassemble_printaddr;
1367 di.di_printf = disassemble_printf;
1368
1369 int base = getBase();
1370 int pc = getPC();
1371 for(int i = base; i < pc; i += 4) {
1372 fprintf(out, "%08x: %08x ", i, *(int*) i);
1373 ::disasm(&di, i, 0);
1374 }
Jack Palevich09555c72009-05-27 12:25:55 -07001375#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001376 return 0;
1377 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001378
Jack Palevich9eed7a22009-07-06 17:24:34 -07001379 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001380 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001381 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001382 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001383 switch(pType->tag) {
1384 case TY_DOUBLE:
1385 return 8;
1386 default:
1387 return 4;
1388 }
1389 }
1390
1391 /**
1392 * Array element alignment (in bytes) for this type of data.
1393 */
1394 virtual size_t sizeOf(Type* pType){
1395 switch(pType->tag) {
1396 case TY_INT:
1397 return 4;
1398 case TY_CHAR:
1399 return 1;
1400 default:
1401 return 0;
1402 case TY_FLOAT:
1403 return 4;
1404 case TY_DOUBLE:
1405 return 8;
1406 case TY_POINTER:
1407 return 4;
1408 }
1409 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001410
1411 virtual size_t stackSizeOf(Type* pType) {
1412 switch(pType->tag) {
1413 case TY_DOUBLE:
1414 return 8;
1415 default:
1416 return 4;
1417 }
1418 }
1419
Jack Palevich22305132009-05-13 10:58:45 -07001420 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001421 static FILE* disasmOut;
1422
1423 static u_int
1424 disassemble_readword(u_int address)
1425 {
1426 return(*((u_int *)address));
1427 }
1428
1429 static void
1430 disassemble_printaddr(u_int address)
1431 {
1432 fprintf(disasmOut, "0x%08x", address);
1433 }
1434
1435 static void
1436 disassemble_printf(const char *fmt, ...) {
1437 va_list ap;
1438 va_start(ap, fmt);
1439 vfprintf(disasmOut, fmt, ap);
1440 va_end(ap);
1441 }
1442
1443 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1444
1445 /** Encode a relative address that might also be
1446 * a label.
1447 */
1448 int encodeAddress(int value) {
1449 int base = getBase();
1450 if (value >= base && value <= getPC() ) {
1451 // This is a label, encode it relative to the base.
1452 value = value - base;
1453 }
1454 return encodeRelAddress(value);
1455 }
1456
1457 int encodeRelAddress(int value) {
1458 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1459 }
Jack Palevich22305132009-05-13 10:58:45 -07001460
Jack Palevichb7718b92009-07-09 22:00:24 -07001461 int calcRegArgCount(Type* pDecl) {
1462 int reg = 0;
1463 Type* pArgs = pDecl->pTail;
1464 while (pArgs && reg < 4) {
1465 Type* pArg = pArgs->pHead;
1466 if ( pArg->tag == TY_DOUBLE) {
1467 int evenReg = (reg + 1) & ~1;
1468 if (evenReg >= 4) {
1469 break;
1470 }
1471 reg = evenReg + 2;
1472 } else {
1473 reg++;
1474 }
1475 pArgs = pArgs->pTail;
1476 }
1477 return reg;
1478 }
1479
1480 /* Pop TOS to R1
1481 * Make sure both R0 and TOS are floats. (Could be ints)
1482 * We know that at least one of R0 and TOS is already a float
1483 */
1484 void setupFloatArgs() {
1485 Type* pR0Type = getR0Type();
1486 Type* pTOSType = getTOSType();
1487 TypeTag tagR0 = collapseType(pR0Type->tag);
1488 TypeTag tagTOS = collapseType(pTOSType->tag);
1489 if (tagR0 != TY_FLOAT) {
1490 assert(tagR0 == TY_INT);
1491 callRuntime((void*) runtime_int_to_float);
1492 }
1493 if (tagTOS != TY_FLOAT) {
1494 assert(tagTOS == TY_INT);
1495 assert(tagR0 == TY_FLOAT);
1496 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1497 o4(0xE59D0004); // ldr r0, [sp, #4]
1498 callRuntime((void*) runtime_int_to_float);
1499 o4(0xE1A01000); // mov r1, r0
1500 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1501 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1502 } else {
1503 // Pop TOS
1504 o4(0xE8BD0002); // ldmfd sp!,{r1}
1505 }
1506 mStackUse -= 4;
1507 popType();
1508 }
1509
1510 /* Pop TOS into R2..R3
1511 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1512 * We know that at least one of R0 and TOS are already a double.
1513 */
1514
1515 void setupDoubleArgs() {
1516 Type* pR0Type = getR0Type();
1517 Type* pTOSType = getTOSType();
1518 TypeTag tagR0 = collapseType(pR0Type->tag);
1519 TypeTag tagTOS = collapseType(pTOSType->tag);
1520 if (tagR0 != TY_DOUBLE) {
1521 if (tagR0 == TY_INT) {
1522 callRuntime((void*) runtime_int_to_double);
1523 } else {
1524 assert(tagR0 == TY_FLOAT);
1525 callRuntime((void*) runtime_float_to_double);
1526 }
1527 }
1528 if (tagTOS != TY_DOUBLE) {
1529 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1530 o4(0xE59D0008); // ldr r0, [sp, #8]
1531 if (tagTOS == TY_INT) {
1532 callRuntime((void*) runtime_int_to_double);
1533 } else {
1534 assert(tagTOS == TY_FLOAT);
1535 callRuntime((void*) runtime_float_to_double);
1536 }
1537 o4(0xE1A02000); // mov r2, r0
1538 o4(0xE1A03001); // mov r3, r1
1539 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1540 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1541 mStackUse -= 4;
1542 } else {
1543 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1544 mStackUse -= 8;
1545 }
1546 popType();
1547 }
1548
1549 void callRuntime(void* fn) {
1550 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001551 o4(0xEA000000); // b .L99
1552 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001553 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001554 }
1555
Jack Palevichb7718b92009-07-09 22:00:24 -07001556 // Integer math:
1557
1558 static int runtime_DIV(int b, int a) {
1559 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001560 }
1561
Jack Palevichb7718b92009-07-09 22:00:24 -07001562 static int runtime_MOD(int b, int a) {
1563 return a % b;
1564 }
1565
1566 // Comparison to zero
1567
1568 static int runtime_is_non_zero_f(float a) {
1569 return a != 0;
1570 }
1571
1572 static int runtime_is_non_zero_d(double a) {
1573 return a != 0;
1574 }
1575
1576 // Comparison to zero
1577
1578 static int runtime_is_zero_f(float a) {
1579 return a == 0;
1580 }
1581
1582 static int runtime_is_zero_d(double a) {
1583 return a == 0;
1584 }
1585
1586 // Type conversion
1587
1588 static int runtime_float_to_int(float a) {
1589 return (int) a;
1590 }
1591
1592 static double runtime_float_to_double(float a) {
1593 return (double) a;
1594 }
1595
1596 static int runtime_double_to_int(double a) {
1597 return (int) a;
1598 }
1599
1600 static float runtime_double_to_float(double a) {
1601 return (float) a;
1602 }
1603
1604 static float runtime_int_to_float(int a) {
1605 return (float) a;
1606 }
1607
1608 static double runtime_int_to_double(int a) {
1609 return (double) a;
1610 }
1611
1612 // Comparisons float
1613
1614 static int runtime_cmp_eq_ff(float b, float a) {
1615 return a == b;
1616 }
1617
1618 static int runtime_cmp_ne_ff(float b, float a) {
1619 return a != b;
1620 }
1621
1622 static int runtime_cmp_lt_ff(float b, float a) {
1623 return a < b;
1624 }
1625
1626 static int runtime_cmp_le_ff(float b, float a) {
1627 return a <= b;
1628 }
1629
1630 static int runtime_cmp_ge_ff(float b, float a) {
1631 return a >= b;
1632 }
1633
1634 static int runtime_cmp_gt_ff(float b, float a) {
1635 return a > b;
1636 }
1637
1638 // Comparisons double
1639
1640 static int runtime_cmp_eq_dd(double b, double a) {
1641 return a == b;
1642 }
1643
1644 static int runtime_cmp_ne_dd(double b, double a) {
1645 return a != b;
1646 }
1647
1648 static int runtime_cmp_lt_dd(double b, double a) {
1649 return a < b;
1650 }
1651
1652 static int runtime_cmp_le_dd(double b, double a) {
1653 return a <= b;
1654 }
1655
1656 static int runtime_cmp_ge_dd(double b, double a) {
1657 return a >= b;
1658 }
1659
1660 static int runtime_cmp_gt_dd(double b, double a) {
1661 return a > b;
1662 }
1663
1664 // Math float
1665
1666 static float runtime_op_add_ff(float b, float a) {
1667 return a + b;
1668 }
1669
1670 static float runtime_op_sub_ff(float b, float a) {
1671 return a - b;
1672 }
1673
1674 static float runtime_op_mul_ff(float b, float a) {
1675 return a * b;
1676 }
1677
1678 static float runtime_op_div_ff(float b, float a) {
1679 return a / b;
1680 }
1681
1682 static float runtime_op_neg_f(float a) {
1683 return -a;
1684 }
1685
1686 // Math double
1687
1688 static double runtime_op_add_dd(double b, double a) {
1689 return a + b;
1690 }
1691
1692 static double runtime_op_sub_dd(double b, double a) {
1693 return a - b;
1694 }
1695
1696 static double runtime_op_mul_dd(double b, double a) {
1697 return a * b;
1698 }
1699
1700 static double runtime_op_div_dd(double b, double a) {
1701 return a / b;
1702 }
1703
1704 static double runtime_op_neg_d(double a) {
1705 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001706 }
-b master422972c2009-06-17 19:13:52 -07001707
1708 static const int STACK_ALIGNMENT = 8;
1709 int mStackUse;
1710 // This variable holds the amount we adjusted the stack in the most
1711 // recent endFunctionCallArguments call. It's examined by the
1712 // following adjustStackAfterCall call.
1713 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001714 };
1715
Jack Palevich09555c72009-05-27 12:25:55 -07001716#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001717
1718#ifdef PROVIDE_X86_CODEGEN
1719
Jack Palevich21a15a22009-05-11 14:49:29 -07001720 class X86CodeGenerator : public CodeGenerator {
1721 public:
1722 X86CodeGenerator() {}
1723 virtual ~X86CodeGenerator() {}
1724
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001725 /* returns address to patch with local variable size
1726 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001727 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001728 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1729 return oad(0xec81, 0); /* sub $xxx, %esp */
1730 }
1731
Jack Palevichb7718b92009-07-09 22:00:24 -07001732 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001733 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001734 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001735 }
1736
Jack Palevich21a15a22009-05-11 14:49:29 -07001737 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001738 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001739 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001740 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001741 }
1742
Jack Palevich1a539db2009-07-08 13:04:41 -07001743 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001744 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001745 switch (pType->tag) {
1746 case TY_FLOAT:
1747 oad(0x05D9, address); // flds
1748 break;
1749 case TY_DOUBLE:
1750 oad(0x05DD, address); // fldl
1751 break;
1752 default:
1753 assert(false);
1754 break;
1755 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001756 }
1757
Jack Palevich22305132009-05-13 10:58:45 -07001758 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001759 return psym(0xe9, t);
1760 }
1761
1762 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001763 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001764 Type* pR0Type = getR0Type();
1765 TypeTag tagR0 = pR0Type->tag;
1766 bool isFloatR0 = isFloatTag(tagR0);
1767 if (isFloatR0) {
1768 o(0xeed9); // fldz
1769 o(0xe9da); // fucompp
1770 o(0xe0df); // fnstsw %ax
1771 o(0x9e); // sahf
1772 } else {
1773 o(0xc085); // test %eax, %eax
1774 }
1775 // Use two output statements to generate one instruction.
1776 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001777 return psym(0x84 + l, t);
1778 }
1779
Jack Palevicha39749f2009-07-08 20:40:31 -07001780 virtual void gcmp(int op, Type* pResultType) {
1781 Type* pR0Type = getR0Type();
1782 Type* pTOSType = getTOSType();
1783 TypeTag tagR0 = pR0Type->tag;
1784 TypeTag tagTOS = pTOSType->tag;
1785 bool isFloatR0 = isFloatTag(tagR0);
1786 bool isFloatTOS = isFloatTag(tagTOS);
1787 if (!isFloatR0 && !isFloatTOS) {
1788 int t = decodeOp(op);
1789 o(0x59); /* pop %ecx */
1790 o(0xc139); /* cmp %eax,%ecx */
1791 li(0, NULL);
1792 o(0x0f); /* setxx %al */
1793 o(t + 0x90);
1794 o(0xc0);
1795 popType();
1796 } else {
1797 setupFloatOperands();
1798 switch (op) {
1799 case OP_EQUALS:
1800 o(0xe9da); // fucompp
1801 o(0xe0df); // fnstsw %ax
1802 o(0x9e); // sahf
1803 o(0xc0940f); // sete %al
1804 o(0xc29b0f); // setnp %dl
1805 o(0xd021); // andl %edx, %eax
1806 break;
1807 case OP_NOT_EQUALS:
1808 o(0xe9da); // fucompp
1809 o(0xe0df); // fnstsw %ax
1810 o(0x9e); // sahf
1811 o(0xc0950f); // setne %al
1812 o(0xc29a0f); // setp %dl
1813 o(0xd009); // orl %edx, %eax
1814 break;
1815 case OP_GREATER_EQUAL:
1816 o(0xe9da); // fucompp
1817 o(0xe0df); // fnstsw %ax
1818 o(0x05c4f6); // testb $5, %ah
1819 o(0xc0940f); // sete %al
1820 break;
1821 case OP_LESS:
1822 o(0xc9d9); // fxch %st(1)
1823 o(0xe9da); // fucompp
1824 o(0xe0df); // fnstsw %ax
1825 o(0x9e); // sahf
1826 o(0xc0970f); // seta %al
1827 break;
1828 case OP_LESS_EQUAL:
1829 o(0xc9d9); // fxch %st(1)
1830 o(0xe9da); // fucompp
1831 o(0xe0df); // fnstsw %ax
1832 o(0x9e); // sahf
1833 o(0xc0930f); // setea %al
1834 break;
1835 case OP_GREATER:
1836 o(0xe9da); // fucompp
1837 o(0xe0df); // fnstsw %ax
1838 o(0x45c4f6); // testb $69, %ah
1839 o(0xc0940f); // sete %al
1840 break;
1841 default:
1842 error("Unknown comparison op");
1843 }
1844 o(0xc0b60f); // movzbl %al, %eax
1845 }
1846 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001847 }
1848
Jack Palevich546b2242009-05-13 15:10:04 -07001849 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001850 Type* pR0Type = getR0Type();
1851 Type* pTOSType = getTOSType();
1852 TypeTag tagR0 = pR0Type->tag;
1853 TypeTag tagTOS = pTOSType->tag;
1854 bool isFloatR0 = isFloatTag(tagR0);
1855 bool isFloatTOS = isFloatTag(tagTOS);
1856 if (!isFloatR0 && !isFloatTOS) {
1857 // TODO: Deal with pointer arithmetic
1858 o(0x59); /* pop %ecx */
1859 o(decodeOp(op));
1860 if (op == OP_MOD)
1861 o(0x92); /* xchg %edx, %eax */
1862 popType();
1863 } else {
1864 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1865 setupFloatOperands();
1866 // Both float. x87 R0 == left hand, x87 R1 == right hand
1867 switch (op) {
1868 case OP_MUL:
1869 o(0xc9de); // fmulp
1870 break;
1871 case OP_DIV:
1872 o(0xf1de); // fdivp
1873 break;
1874 case OP_PLUS:
1875 o(0xc1de); // faddp
1876 break;
1877 case OP_MINUS:
1878 o(0xe1de); // fsubp
1879 break;
1880 default:
1881 error("Unsupported binary floating operation.");
1882 break;
1883 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001884 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001885 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001886 }
1887
Jack Palevicha39749f2009-07-08 20:40:31 -07001888 virtual void gUnaryCmp(int op, Type* pResultType) {
1889 if (op != OP_LOGICAL_NOT) {
1890 error("Unknown unary cmp %d", op);
1891 } else {
1892 Type* pR0Type = getR0Type();
1893 TypeTag tag = collapseType(pR0Type->tag);
1894 switch(tag) {
1895 case TY_INT: {
1896 oad(0xb9, 0); /* movl $0, %ecx */
1897 int t = decodeOp(op);
1898 o(0xc139); /* cmp %eax,%ecx */
1899 li(0, NULL);
1900 o(0x0f); /* setxx %al */
1901 o(t + 0x90);
1902 o(0xc0);
1903 }
1904 break;
1905 case TY_FLOAT:
1906 case TY_DOUBLE:
1907 o(0xeed9); // fldz
1908 o(0xe9da); // fucompp
1909 o(0xe0df); // fnstsw %ax
1910 o(0x9e); // sahf
1911 o(0xc0950f); // setne %al
1912 o(0xc29a0f); // setp %dl
1913 o(0xd009); // orl %edx, %eax
1914 o(0xc0b60f); // movzbl %al, %eax
1915 o(0x01f083); // xorl $1, %eax
1916 break;
1917 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001918 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07001919 break;
1920 }
1921 }
1922 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001923 }
1924
1925 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001926 Type* pR0Type = getR0Type();
1927 TypeTag tag = collapseType(pR0Type->tag);
1928 switch(tag) {
1929 case TY_INT:
1930 oad(0xb9, 0); /* movl $0, %ecx */
1931 o(decodeOp(op));
1932 break;
1933 case TY_FLOAT:
1934 case TY_DOUBLE:
1935 switch (op) {
1936 case OP_MINUS:
1937 o(0xe0d9); // fchs
1938 break;
1939 case OP_BIT_NOT:
1940 error("Can't apply '~' operator to a float or double.");
1941 break;
1942 default:
1943 error("Unknown unary op %d\n", op);
1944 break;
1945 }
1946 break;
1947 default:
1948 error("genUnaryOp unsupported type");
1949 break;
1950 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001951 }
1952
Jack Palevich1cdef202009-05-22 12:06:27 -07001953 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001954 Type* pR0Type = getR0Type();
1955 TypeTag r0ct = collapseType(pR0Type->tag);
1956 switch(r0ct) {
1957 case TY_INT:
1958 o(0x50); /* push %eax */
1959 break;
1960 case TY_FLOAT:
1961 o(0x50); /* push %eax */
1962 o(0x241cd9); // fstps 0(%esp)
1963 break;
1964 case TY_DOUBLE:
1965 o(0x50); /* push %eax */
1966 o(0x50); /* push %eax */
1967 o(0x241cdd); // fstpl 0(%esp)
1968 break;
1969 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001970 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07001971 break;
1972 }
Jack Palevich8df46192009-07-07 14:48:51 -07001973 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07001974 }
1975
Jack Palevich9eed7a22009-07-06 17:24:34 -07001976 virtual void storeR0ToTOS(Type* pPointerType) {
1977 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07001978 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07001979 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001980 switch (pPointerType->pHead->tag) {
1981 case TY_INT:
1982 o(0x0189); /* movl %eax/%al, (%ecx) */
1983 break;
1984 case TY_CHAR:
1985 o(0x0188); /* movl %eax/%al, (%ecx) */
1986 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001987 case TY_FLOAT:
1988 o(0x19d9); /* fstps (%ecx) */
1989 break;
1990 case TY_DOUBLE:
1991 o(0x19dd); /* fstpl (%ecx) */
1992 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001993 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001994 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001995 break;
1996 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001997 }
1998
Jack Palevich9eed7a22009-07-06 17:24:34 -07001999 virtual void loadR0FromR0(Type* pPointerType) {
2000 assert(pPointerType->tag == TY_POINTER);
2001 switch (pPointerType->pHead->tag) {
2002 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002003 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002004 break;
2005 case TY_CHAR:
2006 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002007 ob(0); /* add zero in code */
2008 break;
2009 case TY_FLOAT:
2010 o2(0x00d9); // flds (%eax)
2011 break;
2012 case TY_DOUBLE:
2013 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002014 break;
2015 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002016 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002017 break;
2018 }
Jack Palevich8df46192009-07-07 14:48:51 -07002019 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002020 }
2021
Jack Palevich8df46192009-07-07 14:48:51 -07002022 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002023 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002024 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002025 }
2026
Jack Palevich9cbd2262009-07-08 16:48:41 -07002027 virtual void storeR0(int ea, Type* pType) {
2028 TypeTag tag = pType->tag;
2029 switch (tag) {
2030 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002031 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002032 gmov(6, ea); /* mov %eax, EA */
2033 break;
2034 case TY_FLOAT:
2035 if (ea < -LOCAL || ea > LOCAL) {
2036 oad(0x1dd9, ea); // fstps ea
2037 } else {
2038 oad(0x9dd9, ea); // fstps ea(%ebp)
2039 }
2040 break;
2041 case TY_DOUBLE:
2042 if (ea < -LOCAL || ea > LOCAL) {
2043 oad(0x1ddd, ea); // fstpl ea
2044 } else {
2045 oad(0x9ddd, ea); // fstpl ea(%ebp)
2046 }
2047 break;
2048 default:
2049 error("Unable to store to type %d", tag);
2050 break;
2051 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002052 }
2053
Jack Palevich8df46192009-07-07 14:48:51 -07002054 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002055 TypeTag tag = collapseType(pType->tag);
2056 switch (tag) {
2057 case TY_INT:
2058 gmov(8, ea); /* mov EA, %eax */
2059 if (isIncDec) {
2060 /* Implement post-increment or post decrement.
2061 */
2062 gmov(0, ea); /* 83 ADD */
2063 o(decodeOp(op));
2064 }
2065 break;
2066 case TY_FLOAT:
2067 if (ea < -LOCAL || ea > LOCAL) {
2068 oad(0x05d9, ea); // flds ea
2069 } else {
2070 oad(0x85d9, ea); // flds ea(%ebp)
2071 }
2072 if (isIncDec) {
2073 error("inc/dec not implemented for float.");
2074 }
2075 break;
2076 case TY_DOUBLE:
2077 if (ea < -LOCAL || ea > LOCAL) {
2078 oad(0x05dd, ea); // fldl ea
2079 } else {
2080 oad(0x85dd, ea); // fldl ea(%ebp)
2081 }
2082 if (isIncDec) {
2083 error("inc/dec not implemented for double.");
2084 }
2085 break;
2086 default:
2087 error("Unable to load type %d", tag);
2088 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002089 }
Jack Palevich8df46192009-07-07 14:48:51 -07002090 setR0Type(pType);
2091 }
2092
2093 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002094 Type* pR0Type = getR0Type();
2095 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002096 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002097 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002098 return;
2099 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002100 if (bitsSame(pType, pR0Type)) {
2101 // do nothing special
2102 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2103 // do nothing special, both held in same register on x87.
2104 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002105 TypeTag r0Tag = collapseType(pR0Type->tag);
2106 TypeTag destTag = collapseType(pType->tag);
2107 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2108 // Convert R0 from int to float
2109 o(0x50); // push %eax
2110 o(0x2404DB); // fildl 0(%esp)
2111 o(0x58); // pop %eax
2112 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2113 // Convert R0 from float to int. Complicated because
2114 // need to save and restore the rounding mode.
2115 o(0x50); // push %eax
2116 o(0x50); // push %eax
2117 o(0x02247cD9); // fnstcw 2(%esp)
2118 o(0x2444b70f); // movzwl 2(%esp), %eax
2119 o(0x02);
2120 o(0x0cb4); // movb $12, %ah
2121 o(0x24048966); // movw %ax, 0(%esp)
2122 o(0x242cd9); // fldcw 0(%esp)
2123 o(0x04245cdb); // fistpl 4(%esp)
2124 o(0x02246cd9); // fldcw 2(%esp)
2125 o(0x58); // pop %eax
2126 o(0x58); // pop %eax
2127 } else {
2128 error("Incompatible types old: %d new: %d",
2129 pR0Type->tag, pType->tag);
2130 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002131 }
2132 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002133 }
2134
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002135 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002136 return oad(0xec81, 0); /* sub $xxx, %esp */
2137 }
2138
Jack Palevich1a539db2009-07-08 13:04:41 -07002139 virtual size_t storeR0ToArg(int l) {
2140 Type* pR0Type = getR0Type();
2141 TypeTag r0ct = collapseType(pR0Type->tag);
2142 switch(r0ct) {
2143 case TY_INT:
2144 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2145 return 4;
2146 case TY_FLOAT:
2147 oad(0x249CD9, l); /* fstps xxx(%esp) */
2148 return 4;
2149 case TY_DOUBLE:
2150 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2151 return 8;
2152 default:
2153 assert(false);
2154 return 0;
2155 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002156 }
2157
Jack Palevichb7718b92009-07-09 22:00:24 -07002158 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002159 * (int*) a = l;
2160 }
2161
Jack Palevich8df46192009-07-07 14:48:51 -07002162 virtual int callForward(int symbol, Type* pFunc) {
2163 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002164 return psym(0xe8, symbol); /* call xxx */
2165 }
2166
Jack Palevich8df46192009-07-07 14:48:51 -07002167 virtual void callRelative(int t, Type* pFunc) {
2168 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002169 psym(0xe8, t); /* call xxx */
2170 }
2171
Jack Palevich8df46192009-07-07 14:48:51 -07002172 virtual void callIndirect(int l, Type* pFunc) {
2173 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002174 oad(0x2494ff, l); /* call *xxx(%esp) */
2175 }
2176
Jack Palevichb7718b92009-07-09 22:00:24 -07002177 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002178 if (isIndirect) {
2179 l += 4;
2180 }
-b master422972c2009-06-17 19:13:52 -07002181 if (l > 0) {
2182 oad(0xc481, l); /* add $xxx, %esp */
2183 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002184 }
2185
Jack Palevicha6535612009-05-13 16:24:17 -07002186 virtual int jumpOffset() {
2187 return 5;
2188 }
2189
2190 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002191 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002192 }
2193
Jack Paleviche7b59062009-05-19 17:12:17 -07002194 /* output a symbol and patch all calls to it */
2195 virtual void gsym(int t) {
2196 int n;
2197 int pc = getPC();
2198 while (t) {
2199 n = *(int *) t; /* next value */
2200 *(int *) t = pc - t - 4;
2201 t = n;
2202 }
2203 }
2204
Jack Palevich1cdef202009-05-22 12:06:27 -07002205 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002206 size_t pagesize = 4096;
2207 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2208 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2209 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2210 if (err) {
2211 error("mprotect() failed: %d", errno);
2212 }
2213 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002214 }
2215
Jack Palevich9eed7a22009-07-06 17:24:34 -07002216 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002217 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002218 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002219 virtual size_t alignmentOf(Type* pType){
2220 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002221 }
2222
2223 /**
2224 * Array element alignment (in bytes) for this type of data.
2225 */
2226 virtual size_t sizeOf(Type* pType){
2227 switch(pType->tag) {
2228 case TY_INT:
2229 return 4;
2230 case TY_CHAR:
2231 return 1;
2232 default:
2233 return 0;
2234 case TY_FLOAT:
2235 return 4;
2236 case TY_DOUBLE:
2237 return 8;
2238 case TY_POINTER:
2239 return 4;
2240 }
2241 }
2242
Jack Palevich9cbd2262009-07-08 16:48:41 -07002243 virtual size_t stackSizeOf(Type* pType) {
2244 switch(pType->tag) {
2245 case TY_DOUBLE:
2246 return 8;
2247 default:
2248 return 4;
2249 }
2250 }
2251
Jack Palevich21a15a22009-05-11 14:49:29 -07002252 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002253
2254 /** Output 1 to 4 bytes.
2255 *
2256 */
2257 void o(int n) {
2258 /* cannot use unsigned, so we must do a hack */
2259 while (n && n != -1) {
2260 ob(n & 0xff);
2261 n = n >> 8;
2262 }
2263 }
2264
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002265 /* Output exactly 2 bytes
2266 */
2267 void o2(int n) {
2268 ob(n & 0xff);
2269 ob(0xff & (n >> 8));
2270 }
2271
Jack Paleviche7b59062009-05-19 17:12:17 -07002272 /* psym is used to put an instruction with a data field which is a
2273 reference to a symbol. It is in fact the same as oad ! */
2274 int psym(int n, int t) {
2275 return oad(n, t);
2276 }
2277
2278 /* instruction + address */
2279 int oad(int n, int t) {
2280 o(n);
2281 int result = getPC();
2282 o4(t);
2283 return result;
2284 }
2285
2286
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002287 static const int operatorHelper[];
2288
2289 int decodeOp(int op) {
2290 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002291 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002292 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002293 }
2294 return operatorHelper[op];
2295 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002296
Jack Palevich546b2242009-05-13 15:10:04 -07002297 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002298 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002299 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002300 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002301
2302 void setupFloatOperands() {
2303 Type* pR0Type = getR0Type();
2304 Type* pTOSType = getTOSType();
2305 TypeTag tagR0 = pR0Type->tag;
2306 TypeTag tagTOS = pTOSType->tag;
2307 bool isFloatR0 = isFloatTag(tagR0);
2308 bool isFloatTOS = isFloatTag(tagTOS);
2309 if (! isFloatR0) {
2310 // Convert R0 from int to float
2311 o(0x50); // push %eax
2312 o(0x2404DB); // fildl 0(%esp)
2313 o(0x58); // pop %eax
2314 }
2315 if (! isFloatTOS){
2316 o(0x2404DB); // fildl 0(%esp);
2317 o(0x58); // pop %eax
2318 } else {
2319 if (tagTOS == TY_FLOAT) {
2320 o(0x2404d9); // flds (%esp)
2321 o(0x58); // pop %eax
2322 } else {
2323 o(0x2404dd); // fldl (%esp)
2324 o(0x58); // pop %eax
2325 o(0x58); // pop %eax
2326 }
2327 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002328 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002329 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002330 };
2331
Jack Paleviche7b59062009-05-19 17:12:17 -07002332#endif // PROVIDE_X86_CODEGEN
2333
Jack Palevichb67b18f2009-06-11 21:12:23 -07002334#ifdef PROVIDE_TRACE_CODEGEN
2335 class TraceCodeGenerator : public CodeGenerator {
2336 private:
2337 CodeGenerator* mpBase;
2338
2339 public:
2340 TraceCodeGenerator(CodeGenerator* pBase) {
2341 mpBase = pBase;
2342 }
2343
2344 virtual ~TraceCodeGenerator() {
2345 delete mpBase;
2346 }
2347
2348 virtual void init(CodeBuf* pCodeBuf) {
2349 mpBase->init(pCodeBuf);
2350 }
2351
2352 void setErrorSink(ErrorSink* pErrorSink) {
2353 mpBase->setErrorSink(pErrorSink);
2354 }
2355
2356 /* returns address to patch with local variable size
2357 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002358 virtual int functionEntry(Type* pDecl) {
2359 int result = mpBase->functionEntry(pDecl);
2360 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002361 return result;
2362 }
2363
Jack Palevichb7718b92009-07-09 22:00:24 -07002364 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2365 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2366 localVariableAddress, localVariableSize);
2367 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002368 }
2369
2370 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002371 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002372 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002373 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002374 }
2375
Jack Palevich1a539db2009-07-08 13:04:41 -07002376 virtual void loadFloat(int address, Type* pType) {
2377 fprintf(stderr, "loadFloat(%d, type)\n", address);
2378 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002379 }
2380
Jack Palevichb67b18f2009-06-11 21:12:23 -07002381 virtual int gjmp(int t) {
2382 int result = mpBase->gjmp(t);
2383 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2384 return result;
2385 }
2386
2387 /* l = 0: je, l == 1: jne */
2388 virtual int gtst(bool l, int t) {
2389 int result = mpBase->gtst(l, t);
2390 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2391 return result;
2392 }
2393
Jack Palevicha39749f2009-07-08 20:40:31 -07002394 virtual void gcmp(int op, Type* pResultType) {
2395 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2396 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002397 }
2398
2399 virtual void genOp(int op) {
2400 fprintf(stderr, "genOp(%d)\n", op);
2401 mpBase->genOp(op);
2402 }
2403
Jack Palevich9eed7a22009-07-06 17:24:34 -07002404
Jack Palevicha39749f2009-07-08 20:40:31 -07002405 virtual void gUnaryCmp(int op, Type* pResultType) {
2406 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2407 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002408 }
2409
2410 virtual void genUnaryOp(int op) {
2411 fprintf(stderr, "genUnaryOp(%d)\n", op);
2412 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002413 }
2414
2415 virtual void pushR0() {
2416 fprintf(stderr, "pushR0()\n");
2417 mpBase->pushR0();
2418 }
2419
Jack Palevich9eed7a22009-07-06 17:24:34 -07002420 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002421 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002422 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002423 }
2424
Jack Palevich9eed7a22009-07-06 17:24:34 -07002425 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002426 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002427 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002428 }
2429
Jack Palevich8df46192009-07-07 14:48:51 -07002430 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002431 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002432 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002433 }
2434
Jack Palevich9cbd2262009-07-08 16:48:41 -07002435 virtual void storeR0(int ea, Type* pType) {
2436 fprintf(stderr, "storeR0(%d, pType)\n", ea);
2437 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002438 }
2439
Jack Palevich8df46192009-07-07 14:48:51 -07002440 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002441 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002442 mpBase->loadR0(ea, isIncDec, op, pType);
2443 }
2444
2445 virtual void convertR0(Type* pType){
2446 fprintf(stderr, "convertR0(pType)\n");
2447 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002448 }
2449
2450 virtual int beginFunctionCallArguments() {
2451 int result = mpBase->beginFunctionCallArguments();
2452 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2453 return result;
2454 }
2455
Jack Palevich1a539db2009-07-08 13:04:41 -07002456 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002457 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07002458 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002459 }
2460
Jack Palevichb7718b92009-07-09 22:00:24 -07002461 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002462 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002463 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002464 }
2465
Jack Palevich8df46192009-07-07 14:48:51 -07002466 virtual int callForward(int symbol, Type* pFunc) {
2467 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002468 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2469 return result;
2470 }
2471
Jack Palevich8df46192009-07-07 14:48:51 -07002472 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002473 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002474 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002475 }
2476
Jack Palevich8df46192009-07-07 14:48:51 -07002477 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002478 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002479 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002480 }
2481
Jack Palevichb7718b92009-07-09 22:00:24 -07002482 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2483 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2484 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002485 }
2486
2487 virtual int jumpOffset() {
2488 return mpBase->jumpOffset();
2489 }
2490
2491 virtual int disassemble(FILE* out) {
2492 return mpBase->disassemble(out);
2493 }
2494
2495 /* output a symbol and patch all calls to it */
2496 virtual void gsym(int t) {
2497 fprintf(stderr, "gsym(%d)\n", t);
2498 mpBase->gsym(t);
2499 }
2500
2501 virtual int finishCompile() {
2502 int result = mpBase->finishCompile();
2503 fprintf(stderr, "finishCompile() = %d\n", result);
2504 return result;
2505 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002506
2507 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002508 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002509 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002510 virtual size_t alignmentOf(Type* pType){
2511 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002512 }
2513
2514 /**
2515 * Array element alignment (in bytes) for this type of data.
2516 */
2517 virtual size_t sizeOf(Type* pType){
2518 return mpBase->sizeOf(pType);
2519 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002520
Jack Palevich9cbd2262009-07-08 16:48:41 -07002521
2522 virtual size_t stackSizeOf(Type* pType) {
2523 return mpBase->stackSizeOf(pType);
2524 }
2525
2526
Jack Palevich1a539db2009-07-08 13:04:41 -07002527 virtual Type* getR0Type() {
2528 return mpBase->getR0Type();
2529 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002530 };
2531
2532#endif // PROVIDE_TRACE_CODEGEN
2533
Jack Palevich569f1352009-06-29 14:29:08 -07002534 class Arena {
2535 public:
2536 // Used to record a given allocation amount.
2537 // Used:
2538 // Mark mark = arena.mark();
2539 // ... lots of arena.allocate()
2540 // arena.free(mark);
2541
2542 struct Mark {
2543 size_t chunk;
2544 size_t offset;
2545 };
2546
2547 Arena() {
2548 mCurrentChunk = 0;
2549 Chunk start(CHUNK_SIZE);
2550 mData.push_back(start);
2551 }
2552
2553 ~Arena() {
2554 for(size_t i = 0; i < mData.size(); i++) {
2555 mData[i].free();
2556 }
2557 }
2558
2559 // Alloc using the standard alignment size safe for any variable
2560 void* alloc(size_t size) {
2561 return alloc(size, 8);
2562 }
2563
2564 Mark mark(){
2565 Mark result;
2566 result.chunk = mCurrentChunk;
2567 result.offset = mData[mCurrentChunk].mOffset;
2568 return result;
2569 }
2570
2571 void freeToMark(const Mark& mark) {
2572 mCurrentChunk = mark.chunk;
2573 mData[mCurrentChunk].mOffset = mark.offset;
2574 }
2575
2576 private:
2577 // Allocate memory aligned to a given size
2578 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2579 // Memory is not zero filled.
2580
2581 void* alloc(size_t size, size_t alignment) {
2582 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2583 if (mCurrentChunk + 1 < mData.size()) {
2584 mCurrentChunk++;
2585 } else {
2586 size_t allocSize = CHUNK_SIZE;
2587 if (allocSize < size + alignment - 1) {
2588 allocSize = size + alignment - 1;
2589 }
2590 Chunk chunk(allocSize);
2591 mData.push_back(chunk);
2592 mCurrentChunk++;
2593 }
2594 }
2595 return mData[mCurrentChunk].allocate(size, alignment);
2596 }
2597
2598 static const size_t CHUNK_SIZE = 128*1024;
2599 // Note: this class does not deallocate its
2600 // memory when it's destroyed. It depends upon
2601 // its parent to deallocate the memory.
2602 struct Chunk {
2603 Chunk() {
2604 mpData = 0;
2605 mSize = 0;
2606 mOffset = 0;
2607 }
2608
2609 Chunk(size_t size) {
2610 mSize = size;
2611 mpData = (char*) malloc(size);
2612 mOffset = 0;
2613 }
2614
2615 ~Chunk() {
2616 // Doesn't deallocate memory.
2617 }
2618
2619 void* allocate(size_t size, size_t alignment) {
2620 size_t alignedOffset = aligned(mOffset, alignment);
2621 void* result = mpData + alignedOffset;
2622 mOffset = alignedOffset + size;
2623 return result;
2624 }
2625
2626 void free() {
2627 if (mpData) {
2628 ::free(mpData);
2629 mpData = 0;
2630 }
2631 }
2632
2633 size_t remainingCapacity(size_t alignment) {
2634 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2635 }
2636
2637 // Assume alignment is a power of two
2638 inline size_t aligned(size_t v, size_t alignment) {
2639 size_t mask = alignment-1;
2640 return (v + mask) & ~mask;
2641 }
2642
2643 char* mpData;
2644 size_t mSize;
2645 size_t mOffset;
2646 };
2647
2648 size_t mCurrentChunk;
2649
2650 Vector<Chunk> mData;
2651 };
2652
Jack Palevich569f1352009-06-29 14:29:08 -07002653 struct VariableInfo;
2654
2655 struct Token {
2656 int hash;
2657 size_t length;
2658 char* pText;
2659 tokenid_t id;
2660
2661 // Current values for the token
2662 char* mpMacroDefinition;
2663 VariableInfo* mpVariableInfo;
2664 };
2665
2666 class TokenTable {
2667 public:
2668 // Don't use 0..0xff, allows characters and operators to be tokens too.
2669
2670 static const int TOKEN_BASE = 0x100;
2671 TokenTable() {
2672 mpMap = hashmapCreate(128, hashFn, equalsFn);
2673 }
2674
2675 ~TokenTable() {
2676 hashmapFree(mpMap);
2677 }
2678
2679 void setArena(Arena* pArena) {
2680 mpArena = pArena;
2681 }
2682
2683 // Returns a token for a given string of characters.
2684 tokenid_t intern(const char* pText, size_t length) {
2685 Token probe;
2686 int hash = hashmapHash((void*) pText, length);
2687 {
2688 Token probe;
2689 probe.hash = hash;
2690 probe.length = length;
2691 probe.pText = (char*) pText;
2692 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2693 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002694 return pValue->id;
2695 }
2696 }
2697
2698 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2699 memset(pToken, 0, sizeof(*pToken));
2700 pToken->hash = hash;
2701 pToken->length = length;
2702 pToken->pText = (char*) mpArena->alloc(length + 1);
2703 memcpy(pToken->pText, pText, length);
2704 pToken->pText[length] = 0;
2705 pToken->id = mTokens.size() + TOKEN_BASE;
2706 mTokens.push_back(pToken);
2707 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002708 return pToken->id;
2709 }
2710
2711 // Return the Token for a given tokenid.
2712 Token& operator[](tokenid_t id) {
2713 return *mTokens[id - TOKEN_BASE];
2714 }
2715
2716 inline size_t size() {
2717 return mTokens.size();
2718 }
2719
2720 private:
2721
2722 static int hashFn(void* pKey) {
2723 Token* pToken = (Token*) pKey;
2724 return pToken->hash;
2725 }
2726
2727 static bool equalsFn(void* keyA, void* keyB) {
2728 Token* pTokenA = (Token*) keyA;
2729 Token* pTokenB = (Token*) keyB;
2730 // Don't need to compare hash values, they should always be equal
2731 return pTokenA->length == pTokenB->length
2732 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2733 }
2734
2735 Hashmap* mpMap;
2736 Vector<Token*> mTokens;
2737 Arena* mpArena;
2738 };
2739
Jack Palevich1cdef202009-05-22 12:06:27 -07002740 class InputStream {
2741 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002742 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002743 int getChar() {
2744 if (bumpLine) {
2745 line++;
2746 bumpLine = false;
2747 }
2748 int ch = get();
2749 if (ch == '\n') {
2750 bumpLine = true;
2751 }
2752 return ch;
2753 }
2754 int getLine() {
2755 return line;
2756 }
2757 protected:
2758 InputStream() :
2759 line(1), bumpLine(false) {
2760 }
2761 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002762 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002763 int line;
2764 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002765 };
2766
2767 class FileInputStream : public InputStream {
2768 public:
2769 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002770 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002771 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002772 FILE* f;
2773 };
2774
2775 class TextInputStream : public InputStream {
2776 public:
2777 TextInputStream(const char* text, size_t textLength)
2778 : pText(text), mTextLength(textLength), mPosition(0) {
2779 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002780
2781 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002782 virtual int get() {
2783 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2784 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002785
Jack Palevich1cdef202009-05-22 12:06:27 -07002786 const char* pText;
2787 size_t mTextLength;
2788 size_t mPosition;
2789 };
2790
Jack Palevicheedf9d22009-06-04 16:23:40 -07002791 class String {
2792 public:
2793 String() {
2794 mpBase = 0;
2795 mUsed = 0;
2796 mSize = 0;
2797 }
2798
Jack Palevich303d8ff2009-06-11 19:06:24 -07002799 String(const char* item, int len, bool adopt) {
2800 if (len < 0) {
2801 len = strlen(item);
2802 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002803 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002804 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002805 mUsed = len;
2806 mSize = len + 1;
2807 } else {
2808 mpBase = 0;
2809 mUsed = 0;
2810 mSize = 0;
2811 appendBytes(item, len);
2812 }
2813 }
2814
Jack Palevich303d8ff2009-06-11 19:06:24 -07002815 String(const String& other) {
2816 mpBase = 0;
2817 mUsed = 0;
2818 mSize = 0;
2819 appendBytes(other.getUnwrapped(), other.len());
2820 }
2821
Jack Palevicheedf9d22009-06-04 16:23:40 -07002822 ~String() {
2823 if (mpBase) {
2824 free(mpBase);
2825 }
2826 }
2827
Jack Palevicha6baa232009-06-12 11:25:59 -07002828 String& operator=(const String& other) {
2829 clear();
2830 appendBytes(other.getUnwrapped(), other.len());
2831 return *this;
2832 }
2833
Jack Palevich303d8ff2009-06-11 19:06:24 -07002834 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002835 return mpBase;
2836 }
2837
Jack Palevich303d8ff2009-06-11 19:06:24 -07002838 void clear() {
2839 mUsed = 0;
2840 if (mSize > 0) {
2841 mpBase[0] = 0;
2842 }
2843 }
2844
Jack Palevicheedf9d22009-06-04 16:23:40 -07002845 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002846 appendBytes(s, strlen(s));
2847 }
2848
2849 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002850 memcpy(ensure(n), s, n + 1);
2851 }
2852
2853 void append(char c) {
2854 * ensure(1) = c;
2855 }
2856
Jack Palevich86351982009-06-30 18:09:56 -07002857 void append(String& other) {
2858 appendBytes(other.getUnwrapped(), other.len());
2859 }
2860
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002861 char* orphan() {
2862 char* result = mpBase;
2863 mpBase = 0;
2864 mUsed = 0;
2865 mSize = 0;
2866 return result;
2867 }
2868
Jack Palevicheedf9d22009-06-04 16:23:40 -07002869 void printf(const char* fmt,...) {
2870 va_list ap;
2871 va_start(ap, fmt);
2872 vprintf(fmt, ap);
2873 va_end(ap);
2874 }
2875
2876 void vprintf(const char* fmt, va_list ap) {
2877 char* temp;
2878 int numChars = vasprintf(&temp, fmt, ap);
2879 memcpy(ensure(numChars), temp, numChars+1);
2880 free(temp);
2881 }
2882
Jack Palevich303d8ff2009-06-11 19:06:24 -07002883 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002884 return mUsed;
2885 }
2886
2887 private:
2888 char* ensure(int n) {
2889 size_t newUsed = mUsed + n;
2890 if (newUsed > mSize) {
2891 size_t newSize = mSize * 2 + 10;
2892 if (newSize < newUsed) {
2893 newSize = newUsed;
2894 }
2895 mpBase = (char*) realloc(mpBase, newSize + 1);
2896 mSize = newSize;
2897 }
2898 mpBase[newUsed] = '\0';
2899 char* result = mpBase + mUsed;
2900 mUsed = newUsed;
2901 return result;
2902 }
2903
2904 char* mpBase;
2905 size_t mUsed;
2906 size_t mSize;
2907 };
2908
Jack Palevich569f1352009-06-29 14:29:08 -07002909 void internKeywords() {
2910 // Note: order has to match TOK_ constants
2911 static const char* keywords[] = {
2912 "int",
2913 "char",
2914 "void",
2915 "if",
2916 "else",
2917 "while",
2918 "break",
2919 "return",
2920 "for",
2921 "pragma",
2922 "define",
2923 "auto",
2924 "case",
2925 "const",
2926 "continue",
2927 "default",
2928 "do",
2929 "double",
2930 "enum",
2931 "extern",
2932 "float",
2933 "goto",
2934 "long",
2935 "register",
2936 "short",
2937 "signed",
2938 "sizeof",
2939 "static",
2940 "struct",
2941 "switch",
2942 "typedef",
2943 "union",
2944 "unsigned",
2945 "volatile",
2946 "_Bool",
2947 "_Complex",
2948 "_Imaginary",
2949 "inline",
2950 "restrict",
2951 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002952
Jack Palevich569f1352009-06-29 14:29:08 -07002953 for(int i = 0; keywords[i]; i++) {
2954 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002955 }
Jack Palevich569f1352009-06-29 14:29:08 -07002956 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002957
Jack Palevich36d94142009-06-08 15:55:32 -07002958 struct InputState {
2959 InputStream* pStream;
2960 int oldCh;
2961 };
2962
Jack Palevich2db168f2009-06-11 14:29:47 -07002963 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002964 void* pAddress;
2965 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07002966 tokenid_t tok;
2967 size_t level;
2968 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07002969 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07002970 };
2971
Jack Palevich303d8ff2009-06-11 19:06:24 -07002972 class SymbolStack {
2973 public:
2974 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07002975 mpArena = 0;
2976 mpTokenTable = 0;
2977 }
2978
2979 void setArena(Arena* pArena) {
2980 mpArena = pArena;
2981 }
2982
2983 void setTokenTable(TokenTable* pTokenTable) {
2984 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07002985 }
2986
2987 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002988 Mark mark;
2989 mark.mArenaMark = mpArena->mark();
2990 mark.mSymbolHead = mStack.size();
2991 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07002992 }
2993
2994 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07002995 // Undo any shadowing that was done:
2996 Mark mark = mLevelStack.back();
2997 mLevelStack.pop_back();
2998 while (mStack.size() > mark.mSymbolHead) {
2999 VariableInfo* pV = mStack.back();
3000 mStack.pop_back();
3001 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003002 }
Jack Palevich569f1352009-06-29 14:29:08 -07003003 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003004 }
3005
Jack Palevich569f1352009-06-29 14:29:08 -07003006 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3007 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3008 return pV && pV->level == level();
3009 }
3010
3011 VariableInfo* add(tokenid_t tok) {
3012 Token& token = (*mpTokenTable)[tok];
3013 VariableInfo* pOldV = token.mpVariableInfo;
3014 VariableInfo* pNewV =
3015 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3016 memset(pNewV, 0, sizeof(VariableInfo));
3017 pNewV->tok = tok;
3018 pNewV->level = level();
3019 pNewV->pOldDefinition = pOldV;
3020 token.mpVariableInfo = pNewV;
3021 mStack.push_back(pNewV);
3022 return pNewV;
3023 }
3024
Jack Palevich86351982009-06-30 18:09:56 -07003025 VariableInfo* add(Type* pType) {
3026 VariableInfo* pVI = add(pType->id);
3027 pVI->pType = pType;
3028 return pVI;
3029 }
3030
Jack Palevich569f1352009-06-29 14:29:08 -07003031 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3032 for (size_t i = 0; i < mStack.size(); i++) {
3033 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003034 break;
3035 }
3036 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003037 }
3038
Jack Palevich303d8ff2009-06-11 19:06:24 -07003039 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003040 inline size_t level() {
3041 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003042 }
3043
Jack Palevich569f1352009-06-29 14:29:08 -07003044 struct Mark {
3045 Arena::Mark mArenaMark;
3046 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003047 };
3048
Jack Palevich569f1352009-06-29 14:29:08 -07003049 Arena* mpArena;
3050 TokenTable* mpTokenTable;
3051 Vector<VariableInfo*> mStack;
3052 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003053 };
Jack Palevich36d94142009-06-08 15:55:32 -07003054
3055 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003056 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003057 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003058 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003059 int tokl; // token operator level
3060 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003061 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003062 intptr_t loc; // local variable index
3063 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003064 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003065 char* dptr; // Macro state: Points to macro text during macro playback.
3066 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003067 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07003068
3069 // Arena for the duration of the compile
3070 Arena mGlobalArena;
3071 // Arena for data that's only needed when compiling a single function
3072 Arena mLocalArena;
3073
3074 TokenTable mTokenTable;
3075 SymbolStack mGlobals;
3076 SymbolStack mLocals;
3077
Jack Palevich40600de2009-07-01 15:32:35 -07003078 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003079 Type* mkpInt; // int
3080 Type* mkpChar; // char
3081 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003082 Type* mkpFloat;
3083 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003084 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003085 Type* mkpIntPtr;
3086 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003087 Type* mkpFloatPtr;
3088 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003089 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003090
Jack Palevich36d94142009-06-08 15:55:32 -07003091 InputStream* file;
3092
3093 CodeBuf codeBuf;
3094 CodeGenerator* pGen;
3095
Jack Palevicheedf9d22009-06-04 16:23:40 -07003096 String mErrorBuf;
3097
Jack Palevicheedf9d22009-06-04 16:23:40 -07003098 String mPragmas;
3099 int mPragmaStringCount;
3100
Jack Palevich21a15a22009-05-11 14:49:29 -07003101 static const int ALLOC_SIZE = 99999;
3102
Jack Palevich303d8ff2009-06-11 19:06:24 -07003103 static const int TOK_DUMMY = 1;
3104 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003105 static const int TOK_NUM_FLOAT = 3;
3106 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003107
3108 // 3..255 are character and/or operators
3109
Jack Palevich2db168f2009-06-11 14:29:47 -07003110 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003111 // Order has to match string list in "internKeywords".
3112 enum {
3113 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3114 TOK_INT = TOK_KEYWORD,
3115 TOK_CHAR,
3116 TOK_VOID,
3117 TOK_IF,
3118 TOK_ELSE,
3119 TOK_WHILE,
3120 TOK_BREAK,
3121 TOK_RETURN,
3122 TOK_FOR,
3123 TOK_PRAGMA,
3124 TOK_DEFINE,
3125 TOK_AUTO,
3126 TOK_CASE,
3127 TOK_CONST,
3128 TOK_CONTINUE,
3129 TOK_DEFAULT,
3130 TOK_DO,
3131 TOK_DOUBLE,
3132 TOK_ENUM,
3133 TOK_EXTERN,
3134 TOK_FLOAT,
3135 TOK_GOTO,
3136 TOK_LONG,
3137 TOK_REGISTER,
3138 TOK_SHORT,
3139 TOK_SIGNED,
3140 TOK_SIZEOF,
3141 TOK_STATIC,
3142 TOK_STRUCT,
3143 TOK_SWITCH,
3144 TOK_TYPEDEF,
3145 TOK_UNION,
3146 TOK_UNSIGNED,
3147 TOK_VOLATILE,
3148 TOK__BOOL,
3149 TOK__COMPLEX,
3150 TOK__IMAGINARY,
3151 TOK_INLINE,
3152 TOK_RESTRICT,
3153 // Symbols start after tokens
3154 TOK_SYMBOL
3155 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003156
3157 static const int LOCAL = 0x200;
3158
3159 static const int SYM_FORWARD = 0;
3160 static const int SYM_DEFINE = 1;
3161
3162 /* tokens in string heap */
3163 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003164
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003165 static const int OP_INCREMENT = 0;
3166 static const int OP_DECREMENT = 1;
3167 static const int OP_MUL = 2;
3168 static const int OP_DIV = 3;
3169 static const int OP_MOD = 4;
3170 static const int OP_PLUS = 5;
3171 static const int OP_MINUS = 6;
3172 static const int OP_SHIFT_LEFT = 7;
3173 static const int OP_SHIFT_RIGHT = 8;
3174 static const int OP_LESS_EQUAL = 9;
3175 static const int OP_GREATER_EQUAL = 10;
3176 static const int OP_LESS = 11;
3177 static const int OP_GREATER = 12;
3178 static const int OP_EQUALS = 13;
3179 static const int OP_NOT_EQUALS = 14;
3180 static const int OP_LOGICAL_AND = 15;
3181 static const int OP_LOGICAL_OR = 16;
3182 static const int OP_BIT_AND = 17;
3183 static const int OP_BIT_XOR = 18;
3184 static const int OP_BIT_OR = 19;
3185 static const int OP_BIT_NOT = 20;
3186 static const int OP_LOGICAL_NOT = 21;
3187 static const int OP_COUNT = 22;
3188
3189 /* Operators are searched from front, the two-character operators appear
3190 * before the single-character operators with the same first character.
3191 * @ is used to pad out single-character operators.
3192 */
3193 static const char* operatorChars;
3194 static const char operatorLevel[];
3195
Jack Palevich569f1352009-06-29 14:29:08 -07003196 /* Called when we detect an internal problem. Does nothing in production.
3197 *
3198 */
3199 void internalError() {
3200 * (char*) 0 = 0;
3201 }
3202
Jack Palevich86351982009-06-30 18:09:56 -07003203 void assert(bool isTrue) {
3204 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003205 internalError();
3206 }
Jack Palevich86351982009-06-30 18:09:56 -07003207 }
3208
Jack Palevich40600de2009-07-01 15:32:35 -07003209 bool isSymbol(tokenid_t t) {
3210 return t >= TOK_SYMBOL &&
3211 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3212 }
3213
3214 bool isSymbolOrKeyword(tokenid_t t) {
3215 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003216 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003217 }
3218
Jack Palevich86351982009-06-30 18:09:56 -07003219 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003220 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003221 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3222 if (pV && pV->tok != t) {
3223 internalError();
3224 }
3225 return pV;
3226 }
3227
3228 inline bool isDefined(tokenid_t t) {
3229 return t >= TOK_SYMBOL && VI(t) != 0;
3230 }
3231
Jack Palevich40600de2009-07-01 15:32:35 -07003232 const char* nameof(tokenid_t t) {
3233 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003234 return mTokenTable[t].pText;
3235 }
3236
Jack Palevich21a15a22009-05-11 14:49:29 -07003237 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003238 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003239 }
3240
3241 void inp() {
3242 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003243 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003244 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003245 dptr = 0;
3246 ch = dch;
3247 }
3248 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003249 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003250#if 0
3251 printf("ch='%c' 0x%x\n", ch, ch);
3252#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003253 }
3254
3255 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003256 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003257 }
3258
Jack Palevichb4758ff2009-06-12 12:49:14 -07003259 /* read a character constant, advances ch to after end of constant */
3260 int getq() {
3261 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003262 if (ch == '\\') {
3263 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003264 if (isoctal(ch)) {
3265 // 1 to 3 octal characters.
3266 val = 0;
3267 for(int i = 0; i < 3; i++) {
3268 if (isoctal(ch)) {
3269 val = (val << 3) + ch - '0';
3270 inp();
3271 }
3272 }
3273 return val;
3274 } else if (ch == 'x' || ch == 'X') {
3275 // N hex chars
3276 inp();
3277 if (! isxdigit(ch)) {
3278 error("'x' character escape requires at least one digit.");
3279 } else {
3280 val = 0;
3281 while (isxdigit(ch)) {
3282 int d = ch;
3283 if (isdigit(d)) {
3284 d -= '0';
3285 } else if (d <= 'F') {
3286 d = d - 'A' + 10;
3287 } else {
3288 d = d - 'a' + 10;
3289 }
3290 val = (val << 4) + d;
3291 inp();
3292 }
3293 }
3294 } else {
3295 int val = ch;
3296 switch (ch) {
3297 case 'a':
3298 val = '\a';
3299 break;
3300 case 'b':
3301 val = '\b';
3302 break;
3303 case 'f':
3304 val = '\f';
3305 break;
3306 case 'n':
3307 val = '\n';
3308 break;
3309 case 'r':
3310 val = '\r';
3311 break;
3312 case 't':
3313 val = '\t';
3314 break;
3315 case 'v':
3316 val = '\v';
3317 break;
3318 case '\\':
3319 val = '\\';
3320 break;
3321 case '\'':
3322 val = '\'';
3323 break;
3324 case '"':
3325 val = '"';
3326 break;
3327 case '?':
3328 val = '?';
3329 break;
3330 default:
3331 error("Undefined character escape %c", ch);
3332 break;
3333 }
3334 inp();
3335 return val;
3336 }
3337 } else {
3338 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003339 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003340 return val;
3341 }
3342
3343 static bool isoctal(int ch) {
3344 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003345 }
3346
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003347 bool acceptCh(int c) {
3348 bool result = c == ch;
3349 if (result) {
3350 pdef(ch);
3351 inp();
3352 }
3353 return result;
3354 }
3355
3356 bool acceptDigitsCh() {
3357 bool result = false;
3358 while (isdigit(ch)) {
3359 result = true;
3360 pdef(ch);
3361 inp();
3362 }
3363 return result;
3364 }
3365
3366 void parseFloat() {
3367 tok = TOK_NUM_DOUBLE;
3368 // mTokenString already has the integral part of the number.
3369 acceptCh('.');
3370 acceptDigitsCh();
3371 bool doExp = true;
3372 if (acceptCh('e') || acceptCh('E')) {
3373 // Don't need to do any extra work
3374 } else if (ch == 'f' || ch == 'F') {
3375 pdef('e'); // So it can be parsed by strtof.
3376 inp();
3377 tok = TOK_NUM_FLOAT;
3378 } else {
3379 doExp = false;
3380 }
3381 if (doExp) {
3382 bool digitsRequired = acceptCh('-');
3383 bool digitsFound = acceptDigitsCh();
3384 if (digitsRequired && ! digitsFound) {
3385 error("malformed exponent");
3386 }
3387 }
3388 char* pText = mTokenString.getUnwrapped();
3389 if (tok == TOK_NUM_FLOAT) {
3390 tokd = strtof(pText, 0);
3391 } else {
3392 tokd = strtod(pText, 0);
3393 }
3394 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
3395 }
3396
Jack Palevich21a15a22009-05-11 14:49:29 -07003397 void next() {
3398 int l, a;
3399
Jack Palevich546b2242009-05-13 15:10:04 -07003400 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003401 if (ch == '#') {
3402 inp();
3403 next();
3404 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003405 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003406 } else if (tok == TOK_PRAGMA) {
3407 doPragma();
3408 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003409 error("Unsupported preprocessor directive \"%s\"",
3410 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003411 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003412 }
3413 inp();
3414 }
3415 tokl = 0;
3416 tok = ch;
3417 /* encode identifiers & numbers */
3418 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003419 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003420 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003421 pdef(ch);
3422 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003423 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003424 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003425 // Start of a numeric constant. Could be integer, float, or
3426 // double, won't know until we look further.
3427 if (ch == '.' || ch == 'e' || ch == 'e'
3428 || ch == 'f' || ch == 'F') {
3429 parseFloat();
3430 } else {
3431 // It's an integer constant
3432 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
3433 tok = TOK_NUM;
3434 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003435 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003436 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
3437 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003438 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07003439 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3440 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003441 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07003442 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003443 dch = ch;
3444 inp();
3445 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003446 }
3447 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003448 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003449 inp();
3450 if (tok == '\'') {
3451 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003452 tokc = getq();
3453 if (ch != '\'') {
3454 error("Expected a ' character, got %c", ch);
3455 } else {
3456 inp();
3457 }
Jack Palevich546b2242009-05-13 15:10:04 -07003458 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003459 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003460 while (ch && ch != EOF) {
3461 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003462 inp();
3463 inp();
3464 if (ch == '/')
3465 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003466 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003467 if (ch == EOF) {
3468 error("End of file inside comment.");
3469 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003470 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003471 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003472 } else if ((tok == '/') & (ch == '/')) {
3473 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003474 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003475 inp();
3476 }
3477 inp();
3478 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003479 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003480 const char* t = operatorChars;
3481 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003482 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003483 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003484 tokl = operatorLevel[opIndex];
3485 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003486 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003487#if 0
3488 printf("%c%c -> tokl=%d tokc=0x%x\n",
3489 l, a, tokl, tokc);
3490#endif
3491 if (a == ch) {
3492 inp();
3493 tok = TOK_DUMMY; /* dummy token for double tokens */
3494 }
3495 break;
3496 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003497 opIndex++;
3498 }
3499 if (l == 0) {
3500 tokl = 0;
3501 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003502 }
3503 }
3504 }
3505#if 0
3506 {
Jack Palevich569f1352009-06-29 14:29:08 -07003507 String buf;
3508 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07003509 fprintf(stderr, "%s\n", buf.getUnwrapped());
3510 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003511#endif
3512 }
3513
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003514 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003515 next();
3516 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003517 String* pName = new String();
3518 while (isspace(ch)) {
3519 inp();
3520 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003521 if (ch == '(') {
3522 delete pName;
3523 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003524 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003525 }
3526 while (isspace(ch)) {
3527 inp();
3528 }
Jack Palevich569f1352009-06-29 14:29:08 -07003529 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003530 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003531 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003532 inp();
3533 }
Jack Palevich569f1352009-06-29 14:29:08 -07003534 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3535 memcpy(pDefn, value.getUnwrapped(), value.len());
3536 pDefn[value.len()] = 0;
3537 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003538 }
3539
Jack Palevicheedf9d22009-06-04 16:23:40 -07003540 void doPragma() {
3541 // # pragma name(val)
3542 int state = 0;
3543 while(ch != EOF && ch != '\n' && state < 10) {
3544 switch(state) {
3545 case 0:
3546 if (isspace(ch)) {
3547 inp();
3548 } else {
3549 state++;
3550 }
3551 break;
3552 case 1:
3553 if (isalnum(ch)) {
3554 mPragmas.append(ch);
3555 inp();
3556 } else if (ch == '(') {
3557 mPragmas.append(0);
3558 inp();
3559 state++;
3560 } else {
3561 state = 11;
3562 }
3563 break;
3564 case 2:
3565 if (isalnum(ch)) {
3566 mPragmas.append(ch);
3567 inp();
3568 } else if (ch == ')') {
3569 mPragmas.append(0);
3570 inp();
3571 state = 10;
3572 } else {
3573 state = 11;
3574 }
3575 break;
3576 }
3577 }
3578 if(state != 10) {
3579 error("Unexpected pragma syntax");
3580 }
3581 mPragmaStringCount += 2;
3582 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003583
Jack Palevichac0e95e2009-05-29 13:53:44 -07003584 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003585 mErrorBuf.printf("%ld: ", file->getLine());
3586 mErrorBuf.vprintf(fmt, ap);
3587 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003588 }
3589
Jack Palevich8b0624c2009-05-20 12:12:06 -07003590 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003591 if (tok != c) {
3592 error("'%c' expected", c);
3593 }
3594 next();
3595 }
3596
Jack Palevich86351982009-06-30 18:09:56 -07003597 bool accept(intptr_t c) {
3598 if (tok == c) {
3599 next();
3600 return true;
3601 }
3602 return false;
3603 }
3604
Jack Palevich40600de2009-07-01 15:32:35 -07003605 bool acceptStringLiteral() {
3606 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003607 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003608 // This while loop merges multiple adjacent string constants.
3609 while (tok == '"') {
3610 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003611 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003612 }
3613 if (ch != '"') {
3614 error("Unterminated string constant.");
3615 }
3616 inp();
3617 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003618 }
Jack Palevich40600de2009-07-01 15:32:35 -07003619 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003620 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003621 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003622 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003623
3624 return true;
3625 }
3626 return false;
3627 }
3628 /* Parse and evaluate a unary expression.
3629 * allowAssignment is true if '=' parsing wanted (quick hack)
3630 */
3631 void unary(bool allowAssignment) {
3632 intptr_t n, t, a;
3633 t = 0;
3634 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3635 if (acceptStringLiteral()) {
3636 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003637 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003638 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003639 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003640 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003641 t = tok;
3642 next();
3643 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003644 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003645 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003646 // Align to 4-byte boundary
3647 glo = (char*) (((intptr_t) glo + 3) & -4);
3648 * (float*) glo = (float) ad;
3649 pGen->loadFloat((int) glo, mkpFloat);
3650 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003651 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003652 // Align to 8-byte boundary
3653 glo = (char*) (((intptr_t) glo + 7) & -8);
3654 * (double*) glo = ad;
3655 pGen->loadFloat((int) glo, mkpDouble);
3656 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003657 } else if (c == 2) {
3658 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003659 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003660 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003661 pGen->gUnaryCmp(a, mkpInt);
3662 else if (t == '+') {
3663 // ignore unary plus.
3664 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003665 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003666 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003667 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003668 // It's either a cast or an expression
3669 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3670 if (pCast) {
3671 skip(')');
3672 unary(false);
3673 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003674 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003675 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003676 skip(')');
3677 }
3678 } else if (t == '*') {
3679 /* This is a pointer dereference.
3680 */
3681 unary(false);
3682 Type* pR0Type = pGen->getR0Type();
3683 if (pR0Type->tag != TY_POINTER) {
3684 error("Expected a pointer type.");
3685 } else {
3686 if (pR0Type->pHead->tag == TY_FUNC) {
3687 t = 0;
3688 }
3689 if (accept('=')) {
3690 pGen->pushR0();
3691 expr();
3692 pGen->storeR0ToTOS(pR0Type);
3693 } else if (t) {
3694 pGen->loadR0FromR0(pR0Type);
3695 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003696 }
Jack Palevich3f226492009-07-02 14:46:19 -07003697 // Else we fall through to the function call below, with
3698 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003699 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003700 VariableInfo* pVI = VI(tok);
3701 pGen->leaR0((int) pVI->pAddress,
3702 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003703 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003704 } else if (t == EOF ) {
3705 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003706 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003707 // Don't have to do anything special here, the error
3708 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003709 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003710 if (!isDefined(t)) {
3711 mGlobals.add(t);
3712 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003713 }
Jack Palevich8df46192009-07-07 14:48:51 -07003714 VariableInfo* pVI = VI(t);
3715 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003716 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003717 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003718 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003719 if (tok == '(') {
3720 pVI->pType = mkpIntFn;
3721 } else {
3722 pVI->pType = mkpInt;
3723 }
Jack Palevich8df46192009-07-07 14:48:51 -07003724 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003725 }
Jack Palevich40600de2009-07-01 15:32:35 -07003726 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003727 /* assignment */
3728 next();
3729 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003730 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003731 } else if (tok != '(') {
3732 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003733 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003734 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003735 }
Jack Palevich8df46192009-07-07 14:48:51 -07003736 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003737 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003738 next();
3739 }
3740 }
3741 }
3742 }
3743
3744 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003745 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003746 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003747 VariableInfo* pVI = NULL;
3748 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003749 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003750 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003751 } else {
3752 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003753 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003754 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003755 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003756 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003757 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003758 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003759 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003760 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003761 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003762 if (! varArgs && !pArgList) {
3763 error ("Unexpected argument.");
3764 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003765 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003766 Type* pTargetType;
3767 if (pArgList) {
3768 pTargetType = pArgList->pHead;
3769 pArgList = pArgList->pTail;
3770 } else {
3771 pTargetType = pGen->getR0Type();
3772 if (pTargetType->tag == TY_FLOAT) {
3773 pTargetType = mkpDouble;
3774 }
3775 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003776 if (pTargetType->tag == TY_VOID) {
3777 error("Can't pass void value for argument %d",
3778 argCount + 1);
3779 } else {
3780 pGen->convertR0(pTargetType);
3781 l += pGen->storeR0ToArg(l);
3782 }
Jack Palevich95727a02009-07-06 12:07:15 -07003783 if (accept(',')) {
3784 // fine
3785 } else if ( tok != ')') {
3786 error("Expected ',' or ')'");
3787 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003788 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003789 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003790 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003791 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003792 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003793 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003794 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003795 if (!n) {
3796 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003797 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3798 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003799 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003800 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003801 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003802 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3803 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003804 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003805 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003806 }
3807 }
3808
Jack Palevich40600de2009-07-01 15:32:35 -07003809 /* Recursive descent parser for binary operations.
3810 */
3811 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003812 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003813 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003814 if (level-- == 1)
3815 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003816 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003817 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003818 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003819 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003820 n = tok;
3821 t = tokc;
3822 next();
3823
Jack Palevich40600de2009-07-01 15:32:35 -07003824 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003825 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003826 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003827 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003828 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003829 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003830
Jack Palevich40600de2009-07-01 15:32:35 -07003831 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003832 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003833 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003834 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003835 }
3836 }
3837 }
3838 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003839 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003840 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003841 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003842 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003843 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003844 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003845 }
3846 }
3847 }
3848
3849 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003850 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003851 }
3852
3853 int test_expr() {
3854 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003855 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003856 }
3857
Jack Palevicha6baa232009-06-12 11:25:59 -07003858 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003859 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003860
Jack Palevich95727a02009-07-06 12:07:15 -07003861 Type* pBaseType;
3862 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003863 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003864 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003865 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003866 next();
3867 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003868 a = test_expr();
3869 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003870 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003871 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003872 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003873 n = pGen->gjmp(0); /* jmp */
3874 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003875 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003876 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003877 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003878 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003879 }
Jack Palevich546b2242009-05-13 15:10:04 -07003880 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003881 t = tok;
3882 next();
3883 skip('(');
3884 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003885 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 a = test_expr();
3887 } else {
3888 if (tok != ';')
3889 expr();
3890 skip(';');
3891 n = codeBuf.getPC();
3892 a = 0;
3893 if (tok != ';')
3894 a = test_expr();
3895 skip(';');
3896 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003897 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003898 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003899 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003900 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003901 n = t + 4;
3902 }
3903 }
3904 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003905 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003906 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003907 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003908 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003909 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003910 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003911 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003913 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003914 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003915 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003916 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003917 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003918 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003919 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003920 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003921 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003922 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003923 if (pReturnType->tag == TY_VOID) {
3924 error("Must not return a value from a void function");
3925 } else {
3926 pGen->convertR0(pReturnType);
3927 }
3928 } else {
3929 if (pReturnType->tag != TY_VOID) {
3930 error("Must specify a value here");
3931 }
Jack Palevich8df46192009-07-07 14:48:51 -07003932 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003933 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003934 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003935 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07003936 } else if (tok != ';')
3937 expr();
3938 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003939 }
3940 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003941
Jack Palevich3f226492009-07-02 14:46:19 -07003942 bool typeEqual(Type* a, Type* b) {
3943 if (a == b) {
3944 return true;
3945 }
3946 if (a == NULL || b == NULL) {
3947 return false;
3948 }
3949 TypeTag at = a->tag;
3950 if (at != b->tag) {
3951 return false;
3952 }
3953 if (at == TY_POINTER) {
3954 return typeEqual(a->pHead, b->pHead);
3955 } else if (at == TY_FUNC || at == TY_PARAM) {
3956 return typeEqual(a->pHead, b->pHead)
3957 && typeEqual(a->pTail, b->pTail);
3958 }
3959 return true;
3960 }
3961
Jack Palevich86351982009-06-30 18:09:56 -07003962 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
3963 assert(tag >= TY_INT && tag <= TY_PARAM);
3964 Type* pType = (Type*) arena.alloc(sizeof(Type));
3965 memset(pType, 0, sizeof(*pType));
3966 pType->tag = tag;
3967 pType->pHead = pHead;
3968 pType->pTail = pTail;
3969 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07003970 }
3971
Jack Palevich3f226492009-07-02 14:46:19 -07003972 Type* createPtrType(Type* pType, Arena& arena) {
3973 return createType(TY_POINTER, pType, NULL, arena);
3974 }
3975
3976 /**
3977 * Try to print a type in declaration order
3978 */
Jack Palevich86351982009-06-30 18:09:56 -07003979 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07003980 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07003981 if (pType == NULL) {
3982 buffer.appendCStr("null");
3983 return;
3984 }
Jack Palevich3f226492009-07-02 14:46:19 -07003985 decodeTypeImp(buffer, pType);
3986 }
3987
3988 void decodeTypeImp(String& buffer, Type* pType) {
3989 decodeTypeImpPrefix(buffer, pType);
3990
Jack Palevich86351982009-06-30 18:09:56 -07003991 String temp;
3992 if (pType->id != 0) {
3993 decodeToken(temp, pType->id);
3994 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07003995 }
3996
3997 decodeTypeImpPostfix(buffer, pType);
3998 }
3999
4000 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4001 TypeTag tag = pType->tag;
4002
4003 if (tag >= TY_INT && tag <= TY_VOID) {
4004 switch (tag) {
4005 case TY_INT:
4006 buffer.appendCStr("int");
4007 break;
4008 case TY_CHAR:
4009 buffer.appendCStr("char");
4010 break;
4011 case TY_VOID:
4012 buffer.appendCStr("void");
4013 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004014 case TY_FLOAT:
4015 buffer.appendCStr("float");
4016 break;
4017 case TY_DOUBLE:
4018 buffer.appendCStr("double");
4019 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004020 default:
4021 break;
4022 }
Jack Palevich86351982009-06-30 18:09:56 -07004023 buffer.append(' ');
4024 }
Jack Palevich3f226492009-07-02 14:46:19 -07004025
4026 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004027 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004028 break;
4029 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004030 break;
4031 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004032 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004033 case TY_FLOAT:
4034 break;
4035 case TY_DOUBLE:
4036 break;
Jack Palevich86351982009-06-30 18:09:56 -07004037 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004038 decodeTypeImpPrefix(buffer, pType->pHead);
4039 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4040 buffer.append('(');
4041 }
4042 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004043 break;
4044 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004045 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004046 break;
4047 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004048 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004049 break;
4050 default:
4051 String temp;
4052 temp.printf("Unknown tag %d", pType->tag);
4053 buffer.append(temp);
4054 break;
4055 }
Jack Palevich3f226492009-07-02 14:46:19 -07004056 }
4057
4058 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4059 TypeTag tag = pType->tag;
4060
4061 switch(tag) {
4062 case TY_POINTER:
4063 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4064 buffer.append(')');
4065 }
4066 decodeTypeImpPostfix(buffer, pType->pHead);
4067 break;
4068 case TY_FUNC:
4069 buffer.append('(');
4070 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4071 decodeTypeImp(buffer, pArg);
4072 if (pArg->pTail) {
4073 buffer.appendCStr(", ");
4074 }
4075 }
4076 buffer.append(')');
4077 break;
4078 default:
4079 break;
Jack Palevich86351982009-06-30 18:09:56 -07004080 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004081 }
4082
Jack Palevich86351982009-06-30 18:09:56 -07004083 void printType(Type* pType) {
4084 String buffer;
4085 decodeType(buffer, pType);
4086 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004087 }
4088
Jack Palevich86351982009-06-30 18:09:56 -07004089 Type* acceptPrimitiveType(Arena& arena) {
4090 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004091 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004092 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004093 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004094 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004095 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004096 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004097 } else if (tok == TOK_FLOAT) {
4098 pType = mkpFloat;
4099 } else if (tok == TOK_DOUBLE) {
4100 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004101 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004102 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004103 }
4104 next();
Jack Palevich86351982009-06-30 18:09:56 -07004105 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004106 }
4107
Jack Palevich3f226492009-07-02 14:46:19 -07004108 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4109 Arena& arena) {
4110 tokenid_t declName = 0;
4111 pType = acceptDecl2(pType, declName, nameAllowed,
4112 nameRequired, arena);
4113 if (declName) {
4114 // Clone the parent type so we can set a unique ID
4115 pType = createType(pType->tag, pType->pHead,
4116 pType->pTail, arena);
4117
Jack Palevich86351982009-06-30 18:09:56 -07004118 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004119 }
Jack Palevich3f226492009-07-02 14:46:19 -07004120 // fprintf(stderr, "Parsed a declaration: ");
4121 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004122 return pType;
4123 }
4124
Jack Palevich3f226492009-07-02 14:46:19 -07004125 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4126 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004127 if (! pType) {
4128 error("Expected a declaration");
4129 }
4130 return pType;
4131 }
4132
Jack Palevich3f226492009-07-02 14:46:19 -07004133 /* Used for accepting types that appear in casts */
4134 Type* acceptCastTypeDeclaration(Arena& arena) {
4135 Type* pType = acceptPrimitiveType(arena);
4136 if (pType) {
4137 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004138 }
Jack Palevich86351982009-06-30 18:09:56 -07004139 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004140 }
4141
Jack Palevich3f226492009-07-02 14:46:19 -07004142 Type* expectCastTypeDeclaration(Arena& arena) {
4143 Type* pType = acceptCastTypeDeclaration(arena);
4144 if (! pType) {
4145 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004146 }
Jack Palevich3f226492009-07-02 14:46:19 -07004147 return pType;
4148 }
4149
4150 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4151 bool nameAllowed, bool nameRequired, Arena& arena) {
4152 int ptrCounter = 0;
4153 while (accept('*')) {
4154 ptrCounter++;
4155 }
4156 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4157 while (ptrCounter-- > 0) {
4158 pType = createType(TY_POINTER, pType, NULL, arena);
4159 }
4160 return pType;
4161 }
4162
4163 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4164 bool nameAllowed, bool nameRequired, Arena& arena) {
4165 // direct-dcl :
4166 // name
4167 // (dcl)
4168 // direct-dcl()
4169 // direct-dcl[]
4170 Type* pNewHead = NULL;
4171 if (accept('(')) {
4172 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4173 nameRequired, arena);
4174 skip(')');
4175 } else if ((declName = acceptSymbol()) != 0) {
4176 if (nameAllowed == false && declName) {
4177 error("Symbol %s not allowed here", nameof(declName));
4178 } else if (nameRequired && ! declName) {
4179 String temp;
4180 decodeToken(temp, tok);
4181 error("Expected symbol. Got %s", temp.getUnwrapped());
4182 }
4183 }
4184 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004185 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004186 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004187 pType = createType(TY_FUNC, pType, pTail, arena);
4188 skip(')');
4189 }
Jack Palevich3f226492009-07-02 14:46:19 -07004190
4191 if (pNewHead) {
4192 Type* pA = pNewHead;
4193 while (pA->pHead) {
4194 pA = pA->pHead;
4195 }
4196 pA->pHead = pType;
4197 pType = pNewHead;
4198 }
Jack Palevich86351982009-06-30 18:09:56 -07004199 return pType;
4200 }
4201
Jack Palevich3f226492009-07-02 14:46:19 -07004202 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004203 Type* pHead = NULL;
4204 Type* pTail = NULL;
4205 for(;;) {
4206 Type* pBaseArg = acceptPrimitiveType(arena);
4207 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004208 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4209 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004210 if (pArg) {
4211 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4212 if (!pHead) {
4213 pHead = pParam;
4214 pTail = pParam;
4215 } else {
4216 pTail->pTail = pParam;
4217 pTail = pParam;
4218 }
4219 }
4220 }
4221 if (! accept(',')) {
4222 break;
4223 }
4224 }
4225 return pHead;
4226 }
4227
4228 Type* expectPrimitiveType(Arena& arena) {
4229 Type* pType = acceptPrimitiveType(arena);
4230 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004231 String buf;
4232 decodeToken(buf, tok);
4233 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004234 }
Jack Palevich86351982009-06-30 18:09:56 -07004235 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004236 }
4237
Jack Palevich86351982009-06-30 18:09:56 -07004238 void addGlobalSymbol(Type* pDecl) {
4239 tokenid_t t = pDecl->id;
4240 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004241 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004242 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004243 }
Jack Palevich86351982009-06-30 18:09:56 -07004244 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004245 }
4246
Jack Palevich86351982009-06-30 18:09:56 -07004247 void reportDuplicate(tokenid_t t) {
4248 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004249 }
4250
Jack Palevich86351982009-06-30 18:09:56 -07004251 void addLocalSymbol(Type* pDecl) {
4252 tokenid_t t = pDecl->id;
4253 if (mLocals.isDefinedAtCurrentLevel(t)) {
4254 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004255 }
Jack Palevich86351982009-06-30 18:09:56 -07004256 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004257 }
4258
Jack Palevich95727a02009-07-06 12:07:15 -07004259 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004260 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004261
Jack Palevich95727a02009-07-06 12:07:15 -07004262 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004263 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004264 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4265 if (!pDecl) {
4266 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004267 }
Jack Palevich86351982009-06-30 18:09:56 -07004268 int variableAddress = 0;
4269 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004270 size_t alignment = pGen->alignmentOf(pDecl);
4271 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004272 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004273 variableAddress = -loc;
4274 VI(pDecl->id)->pAddress = (void*) variableAddress;
4275 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004276 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004277 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004278 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004279 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004280 if (tok == ',')
4281 next();
4282 }
4283 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004284 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004285 }
4286 }
4287
Jack Palevichf1728be2009-06-12 13:53:51 -07004288 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004289 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004290 }
4291
Jack Palevich569f1352009-06-29 14:29:08 -07004292 void decodeToken(String& buffer, tokenid_t token) {
4293 if (token == EOF ) {
4294 buffer.printf("EOF");
4295 } else if (token == TOK_NUM) {
4296 buffer.printf("numeric constant");
4297 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004298 if (token < 32) {
4299 buffer.printf("'\\x%02x'", token);
4300 } else {
4301 buffer.printf("'%c'", token);
4302 }
Jack Palevich569f1352009-06-29 14:29:08 -07004303 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4304 buffer.printf("keyword \"%s\"", nameof(token));
4305 } else {
4306 buffer.printf("symbol \"%s\"", nameof(token));
4307 }
4308 }
4309
Jack Palevich40600de2009-07-01 15:32:35 -07004310 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004311 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004312 if (!result) {
4313 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07004314 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07004315 error("Expected symbol. Got %s", temp.getUnwrapped());
4316 }
4317 return result;
4318 }
4319
Jack Palevich86351982009-06-30 18:09:56 -07004320 tokenid_t acceptSymbol() {
4321 tokenid_t result = 0;
4322 if (tok >= TOK_SYMBOL) {
4323 result = tok;
4324 next();
Jack Palevich86351982009-06-30 18:09:56 -07004325 }
4326 return result;
4327 }
4328
Jack Palevichb7c81e92009-06-04 19:56:13 -07004329 void globalDeclarations() {
4330 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004331 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4332 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004333 break;
4334 }
Jack Palevich86351982009-06-30 18:09:56 -07004335 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4336 if (!pDecl) {
4337 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004338 }
Jack Palevich86351982009-06-30 18:09:56 -07004339 if (! isDefined(pDecl->id)) {
4340 addGlobalSymbol(pDecl);
4341 }
4342 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004343 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004344 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004345 }
Jack Palevich86351982009-06-30 18:09:56 -07004346 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004347 // it's a variable declaration
4348 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004349 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004350 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004351 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004352 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004353 }
Jack Palevich86351982009-06-30 18:09:56 -07004354 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004355 if (tok == TOK_NUM) {
4356 if (name) {
4357 * (int*) name->pAddress = tokc;
4358 }
4359 next();
4360 } else {
4361 error("Expected an integer constant");
4362 }
4363 }
Jack Palevich86351982009-06-30 18:09:56 -07004364 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004365 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004366 }
Jack Palevich86351982009-06-30 18:09:56 -07004367 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4368 if (!pDecl) {
4369 break;
4370 }
4371 if (! isDefined(pDecl->id)) {
4372 addGlobalSymbol(pDecl);
4373 }
4374 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004375 }
4376 skip(';');
4377 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004378 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004379 if (accept(';')) {
4380 // forward declaration.
4381 } else {
4382 if (name) {
4383 /* patch forward references (XXX: does not work for function
4384 pointers) */
4385 pGen->gsym((int) name->pForward);
4386 /* put function address */
4387 name->pAddress = (void*) codeBuf.getPC();
4388 }
4389 // Calculate stack offsets for parameters
4390 mLocals.pushLevel();
4391 intptr_t a = 8;
4392 int argCount = 0;
4393 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4394 Type* pArg = pP->pHead;
4395 addLocalSymbol(pArg);
4396 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004397 size_t alignment = pGen->alignmentOf(pArg);
4398 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004399 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004400 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004401 argCount++;
4402 }
4403 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004404 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004405 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004406 block(0, true);
4407 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004408 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004409 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004410 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004411 }
4412 }
4413 }
4414
Jack Palevich9cbd2262009-07-08 16:48:41 -07004415 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4416 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4417 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004418 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004419 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004420 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004421 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004422 char* result = (char*) base;
4423 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004424 return result;
4425 }
4426
Jack Palevich21a15a22009-05-11 14:49:29 -07004427 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004428 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004429 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004430 pGlobalBase = 0;
4431 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004432 if (pGen) {
4433 delete pGen;
4434 pGen = 0;
4435 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004436 if (file) {
4437 delete file;
4438 file = 0;
4439 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004440 }
4441
4442 void clear() {
4443 tok = 0;
4444 tokc = 0;
4445 tokl = 0;
4446 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004447 rsym = 0;
4448 loc = 0;
4449 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004450 dptr = 0;
4451 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004452 file = 0;
4453 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004454 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004455 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004456 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004457
Jack Palevich22305132009-05-13 10:58:45 -07004458 void setArchitecture(const char* architecture) {
4459 delete pGen;
4460 pGen = 0;
4461
4462 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004463#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004464 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004465 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004466 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004467#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004468#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004469 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004470 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004471 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004472#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004473 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004474 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004475 }
4476 }
4477
4478 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004479#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004480 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004481#elif defined(DEFAULT_X86_CODEGEN)
4482 pGen = new X86CodeGenerator();
4483#endif
4484 }
4485 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004486 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004487 } else {
4488 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07004489 }
4490 }
4491
Jack Palevich77ae76e2009-05-10 19:59:24 -07004492public:
Jack Palevich22305132009-05-13 10:58:45 -07004493 struct args {
4494 args() {
4495 architecture = 0;
4496 }
4497 const char* architecture;
4498 };
4499
Jack Paleviche7b59062009-05-19 17:12:17 -07004500 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004501 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004502 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004503
Jack Paleviche7b59062009-05-19 17:12:17 -07004504 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004505 cleanup();
4506 }
4507
Jack Palevich1cdef202009-05-22 12:06:27 -07004508 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004509 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004510
4511 cleanup();
4512 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004513 mTokenTable.setArena(&mGlobalArena);
4514 mGlobals.setArena(&mGlobalArena);
4515 mGlobals.setTokenTable(&mTokenTable);
4516 mLocals.setArena(&mLocalArena);
4517 mLocals.setTokenTable(&mTokenTable);
4518
4519 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07004520 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004521 codeBuf.init(ALLOC_SIZE);
4522 setArchitecture(NULL);
4523 if (!pGen) {
4524 return -1;
4525 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004526#ifdef PROVIDE_TRACE_CODEGEN
4527 pGen = new TraceCodeGenerator(pGen);
4528#endif
4529 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004530 pGen->init(&codeBuf);
4531 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004532 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4533 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004534 inp();
4535 next();
4536 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004537 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004538 result = pGen->finishCompile();
4539 if (result == 0) {
4540 if (mErrorBuf.len()) {
4541 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004542 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004543 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004544 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004545 }
4546
Jack Palevich86351982009-06-30 18:09:56 -07004547 void createPrimitiveTypes() {
4548 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4549 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4550 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004551 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4552 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004553 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004554 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4555 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004556 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4557 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004558 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004559 }
4560
Jack Palevicha6baa232009-06-12 11:25:59 -07004561 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004562 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004563 }
4564
Jack Palevich569f1352009-06-29 14:29:08 -07004565 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004566 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004567 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004568 }
4569
Jack Palevich569f1352009-06-29 14:29:08 -07004570 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004571 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004572 error("Undefined forward reference: %s",
4573 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004574 }
4575 return true;
4576 }
4577
Jack Palevich21a15a22009-05-11 14:49:29 -07004578 int dump(FILE* out) {
4579 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4580 return 0;
4581 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004582
Jack Palevicha6535612009-05-13 16:24:17 -07004583 int disassemble(FILE* out) {
4584 return pGen->disassemble(out);
4585 }
4586
Jack Palevich1cdef202009-05-22 12:06:27 -07004587 /* Look through the symbol table to find a symbol.
4588 * If found, return its value.
4589 */
4590 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004591 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4592 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004593 if (pVariableInfo) {
4594 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004595 }
4596 return NULL;
4597 }
4598
Jack Palevicheedf9d22009-06-04 16:23:40 -07004599 void getPragmas(ACCsizei* actualStringCount,
4600 ACCsizei maxStringCount, ACCchar** strings) {
4601 int stringCount = mPragmaStringCount;
4602 if (actualStringCount) {
4603 *actualStringCount = stringCount;
4604 }
4605 if (stringCount > maxStringCount) {
4606 stringCount = maxStringCount;
4607 }
4608 if (strings) {
4609 char* pPragmas = mPragmas.getUnwrapped();
4610 while (stringCount-- > 0) {
4611 *strings++ = pPragmas;
4612 pPragmas += strlen(pPragmas) + 1;
4613 }
4614 }
4615 }
4616
Jack Palevichac0e95e2009-05-29 13:53:44 -07004617 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004618 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004619 }
4620
Jack Palevich77ae76e2009-05-10 19:59:24 -07004621};
4622
Jack Paleviche7b59062009-05-19 17:12:17 -07004623const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004624 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4625
Jack Paleviche7b59062009-05-19 17:12:17 -07004626const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004627 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4628 5, 5, /* ==, != */
4629 9, 10, /* &&, || */
4630 6, 7, 8, /* & ^ | */
4631 2, 2 /* ~ ! */
4632 };
4633
Jack Palevich8b0624c2009-05-20 12:12:06 -07004634#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004635FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004636#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004637
Jack Palevich8b0624c2009-05-20 12:12:06 -07004638#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004639const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004640 0x1, // ++
4641 0xff, // --
4642 0xc1af0f, // *
4643 0xf9f79991, // /
4644 0xf9f79991, // % (With manual assist to swap results)
4645 0xc801, // +
4646 0xd8f7c829, // -
4647 0xe0d391, // <<
4648 0xf8d391, // >>
4649 0xe, // <=
4650 0xd, // >=
4651 0xc, // <
4652 0xf, // >
4653 0x4, // ==
4654 0x5, // !=
4655 0x0, // &&
4656 0x1, // ||
4657 0xc821, // &
4658 0xc831, // ^
4659 0xc809, // |
4660 0xd0f7, // ~
4661 0x4 // !
4662};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004663#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004664
Jack Palevich1cdef202009-05-22 12:06:27 -07004665struct ACCscript {
4666 ACCscript() {
4667 text = 0;
4668 textLength = 0;
4669 accError = ACC_NO_ERROR;
4670 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004671
Jack Palevich1cdef202009-05-22 12:06:27 -07004672 ~ACCscript() {
4673 delete text;
4674 }
Jack Palevich546b2242009-05-13 15:10:04 -07004675
Jack Palevich1cdef202009-05-22 12:06:27 -07004676 void setError(ACCenum error) {
4677 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4678 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004679 }
4680 }
4681
Jack Palevich1cdef202009-05-22 12:06:27 -07004682 ACCenum getError() {
4683 ACCenum result = accError;
4684 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004685 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004686 }
4687
Jack Palevich1cdef202009-05-22 12:06:27 -07004688 Compiler compiler;
4689 char* text;
4690 int textLength;
4691 ACCenum accError;
4692};
4693
4694
4695extern "C"
4696ACCscript* accCreateScript() {
4697 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004698}
Jack Palevich1cdef202009-05-22 12:06:27 -07004699
4700extern "C"
4701ACCenum accGetError( ACCscript* script ) {
4702 return script->getError();
4703}
4704
4705extern "C"
4706void accDeleteScript(ACCscript* script) {
4707 delete script;
4708}
4709
4710extern "C"
4711void accScriptSource(ACCscript* script,
4712 ACCsizei count,
4713 const ACCchar ** string,
4714 const ACCint * length) {
4715 int totalLength = 0;
4716 for(int i = 0; i < count; i++) {
4717 int len = -1;
4718 const ACCchar* s = string[i];
4719 if (length) {
4720 len = length[i];
4721 }
4722 if (len < 0) {
4723 len = strlen(s);
4724 }
4725 totalLength += len;
4726 }
4727 delete script->text;
4728 char* text = new char[totalLength + 1];
4729 script->text = text;
4730 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004731 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004732 for(int i = 0; i < count; i++) {
4733 int len = -1;
4734 const ACCchar* s = string[i];
4735 if (length) {
4736 len = length[i];
4737 }
4738 if (len < 0) {
4739 len = strlen(s);
4740 }
Jack Palevich09555c72009-05-27 12:25:55 -07004741 memcpy(dest, s, len);
4742 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004743 }
4744 text[totalLength] = '\0';
4745}
4746
4747extern "C"
4748void accCompileScript(ACCscript* script) {
4749 int result = script->compiler.compile(script->text, script->textLength);
4750 if (result) {
4751 script->setError(ACC_INVALID_OPERATION);
4752 }
4753}
4754
4755extern "C"
4756void accGetScriptiv(ACCscript* script,
4757 ACCenum pname,
4758 ACCint * params) {
4759 switch (pname) {
4760 case ACC_INFO_LOG_LENGTH:
4761 *params = 0;
4762 break;
4763 }
4764}
4765
4766extern "C"
4767void accGetScriptInfoLog(ACCscript* script,
4768 ACCsizei maxLength,
4769 ACCsizei * length,
4770 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004771 char* message = script->compiler.getErrorMessage();
4772 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004773 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004774 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004775 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004776 if (infoLog && maxLength > 0) {
4777 int trimmedLength = maxLength < messageLength ?
4778 maxLength : messageLength;
4779 memcpy(infoLog, message, trimmedLength);
4780 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004781 }
4782}
4783
4784extern "C"
4785void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4786 ACCvoid ** address) {
4787 void* value = script->compiler.lookup(name);
4788 if (value) {
4789 *address = value;
4790 } else {
4791 script->setError(ACC_INVALID_VALUE);
4792 }
4793}
4794
Jack Palevicheedf9d22009-06-04 16:23:40 -07004795extern "C"
4796void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4797 ACCsizei maxStringCount, ACCchar** strings){
4798 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4799}
4800
-b master422972c2009-06-17 19:13:52 -07004801extern "C"
4802void accDisassemble(ACCscript* script) {
4803 script->compiler.disassemble(stderr);
4804}
4805
Jack Palevicheedf9d22009-06-04 16:23:40 -07004806
Jack Palevich1cdef202009-05-22 12:06:27 -07004807} // namespace acc
4808