blob: 7f726f199ad1318bf27aa415c4db6c5837e96365 [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 Palevich25c0cca2009-07-13 16:56:28 -07001022 case TY_CHAR:
1023 if (ea > -LOCAL && ea < LOCAL) {
1024 // Local, fp relative
1025 if (ea < -4095 || ea > 4095) {
1026 error("Offset out of range: %08x", ea);
1027 }
1028 if (ea < 0) {
1029 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1030 } else {
1031 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1032 }
1033 } else{
1034 // Global, absolute
1035 o4(0xE59F1000); // ldr r1, .L1
1036 o4(0xEA000000); // b .L99
1037 o4(ea); // .L1: .word 0
1038 o4(0xE5C10000); // .L99: strb r0, [r1]
1039 }
1040 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001041 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001042 case TY_INT:
1043 case TY_FLOAT:
1044 if (ea > -LOCAL && ea < LOCAL) {
1045 // Local, fp relative
1046 if (ea < -4095 || ea > 4095) {
1047 error("Offset out of range: %08x", ea);
1048 }
1049 if (ea < 0) {
1050 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1051 } else {
1052 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1053 }
1054 } else{
1055 // Global, absolute
1056 o4(0xE59F1000); // ldr r1, .L1
1057 o4(0xEA000000); // b .L99
1058 o4(ea); // .L1: .word 0
1059 o4(0xE5810000); // .L99: str r0, [r1]
1060 }
1061 break;
1062 case TY_DOUBLE:
1063 if ((ea & 0x7) != 0) {
1064 error("double address is not aligned: %d", ea);
1065 }
1066 if (ea > -LOCAL && ea < LOCAL) {
1067 // Local, fp relative
1068 if (ea < -4095 || ea > 4095) {
1069 error("Offset out of range: %08x", ea);
1070 }
1071 if (ea < 0) {
1072 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1073 o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4]
1074#if 0
1075 // strd doesn't seem to work. Is encoding wrong?
1076 } else if (ea < 0) {
1077 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1078 } else if (ea < 256) {
1079 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1080#endif
1081 } else {
1082 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1083 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1084 }
1085 } else{
1086 // Global, absolute
1087 o4(0xE59F2000); // ldr r2, .L1
1088 o4(0xEA000000); // b .L99
1089 o4(ea); // .L1: .word 0
1090 o4(0xE1C200F0); // .L99: strd r0, [r2]
1091 }
1092 break;
1093 default:
1094 error("Unable to store to type %d", tag);
1095 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001096 }
Jack Palevich22305132009-05-13 10:58:45 -07001097 }
1098
Jack Palevich8df46192009-07-07 14:48:51 -07001099 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001100 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich25c0cca2009-07-13 16:56:28 -07001101 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001102 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001103 case TY_CHAR:
1104 if (ea < LOCAL) {
1105 // Local, fp relative
1106 if (ea < -4095 || ea > 4095) {
1107 error("Offset out of range: %08x", ea);
1108 }
1109 if (ea < 0) {
1110 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1111 } else {
1112 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1113 }
1114 } else {
1115 // Global, absolute
1116 o4(0xE59F2000); // ldr r2, .L1
1117 o4(0xEA000000); // b .L99
1118 o4(ea); // .L1: .word ea
1119 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1120 }
1121
1122 if (isIncDec) {
1123 error("inc/dec not implemented for char.");
1124 }
1125 break;
1126 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001127 case TY_INT:
1128 case TY_FLOAT:
1129 if (ea < LOCAL) {
1130 // Local, fp relative
1131 if (ea < -4095 || ea > 4095) {
1132 error("Offset out of range: %08x", ea);
1133 }
1134 if (ea < 0) {
1135 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1136 } else {
1137 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1138 }
1139 } else {
1140 // Global, absolute
1141 o4(0xE59F2000); // ldr r2, .L1
1142 o4(0xEA000000); // b .L99
1143 o4(ea); // .L1: .word ea
1144 o4(0xE5920000); // .L99: ldr r0, [r2]
1145 }
Jack Palevich22305132009-05-13 10:58:45 -07001146
Jack Palevichb7718b92009-07-09 22:00:24 -07001147 if (isIncDec) {
1148 if (tag == TY_INT) {
1149 switch (op) {
1150 case OP_INCREMENT:
1151 o4(0xE2801001); // add r1, r0, #1
1152 break;
1153 case OP_DECREMENT:
1154 o4(0xE2401001); // sub r1, r0, #1
1155 break;
1156 default:
1157 error("unknown opcode: %d", op);
1158 }
1159 if (ea < LOCAL) {
1160 // Local, fp relative
1161 // Don't need range check, was already checked above
1162 if (ea < 0) {
1163 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1164 } else {
1165 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1166 }
1167 } else{
1168 // Global, absolute
1169 // r2 is already set up from before.
1170 o4(0xE5821000); // str r1, [r2]
1171 }
1172 }
1173 else {
1174 error("inc/dec not implemented for float.");
1175 }
1176 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001177 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001178 case TY_DOUBLE:
1179 if ((ea & 0x7) != 0) {
1180 error("double address is not aligned: %d", ea);
1181 }
1182 if (ea < LOCAL) {
1183 // Local, fp relative
1184 if (ea < -4095 || ea > 4095) {
1185 error("Offset out of range: %08x", ea);
1186 }
1187 if (ea < 0) {
1188 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1189 o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4]
1190 } else {
1191 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1192 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1193 }
1194 } else {
1195 // Global, absolute
1196 o4(0xE59F2000); // ldr r2, .L1
1197 o4(0xEA000000); // b .L99
1198 o4(ea); // .L1: .word ea
1199 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1200 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001201 break;
1202 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001203 error("Unable to load type %d", tag);
1204 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001205 }
Jack Palevich8df46192009-07-07 14:48:51 -07001206 setR0Type(pType);
1207 }
1208
1209 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001210 Type* pR0Type = getR0Type();
1211 if (bitsSame(pType, pR0Type)) {
1212 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001213 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001214 TypeTag r0Tag = collapseType(pR0Type->tag);
1215 TypeTag destTag = collapseType(pType->tag);
1216 if (r0Tag == TY_INT) {
1217 if (destTag == TY_FLOAT) {
1218 callRuntime((void*) runtime_int_to_float);
1219 } else {
1220 assert(destTag == TY_DOUBLE);
1221 callRuntime((void*) runtime_int_to_double);
1222 }
1223 } else if (r0Tag == TY_FLOAT) {
1224 if (destTag == TY_INT) {
1225 callRuntime((void*) runtime_float_to_int);
1226 } else {
1227 assert(destTag == TY_DOUBLE);
1228 callRuntime((void*) runtime_float_to_double);
1229 }
1230 } else {
1231 assert (r0Tag == TY_DOUBLE);
1232 if (destTag == TY_INT) {
1233 callRuntime((void*) runtime_double_to_int);
1234 } else {
1235 assert(destTag == TY_FLOAT);
1236 callRuntime((void*) runtime_double_to_float);
1237 }
1238 }
Jack Palevich8df46192009-07-07 14:48:51 -07001239 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001240 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001241 }
1242
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001243 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001244 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001245 return o4(0xE24DDF00); // Placeholder
1246 }
1247
Jack Palevich1a539db2009-07-08 13:04:41 -07001248 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001249 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevichb7718b92009-07-09 22:00:24 -07001250 Type* pR0Type = getR0Type();
1251 TypeTag r0ct = collapseType(pR0Type->tag);
1252 switch(r0ct) {
1253 case TY_INT:
1254 case TY_FLOAT:
1255 if (l < 0 || l > 4096-4) {
1256 error("l out of range for stack offset: 0x%08x", l);
1257 }
1258 o4(0xE58D0000 + l); // str r0, [sp, #l]
1259 return 4;
1260 case TY_DOUBLE: {
1261 // Align to 8 byte boundary
1262 int l2 = (l + 7) & ~7;
1263 if (l2 < 0 || l2 > 4096-8) {
1264 error("l out of range for stack offset: 0x%08x", l);
1265 }
1266 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1267 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1268 return (l2 - l) + 8;
1269 }
1270 default:
1271 assert(false);
1272 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001273 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001274 }
1275
Jack Palevichb7718b92009-07-09 22:00:24 -07001276 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001277 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001278 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001279 // Have to calculate register arg count from actual stack size,
1280 // in order to properly handle ... functions.
1281 int regArgCount = l >> 2;
1282 if (regArgCount > 4) {
1283 regArgCount = 4;
1284 }
1285 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001286 argumentStackUse -= regArgCount * 4;
1287 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1288 }
1289 mStackUse += argumentStackUse;
1290
1291 // Align stack.
1292 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1293 * STACK_ALIGNMENT);
1294 mStackAlignmentAdjustment = 0;
1295 if (missalignment > 0) {
1296 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1297 }
1298 l += mStackAlignmentAdjustment;
1299
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001300 if (l < 0 || l > 0x3FC) {
1301 error("L out of range for stack adjustment: 0x%08x", l);
1302 }
1303 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001304 mStackUse += mStackAlignmentAdjustment;
1305 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1306 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001307 }
1308
Jack Palevich8df46192009-07-07 14:48:51 -07001309 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001310 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001311 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001312 // Forward calls are always short (local)
1313 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001314 }
1315
Jack Palevich8df46192009-07-07 14:48:51 -07001316 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001317 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001318 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001319 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001320 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001321 if (t >= - (1 << 25) && t < (1 << 25)) {
1322 o4(0xEB000000 | encodeAddress(t));
1323 } else {
1324 // Long call.
1325 o4(0xE59FC000); // ldr r12, .L1
1326 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001327 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001328 o4(0xE08CC00F); // .L99: add r12,pc
1329 o4(0xE12FFF3C); // blx r12
1330 }
Jack Palevich22305132009-05-13 10:58:45 -07001331 }
1332
Jack Palevich8df46192009-07-07 14:48:51 -07001333 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001334 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001335 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001336 int argCount = l >> 2;
1337 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001338 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001339 if (adjustedL < 0 || adjustedL > 4096-4) {
1340 error("l out of range for stack offset: 0x%08x", l);
1341 }
1342 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1343 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001344 }
1345
Jack Palevichb7718b92009-07-09 22:00:24 -07001346 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001347 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001348 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001349 // Have to calculate register arg count from actual stack size,
1350 // in order to properly handle ... functions.
1351 int regArgCount = l >> 2;
1352 if (regArgCount > 4) {
1353 regArgCount = 4;
1354 }
1355 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001356 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1357 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001358 if (stackUse) {
1359 if (stackUse < 0 || stackUse > 255) {
1360 error("L out of range for stack adjustment: 0x%08x", l);
1361 }
1362 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001363 mStackUse -= stackUse * 4;
1364 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001365 }
Jack Palevich22305132009-05-13 10:58:45 -07001366 }
1367
Jack Palevicha6535612009-05-13 16:24:17 -07001368 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001369 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001370 }
1371
1372 /* output a symbol and patch all calls to it */
1373 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001374 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001375 int n;
1376 int base = getBase();
1377 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001378 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001379 while (t) {
1380 int data = * (int*) t;
1381 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1382 if (decodedOffset == 0) {
1383 n = 0;
1384 } else {
1385 n = base + decodedOffset; /* next value */
1386 }
1387 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1388 | encodeRelAddress(pc - t - 8);
1389 t = n;
1390 }
1391 }
1392
Jack Palevich1cdef202009-05-22 12:06:27 -07001393 virtual int finishCompile() {
1394#if defined(__arm__)
1395 const long base = long(getBase());
1396 const long curr = long(getPC());
1397 int err = cacheflush(base, curr, 0);
1398 return err;
1399#else
1400 return 0;
1401#endif
1402 }
1403
Jack Palevicha6535612009-05-13 16:24:17 -07001404 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001405#ifdef ENABLE_ARM_DISASSEMBLY
1406 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001407 disasm_interface_t di;
1408 di.di_readword = disassemble_readword;
1409 di.di_printaddr = disassemble_printaddr;
1410 di.di_printf = disassemble_printf;
1411
1412 int base = getBase();
1413 int pc = getPC();
1414 for(int i = base; i < pc; i += 4) {
1415 fprintf(out, "%08x: %08x ", i, *(int*) i);
1416 ::disasm(&di, i, 0);
1417 }
Jack Palevich09555c72009-05-27 12:25:55 -07001418#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001419 return 0;
1420 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001421
Jack Palevich9eed7a22009-07-06 17:24:34 -07001422 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001423 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001424 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001425 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001426 switch(pType->tag) {
1427 case TY_DOUBLE:
1428 return 8;
1429 default:
1430 return 4;
1431 }
1432 }
1433
1434 /**
1435 * Array element alignment (in bytes) for this type of data.
1436 */
1437 virtual size_t sizeOf(Type* pType){
1438 switch(pType->tag) {
1439 case TY_INT:
1440 return 4;
1441 case TY_CHAR:
1442 return 1;
1443 default:
1444 return 0;
1445 case TY_FLOAT:
1446 return 4;
1447 case TY_DOUBLE:
1448 return 8;
1449 case TY_POINTER:
1450 return 4;
1451 }
1452 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001453
1454 virtual size_t stackSizeOf(Type* pType) {
1455 switch(pType->tag) {
1456 case TY_DOUBLE:
1457 return 8;
1458 default:
1459 return 4;
1460 }
1461 }
1462
Jack Palevich22305132009-05-13 10:58:45 -07001463 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001464 static FILE* disasmOut;
1465
1466 static u_int
1467 disassemble_readword(u_int address)
1468 {
1469 return(*((u_int *)address));
1470 }
1471
1472 static void
1473 disassemble_printaddr(u_int address)
1474 {
1475 fprintf(disasmOut, "0x%08x", address);
1476 }
1477
1478 static void
1479 disassemble_printf(const char *fmt, ...) {
1480 va_list ap;
1481 va_start(ap, fmt);
1482 vfprintf(disasmOut, fmt, ap);
1483 va_end(ap);
1484 }
1485
1486 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1487
1488 /** Encode a relative address that might also be
1489 * a label.
1490 */
1491 int encodeAddress(int value) {
1492 int base = getBase();
1493 if (value >= base && value <= getPC() ) {
1494 // This is a label, encode it relative to the base.
1495 value = value - base;
1496 }
1497 return encodeRelAddress(value);
1498 }
1499
1500 int encodeRelAddress(int value) {
1501 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1502 }
Jack Palevich22305132009-05-13 10:58:45 -07001503
Jack Palevichb7718b92009-07-09 22:00:24 -07001504 int calcRegArgCount(Type* pDecl) {
1505 int reg = 0;
1506 Type* pArgs = pDecl->pTail;
1507 while (pArgs && reg < 4) {
1508 Type* pArg = pArgs->pHead;
1509 if ( pArg->tag == TY_DOUBLE) {
1510 int evenReg = (reg + 1) & ~1;
1511 if (evenReg >= 4) {
1512 break;
1513 }
1514 reg = evenReg + 2;
1515 } else {
1516 reg++;
1517 }
1518 pArgs = pArgs->pTail;
1519 }
1520 return reg;
1521 }
1522
1523 /* Pop TOS to R1
1524 * Make sure both R0 and TOS are floats. (Could be ints)
1525 * We know that at least one of R0 and TOS is already a float
1526 */
1527 void setupFloatArgs() {
1528 Type* pR0Type = getR0Type();
1529 Type* pTOSType = getTOSType();
1530 TypeTag tagR0 = collapseType(pR0Type->tag);
1531 TypeTag tagTOS = collapseType(pTOSType->tag);
1532 if (tagR0 != TY_FLOAT) {
1533 assert(tagR0 == TY_INT);
1534 callRuntime((void*) runtime_int_to_float);
1535 }
1536 if (tagTOS != TY_FLOAT) {
1537 assert(tagTOS == TY_INT);
1538 assert(tagR0 == TY_FLOAT);
1539 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1540 o4(0xE59D0004); // ldr r0, [sp, #4]
1541 callRuntime((void*) runtime_int_to_float);
1542 o4(0xE1A01000); // mov r1, r0
1543 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1544 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1545 } else {
1546 // Pop TOS
1547 o4(0xE8BD0002); // ldmfd sp!,{r1}
1548 }
1549 mStackUse -= 4;
1550 popType();
1551 }
1552
1553 /* Pop TOS into R2..R3
1554 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1555 * We know that at least one of R0 and TOS are already a double.
1556 */
1557
1558 void setupDoubleArgs() {
1559 Type* pR0Type = getR0Type();
1560 Type* pTOSType = getTOSType();
1561 TypeTag tagR0 = collapseType(pR0Type->tag);
1562 TypeTag tagTOS = collapseType(pTOSType->tag);
1563 if (tagR0 != TY_DOUBLE) {
1564 if (tagR0 == TY_INT) {
1565 callRuntime((void*) runtime_int_to_double);
1566 } else {
1567 assert(tagR0 == TY_FLOAT);
1568 callRuntime((void*) runtime_float_to_double);
1569 }
1570 }
1571 if (tagTOS != TY_DOUBLE) {
1572 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1573 o4(0xE59D0008); // ldr r0, [sp, #8]
1574 if (tagTOS == TY_INT) {
1575 callRuntime((void*) runtime_int_to_double);
1576 } else {
1577 assert(tagTOS == TY_FLOAT);
1578 callRuntime((void*) runtime_float_to_double);
1579 }
1580 o4(0xE1A02000); // mov r2, r0
1581 o4(0xE1A03001); // mov r3, r1
1582 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1583 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1584 mStackUse -= 4;
1585 } else {
1586 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1587 mStackUse -= 8;
1588 }
1589 popType();
1590 }
1591
1592 void callRuntime(void* fn) {
1593 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001594 o4(0xEA000000); // b .L99
1595 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001596 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001597 }
1598
Jack Palevichb7718b92009-07-09 22:00:24 -07001599 // Integer math:
1600
1601 static int runtime_DIV(int b, int a) {
1602 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001603 }
1604
Jack Palevichb7718b92009-07-09 22:00:24 -07001605 static int runtime_MOD(int b, int a) {
1606 return a % b;
1607 }
1608
1609 // Comparison to zero
1610
1611 static int runtime_is_non_zero_f(float a) {
1612 return a != 0;
1613 }
1614
1615 static int runtime_is_non_zero_d(double a) {
1616 return a != 0;
1617 }
1618
1619 // Comparison to zero
1620
1621 static int runtime_is_zero_f(float a) {
1622 return a == 0;
1623 }
1624
1625 static int runtime_is_zero_d(double a) {
1626 return a == 0;
1627 }
1628
1629 // Type conversion
1630
1631 static int runtime_float_to_int(float a) {
1632 return (int) a;
1633 }
1634
1635 static double runtime_float_to_double(float a) {
1636 return (double) a;
1637 }
1638
1639 static int runtime_double_to_int(double a) {
1640 return (int) a;
1641 }
1642
1643 static float runtime_double_to_float(double a) {
1644 return (float) a;
1645 }
1646
1647 static float runtime_int_to_float(int a) {
1648 return (float) a;
1649 }
1650
1651 static double runtime_int_to_double(int a) {
1652 return (double) a;
1653 }
1654
1655 // Comparisons float
1656
1657 static int runtime_cmp_eq_ff(float b, float a) {
1658 return a == b;
1659 }
1660
1661 static int runtime_cmp_ne_ff(float b, float a) {
1662 return a != b;
1663 }
1664
1665 static int runtime_cmp_lt_ff(float b, float a) {
1666 return a < b;
1667 }
1668
1669 static int runtime_cmp_le_ff(float b, float a) {
1670 return a <= b;
1671 }
1672
1673 static int runtime_cmp_ge_ff(float b, float a) {
1674 return a >= b;
1675 }
1676
1677 static int runtime_cmp_gt_ff(float b, float a) {
1678 return a > b;
1679 }
1680
1681 // Comparisons double
1682
1683 static int runtime_cmp_eq_dd(double b, double a) {
1684 return a == b;
1685 }
1686
1687 static int runtime_cmp_ne_dd(double b, double a) {
1688 return a != b;
1689 }
1690
1691 static int runtime_cmp_lt_dd(double b, double a) {
1692 return a < b;
1693 }
1694
1695 static int runtime_cmp_le_dd(double b, double a) {
1696 return a <= b;
1697 }
1698
1699 static int runtime_cmp_ge_dd(double b, double a) {
1700 return a >= b;
1701 }
1702
1703 static int runtime_cmp_gt_dd(double b, double a) {
1704 return a > b;
1705 }
1706
1707 // Math float
1708
1709 static float runtime_op_add_ff(float b, float a) {
1710 return a + b;
1711 }
1712
1713 static float runtime_op_sub_ff(float b, float a) {
1714 return a - b;
1715 }
1716
1717 static float runtime_op_mul_ff(float b, float a) {
1718 return a * b;
1719 }
1720
1721 static float runtime_op_div_ff(float b, float a) {
1722 return a / b;
1723 }
1724
1725 static float runtime_op_neg_f(float a) {
1726 return -a;
1727 }
1728
1729 // Math double
1730
1731 static double runtime_op_add_dd(double b, double a) {
1732 return a + b;
1733 }
1734
1735 static double runtime_op_sub_dd(double b, double a) {
1736 return a - b;
1737 }
1738
1739 static double runtime_op_mul_dd(double b, double a) {
1740 return a * b;
1741 }
1742
1743 static double runtime_op_div_dd(double b, double a) {
1744 return a / b;
1745 }
1746
1747 static double runtime_op_neg_d(double a) {
1748 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001749 }
-b master422972c2009-06-17 19:13:52 -07001750
1751 static const int STACK_ALIGNMENT = 8;
1752 int mStackUse;
1753 // This variable holds the amount we adjusted the stack in the most
1754 // recent endFunctionCallArguments call. It's examined by the
1755 // following adjustStackAfterCall call.
1756 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001757 };
1758
Jack Palevich09555c72009-05-27 12:25:55 -07001759#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001760
1761#ifdef PROVIDE_X86_CODEGEN
1762
Jack Palevich21a15a22009-05-11 14:49:29 -07001763 class X86CodeGenerator : public CodeGenerator {
1764 public:
1765 X86CodeGenerator() {}
1766 virtual ~X86CodeGenerator() {}
1767
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001768 /* returns address to patch with local variable size
1769 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001770 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001771 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1772 return oad(0xec81, 0); /* sub $xxx, %esp */
1773 }
1774
Jack Palevichb7718b92009-07-09 22:00:24 -07001775 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001776 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001777 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001778 }
1779
Jack Palevich21a15a22009-05-11 14:49:29 -07001780 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001781 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001782 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001783 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001784 }
1785
Jack Palevich1a539db2009-07-08 13:04:41 -07001786 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001787 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001788 switch (pType->tag) {
1789 case TY_FLOAT:
1790 oad(0x05D9, address); // flds
1791 break;
1792 case TY_DOUBLE:
1793 oad(0x05DD, address); // fldl
1794 break;
1795 default:
1796 assert(false);
1797 break;
1798 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001799 }
1800
Jack Palevich22305132009-05-13 10:58:45 -07001801 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001802 return psym(0xe9, t);
1803 }
1804
1805 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001806 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001807 Type* pR0Type = getR0Type();
1808 TypeTag tagR0 = pR0Type->tag;
1809 bool isFloatR0 = isFloatTag(tagR0);
1810 if (isFloatR0) {
1811 o(0xeed9); // fldz
1812 o(0xe9da); // fucompp
1813 o(0xe0df); // fnstsw %ax
1814 o(0x9e); // sahf
1815 } else {
1816 o(0xc085); // test %eax, %eax
1817 }
1818 // Use two output statements to generate one instruction.
1819 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001820 return psym(0x84 + l, t);
1821 }
1822
Jack Palevicha39749f2009-07-08 20:40:31 -07001823 virtual void gcmp(int op, Type* pResultType) {
1824 Type* pR0Type = getR0Type();
1825 Type* pTOSType = getTOSType();
1826 TypeTag tagR0 = pR0Type->tag;
1827 TypeTag tagTOS = pTOSType->tag;
1828 bool isFloatR0 = isFloatTag(tagR0);
1829 bool isFloatTOS = isFloatTag(tagTOS);
1830 if (!isFloatR0 && !isFloatTOS) {
1831 int t = decodeOp(op);
1832 o(0x59); /* pop %ecx */
1833 o(0xc139); /* cmp %eax,%ecx */
1834 li(0, NULL);
1835 o(0x0f); /* setxx %al */
1836 o(t + 0x90);
1837 o(0xc0);
1838 popType();
1839 } else {
1840 setupFloatOperands();
1841 switch (op) {
1842 case OP_EQUALS:
1843 o(0xe9da); // fucompp
1844 o(0xe0df); // fnstsw %ax
1845 o(0x9e); // sahf
1846 o(0xc0940f); // sete %al
1847 o(0xc29b0f); // setnp %dl
1848 o(0xd021); // andl %edx, %eax
1849 break;
1850 case OP_NOT_EQUALS:
1851 o(0xe9da); // fucompp
1852 o(0xe0df); // fnstsw %ax
1853 o(0x9e); // sahf
1854 o(0xc0950f); // setne %al
1855 o(0xc29a0f); // setp %dl
1856 o(0xd009); // orl %edx, %eax
1857 break;
1858 case OP_GREATER_EQUAL:
1859 o(0xe9da); // fucompp
1860 o(0xe0df); // fnstsw %ax
1861 o(0x05c4f6); // testb $5, %ah
1862 o(0xc0940f); // sete %al
1863 break;
1864 case OP_LESS:
1865 o(0xc9d9); // fxch %st(1)
1866 o(0xe9da); // fucompp
1867 o(0xe0df); // fnstsw %ax
1868 o(0x9e); // sahf
1869 o(0xc0970f); // seta %al
1870 break;
1871 case OP_LESS_EQUAL:
1872 o(0xc9d9); // fxch %st(1)
1873 o(0xe9da); // fucompp
1874 o(0xe0df); // fnstsw %ax
1875 o(0x9e); // sahf
1876 o(0xc0930f); // setea %al
1877 break;
1878 case OP_GREATER:
1879 o(0xe9da); // fucompp
1880 o(0xe0df); // fnstsw %ax
1881 o(0x45c4f6); // testb $69, %ah
1882 o(0xc0940f); // sete %al
1883 break;
1884 default:
1885 error("Unknown comparison op");
1886 }
1887 o(0xc0b60f); // movzbl %al, %eax
1888 }
1889 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001890 }
1891
Jack Palevich546b2242009-05-13 15:10:04 -07001892 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001893 Type* pR0Type = getR0Type();
1894 Type* pTOSType = getTOSType();
1895 TypeTag tagR0 = pR0Type->tag;
1896 TypeTag tagTOS = pTOSType->tag;
1897 bool isFloatR0 = isFloatTag(tagR0);
1898 bool isFloatTOS = isFloatTag(tagTOS);
1899 if (!isFloatR0 && !isFloatTOS) {
1900 // TODO: Deal with pointer arithmetic
1901 o(0x59); /* pop %ecx */
1902 o(decodeOp(op));
1903 if (op == OP_MOD)
1904 o(0x92); /* xchg %edx, %eax */
1905 popType();
1906 } else {
1907 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1908 setupFloatOperands();
1909 // Both float. x87 R0 == left hand, x87 R1 == right hand
1910 switch (op) {
1911 case OP_MUL:
1912 o(0xc9de); // fmulp
1913 break;
1914 case OP_DIV:
1915 o(0xf1de); // fdivp
1916 break;
1917 case OP_PLUS:
1918 o(0xc1de); // faddp
1919 break;
1920 case OP_MINUS:
1921 o(0xe1de); // fsubp
1922 break;
1923 default:
1924 error("Unsupported binary floating operation.");
1925 break;
1926 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001927 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001928 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001929 }
1930
Jack Palevicha39749f2009-07-08 20:40:31 -07001931 virtual void gUnaryCmp(int op, Type* pResultType) {
1932 if (op != OP_LOGICAL_NOT) {
1933 error("Unknown unary cmp %d", op);
1934 } else {
1935 Type* pR0Type = getR0Type();
1936 TypeTag tag = collapseType(pR0Type->tag);
1937 switch(tag) {
1938 case TY_INT: {
1939 oad(0xb9, 0); /* movl $0, %ecx */
1940 int t = decodeOp(op);
1941 o(0xc139); /* cmp %eax,%ecx */
1942 li(0, NULL);
1943 o(0x0f); /* setxx %al */
1944 o(t + 0x90);
1945 o(0xc0);
1946 }
1947 break;
1948 case TY_FLOAT:
1949 case TY_DOUBLE:
1950 o(0xeed9); // fldz
1951 o(0xe9da); // fucompp
1952 o(0xe0df); // fnstsw %ax
1953 o(0x9e); // sahf
1954 o(0xc0950f); // setne %al
1955 o(0xc29a0f); // setp %dl
1956 o(0xd009); // orl %edx, %eax
1957 o(0xc0b60f); // movzbl %al, %eax
1958 o(0x01f083); // xorl $1, %eax
1959 break;
1960 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001961 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07001962 break;
1963 }
1964 }
1965 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001966 }
1967
1968 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001969 Type* pR0Type = getR0Type();
1970 TypeTag tag = collapseType(pR0Type->tag);
1971 switch(tag) {
1972 case TY_INT:
1973 oad(0xb9, 0); /* movl $0, %ecx */
1974 o(decodeOp(op));
1975 break;
1976 case TY_FLOAT:
1977 case TY_DOUBLE:
1978 switch (op) {
1979 case OP_MINUS:
1980 o(0xe0d9); // fchs
1981 break;
1982 case OP_BIT_NOT:
1983 error("Can't apply '~' operator to a float or double.");
1984 break;
1985 default:
1986 error("Unknown unary op %d\n", op);
1987 break;
1988 }
1989 break;
1990 default:
1991 error("genUnaryOp unsupported type");
1992 break;
1993 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001994 }
1995
Jack Palevich1cdef202009-05-22 12:06:27 -07001996 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07001997 Type* pR0Type = getR0Type();
1998 TypeTag r0ct = collapseType(pR0Type->tag);
1999 switch(r0ct) {
2000 case TY_INT:
2001 o(0x50); /* push %eax */
2002 break;
2003 case TY_FLOAT:
2004 o(0x50); /* push %eax */
2005 o(0x241cd9); // fstps 0(%esp)
2006 break;
2007 case TY_DOUBLE:
2008 o(0x50); /* push %eax */
2009 o(0x50); /* push %eax */
2010 o(0x241cdd); // fstpl 0(%esp)
2011 break;
2012 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002013 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002014 break;
2015 }
Jack Palevich8df46192009-07-07 14:48:51 -07002016 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002017 }
2018
Jack Palevich9eed7a22009-07-06 17:24:34 -07002019 virtual void storeR0ToTOS(Type* pPointerType) {
2020 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07002021 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002022 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002023 switch (pPointerType->pHead->tag) {
2024 case TY_INT:
2025 o(0x0189); /* movl %eax/%al, (%ecx) */
2026 break;
2027 case TY_CHAR:
2028 o(0x0188); /* movl %eax/%al, (%ecx) */
2029 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002030 case TY_FLOAT:
2031 o(0x19d9); /* fstps (%ecx) */
2032 break;
2033 case TY_DOUBLE:
2034 o(0x19dd); /* fstpl (%ecx) */
2035 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002036 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002037 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002038 break;
2039 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002040 }
2041
Jack Palevich9eed7a22009-07-06 17:24:34 -07002042 virtual void loadR0FromR0(Type* pPointerType) {
2043 assert(pPointerType->tag == TY_POINTER);
2044 switch (pPointerType->pHead->tag) {
2045 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002046 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002047 break;
2048 case TY_CHAR:
2049 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002050 ob(0); /* add zero in code */
2051 break;
2052 case TY_FLOAT:
2053 o2(0x00d9); // flds (%eax)
2054 break;
2055 case TY_DOUBLE:
2056 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002057 break;
2058 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002059 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002060 break;
2061 }
Jack Palevich8df46192009-07-07 14:48:51 -07002062 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002063 }
2064
Jack Palevich8df46192009-07-07 14:48:51 -07002065 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002066 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002067 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002068 }
2069
Jack Palevich9cbd2262009-07-08 16:48:41 -07002070 virtual void storeR0(int ea, Type* pType) {
2071 TypeTag tag = pType->tag;
2072 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002073 case TY_CHAR:
2074 if (ea < -LOCAL || ea > LOCAL) {
2075 oad(0xa2, ea); // movb %al,ea
2076 } else {
2077 oad(0x8588, ea); // movb %al,ea(%ebp)
2078 }
2079 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002080 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002081 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002082 gmov(6, ea); /* mov %eax, EA */
2083 break;
2084 case TY_FLOAT:
2085 if (ea < -LOCAL || ea > LOCAL) {
2086 oad(0x1dd9, ea); // fstps ea
2087 } else {
2088 oad(0x9dd9, ea); // fstps ea(%ebp)
2089 }
2090 break;
2091 case TY_DOUBLE:
2092 if (ea < -LOCAL || ea > LOCAL) {
2093 oad(0x1ddd, ea); // fstpl ea
2094 } else {
2095 oad(0x9ddd, ea); // fstpl ea(%ebp)
2096 }
2097 break;
2098 default:
2099 error("Unable to store to type %d", tag);
2100 break;
2101 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002102 }
2103
Jack Palevich8df46192009-07-07 14:48:51 -07002104 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002105 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002106 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002107 case TY_CHAR:
2108 if (ea < -LOCAL || ea > LOCAL) {
2109 oad(0x05BE0F, ea); // movsbl ea,%eax
2110 } else {
2111 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2112 }
2113 if (isIncDec) {
2114 error("inc/dec not implemented for char.");
2115 }
2116 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002117 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002118 case TY_POINTER:
2119 if (tag == TY_CHAR) {
2120 } else {
2121 gmov(8, ea); /* mov EA, %eax */
2122 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002123 if (isIncDec) {
2124 /* Implement post-increment or post decrement.
2125 */
2126 gmov(0, ea); /* 83 ADD */
2127 o(decodeOp(op));
2128 }
2129 break;
2130 case TY_FLOAT:
2131 if (ea < -LOCAL || ea > LOCAL) {
2132 oad(0x05d9, ea); // flds ea
2133 } else {
2134 oad(0x85d9, ea); // flds ea(%ebp)
2135 }
2136 if (isIncDec) {
2137 error("inc/dec not implemented for float.");
2138 }
2139 break;
2140 case TY_DOUBLE:
2141 if (ea < -LOCAL || ea > LOCAL) {
2142 oad(0x05dd, ea); // fldl ea
2143 } else {
2144 oad(0x85dd, ea); // fldl ea(%ebp)
2145 }
2146 if (isIncDec) {
2147 error("inc/dec not implemented for double.");
2148 }
2149 break;
2150 default:
2151 error("Unable to load type %d", tag);
2152 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002153 }
Jack Palevich8df46192009-07-07 14:48:51 -07002154 setR0Type(pType);
2155 }
2156
2157 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002158 Type* pR0Type = getR0Type();
2159 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002160 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002161 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002162 return;
2163 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002164 if (bitsSame(pType, pR0Type)) {
2165 // do nothing special
2166 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2167 // do nothing special, both held in same register on x87.
2168 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002169 TypeTag r0Tag = collapseType(pR0Type->tag);
2170 TypeTag destTag = collapseType(pType->tag);
2171 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2172 // Convert R0 from int to float
2173 o(0x50); // push %eax
2174 o(0x2404DB); // fildl 0(%esp)
2175 o(0x58); // pop %eax
2176 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2177 // Convert R0 from float to int. Complicated because
2178 // need to save and restore the rounding mode.
2179 o(0x50); // push %eax
2180 o(0x50); // push %eax
2181 o(0x02247cD9); // fnstcw 2(%esp)
2182 o(0x2444b70f); // movzwl 2(%esp), %eax
2183 o(0x02);
2184 o(0x0cb4); // movb $12, %ah
2185 o(0x24048966); // movw %ax, 0(%esp)
2186 o(0x242cd9); // fldcw 0(%esp)
2187 o(0x04245cdb); // fistpl 4(%esp)
2188 o(0x02246cd9); // fldcw 2(%esp)
2189 o(0x58); // pop %eax
2190 o(0x58); // pop %eax
2191 } else {
2192 error("Incompatible types old: %d new: %d",
2193 pR0Type->tag, pType->tag);
2194 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002195 }
2196 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002197 }
2198
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002199 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002200 return oad(0xec81, 0); /* sub $xxx, %esp */
2201 }
2202
Jack Palevich1a539db2009-07-08 13:04:41 -07002203 virtual size_t storeR0ToArg(int l) {
2204 Type* pR0Type = getR0Type();
2205 TypeTag r0ct = collapseType(pR0Type->tag);
2206 switch(r0ct) {
2207 case TY_INT:
2208 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2209 return 4;
2210 case TY_FLOAT:
2211 oad(0x249CD9, l); /* fstps xxx(%esp) */
2212 return 4;
2213 case TY_DOUBLE:
2214 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2215 return 8;
2216 default:
2217 assert(false);
2218 return 0;
2219 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002220 }
2221
Jack Palevichb7718b92009-07-09 22:00:24 -07002222 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002223 * (int*) a = l;
2224 }
2225
Jack Palevich8df46192009-07-07 14:48:51 -07002226 virtual int callForward(int symbol, Type* pFunc) {
2227 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002228 return psym(0xe8, symbol); /* call xxx */
2229 }
2230
Jack Palevich8df46192009-07-07 14:48:51 -07002231 virtual void callRelative(int t, Type* pFunc) {
2232 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002233 psym(0xe8, t); /* call xxx */
2234 }
2235
Jack Palevich8df46192009-07-07 14:48:51 -07002236 virtual void callIndirect(int l, Type* pFunc) {
2237 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002238 oad(0x2494ff, l); /* call *xxx(%esp) */
2239 }
2240
Jack Palevichb7718b92009-07-09 22:00:24 -07002241 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002242 if (isIndirect) {
2243 l += 4;
2244 }
-b master422972c2009-06-17 19:13:52 -07002245 if (l > 0) {
2246 oad(0xc481, l); /* add $xxx, %esp */
2247 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002248 }
2249
Jack Palevicha6535612009-05-13 16:24:17 -07002250 virtual int jumpOffset() {
2251 return 5;
2252 }
2253
2254 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002255 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002256 }
2257
Jack Paleviche7b59062009-05-19 17:12:17 -07002258 /* output a symbol and patch all calls to it */
2259 virtual void gsym(int t) {
2260 int n;
2261 int pc = getPC();
2262 while (t) {
2263 n = *(int *) t; /* next value */
2264 *(int *) t = pc - t - 4;
2265 t = n;
2266 }
2267 }
2268
Jack Palevich1cdef202009-05-22 12:06:27 -07002269 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002270 size_t pagesize = 4096;
2271 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2272 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2273 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2274 if (err) {
2275 error("mprotect() failed: %d", errno);
2276 }
2277 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002278 }
2279
Jack Palevich9eed7a22009-07-06 17:24:34 -07002280 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002281 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002282 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002283 virtual size_t alignmentOf(Type* pType){
2284 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002285 }
2286
2287 /**
2288 * Array element alignment (in bytes) for this type of data.
2289 */
2290 virtual size_t sizeOf(Type* pType){
2291 switch(pType->tag) {
2292 case TY_INT:
2293 return 4;
2294 case TY_CHAR:
2295 return 1;
2296 default:
2297 return 0;
2298 case TY_FLOAT:
2299 return 4;
2300 case TY_DOUBLE:
2301 return 8;
2302 case TY_POINTER:
2303 return 4;
2304 }
2305 }
2306
Jack Palevich9cbd2262009-07-08 16:48:41 -07002307 virtual size_t stackSizeOf(Type* pType) {
2308 switch(pType->tag) {
2309 case TY_DOUBLE:
2310 return 8;
2311 default:
2312 return 4;
2313 }
2314 }
2315
Jack Palevich21a15a22009-05-11 14:49:29 -07002316 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002317
2318 /** Output 1 to 4 bytes.
2319 *
2320 */
2321 void o(int n) {
2322 /* cannot use unsigned, so we must do a hack */
2323 while (n && n != -1) {
2324 ob(n & 0xff);
2325 n = n >> 8;
2326 }
2327 }
2328
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002329 /* Output exactly 2 bytes
2330 */
2331 void o2(int n) {
2332 ob(n & 0xff);
2333 ob(0xff & (n >> 8));
2334 }
2335
Jack Paleviche7b59062009-05-19 17:12:17 -07002336 /* psym is used to put an instruction with a data field which is a
2337 reference to a symbol. It is in fact the same as oad ! */
2338 int psym(int n, int t) {
2339 return oad(n, t);
2340 }
2341
2342 /* instruction + address */
2343 int oad(int n, int t) {
2344 o(n);
2345 int result = getPC();
2346 o4(t);
2347 return result;
2348 }
2349
2350
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002351 static const int operatorHelper[];
2352
2353 int decodeOp(int op) {
2354 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002355 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002356 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002357 }
2358 return operatorHelper[op];
2359 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002360
Jack Palevich546b2242009-05-13 15:10:04 -07002361 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002362 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002363 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002364 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002365
2366 void setupFloatOperands() {
2367 Type* pR0Type = getR0Type();
2368 Type* pTOSType = getTOSType();
2369 TypeTag tagR0 = pR0Type->tag;
2370 TypeTag tagTOS = pTOSType->tag;
2371 bool isFloatR0 = isFloatTag(tagR0);
2372 bool isFloatTOS = isFloatTag(tagTOS);
2373 if (! isFloatR0) {
2374 // Convert R0 from int to float
2375 o(0x50); // push %eax
2376 o(0x2404DB); // fildl 0(%esp)
2377 o(0x58); // pop %eax
2378 }
2379 if (! isFloatTOS){
2380 o(0x2404DB); // fildl 0(%esp);
2381 o(0x58); // pop %eax
2382 } else {
2383 if (tagTOS == TY_FLOAT) {
2384 o(0x2404d9); // flds (%esp)
2385 o(0x58); // pop %eax
2386 } else {
2387 o(0x2404dd); // fldl (%esp)
2388 o(0x58); // pop %eax
2389 o(0x58); // pop %eax
2390 }
2391 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002392 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002393 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002394 };
2395
Jack Paleviche7b59062009-05-19 17:12:17 -07002396#endif // PROVIDE_X86_CODEGEN
2397
Jack Palevichb67b18f2009-06-11 21:12:23 -07002398#ifdef PROVIDE_TRACE_CODEGEN
2399 class TraceCodeGenerator : public CodeGenerator {
2400 private:
2401 CodeGenerator* mpBase;
2402
2403 public:
2404 TraceCodeGenerator(CodeGenerator* pBase) {
2405 mpBase = pBase;
2406 }
2407
2408 virtual ~TraceCodeGenerator() {
2409 delete mpBase;
2410 }
2411
2412 virtual void init(CodeBuf* pCodeBuf) {
2413 mpBase->init(pCodeBuf);
2414 }
2415
2416 void setErrorSink(ErrorSink* pErrorSink) {
2417 mpBase->setErrorSink(pErrorSink);
2418 }
2419
2420 /* returns address to patch with local variable size
2421 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002422 virtual int functionEntry(Type* pDecl) {
2423 int result = mpBase->functionEntry(pDecl);
2424 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002425 return result;
2426 }
2427
Jack Palevichb7718b92009-07-09 22:00:24 -07002428 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2429 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2430 localVariableAddress, localVariableSize);
2431 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002432 }
2433
2434 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002435 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002436 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002437 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002438 }
2439
Jack Palevich1a539db2009-07-08 13:04:41 -07002440 virtual void loadFloat(int address, Type* pType) {
2441 fprintf(stderr, "loadFloat(%d, type)\n", address);
2442 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002443 }
2444
Jack Palevichb67b18f2009-06-11 21:12:23 -07002445 virtual int gjmp(int t) {
2446 int result = mpBase->gjmp(t);
2447 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2448 return result;
2449 }
2450
2451 /* l = 0: je, l == 1: jne */
2452 virtual int gtst(bool l, int t) {
2453 int result = mpBase->gtst(l, t);
2454 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2455 return result;
2456 }
2457
Jack Palevicha39749f2009-07-08 20:40:31 -07002458 virtual void gcmp(int op, Type* pResultType) {
2459 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2460 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002461 }
2462
2463 virtual void genOp(int op) {
2464 fprintf(stderr, "genOp(%d)\n", op);
2465 mpBase->genOp(op);
2466 }
2467
Jack Palevich9eed7a22009-07-06 17:24:34 -07002468
Jack Palevicha39749f2009-07-08 20:40:31 -07002469 virtual void gUnaryCmp(int op, Type* pResultType) {
2470 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2471 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002472 }
2473
2474 virtual void genUnaryOp(int op) {
2475 fprintf(stderr, "genUnaryOp(%d)\n", op);
2476 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002477 }
2478
2479 virtual void pushR0() {
2480 fprintf(stderr, "pushR0()\n");
2481 mpBase->pushR0();
2482 }
2483
Jack Palevich9eed7a22009-07-06 17:24:34 -07002484 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002485 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002486 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002487 }
2488
Jack Palevich9eed7a22009-07-06 17:24:34 -07002489 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002490 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002491 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002492 }
2493
Jack Palevich8df46192009-07-07 14:48:51 -07002494 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002495 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002496 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002497 }
2498
Jack Palevich9cbd2262009-07-08 16:48:41 -07002499 virtual void storeR0(int ea, Type* pType) {
2500 fprintf(stderr, "storeR0(%d, pType)\n", ea);
2501 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002502 }
2503
Jack Palevich8df46192009-07-07 14:48:51 -07002504 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002505 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002506 mpBase->loadR0(ea, isIncDec, op, pType);
2507 }
2508
2509 virtual void convertR0(Type* pType){
2510 fprintf(stderr, "convertR0(pType)\n");
2511 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002512 }
2513
2514 virtual int beginFunctionCallArguments() {
2515 int result = mpBase->beginFunctionCallArguments();
2516 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2517 return result;
2518 }
2519
Jack Palevich1a539db2009-07-08 13:04:41 -07002520 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002521 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07002522 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002523 }
2524
Jack Palevichb7718b92009-07-09 22:00:24 -07002525 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002526 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002527 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002528 }
2529
Jack Palevich8df46192009-07-07 14:48:51 -07002530 virtual int callForward(int symbol, Type* pFunc) {
2531 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002532 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2533 return result;
2534 }
2535
Jack Palevich8df46192009-07-07 14:48:51 -07002536 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002537 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002538 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002539 }
2540
Jack Palevich8df46192009-07-07 14:48:51 -07002541 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002542 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002543 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002544 }
2545
Jack Palevichb7718b92009-07-09 22:00:24 -07002546 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2547 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2548 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002549 }
2550
2551 virtual int jumpOffset() {
2552 return mpBase->jumpOffset();
2553 }
2554
2555 virtual int disassemble(FILE* out) {
2556 return mpBase->disassemble(out);
2557 }
2558
2559 /* output a symbol and patch all calls to it */
2560 virtual void gsym(int t) {
2561 fprintf(stderr, "gsym(%d)\n", t);
2562 mpBase->gsym(t);
2563 }
2564
2565 virtual int finishCompile() {
2566 int result = mpBase->finishCompile();
2567 fprintf(stderr, "finishCompile() = %d\n", result);
2568 return result;
2569 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002570
2571 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002572 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002573 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002574 virtual size_t alignmentOf(Type* pType){
2575 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002576 }
2577
2578 /**
2579 * Array element alignment (in bytes) for this type of data.
2580 */
2581 virtual size_t sizeOf(Type* pType){
2582 return mpBase->sizeOf(pType);
2583 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002584
Jack Palevich9cbd2262009-07-08 16:48:41 -07002585
2586 virtual size_t stackSizeOf(Type* pType) {
2587 return mpBase->stackSizeOf(pType);
2588 }
2589
2590
Jack Palevich1a539db2009-07-08 13:04:41 -07002591 virtual Type* getR0Type() {
2592 return mpBase->getR0Type();
2593 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002594 };
2595
2596#endif // PROVIDE_TRACE_CODEGEN
2597
Jack Palevich569f1352009-06-29 14:29:08 -07002598 class Arena {
2599 public:
2600 // Used to record a given allocation amount.
2601 // Used:
2602 // Mark mark = arena.mark();
2603 // ... lots of arena.allocate()
2604 // arena.free(mark);
2605
2606 struct Mark {
2607 size_t chunk;
2608 size_t offset;
2609 };
2610
2611 Arena() {
2612 mCurrentChunk = 0;
2613 Chunk start(CHUNK_SIZE);
2614 mData.push_back(start);
2615 }
2616
2617 ~Arena() {
2618 for(size_t i = 0; i < mData.size(); i++) {
2619 mData[i].free();
2620 }
2621 }
2622
2623 // Alloc using the standard alignment size safe for any variable
2624 void* alloc(size_t size) {
2625 return alloc(size, 8);
2626 }
2627
2628 Mark mark(){
2629 Mark result;
2630 result.chunk = mCurrentChunk;
2631 result.offset = mData[mCurrentChunk].mOffset;
2632 return result;
2633 }
2634
2635 void freeToMark(const Mark& mark) {
2636 mCurrentChunk = mark.chunk;
2637 mData[mCurrentChunk].mOffset = mark.offset;
2638 }
2639
2640 private:
2641 // Allocate memory aligned to a given size
2642 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2643 // Memory is not zero filled.
2644
2645 void* alloc(size_t size, size_t alignment) {
2646 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2647 if (mCurrentChunk + 1 < mData.size()) {
2648 mCurrentChunk++;
2649 } else {
2650 size_t allocSize = CHUNK_SIZE;
2651 if (allocSize < size + alignment - 1) {
2652 allocSize = size + alignment - 1;
2653 }
2654 Chunk chunk(allocSize);
2655 mData.push_back(chunk);
2656 mCurrentChunk++;
2657 }
2658 }
2659 return mData[mCurrentChunk].allocate(size, alignment);
2660 }
2661
2662 static const size_t CHUNK_SIZE = 128*1024;
2663 // Note: this class does not deallocate its
2664 // memory when it's destroyed. It depends upon
2665 // its parent to deallocate the memory.
2666 struct Chunk {
2667 Chunk() {
2668 mpData = 0;
2669 mSize = 0;
2670 mOffset = 0;
2671 }
2672
2673 Chunk(size_t size) {
2674 mSize = size;
2675 mpData = (char*) malloc(size);
2676 mOffset = 0;
2677 }
2678
2679 ~Chunk() {
2680 // Doesn't deallocate memory.
2681 }
2682
2683 void* allocate(size_t size, size_t alignment) {
2684 size_t alignedOffset = aligned(mOffset, alignment);
2685 void* result = mpData + alignedOffset;
2686 mOffset = alignedOffset + size;
2687 return result;
2688 }
2689
2690 void free() {
2691 if (mpData) {
2692 ::free(mpData);
2693 mpData = 0;
2694 }
2695 }
2696
2697 size_t remainingCapacity(size_t alignment) {
2698 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2699 }
2700
2701 // Assume alignment is a power of two
2702 inline size_t aligned(size_t v, size_t alignment) {
2703 size_t mask = alignment-1;
2704 return (v + mask) & ~mask;
2705 }
2706
2707 char* mpData;
2708 size_t mSize;
2709 size_t mOffset;
2710 };
2711
2712 size_t mCurrentChunk;
2713
2714 Vector<Chunk> mData;
2715 };
2716
Jack Palevich569f1352009-06-29 14:29:08 -07002717 struct VariableInfo;
2718
2719 struct Token {
2720 int hash;
2721 size_t length;
2722 char* pText;
2723 tokenid_t id;
2724
2725 // Current values for the token
2726 char* mpMacroDefinition;
2727 VariableInfo* mpVariableInfo;
2728 };
2729
2730 class TokenTable {
2731 public:
2732 // Don't use 0..0xff, allows characters and operators to be tokens too.
2733
2734 static const int TOKEN_BASE = 0x100;
2735 TokenTable() {
2736 mpMap = hashmapCreate(128, hashFn, equalsFn);
2737 }
2738
2739 ~TokenTable() {
2740 hashmapFree(mpMap);
2741 }
2742
2743 void setArena(Arena* pArena) {
2744 mpArena = pArena;
2745 }
2746
2747 // Returns a token for a given string of characters.
2748 tokenid_t intern(const char* pText, size_t length) {
2749 Token probe;
2750 int hash = hashmapHash((void*) pText, length);
2751 {
2752 Token probe;
2753 probe.hash = hash;
2754 probe.length = length;
2755 probe.pText = (char*) pText;
2756 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2757 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002758 return pValue->id;
2759 }
2760 }
2761
2762 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2763 memset(pToken, 0, sizeof(*pToken));
2764 pToken->hash = hash;
2765 pToken->length = length;
2766 pToken->pText = (char*) mpArena->alloc(length + 1);
2767 memcpy(pToken->pText, pText, length);
2768 pToken->pText[length] = 0;
2769 pToken->id = mTokens.size() + TOKEN_BASE;
2770 mTokens.push_back(pToken);
2771 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002772 return pToken->id;
2773 }
2774
2775 // Return the Token for a given tokenid.
2776 Token& operator[](tokenid_t id) {
2777 return *mTokens[id - TOKEN_BASE];
2778 }
2779
2780 inline size_t size() {
2781 return mTokens.size();
2782 }
2783
2784 private:
2785
2786 static int hashFn(void* pKey) {
2787 Token* pToken = (Token*) pKey;
2788 return pToken->hash;
2789 }
2790
2791 static bool equalsFn(void* keyA, void* keyB) {
2792 Token* pTokenA = (Token*) keyA;
2793 Token* pTokenB = (Token*) keyB;
2794 // Don't need to compare hash values, they should always be equal
2795 return pTokenA->length == pTokenB->length
2796 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2797 }
2798
2799 Hashmap* mpMap;
2800 Vector<Token*> mTokens;
2801 Arena* mpArena;
2802 };
2803
Jack Palevich1cdef202009-05-22 12:06:27 -07002804 class InputStream {
2805 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002806 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002807 int getChar() {
2808 if (bumpLine) {
2809 line++;
2810 bumpLine = false;
2811 }
2812 int ch = get();
2813 if (ch == '\n') {
2814 bumpLine = true;
2815 }
2816 return ch;
2817 }
2818 int getLine() {
2819 return line;
2820 }
2821 protected:
2822 InputStream() :
2823 line(1), bumpLine(false) {
2824 }
2825 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002826 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002827 int line;
2828 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002829 };
2830
2831 class FileInputStream : public InputStream {
2832 public:
2833 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002834 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002835 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002836 FILE* f;
2837 };
2838
2839 class TextInputStream : public InputStream {
2840 public:
2841 TextInputStream(const char* text, size_t textLength)
2842 : pText(text), mTextLength(textLength), mPosition(0) {
2843 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002844
2845 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002846 virtual int get() {
2847 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2848 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002849
Jack Palevich1cdef202009-05-22 12:06:27 -07002850 const char* pText;
2851 size_t mTextLength;
2852 size_t mPosition;
2853 };
2854
Jack Palevicheedf9d22009-06-04 16:23:40 -07002855 class String {
2856 public:
2857 String() {
2858 mpBase = 0;
2859 mUsed = 0;
2860 mSize = 0;
2861 }
2862
Jack Palevich303d8ff2009-06-11 19:06:24 -07002863 String(const char* item, int len, bool adopt) {
2864 if (len < 0) {
2865 len = strlen(item);
2866 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002867 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002868 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002869 mUsed = len;
2870 mSize = len + 1;
2871 } else {
2872 mpBase = 0;
2873 mUsed = 0;
2874 mSize = 0;
2875 appendBytes(item, len);
2876 }
2877 }
2878
Jack Palevich303d8ff2009-06-11 19:06:24 -07002879 String(const String& other) {
2880 mpBase = 0;
2881 mUsed = 0;
2882 mSize = 0;
2883 appendBytes(other.getUnwrapped(), other.len());
2884 }
2885
Jack Palevicheedf9d22009-06-04 16:23:40 -07002886 ~String() {
2887 if (mpBase) {
2888 free(mpBase);
2889 }
2890 }
2891
Jack Palevicha6baa232009-06-12 11:25:59 -07002892 String& operator=(const String& other) {
2893 clear();
2894 appendBytes(other.getUnwrapped(), other.len());
2895 return *this;
2896 }
2897
Jack Palevich303d8ff2009-06-11 19:06:24 -07002898 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002899 return mpBase;
2900 }
2901
Jack Palevich303d8ff2009-06-11 19:06:24 -07002902 void clear() {
2903 mUsed = 0;
2904 if (mSize > 0) {
2905 mpBase[0] = 0;
2906 }
2907 }
2908
Jack Palevicheedf9d22009-06-04 16:23:40 -07002909 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002910 appendBytes(s, strlen(s));
2911 }
2912
2913 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002914 memcpy(ensure(n), s, n + 1);
2915 }
2916
2917 void append(char c) {
2918 * ensure(1) = c;
2919 }
2920
Jack Palevich86351982009-06-30 18:09:56 -07002921 void append(String& other) {
2922 appendBytes(other.getUnwrapped(), other.len());
2923 }
2924
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002925 char* orphan() {
2926 char* result = mpBase;
2927 mpBase = 0;
2928 mUsed = 0;
2929 mSize = 0;
2930 return result;
2931 }
2932
Jack Palevicheedf9d22009-06-04 16:23:40 -07002933 void printf(const char* fmt,...) {
2934 va_list ap;
2935 va_start(ap, fmt);
2936 vprintf(fmt, ap);
2937 va_end(ap);
2938 }
2939
2940 void vprintf(const char* fmt, va_list ap) {
2941 char* temp;
2942 int numChars = vasprintf(&temp, fmt, ap);
2943 memcpy(ensure(numChars), temp, numChars+1);
2944 free(temp);
2945 }
2946
Jack Palevich303d8ff2009-06-11 19:06:24 -07002947 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002948 return mUsed;
2949 }
2950
2951 private:
2952 char* ensure(int n) {
2953 size_t newUsed = mUsed + n;
2954 if (newUsed > mSize) {
2955 size_t newSize = mSize * 2 + 10;
2956 if (newSize < newUsed) {
2957 newSize = newUsed;
2958 }
2959 mpBase = (char*) realloc(mpBase, newSize + 1);
2960 mSize = newSize;
2961 }
2962 mpBase[newUsed] = '\0';
2963 char* result = mpBase + mUsed;
2964 mUsed = newUsed;
2965 return result;
2966 }
2967
2968 char* mpBase;
2969 size_t mUsed;
2970 size_t mSize;
2971 };
2972
Jack Palevich569f1352009-06-29 14:29:08 -07002973 void internKeywords() {
2974 // Note: order has to match TOK_ constants
2975 static const char* keywords[] = {
2976 "int",
2977 "char",
2978 "void",
2979 "if",
2980 "else",
2981 "while",
2982 "break",
2983 "return",
2984 "for",
2985 "pragma",
2986 "define",
2987 "auto",
2988 "case",
2989 "const",
2990 "continue",
2991 "default",
2992 "do",
2993 "double",
2994 "enum",
2995 "extern",
2996 "float",
2997 "goto",
2998 "long",
2999 "register",
3000 "short",
3001 "signed",
3002 "sizeof",
3003 "static",
3004 "struct",
3005 "switch",
3006 "typedef",
3007 "union",
3008 "unsigned",
3009 "volatile",
3010 "_Bool",
3011 "_Complex",
3012 "_Imaginary",
3013 "inline",
3014 "restrict",
3015 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003016
Jack Palevich569f1352009-06-29 14:29:08 -07003017 for(int i = 0; keywords[i]; i++) {
3018 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003019 }
Jack Palevich569f1352009-06-29 14:29:08 -07003020 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003021
Jack Palevich36d94142009-06-08 15:55:32 -07003022 struct InputState {
3023 InputStream* pStream;
3024 int oldCh;
3025 };
3026
Jack Palevich2db168f2009-06-11 14:29:47 -07003027 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003028 void* pAddress;
3029 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003030 tokenid_t tok;
3031 size_t level;
3032 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003033 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003034 };
3035
Jack Palevich303d8ff2009-06-11 19:06:24 -07003036 class SymbolStack {
3037 public:
3038 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003039 mpArena = 0;
3040 mpTokenTable = 0;
3041 }
3042
3043 void setArena(Arena* pArena) {
3044 mpArena = pArena;
3045 }
3046
3047 void setTokenTable(TokenTable* pTokenTable) {
3048 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003049 }
3050
3051 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003052 Mark mark;
3053 mark.mArenaMark = mpArena->mark();
3054 mark.mSymbolHead = mStack.size();
3055 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003056 }
3057
3058 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003059 // Undo any shadowing that was done:
3060 Mark mark = mLevelStack.back();
3061 mLevelStack.pop_back();
3062 while (mStack.size() > mark.mSymbolHead) {
3063 VariableInfo* pV = mStack.back();
3064 mStack.pop_back();
3065 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003066 }
Jack Palevich569f1352009-06-29 14:29:08 -07003067 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003068 }
3069
Jack Palevich569f1352009-06-29 14:29:08 -07003070 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3071 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3072 return pV && pV->level == level();
3073 }
3074
3075 VariableInfo* add(tokenid_t tok) {
3076 Token& token = (*mpTokenTable)[tok];
3077 VariableInfo* pOldV = token.mpVariableInfo;
3078 VariableInfo* pNewV =
3079 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3080 memset(pNewV, 0, sizeof(VariableInfo));
3081 pNewV->tok = tok;
3082 pNewV->level = level();
3083 pNewV->pOldDefinition = pOldV;
3084 token.mpVariableInfo = pNewV;
3085 mStack.push_back(pNewV);
3086 return pNewV;
3087 }
3088
Jack Palevich86351982009-06-30 18:09:56 -07003089 VariableInfo* add(Type* pType) {
3090 VariableInfo* pVI = add(pType->id);
3091 pVI->pType = pType;
3092 return pVI;
3093 }
3094
Jack Palevich569f1352009-06-29 14:29:08 -07003095 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3096 for (size_t i = 0; i < mStack.size(); i++) {
3097 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003098 break;
3099 }
3100 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003101 }
3102
Jack Palevich303d8ff2009-06-11 19:06:24 -07003103 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003104 inline size_t level() {
3105 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003106 }
3107
Jack Palevich569f1352009-06-29 14:29:08 -07003108 struct Mark {
3109 Arena::Mark mArenaMark;
3110 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003111 };
3112
Jack Palevich569f1352009-06-29 14:29:08 -07003113 Arena* mpArena;
3114 TokenTable* mpTokenTable;
3115 Vector<VariableInfo*> mStack;
3116 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003117 };
Jack Palevich36d94142009-06-08 15:55:32 -07003118
3119 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003120 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003121 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003122 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003123 int tokl; // token operator level
3124 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003125 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003126 intptr_t loc; // local variable index
3127 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003128 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003129 char* dptr; // Macro state: Points to macro text during macro playback.
3130 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003131 char* pGlobalBase;
Jack Palevich569f1352009-06-29 14:29:08 -07003132
3133 // Arena for the duration of the compile
3134 Arena mGlobalArena;
3135 // Arena for data that's only needed when compiling a single function
3136 Arena mLocalArena;
3137
3138 TokenTable mTokenTable;
3139 SymbolStack mGlobals;
3140 SymbolStack mLocals;
3141
Jack Palevich40600de2009-07-01 15:32:35 -07003142 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003143 Type* mkpInt; // int
3144 Type* mkpChar; // char
3145 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003146 Type* mkpFloat;
3147 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003148 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003149 Type* mkpIntPtr;
3150 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003151 Type* mkpFloatPtr;
3152 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003153 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003154
Jack Palevich36d94142009-06-08 15:55:32 -07003155 InputStream* file;
3156
3157 CodeBuf codeBuf;
3158 CodeGenerator* pGen;
3159
Jack Palevicheedf9d22009-06-04 16:23:40 -07003160 String mErrorBuf;
3161
Jack Palevicheedf9d22009-06-04 16:23:40 -07003162 String mPragmas;
3163 int mPragmaStringCount;
3164
Jack Palevich21a15a22009-05-11 14:49:29 -07003165 static const int ALLOC_SIZE = 99999;
3166
Jack Palevich303d8ff2009-06-11 19:06:24 -07003167 static const int TOK_DUMMY = 1;
3168 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003169 static const int TOK_NUM_FLOAT = 3;
3170 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003171
3172 // 3..255 are character and/or operators
3173
Jack Palevich2db168f2009-06-11 14:29:47 -07003174 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003175 // Order has to match string list in "internKeywords".
3176 enum {
3177 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3178 TOK_INT = TOK_KEYWORD,
3179 TOK_CHAR,
3180 TOK_VOID,
3181 TOK_IF,
3182 TOK_ELSE,
3183 TOK_WHILE,
3184 TOK_BREAK,
3185 TOK_RETURN,
3186 TOK_FOR,
3187 TOK_PRAGMA,
3188 TOK_DEFINE,
3189 TOK_AUTO,
3190 TOK_CASE,
3191 TOK_CONST,
3192 TOK_CONTINUE,
3193 TOK_DEFAULT,
3194 TOK_DO,
3195 TOK_DOUBLE,
3196 TOK_ENUM,
3197 TOK_EXTERN,
3198 TOK_FLOAT,
3199 TOK_GOTO,
3200 TOK_LONG,
3201 TOK_REGISTER,
3202 TOK_SHORT,
3203 TOK_SIGNED,
3204 TOK_SIZEOF,
3205 TOK_STATIC,
3206 TOK_STRUCT,
3207 TOK_SWITCH,
3208 TOK_TYPEDEF,
3209 TOK_UNION,
3210 TOK_UNSIGNED,
3211 TOK_VOLATILE,
3212 TOK__BOOL,
3213 TOK__COMPLEX,
3214 TOK__IMAGINARY,
3215 TOK_INLINE,
3216 TOK_RESTRICT,
3217 // Symbols start after tokens
3218 TOK_SYMBOL
3219 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003220
3221 static const int LOCAL = 0x200;
3222
3223 static const int SYM_FORWARD = 0;
3224 static const int SYM_DEFINE = 1;
3225
3226 /* tokens in string heap */
3227 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003228
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003229 static const int OP_INCREMENT = 0;
3230 static const int OP_DECREMENT = 1;
3231 static const int OP_MUL = 2;
3232 static const int OP_DIV = 3;
3233 static const int OP_MOD = 4;
3234 static const int OP_PLUS = 5;
3235 static const int OP_MINUS = 6;
3236 static const int OP_SHIFT_LEFT = 7;
3237 static const int OP_SHIFT_RIGHT = 8;
3238 static const int OP_LESS_EQUAL = 9;
3239 static const int OP_GREATER_EQUAL = 10;
3240 static const int OP_LESS = 11;
3241 static const int OP_GREATER = 12;
3242 static const int OP_EQUALS = 13;
3243 static const int OP_NOT_EQUALS = 14;
3244 static const int OP_LOGICAL_AND = 15;
3245 static const int OP_LOGICAL_OR = 16;
3246 static const int OP_BIT_AND = 17;
3247 static const int OP_BIT_XOR = 18;
3248 static const int OP_BIT_OR = 19;
3249 static const int OP_BIT_NOT = 20;
3250 static const int OP_LOGICAL_NOT = 21;
3251 static const int OP_COUNT = 22;
3252
3253 /* Operators are searched from front, the two-character operators appear
3254 * before the single-character operators with the same first character.
3255 * @ is used to pad out single-character operators.
3256 */
3257 static const char* operatorChars;
3258 static const char operatorLevel[];
3259
Jack Palevich569f1352009-06-29 14:29:08 -07003260 /* Called when we detect an internal problem. Does nothing in production.
3261 *
3262 */
3263 void internalError() {
3264 * (char*) 0 = 0;
3265 }
3266
Jack Palevich86351982009-06-30 18:09:56 -07003267 void assert(bool isTrue) {
3268 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003269 internalError();
3270 }
Jack Palevich86351982009-06-30 18:09:56 -07003271 }
3272
Jack Palevich40600de2009-07-01 15:32:35 -07003273 bool isSymbol(tokenid_t t) {
3274 return t >= TOK_SYMBOL &&
3275 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3276 }
3277
3278 bool isSymbolOrKeyword(tokenid_t t) {
3279 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003280 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003281 }
3282
Jack Palevich86351982009-06-30 18:09:56 -07003283 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003284 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003285 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3286 if (pV && pV->tok != t) {
3287 internalError();
3288 }
3289 return pV;
3290 }
3291
3292 inline bool isDefined(tokenid_t t) {
3293 return t >= TOK_SYMBOL && VI(t) != 0;
3294 }
3295
Jack Palevich40600de2009-07-01 15:32:35 -07003296 const char* nameof(tokenid_t t) {
3297 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003298 return mTokenTable[t].pText;
3299 }
3300
Jack Palevich21a15a22009-05-11 14:49:29 -07003301 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003302 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003303 }
3304
3305 void inp() {
3306 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003307 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003308 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003309 dptr = 0;
3310 ch = dch;
3311 }
3312 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003313 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003314#if 0
3315 printf("ch='%c' 0x%x\n", ch, ch);
3316#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003317 }
3318
3319 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003320 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003321 }
3322
Jack Palevichb4758ff2009-06-12 12:49:14 -07003323 /* read a character constant, advances ch to after end of constant */
3324 int getq() {
3325 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003326 if (ch == '\\') {
3327 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003328 if (isoctal(ch)) {
3329 // 1 to 3 octal characters.
3330 val = 0;
3331 for(int i = 0; i < 3; i++) {
3332 if (isoctal(ch)) {
3333 val = (val << 3) + ch - '0';
3334 inp();
3335 }
3336 }
3337 return val;
3338 } else if (ch == 'x' || ch == 'X') {
3339 // N hex chars
3340 inp();
3341 if (! isxdigit(ch)) {
3342 error("'x' character escape requires at least one digit.");
3343 } else {
3344 val = 0;
3345 while (isxdigit(ch)) {
3346 int d = ch;
3347 if (isdigit(d)) {
3348 d -= '0';
3349 } else if (d <= 'F') {
3350 d = d - 'A' + 10;
3351 } else {
3352 d = d - 'a' + 10;
3353 }
3354 val = (val << 4) + d;
3355 inp();
3356 }
3357 }
3358 } else {
3359 int val = ch;
3360 switch (ch) {
3361 case 'a':
3362 val = '\a';
3363 break;
3364 case 'b':
3365 val = '\b';
3366 break;
3367 case 'f':
3368 val = '\f';
3369 break;
3370 case 'n':
3371 val = '\n';
3372 break;
3373 case 'r':
3374 val = '\r';
3375 break;
3376 case 't':
3377 val = '\t';
3378 break;
3379 case 'v':
3380 val = '\v';
3381 break;
3382 case '\\':
3383 val = '\\';
3384 break;
3385 case '\'':
3386 val = '\'';
3387 break;
3388 case '"':
3389 val = '"';
3390 break;
3391 case '?':
3392 val = '?';
3393 break;
3394 default:
3395 error("Undefined character escape %c", ch);
3396 break;
3397 }
3398 inp();
3399 return val;
3400 }
3401 } else {
3402 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003403 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003404 return val;
3405 }
3406
3407 static bool isoctal(int ch) {
3408 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003409 }
3410
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003411 bool acceptCh(int c) {
3412 bool result = c == ch;
3413 if (result) {
3414 pdef(ch);
3415 inp();
3416 }
3417 return result;
3418 }
3419
3420 bool acceptDigitsCh() {
3421 bool result = false;
3422 while (isdigit(ch)) {
3423 result = true;
3424 pdef(ch);
3425 inp();
3426 }
3427 return result;
3428 }
3429
3430 void parseFloat() {
3431 tok = TOK_NUM_DOUBLE;
3432 // mTokenString already has the integral part of the number.
3433 acceptCh('.');
3434 acceptDigitsCh();
3435 bool doExp = true;
3436 if (acceptCh('e') || acceptCh('E')) {
3437 // Don't need to do any extra work
3438 } else if (ch == 'f' || ch == 'F') {
3439 pdef('e'); // So it can be parsed by strtof.
3440 inp();
3441 tok = TOK_NUM_FLOAT;
3442 } else {
3443 doExp = false;
3444 }
3445 if (doExp) {
3446 bool digitsRequired = acceptCh('-');
3447 bool digitsFound = acceptDigitsCh();
3448 if (digitsRequired && ! digitsFound) {
3449 error("malformed exponent");
3450 }
3451 }
3452 char* pText = mTokenString.getUnwrapped();
3453 if (tok == TOK_NUM_FLOAT) {
3454 tokd = strtof(pText, 0);
3455 } else {
3456 tokd = strtod(pText, 0);
3457 }
3458 //fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
3459 }
3460
Jack Palevich21a15a22009-05-11 14:49:29 -07003461 void next() {
3462 int l, a;
3463
Jack Palevich546b2242009-05-13 15:10:04 -07003464 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003465 if (ch == '#') {
3466 inp();
3467 next();
3468 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003469 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003470 } else if (tok == TOK_PRAGMA) {
3471 doPragma();
3472 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003473 error("Unsupported preprocessor directive \"%s\"",
3474 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003475 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003476 }
3477 inp();
3478 }
3479 tokl = 0;
3480 tok = ch;
3481 /* encode identifiers & numbers */
3482 if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003483 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003484 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003485 pdef(ch);
3486 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003487 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003488 if (isdigit(tok)) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003489 // Start of a numeric constant. Could be integer, float, or
3490 // double, won't know until we look further.
3491 if (ch == '.' || ch == 'e' || ch == 'e'
3492 || ch == 'f' || ch == 'F') {
3493 parseFloat();
3494 } else {
3495 // It's an integer constant
3496 tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
3497 tok = TOK_NUM;
3498 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003499 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003500 tok = mTokenTable.intern(mTokenString.getUnwrapped(),
3501 mTokenString.len());
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003502 // Is this a macro?
Jack Palevich569f1352009-06-29 14:29:08 -07003503 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3504 if(pMacroDefinition) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003505 // Yes, it is a macro
Jack Palevich569f1352009-06-29 14:29:08 -07003506 dptr = pMacroDefinition;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003507 dch = ch;
3508 inp();
3509 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003510 }
3511 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003512 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003513 inp();
3514 if (tok == '\'') {
3515 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003516 tokc = getq();
3517 if (ch != '\'') {
3518 error("Expected a ' character, got %c", ch);
3519 } else {
3520 inp();
3521 }
Jack Palevich546b2242009-05-13 15:10:04 -07003522 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003523 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003524 while (ch && ch != EOF) {
3525 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003526 inp();
3527 inp();
3528 if (ch == '/')
3529 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003530 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003531 if (ch == EOF) {
3532 error("End of file inside comment.");
3533 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003534 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003535 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003536 } else if ((tok == '/') & (ch == '/')) {
3537 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003538 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003539 inp();
3540 }
3541 inp();
3542 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003543 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003544 const char* t = operatorChars;
3545 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003546 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003547 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003548 tokl = operatorLevel[opIndex];
3549 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003550 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003551#if 0
3552 printf("%c%c -> tokl=%d tokc=0x%x\n",
3553 l, a, tokl, tokc);
3554#endif
3555 if (a == ch) {
3556 inp();
3557 tok = TOK_DUMMY; /* dummy token for double tokens */
3558 }
3559 break;
3560 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003561 opIndex++;
3562 }
3563 if (l == 0) {
3564 tokl = 0;
3565 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003566 }
3567 }
3568 }
3569#if 0
3570 {
Jack Palevich569f1352009-06-29 14:29:08 -07003571 String buf;
3572 decodeToken(buf, tok);
Jack Palevich86351982009-06-30 18:09:56 -07003573 fprintf(stderr, "%s\n", buf.getUnwrapped());
3574 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003575#endif
3576 }
3577
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003578 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003579 next();
3580 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003581 String* pName = new String();
3582 while (isspace(ch)) {
3583 inp();
3584 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003585 if (ch == '(') {
3586 delete pName;
3587 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003588 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003589 }
3590 while (isspace(ch)) {
3591 inp();
3592 }
Jack Palevich569f1352009-06-29 14:29:08 -07003593 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003594 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003595 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003596 inp();
3597 }
Jack Palevich569f1352009-06-29 14:29:08 -07003598 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3599 memcpy(pDefn, value.getUnwrapped(), value.len());
3600 pDefn[value.len()] = 0;
3601 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003602 }
3603
Jack Palevicheedf9d22009-06-04 16:23:40 -07003604 void doPragma() {
3605 // # pragma name(val)
3606 int state = 0;
3607 while(ch != EOF && ch != '\n' && state < 10) {
3608 switch(state) {
3609 case 0:
3610 if (isspace(ch)) {
3611 inp();
3612 } else {
3613 state++;
3614 }
3615 break;
3616 case 1:
3617 if (isalnum(ch)) {
3618 mPragmas.append(ch);
3619 inp();
3620 } else if (ch == '(') {
3621 mPragmas.append(0);
3622 inp();
3623 state++;
3624 } else {
3625 state = 11;
3626 }
3627 break;
3628 case 2:
3629 if (isalnum(ch)) {
3630 mPragmas.append(ch);
3631 inp();
3632 } else if (ch == ')') {
3633 mPragmas.append(0);
3634 inp();
3635 state = 10;
3636 } else {
3637 state = 11;
3638 }
3639 break;
3640 }
3641 }
3642 if(state != 10) {
3643 error("Unexpected pragma syntax");
3644 }
3645 mPragmaStringCount += 2;
3646 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003647
Jack Palevichac0e95e2009-05-29 13:53:44 -07003648 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003649 mErrorBuf.printf("%ld: ", file->getLine());
3650 mErrorBuf.vprintf(fmt, ap);
3651 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003652 }
3653
Jack Palevich8b0624c2009-05-20 12:12:06 -07003654 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 if (tok != c) {
3656 error("'%c' expected", c);
3657 }
3658 next();
3659 }
3660
Jack Palevich86351982009-06-30 18:09:56 -07003661 bool accept(intptr_t c) {
3662 if (tok == c) {
3663 next();
3664 return true;
3665 }
3666 return false;
3667 }
3668
Jack Palevich40600de2009-07-01 15:32:35 -07003669 bool acceptStringLiteral() {
3670 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003671 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003672 // This while loop merges multiple adjacent string constants.
3673 while (tok == '"') {
3674 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003675 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003676 }
3677 if (ch != '"') {
3678 error("Unterminated string constant.");
3679 }
3680 inp();
3681 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003682 }
Jack Palevich40600de2009-07-01 15:32:35 -07003683 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003684 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003685 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003686 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003687
3688 return true;
3689 }
3690 return false;
3691 }
3692 /* Parse and evaluate a unary expression.
3693 * allowAssignment is true if '=' parsing wanted (quick hack)
3694 */
3695 void unary(bool allowAssignment) {
3696 intptr_t n, t, a;
3697 t = 0;
3698 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3699 if (acceptStringLiteral()) {
3700 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003701 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003702 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003703 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003704 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003705 t = tok;
3706 next();
3707 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003708 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003709 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003710 // Align to 4-byte boundary
3711 glo = (char*) (((intptr_t) glo + 3) & -4);
3712 * (float*) glo = (float) ad;
3713 pGen->loadFloat((int) glo, mkpFloat);
3714 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003715 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003716 // Align to 8-byte boundary
3717 glo = (char*) (((intptr_t) glo + 7) & -8);
3718 * (double*) glo = ad;
3719 pGen->loadFloat((int) glo, mkpDouble);
3720 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003721 } else if (c == 2) {
3722 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003723 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003724 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003725 pGen->gUnaryCmp(a, mkpInt);
3726 else if (t == '+') {
3727 // ignore unary plus.
3728 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003729 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003730 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003731 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003732 // It's either a cast or an expression
3733 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3734 if (pCast) {
3735 skip(')');
3736 unary(false);
3737 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003738 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003739 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003740 skip(')');
3741 }
3742 } else if (t == '*') {
3743 /* This is a pointer dereference.
3744 */
3745 unary(false);
3746 Type* pR0Type = pGen->getR0Type();
3747 if (pR0Type->tag != TY_POINTER) {
3748 error("Expected a pointer type.");
3749 } else {
3750 if (pR0Type->pHead->tag == TY_FUNC) {
3751 t = 0;
3752 }
3753 if (accept('=')) {
3754 pGen->pushR0();
3755 expr();
3756 pGen->storeR0ToTOS(pR0Type);
3757 } else if (t) {
3758 pGen->loadR0FromR0(pR0Type);
3759 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003760 }
Jack Palevich3f226492009-07-02 14:46:19 -07003761 // Else we fall through to the function call below, with
3762 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003763 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003764 VariableInfo* pVI = VI(tok);
3765 pGen->leaR0((int) pVI->pAddress,
3766 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003767 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003768 } else if (t == EOF ) {
3769 error("Unexpected EOF.");
Jack Palevich40600de2009-07-01 15:32:35 -07003770 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003771 // Don't have to do anything special here, the error
3772 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003773 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003774 if (!isDefined(t)) {
3775 mGlobals.add(t);
3776 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003777 }
Jack Palevich8df46192009-07-07 14:48:51 -07003778 VariableInfo* pVI = VI(t);
3779 n = (intptr_t) pVI->pAddress;
Jack Palevich21a15a22009-05-11 14:49:29 -07003780 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003781 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003782 n = (intptr_t) dlsym(RTLD_DEFAULT, nameof(t));
Jack Palevich1a539db2009-07-08 13:04:41 -07003783 if (tok == '(') {
3784 pVI->pType = mkpIntFn;
3785 } else {
3786 pVI->pType = mkpInt;
3787 }
Jack Palevich8df46192009-07-07 14:48:51 -07003788 pVI->pAddress = (void*) n;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003789 }
Jack Palevich40600de2009-07-01 15:32:35 -07003790 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003791 /* assignment */
3792 next();
3793 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003794 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003795 } else if (tok != '(') {
3796 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003797 if (!n) {
Jack Palevich40600de2009-07-01 15:32:35 -07003798 error("Undefined variable %s", nameof(t));
Jack Palevicha6baa232009-06-12 11:25:59 -07003799 }
Jack Palevich8df46192009-07-07 14:48:51 -07003800 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003801 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003802 next();
3803 }
3804 }
3805 }
3806 }
3807
3808 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003809 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003810 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003811 VariableInfo* pVI = NULL;
3812 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003813 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003814 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003815 } else {
3816 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003817 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003818 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003819 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003820 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003821 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003822 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003823 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003824 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003825 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003826 if (! varArgs && !pArgList) {
3827 error ("Unexpected argument.");
3828 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003829 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003830 Type* pTargetType;
3831 if (pArgList) {
3832 pTargetType = pArgList->pHead;
3833 pArgList = pArgList->pTail;
3834 } else {
3835 pTargetType = pGen->getR0Type();
3836 if (pTargetType->tag == TY_FLOAT) {
3837 pTargetType = mkpDouble;
3838 }
3839 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003840 if (pTargetType->tag == TY_VOID) {
3841 error("Can't pass void value for argument %d",
3842 argCount + 1);
3843 } else {
3844 pGen->convertR0(pTargetType);
3845 l += pGen->storeR0ToArg(l);
3846 }
Jack Palevich95727a02009-07-06 12:07:15 -07003847 if (accept(',')) {
3848 // fine
3849 } else if ( tok != ')') {
3850 error("Expected ',' or ')'");
3851 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003852 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003853 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003854 if (! varArgs && pArgList) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003855 error ("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07003856 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003857 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003858 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07003859 if (!n) {
3860 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07003861 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
3862 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003863 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07003864 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003865 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07003866 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
3867 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003868 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003869 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07003870 }
3871 }
3872
Jack Palevich40600de2009-07-01 15:32:35 -07003873 /* Recursive descent parser for binary operations.
3874 */
3875 void binaryOp(int level) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003876 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07003877 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003878 if (level-- == 1)
3879 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07003880 else {
Jack Palevich40600de2009-07-01 15:32:35 -07003881 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003882 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003883 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003884 n = tok;
3885 t = tokc;
3886 next();
3887
Jack Palevich40600de2009-07-01 15:32:35 -07003888 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003889 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003890 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07003892 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07003893 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07003894
Jack Palevich40600de2009-07-01 15:32:35 -07003895 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07003896 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003897 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003898 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003899 }
3900 }
3901 }
3902 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07003903 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003904 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07003905 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07003906 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003907 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07003908 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07003909 }
3910 }
3911 }
3912
3913 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07003914 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07003915 }
3916
3917 int test_expr() {
3918 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003919 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003920 }
3921
Jack Palevicha6baa232009-06-12 11:25:59 -07003922 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07003923 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07003924
Jack Palevich95727a02009-07-06 12:07:15 -07003925 Type* pBaseType;
3926 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003927 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07003928 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07003929 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003930 next();
3931 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07003932 a = test_expr();
3933 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003934 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003935 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003936 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003937 n = pGen->gjmp(0); /* jmp */
3938 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07003939 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003940 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07003941 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003942 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003943 }
Jack Palevich546b2242009-05-13 15:10:04 -07003944 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003945 t = tok;
3946 next();
3947 skip('(');
3948 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07003949 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07003950 a = test_expr();
3951 } else {
3952 if (tok != ';')
3953 expr();
3954 skip(';');
3955 n = codeBuf.getPC();
3956 a = 0;
3957 if (tok != ';')
3958 a = test_expr();
3959 skip(';');
3960 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003961 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07003962 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07003963 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003964 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003965 n = t + 4;
3966 }
3967 }
3968 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07003969 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07003970 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003971 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07003972 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07003973 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003974 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003975 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003976 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003977 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07003978 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003979 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07003980 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07003981 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07003982 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003983 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07003984 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07003985 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003986 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003987 if (pReturnType->tag == TY_VOID) {
3988 error("Must not return a value from a void function");
3989 } else {
3990 pGen->convertR0(pReturnType);
3991 }
3992 } else {
3993 if (pReturnType->tag != TY_VOID) {
3994 error("Must specify a value here");
3995 }
Jack Palevich8df46192009-07-07 14:48:51 -07003996 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003997 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07003998 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003999 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004000 } else if (tok != ';')
4001 expr();
4002 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004003 }
4004 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004005
Jack Palevich3f226492009-07-02 14:46:19 -07004006 bool typeEqual(Type* a, Type* b) {
4007 if (a == b) {
4008 return true;
4009 }
4010 if (a == NULL || b == NULL) {
4011 return false;
4012 }
4013 TypeTag at = a->tag;
4014 if (at != b->tag) {
4015 return false;
4016 }
4017 if (at == TY_POINTER) {
4018 return typeEqual(a->pHead, b->pHead);
4019 } else if (at == TY_FUNC || at == TY_PARAM) {
4020 return typeEqual(a->pHead, b->pHead)
4021 && typeEqual(a->pTail, b->pTail);
4022 }
4023 return true;
4024 }
4025
Jack Palevich86351982009-06-30 18:09:56 -07004026 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4027 assert(tag >= TY_INT && tag <= TY_PARAM);
4028 Type* pType = (Type*) arena.alloc(sizeof(Type));
4029 memset(pType, 0, sizeof(*pType));
4030 pType->tag = tag;
4031 pType->pHead = pHead;
4032 pType->pTail = pTail;
4033 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004034 }
4035
Jack Palevich3f226492009-07-02 14:46:19 -07004036 Type* createPtrType(Type* pType, Arena& arena) {
4037 return createType(TY_POINTER, pType, NULL, arena);
4038 }
4039
4040 /**
4041 * Try to print a type in declaration order
4042 */
Jack Palevich86351982009-06-30 18:09:56 -07004043 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004044 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004045 if (pType == NULL) {
4046 buffer.appendCStr("null");
4047 return;
4048 }
Jack Palevich3f226492009-07-02 14:46:19 -07004049 decodeTypeImp(buffer, pType);
4050 }
4051
4052 void decodeTypeImp(String& buffer, Type* pType) {
4053 decodeTypeImpPrefix(buffer, pType);
4054
Jack Palevich86351982009-06-30 18:09:56 -07004055 String temp;
4056 if (pType->id != 0) {
4057 decodeToken(temp, pType->id);
4058 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004059 }
4060
4061 decodeTypeImpPostfix(buffer, pType);
4062 }
4063
4064 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4065 TypeTag tag = pType->tag;
4066
4067 if (tag >= TY_INT && tag <= TY_VOID) {
4068 switch (tag) {
4069 case TY_INT:
4070 buffer.appendCStr("int");
4071 break;
4072 case TY_CHAR:
4073 buffer.appendCStr("char");
4074 break;
4075 case TY_VOID:
4076 buffer.appendCStr("void");
4077 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004078 case TY_FLOAT:
4079 buffer.appendCStr("float");
4080 break;
4081 case TY_DOUBLE:
4082 buffer.appendCStr("double");
4083 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004084 default:
4085 break;
4086 }
Jack Palevich86351982009-06-30 18:09:56 -07004087 buffer.append(' ');
4088 }
Jack Palevich3f226492009-07-02 14:46:19 -07004089
4090 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004091 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004092 break;
4093 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004094 break;
4095 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004096 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004097 case TY_FLOAT:
4098 break;
4099 case TY_DOUBLE:
4100 break;
Jack Palevich86351982009-06-30 18:09:56 -07004101 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004102 decodeTypeImpPrefix(buffer, pType->pHead);
4103 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4104 buffer.append('(');
4105 }
4106 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004107 break;
4108 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004109 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004110 break;
4111 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004112 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004113 break;
4114 default:
4115 String temp;
4116 temp.printf("Unknown tag %d", pType->tag);
4117 buffer.append(temp);
4118 break;
4119 }
Jack Palevich3f226492009-07-02 14:46:19 -07004120 }
4121
4122 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4123 TypeTag tag = pType->tag;
4124
4125 switch(tag) {
4126 case TY_POINTER:
4127 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4128 buffer.append(')');
4129 }
4130 decodeTypeImpPostfix(buffer, pType->pHead);
4131 break;
4132 case TY_FUNC:
4133 buffer.append('(');
4134 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4135 decodeTypeImp(buffer, pArg);
4136 if (pArg->pTail) {
4137 buffer.appendCStr(", ");
4138 }
4139 }
4140 buffer.append(')');
4141 break;
4142 default:
4143 break;
Jack Palevich86351982009-06-30 18:09:56 -07004144 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004145 }
4146
Jack Palevich86351982009-06-30 18:09:56 -07004147 void printType(Type* pType) {
4148 String buffer;
4149 decodeType(buffer, pType);
4150 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004151 }
4152
Jack Palevich86351982009-06-30 18:09:56 -07004153 Type* acceptPrimitiveType(Arena& arena) {
4154 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004155 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004156 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004157 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004158 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004159 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004160 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004161 } else if (tok == TOK_FLOAT) {
4162 pType = mkpFloat;
4163 } else if (tok == TOK_DOUBLE) {
4164 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004165 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004166 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004167 }
4168 next();
Jack Palevich86351982009-06-30 18:09:56 -07004169 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004170 }
4171
Jack Palevich3f226492009-07-02 14:46:19 -07004172 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4173 Arena& arena) {
4174 tokenid_t declName = 0;
4175 pType = acceptDecl2(pType, declName, nameAllowed,
4176 nameRequired, arena);
4177 if (declName) {
4178 // Clone the parent type so we can set a unique ID
4179 pType = createType(pType->tag, pType->pHead,
4180 pType->pTail, arena);
4181
Jack Palevich86351982009-06-30 18:09:56 -07004182 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004183 }
Jack Palevich3f226492009-07-02 14:46:19 -07004184 // fprintf(stderr, "Parsed a declaration: ");
4185 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004186 return pType;
4187 }
4188
Jack Palevich3f226492009-07-02 14:46:19 -07004189 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4190 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004191 if (! pType) {
4192 error("Expected a declaration");
4193 }
4194 return pType;
4195 }
4196
Jack Palevich3f226492009-07-02 14:46:19 -07004197 /* Used for accepting types that appear in casts */
4198 Type* acceptCastTypeDeclaration(Arena& arena) {
4199 Type* pType = acceptPrimitiveType(arena);
4200 if (pType) {
4201 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004202 }
Jack Palevich86351982009-06-30 18:09:56 -07004203 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004204 }
4205
Jack Palevich3f226492009-07-02 14:46:19 -07004206 Type* expectCastTypeDeclaration(Arena& arena) {
4207 Type* pType = acceptCastTypeDeclaration(arena);
4208 if (! pType) {
4209 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004210 }
Jack Palevich3f226492009-07-02 14:46:19 -07004211 return pType;
4212 }
4213
4214 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4215 bool nameAllowed, bool nameRequired, Arena& arena) {
4216 int ptrCounter = 0;
4217 while (accept('*')) {
4218 ptrCounter++;
4219 }
4220 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4221 while (ptrCounter-- > 0) {
4222 pType = createType(TY_POINTER, pType, NULL, arena);
4223 }
4224 return pType;
4225 }
4226
4227 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4228 bool nameAllowed, bool nameRequired, Arena& arena) {
4229 // direct-dcl :
4230 // name
4231 // (dcl)
4232 // direct-dcl()
4233 // direct-dcl[]
4234 Type* pNewHead = NULL;
4235 if (accept('(')) {
4236 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4237 nameRequired, arena);
4238 skip(')');
4239 } else if ((declName = acceptSymbol()) != 0) {
4240 if (nameAllowed == false && declName) {
4241 error("Symbol %s not allowed here", nameof(declName));
4242 } else if (nameRequired && ! declName) {
4243 String temp;
4244 decodeToken(temp, tok);
4245 error("Expected symbol. Got %s", temp.getUnwrapped());
4246 }
4247 }
4248 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004249 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004250 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004251 pType = createType(TY_FUNC, pType, pTail, arena);
4252 skip(')');
4253 }
Jack Palevich3f226492009-07-02 14:46:19 -07004254
4255 if (pNewHead) {
4256 Type* pA = pNewHead;
4257 while (pA->pHead) {
4258 pA = pA->pHead;
4259 }
4260 pA->pHead = pType;
4261 pType = pNewHead;
4262 }
Jack Palevich86351982009-06-30 18:09:56 -07004263 return pType;
4264 }
4265
Jack Palevich3f226492009-07-02 14:46:19 -07004266 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004267 Type* pHead = NULL;
4268 Type* pTail = NULL;
4269 for(;;) {
4270 Type* pBaseArg = acceptPrimitiveType(arena);
4271 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004272 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4273 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004274 if (pArg) {
4275 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4276 if (!pHead) {
4277 pHead = pParam;
4278 pTail = pParam;
4279 } else {
4280 pTail->pTail = pParam;
4281 pTail = pParam;
4282 }
4283 }
4284 }
4285 if (! accept(',')) {
4286 break;
4287 }
4288 }
4289 return pHead;
4290 }
4291
4292 Type* expectPrimitiveType(Arena& arena) {
4293 Type* pType = acceptPrimitiveType(arena);
4294 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004295 String buf;
4296 decodeToken(buf, tok);
4297 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004298 }
Jack Palevich86351982009-06-30 18:09:56 -07004299 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004300 }
4301
Jack Palevich86351982009-06-30 18:09:56 -07004302 void addGlobalSymbol(Type* pDecl) {
4303 tokenid_t t = pDecl->id;
4304 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004305 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004306 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004307 }
Jack Palevich86351982009-06-30 18:09:56 -07004308 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004309 }
4310
Jack Palevich86351982009-06-30 18:09:56 -07004311 void reportDuplicate(tokenid_t t) {
4312 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004313 }
4314
Jack Palevich86351982009-06-30 18:09:56 -07004315 void addLocalSymbol(Type* pDecl) {
4316 tokenid_t t = pDecl->id;
4317 if (mLocals.isDefinedAtCurrentLevel(t)) {
4318 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004319 }
Jack Palevich86351982009-06-30 18:09:56 -07004320 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004321 }
4322
Jack Palevich95727a02009-07-06 12:07:15 -07004323 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004324 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004325
Jack Palevich95727a02009-07-06 12:07:15 -07004326 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004327 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004328 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4329 if (!pDecl) {
4330 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004331 }
Jack Palevich86351982009-06-30 18:09:56 -07004332 int variableAddress = 0;
4333 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004334 size_t alignment = pGen->alignmentOf(pDecl);
4335 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004336 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004337 variableAddress = -loc;
4338 VI(pDecl->id)->pAddress = (void*) variableAddress;
4339 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004340 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004341 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004342 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004343 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004344 if (tok == ',')
4345 next();
4346 }
4347 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004348 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004349 }
4350 }
4351
Jack Palevichf1728be2009-06-12 13:53:51 -07004352 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004353 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004354 }
4355
Jack Palevich569f1352009-06-29 14:29:08 -07004356 void decodeToken(String& buffer, tokenid_t token) {
4357 if (token == EOF ) {
4358 buffer.printf("EOF");
4359 } else if (token == TOK_NUM) {
4360 buffer.printf("numeric constant");
4361 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004362 if (token < 32) {
4363 buffer.printf("'\\x%02x'", token);
4364 } else {
4365 buffer.printf("'%c'", token);
4366 }
Jack Palevich569f1352009-06-29 14:29:08 -07004367 } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4368 buffer.printf("keyword \"%s\"", nameof(token));
4369 } else {
4370 buffer.printf("symbol \"%s\"", nameof(token));
4371 }
4372 }
4373
Jack Palevich40600de2009-07-01 15:32:35 -07004374 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004375 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004376 if (!result) {
4377 String temp;
Jack Palevich569f1352009-06-29 14:29:08 -07004378 decodeToken(temp, token);
Jack Palevichf1728be2009-06-12 13:53:51 -07004379 error("Expected symbol. Got %s", temp.getUnwrapped());
4380 }
4381 return result;
4382 }
4383
Jack Palevich86351982009-06-30 18:09:56 -07004384 tokenid_t acceptSymbol() {
4385 tokenid_t result = 0;
4386 if (tok >= TOK_SYMBOL) {
4387 result = tok;
4388 next();
Jack Palevich86351982009-06-30 18:09:56 -07004389 }
4390 return result;
4391 }
4392
Jack Palevichb7c81e92009-06-04 19:56:13 -07004393 void globalDeclarations() {
4394 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004395 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4396 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004397 break;
4398 }
Jack Palevich86351982009-06-30 18:09:56 -07004399 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4400 if (!pDecl) {
4401 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004402 }
Jack Palevich86351982009-06-30 18:09:56 -07004403 if (! isDefined(pDecl->id)) {
4404 addGlobalSymbol(pDecl);
4405 }
4406 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004407 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004408 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004409 }
Jack Palevich86351982009-06-30 18:09:56 -07004410 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004411 // it's a variable declaration
4412 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004413 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004414 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004415 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004416 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004417 }
Jack Palevich86351982009-06-30 18:09:56 -07004418 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004419 if (tok == TOK_NUM) {
4420 if (name) {
4421 * (int*) name->pAddress = tokc;
4422 }
4423 next();
4424 } else {
4425 error("Expected an integer constant");
4426 }
4427 }
Jack Palevich86351982009-06-30 18:09:56 -07004428 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004429 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004430 }
Jack Palevich86351982009-06-30 18:09:56 -07004431 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4432 if (!pDecl) {
4433 break;
4434 }
4435 if (! isDefined(pDecl->id)) {
4436 addGlobalSymbol(pDecl);
4437 }
4438 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004439 }
4440 skip(';');
4441 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004442 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004443 if (accept(';')) {
4444 // forward declaration.
4445 } else {
4446 if (name) {
4447 /* patch forward references (XXX: does not work for function
4448 pointers) */
4449 pGen->gsym((int) name->pForward);
4450 /* put function address */
4451 name->pAddress = (void*) codeBuf.getPC();
4452 }
4453 // Calculate stack offsets for parameters
4454 mLocals.pushLevel();
4455 intptr_t a = 8;
4456 int argCount = 0;
4457 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4458 Type* pArg = pP->pHead;
4459 addLocalSymbol(pArg);
4460 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004461 size_t alignment = pGen->alignmentOf(pArg);
4462 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004463 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004464 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004465 argCount++;
4466 }
4467 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004468 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004469 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004470 block(0, true);
4471 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004472 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004473 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004474 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004475 }
4476 }
4477 }
4478
Jack Palevich9cbd2262009-07-08 16:48:41 -07004479 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4480 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4481 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004482 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004483 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004484 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004485 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004486 char* result = (char*) base;
4487 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004488 return result;
4489 }
4490
Jack Palevich21a15a22009-05-11 14:49:29 -07004491 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004492 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004493 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004494 pGlobalBase = 0;
4495 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004496 if (pGen) {
4497 delete pGen;
4498 pGen = 0;
4499 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004500 if (file) {
4501 delete file;
4502 file = 0;
4503 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004504 }
4505
4506 void clear() {
4507 tok = 0;
4508 tokc = 0;
4509 tokl = 0;
4510 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004511 rsym = 0;
4512 loc = 0;
4513 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004514 dptr = 0;
4515 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004516 file = 0;
4517 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004518 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004519 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004520 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004521
Jack Palevich22305132009-05-13 10:58:45 -07004522 void setArchitecture(const char* architecture) {
4523 delete pGen;
4524 pGen = 0;
4525
4526 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004527#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004528 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004529 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004530 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004531#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004532#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004533 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004534 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004535 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004536#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004537 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004538 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004539 }
4540 }
4541
4542 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004543#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004544 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004545#elif defined(DEFAULT_X86_CODEGEN)
4546 pGen = new X86CodeGenerator();
4547#endif
4548 }
4549 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004550 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004551 } else {
4552 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07004553 }
4554 }
4555
Jack Palevich77ae76e2009-05-10 19:59:24 -07004556public:
Jack Palevich22305132009-05-13 10:58:45 -07004557 struct args {
4558 args() {
4559 architecture = 0;
4560 }
4561 const char* architecture;
4562 };
4563
Jack Paleviche7b59062009-05-19 17:12:17 -07004564 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004565 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004566 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004567
Jack Paleviche7b59062009-05-19 17:12:17 -07004568 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004569 cleanup();
4570 }
4571
Jack Palevich1cdef202009-05-22 12:06:27 -07004572 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004573 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004574
4575 cleanup();
4576 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004577 mTokenTable.setArena(&mGlobalArena);
4578 mGlobals.setArena(&mGlobalArena);
4579 mGlobals.setTokenTable(&mTokenTable);
4580 mLocals.setArena(&mLocalArena);
4581 mLocals.setTokenTable(&mTokenTable);
4582
4583 internKeywords();
Jack Palevich86351982009-06-30 18:09:56 -07004584 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004585 codeBuf.init(ALLOC_SIZE);
4586 setArchitecture(NULL);
4587 if (!pGen) {
4588 return -1;
4589 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004590#ifdef PROVIDE_TRACE_CODEGEN
4591 pGen = new TraceCodeGenerator(pGen);
4592#endif
4593 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004594 pGen->init(&codeBuf);
4595 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004596 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4597 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004598 inp();
4599 next();
4600 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004601 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004602 result = pGen->finishCompile();
4603 if (result == 0) {
4604 if (mErrorBuf.len()) {
4605 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004606 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004607 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004608 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004609 }
4610
Jack Palevich86351982009-06-30 18:09:56 -07004611 void createPrimitiveTypes() {
4612 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4613 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4614 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004615 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4616 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004617 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004618 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4619 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004620 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4621 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004622 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004623 }
4624
Jack Palevicha6baa232009-06-12 11:25:59 -07004625 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004626 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004627 }
4628
Jack Palevich569f1352009-06-29 14:29:08 -07004629 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004630 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004631 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004632 }
4633
Jack Palevich569f1352009-06-29 14:29:08 -07004634 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004635 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004636 error("Undefined forward reference: %s",
4637 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004638 }
4639 return true;
4640 }
4641
Jack Palevich21a15a22009-05-11 14:49:29 -07004642 int dump(FILE* out) {
4643 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4644 return 0;
4645 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004646
Jack Palevicha6535612009-05-13 16:24:17 -07004647 int disassemble(FILE* out) {
4648 return pGen->disassemble(out);
4649 }
4650
Jack Palevich1cdef202009-05-22 12:06:27 -07004651 /* Look through the symbol table to find a symbol.
4652 * If found, return its value.
4653 */
4654 void* lookup(const char* name) {
Jack Palevich569f1352009-06-29 14:29:08 -07004655 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4656 VariableInfo* pVariableInfo = VI(tok);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004657 if (pVariableInfo) {
4658 return pVariableInfo->pAddress;
Jack Palevich1cdef202009-05-22 12:06:27 -07004659 }
4660 return NULL;
4661 }
4662
Jack Palevicheedf9d22009-06-04 16:23:40 -07004663 void getPragmas(ACCsizei* actualStringCount,
4664 ACCsizei maxStringCount, ACCchar** strings) {
4665 int stringCount = mPragmaStringCount;
4666 if (actualStringCount) {
4667 *actualStringCount = stringCount;
4668 }
4669 if (stringCount > maxStringCount) {
4670 stringCount = maxStringCount;
4671 }
4672 if (strings) {
4673 char* pPragmas = mPragmas.getUnwrapped();
4674 while (stringCount-- > 0) {
4675 *strings++ = pPragmas;
4676 pPragmas += strlen(pPragmas) + 1;
4677 }
4678 }
4679 }
4680
Jack Palevichac0e95e2009-05-29 13:53:44 -07004681 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004682 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004683 }
4684
Jack Palevich77ae76e2009-05-10 19:59:24 -07004685};
4686
Jack Paleviche7b59062009-05-19 17:12:17 -07004687const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004688 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4689
Jack Paleviche7b59062009-05-19 17:12:17 -07004690const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004691 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4692 5, 5, /* ==, != */
4693 9, 10, /* &&, || */
4694 6, 7, 8, /* & ^ | */
4695 2, 2 /* ~ ! */
4696 };
4697
Jack Palevich8b0624c2009-05-20 12:12:06 -07004698#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004699FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004700#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004701
Jack Palevich8b0624c2009-05-20 12:12:06 -07004702#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004703const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004704 0x1, // ++
4705 0xff, // --
4706 0xc1af0f, // *
4707 0xf9f79991, // /
4708 0xf9f79991, // % (With manual assist to swap results)
4709 0xc801, // +
4710 0xd8f7c829, // -
4711 0xe0d391, // <<
4712 0xf8d391, // >>
4713 0xe, // <=
4714 0xd, // >=
4715 0xc, // <
4716 0xf, // >
4717 0x4, // ==
4718 0x5, // !=
4719 0x0, // &&
4720 0x1, // ||
4721 0xc821, // &
4722 0xc831, // ^
4723 0xc809, // |
4724 0xd0f7, // ~
4725 0x4 // !
4726};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004727#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004728
Jack Palevich1cdef202009-05-22 12:06:27 -07004729struct ACCscript {
4730 ACCscript() {
4731 text = 0;
4732 textLength = 0;
4733 accError = ACC_NO_ERROR;
4734 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004735
Jack Palevich1cdef202009-05-22 12:06:27 -07004736 ~ACCscript() {
4737 delete text;
4738 }
Jack Palevich546b2242009-05-13 15:10:04 -07004739
Jack Palevich1cdef202009-05-22 12:06:27 -07004740 void setError(ACCenum error) {
4741 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4742 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004743 }
4744 }
4745
Jack Palevich1cdef202009-05-22 12:06:27 -07004746 ACCenum getError() {
4747 ACCenum result = accError;
4748 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004749 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004750 }
4751
Jack Palevich1cdef202009-05-22 12:06:27 -07004752 Compiler compiler;
4753 char* text;
4754 int textLength;
4755 ACCenum accError;
4756};
4757
4758
4759extern "C"
4760ACCscript* accCreateScript() {
4761 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004762}
Jack Palevich1cdef202009-05-22 12:06:27 -07004763
4764extern "C"
4765ACCenum accGetError( ACCscript* script ) {
4766 return script->getError();
4767}
4768
4769extern "C"
4770void accDeleteScript(ACCscript* script) {
4771 delete script;
4772}
4773
4774extern "C"
4775void accScriptSource(ACCscript* script,
4776 ACCsizei count,
4777 const ACCchar ** string,
4778 const ACCint * length) {
4779 int totalLength = 0;
4780 for(int i = 0; i < count; i++) {
4781 int len = -1;
4782 const ACCchar* s = string[i];
4783 if (length) {
4784 len = length[i];
4785 }
4786 if (len < 0) {
4787 len = strlen(s);
4788 }
4789 totalLength += len;
4790 }
4791 delete script->text;
4792 char* text = new char[totalLength + 1];
4793 script->text = text;
4794 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004795 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004796 for(int i = 0; i < count; i++) {
4797 int len = -1;
4798 const ACCchar* s = string[i];
4799 if (length) {
4800 len = length[i];
4801 }
4802 if (len < 0) {
4803 len = strlen(s);
4804 }
Jack Palevich09555c72009-05-27 12:25:55 -07004805 memcpy(dest, s, len);
4806 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07004807 }
4808 text[totalLength] = '\0';
4809}
4810
4811extern "C"
4812void accCompileScript(ACCscript* script) {
4813 int result = script->compiler.compile(script->text, script->textLength);
4814 if (result) {
4815 script->setError(ACC_INVALID_OPERATION);
4816 }
4817}
4818
4819extern "C"
4820void accGetScriptiv(ACCscript* script,
4821 ACCenum pname,
4822 ACCint * params) {
4823 switch (pname) {
4824 case ACC_INFO_LOG_LENGTH:
4825 *params = 0;
4826 break;
4827 }
4828}
4829
4830extern "C"
4831void accGetScriptInfoLog(ACCscript* script,
4832 ACCsizei maxLength,
4833 ACCsizei * length,
4834 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004835 char* message = script->compiler.getErrorMessage();
4836 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07004837 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004838 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07004839 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07004840 if (infoLog && maxLength > 0) {
4841 int trimmedLength = maxLength < messageLength ?
4842 maxLength : messageLength;
4843 memcpy(infoLog, message, trimmedLength);
4844 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07004845 }
4846}
4847
4848extern "C"
4849void accGetScriptLabel(ACCscript* script, const ACCchar * name,
4850 ACCvoid ** address) {
4851 void* value = script->compiler.lookup(name);
4852 if (value) {
4853 *address = value;
4854 } else {
4855 script->setError(ACC_INVALID_VALUE);
4856 }
4857}
4858
Jack Palevicheedf9d22009-06-04 16:23:40 -07004859extern "C"
4860void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
4861 ACCsizei maxStringCount, ACCchar** strings){
4862 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
4863}
4864
-b master422972c2009-06-17 19:13:52 -07004865extern "C"
4866void accDisassemble(ACCscript* script) {
4867 script->compiler.disassemble(stderr);
4868}
4869
Jack Palevicheedf9d22009-06-04 16:23:40 -07004870
Jack Palevich1cdef202009-05-22 12:06:27 -07004871} // namespace acc
4872