blob: 1a3d315adbbd9a987bc841d8547cd2e3d53efa2d [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>
Jack Palevich8dc662e2009-06-09 22:53:47 +000012#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070014#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070015#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070016#include <stdlib.h>
17#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070018#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich8dc662e2009-06-09 22:53:47 +000020#if defined(__i386__)
21#include <sys/mman.h>
22#endif
23
Jack Palevich546b2242009-05-13 15:10:04 -070024#if defined(__arm__)
25#include <unistd.h>
26#endif
27
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Paleviche7b59062009-05-19 17:12:17 -070039#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070040#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
Jack Palevicha6535612009-05-13 16:24:17 -070042
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
51// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070052// #define PROVIDE_TRACE_CODEGEN
53
Jack Palevichbbf8ab52009-05-11 11:54:30 -070054namespace acc {
55
Jack Palevich8df46192009-07-07 14:48:51 -070056// Subset of STL vector.
57template<class E> class Vector {
58 public:
59 Vector() {
60 mpBase = 0;
61 mUsed = 0;
62 mSize = 0;
63 }
64
65 ~Vector() {
66 if (mpBase) {
67 for(size_t i = 0; i < mUsed; i++) {
68 mpBase[mUsed].~E();
69 }
70 free(mpBase);
71 }
72 }
73
74 inline E& operator[](size_t i) {
75 return mpBase[i];
76 }
77
78 inline E& front() {
79 return mpBase[0];
80 }
81
82 inline E& back() {
83 return mpBase[mUsed - 1];
84 }
85
86 void pop_back() {
87 mUsed -= 1;
88 mpBase[mUsed].~E();
89 }
90
91 void push_back(const E& item) {
92 * ensure(1) = item;
93 }
94
95 size_t size() {
96 return mUsed;
97 }
98
99private:
100 E* ensure(int n) {
101 size_t newUsed = mUsed + n;
102 if (newUsed > mSize) {
103 size_t newSize = mSize * 2 + 10;
104 if (newSize < newUsed) {
105 newSize = newUsed;
106 }
107 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
108 mSize = newSize;
109 }
110 E* result = mpBase + mUsed;
111 mUsed = newUsed;
112 return result;
113 }
114
115 E* mpBase;
116 size_t mUsed;
117 size_t mSize;
118};
119
Jack Palevichac0e95e2009-05-29 13:53:44 -0700120class ErrorSink {
121public:
122 void error(const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 verror(fmt, ap);
126 va_end(ap);
127 }
128
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700129 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
136 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
137 TY_POINTER, TY_FUNC, TY_PARAM
138 };
139
140 struct Type {
141 TypeTag tag;
142 tokenid_t id; // For function arguments
143 Type* pHead;
144 Type* pTail;
145 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700146
Jack Palevichba929a42009-07-17 10:20:32 -0700147 enum ExpressionType {
148 ET_RVALUE,
149 ET_LVALUE
150 };
151
152 struct ExpressionValue {
153 ExpressionValue() {
154 et = ET_RVALUE;
155 pType = NULL;
156 }
157 ExpressionType et;
158 Type* pType;
159 };
160
Jack Palevich21a15a22009-05-11 14:49:29 -0700161 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700162 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700163 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700164 ErrorSink* mErrorSink;
165 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700166 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700167
Jack Palevich21a15a22009-05-11 14:49:29 -0700168 void release() {
169 if (pProgramBase != 0) {
170 free(pProgramBase);
171 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700172 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 }
174
Jack Palevich0a280a02009-06-11 10:53:51 -0700175 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700176 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700177 bool overflow = newSize > mSize;
178 if (overflow && !mOverflowed) {
179 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700180 if (mErrorSink) {
181 mErrorSink->error("Code too large: %d bytes", newSize);
182 }
183 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700184 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 }
186
Jack Palevich21a15a22009-05-11 14:49:29 -0700187 public:
188 CodeBuf() {
189 pProgramBase = 0;
190 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700191 mErrorSink = 0;
192 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700193 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
196 ~CodeBuf() {
197 release();
198 }
199
200 void init(int size) {
201 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700202 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700203 pProgramBase = (char*) calloc(1, size);
204 ind = pProgramBase;
205 }
206
Jack Palevichac0e95e2009-05-29 13:53:44 -0700207 void setErrorSink(ErrorSink* pErrorSink) {
208 mErrorSink = pErrorSink;
209 }
210
Jack Palevich546b2242009-05-13 15:10:04 -0700211 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(4)) {
213 return 0;
214 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700215 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700216 * (int*) ind = n;
217 ind += 4;
218 return result;
219 }
220
Jack Palevich21a15a22009-05-11 14:49:29 -0700221 /*
222 * Output a byte. Handles all values, 0..ff.
223 */
224 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700225 if(check(1)) {
226 return;
227 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 *ind++ = n;
229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 inline void* getBase() {
232 return (void*) pProgramBase;
233 }
234
Jack Palevich8b0624c2009-05-20 12:12:06 -0700235 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700236 return ind - pProgramBase;
237 }
238
Jack Palevich8b0624c2009-05-20 12:12:06 -0700239 intptr_t getPC() {
240 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 }
242 };
243
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 /**
245 * A code generator creates an in-memory program, generating the code on
246 * the fly. There is one code generator implementation for each supported
247 * architecture.
248 *
249 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700250 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700251 * FP - a frame pointer for accessing function arguments and local
252 * variables.
253 * SP - a stack pointer for storing intermediate results while evaluating
254 * expressions. The stack pointer grows downwards.
255 *
256 * The function calling convention is that all arguments are placed on the
257 * stack such that the first argument has the lowest address.
258 * After the call, the result is in R0. The caller is responsible for
259 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700260 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 * FP and SP registers are saved.
262 */
263
Jack Palevich21a15a22009-05-11 14:49:29 -0700264 class CodeGenerator {
265 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 CodeGenerator() {
267 mErrorSink = 0;
268 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700269 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700270 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700271 virtual ~CodeGenerator() {}
272
Jack Palevich22305132009-05-13 10:58:45 -0700273 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700275 pCodeBuf->setErrorSink(mErrorSink);
276 }
277
Jack Palevichb67b18f2009-06-11 21:12:23 -0700278 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700279 mErrorSink = pErrorSink;
280 if (pCodeBuf) {
281 pCodeBuf->setErrorSink(mErrorSink);
282 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
284
Jack Palevich58c30ee2009-07-17 16:35:23 -0700285 /* Give the code generator some utility types so it can
286 * use its own types as needed for the results of some
287 * operations like gcmp.
288 */
289
Jack Palevicha8f427f2009-07-13 18:40:08 -0700290 void setTypes(Type* pInt) {
291 mkpInt = pInt;
292 }
293
Jack Palevich1cdef202009-05-22 12:06:27 -0700294 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700295 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700296 * Save the old value of the FP.
297 * Set the new value of the FP.
298 * Convert from the native platform calling convention to
299 * our stack-based calling convention. This may require
300 * pushing arguments from registers to the stack.
301 * Allocate "N" bytes of stack space. N isn't known yet, so
302 * just emit the instructions for adjusting the stack, and return
303 * the address to patch up. The patching will be done in
304 * functionExit().
305 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700306 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700307 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700308
Jack Palevich1cdef202009-05-22 12:06:27 -0700309 /* Emit a function epilog.
310 * Restore the old SP and FP register values.
311 * Return to the calling function.
312 * argCount - the number of arguments to the function.
313 * localVariableAddress - returned from functionEntry()
314 * localVariableSize - the size in bytes of the local variables.
315 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700316 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700318
Jack Palevich1cdef202009-05-22 12:06:27 -0700319 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700320 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700321
Jack Palevich1a539db2009-07-08 13:04:41 -0700322 /* Load floating point value from global address. */
323 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Jump to a target, and return the address of the word that
326 * holds the target data, in case it needs to be fixed up later.
327 */
Jack Palevich22305132009-05-13 10:58:45 -0700328 virtual int gjmp(int t) = 0;
329
Jack Palevich1cdef202009-05-22 12:06:27 -0700330 /* Test R0 and jump to a target if the test succeeds.
331 * l = 0: je, l == 1: jne
332 * Return the address of the word that holds the targed data, in
333 * case it needs to be fixed up later.
334 */
Jack Palevich22305132009-05-13 10:58:45 -0700335 virtual int gtst(bool l, int t) = 0;
336
Jack Palevich9eed7a22009-07-06 17:24:34 -0700337 /* Compare TOS against R0, and store the boolean result in R0.
338 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 * op specifies the comparison.
340 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700341 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700342
Jack Palevich9eed7a22009-07-06 17:24:34 -0700343 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 */
Jack Palevich546b2242009-05-13 15:10:04 -0700347 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700348
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 /* Compare 0 against R0, and store the boolean result in R0.
350 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700352 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353
354 /* Perform the arithmetic op specified by op. 0 is the
355 * left argument, R0 is the right argument.
356 */
357 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700359 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 */
361 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700363 /* Turn R0, TOS into R0 TOS R0 */
364
365 virtual void over() = 0;
366
367 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700368 */
369 virtual void popR0() = 0;
370
Jack Palevich9eed7a22009-07-06 17:24:34 -0700371 /* Store R0 to the address stored in TOS.
372 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700373 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700374 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700378 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 /* Load the absolute address of a variable to R0.
381 * If ea <= LOCAL, then this is a local variable, or an
382 * argument, addressed relative to FP.
383 * else it is an absolute global address.
384 */
Jack Palevich8df46192009-07-07 14:48:51 -0700385 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700386
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 /* Store R0 to a variable.
388 * If ea <= LOCAL, then this is a local variable, or an
389 * argument, addressed relative to FP.
390 * else it is an absolute global address.
391 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700392 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700393
Jack Palevich1cdef202009-05-22 12:06:27 -0700394 /* load R0 from a variable.
395 * If ea <= LOCAL, then this is a local variable, or an
396 * argument, addressed relative to FP.
397 * else it is an absolute global address.
Jack Palevich1cdef202009-05-22 12:06:27 -0700398 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700399 virtual void loadR0(int ea, Type* pType) = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700400
401 /**
402 * Convert R0 to the given type.
403 */
404 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 /* Emit code to adjust the stack for a function call. Return the
407 * label for the address of the instruction that adjusts the
408 * stack size. This will be passed as argument "a" to
409 * endFunctionCallArguments.
410 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700411 virtual int beginFunctionCallArguments() = 0;
412
Jack Palevich1cdef202009-05-22 12:06:27 -0700413 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700414 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700415 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700416 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700417
Jack Palevich1cdef202009-05-22 12:06:27 -0700418 /* Patch the function call preamble.
419 * a is the address returned from beginFunctionCallArguments
420 * l is the number of bytes the arguments took on the stack.
421 * Typically you would also emit code to convert the argument
422 * list into whatever the native function calling convention is.
423 * On ARM for example you would pop the first 5 arguments into
424 * R0..R4
425 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700426 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevich1cdef202009-05-22 12:06:27 -0700428 /* Emit a call to an unknown function. The argument "symbol" needs to
429 * be stored in the location where the address should go. It forms
430 * a chain. The address will be patched later.
431 * Return the address of the word that has to be patched.
432 */
Jack Palevich8df46192009-07-07 14:48:51 -0700433 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700434
Jack Palevich1cdef202009-05-22 12:06:27 -0700435 /* Call a function using PC-relative addressing. t is the PC-relative
436 * address of the function. It has already been adjusted for the
437 * architectural jump offset, so just store it as-is.
438 */
Jack Palevich8df46192009-07-07 14:48:51 -0700439 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Call a function pointer. L is the number of bytes the arguments
442 * take on the stack. The address of the function is stored at
443 * location SP + l.
444 */
Jack Palevich8df46192009-07-07 14:48:51 -0700445 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700446
Jack Palevich1cdef202009-05-22 12:06:27 -0700447 /* Adjust SP after returning from a function call. l is the
448 * number of bytes of arguments stored on the stack. isIndirect
449 * is true if this was an indirect call. (In which case the
450 * address of the function is stored at location SP + l.)
451 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700452 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700453
Jack Palevich1cdef202009-05-22 12:06:27 -0700454 /* Print a disassembly of the assembled code to out. Return
455 * non-zero if there is an error.
456 */
Jack Palevicha6535612009-05-13 16:24:17 -0700457 virtual int disassemble(FILE* out) = 0;
458
Jack Palevich1cdef202009-05-22 12:06:27 -0700459 /* Generate a symbol at the current PC. t is the head of a
460 * linked list of addresses to patch.
461 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700462 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700463
Jack Palevich1cdef202009-05-22 12:06:27 -0700464 /*
465 * Do any cleanup work required at the end of a compile.
466 * For example, an instruction cache might need to be
467 * invalidated.
468 * Return non-zero if there is an error.
469 */
470 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700471
Jack Palevicha6535612009-05-13 16:24:17 -0700472 /**
473 * Adjust relative branches by this amount.
474 */
475 virtual int jumpOffset() = 0;
476
Jack Palevich9eed7a22009-07-06 17:24:34 -0700477 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700478 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700479 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700480 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700481
482 /**
483 * Array element alignment (in bytes) for this type of data.
484 */
485 virtual size_t sizeOf(Type* type) = 0;
486
Jack Palevich9cbd2262009-07-08 16:48:41 -0700487 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700488 * Stack alignment of this type of data
489 */
490 virtual size_t stackAlignmentOf(Type* pType) = 0;
491
492 /**
493 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700494 */
495 virtual size_t stackSizeOf(Type* pType) = 0;
496
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700497 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700498 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700499 }
500
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700501 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700502 return mExpressionStack.back().et;
503 }
504
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700505 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700506 mExpressionStack.back().et = et;
507 }
508
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700509 virtual size_t getExpressionStackDepth() {
510 return mExpressionStack.size();
511 }
512
Jack Palevich21a15a22009-05-11 14:49:29 -0700513 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700514 /*
515 * Output a byte. Handles all values, 0..ff.
516 */
517 void ob(int n) {
518 pCodeBuf->ob(n);
519 }
520
Jack Palevich8b0624c2009-05-20 12:12:06 -0700521 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700522 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700523 }
524
Jack Palevich8b0624c2009-05-20 12:12:06 -0700525 intptr_t getBase() {
526 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700527 }
528
Jack Palevich8b0624c2009-05-20 12:12:06 -0700529 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700530 return pCodeBuf->getPC();
531 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700532
533 intptr_t getSize() {
534 return pCodeBuf->getSize();
535 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700536
537 void error(const char* fmt,...) {
538 va_list ap;
539 va_start(ap, fmt);
540 mErrorSink->verror(fmt, ap);
541 va_end(ap);
542 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700543
544 void assert(bool test) {
545 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700546 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700547 error("code generator assertion failed.");
548 }
549 }
Jack Palevich8df46192009-07-07 14:48:51 -0700550
551 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700552 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700553 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700554 }
555
Jack Palevich8df46192009-07-07 14:48:51 -0700556 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700557 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700558 }
559
560 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700561 if (mExpressionStack.size()) {
562 mExpressionStack.push_back(mExpressionStack.back());
563 } else {
564 mExpressionStack.push_back(ExpressionValue());
565 }
566
Jack Palevich8df46192009-07-07 14:48:51 -0700567 }
568
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700569 void overType() {
570 size_t size = mExpressionStack.size();
571 if (size >= 2) {
572 mExpressionStack.push_back(mExpressionStack.back());
573 mExpressionStack[size-1] = mExpressionStack[size-2];
574 mExpressionStack[size-2] = mExpressionStack[size];
575 }
576 }
577
Jack Palevich8df46192009-07-07 14:48:51 -0700578 void popType() {
579 mExpressionStack.pop_back();
580 }
581
582 bool bitsSame(Type* pA, Type* pB) {
583 return collapseType(pA->tag) == collapseType(pB->tag);
584 }
585
586 TypeTag collapseType(TypeTag tag) {
587 static const TypeTag collapsedTag[] = {
588 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
589 TY_VOID, TY_VOID};
590 return collapsedTag[tag];
591 }
592
Jack Palevich1a539db2009-07-08 13:04:41 -0700593 TypeTag collapseTypeR0() {
594 return collapseType(getR0Type()->tag);
595 }
596
597 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700598 return isFloatTag(pType->tag);
599 }
600
601 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700602 return tag == TY_FLOAT || tag == TY_DOUBLE;
603 }
604
Jack Palevicha8f427f2009-07-13 18:40:08 -0700605 Type* mkpInt;
606
Jack Palevich21a15a22009-05-11 14:49:29 -0700607 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700608 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700609 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700610 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700611 };
612
Jack Paleviche7b59062009-05-19 17:12:17 -0700613#ifdef PROVIDE_ARM_CODEGEN
614
Jack Palevich22305132009-05-13 10:58:45 -0700615 class ARMCodeGenerator : public CodeGenerator {
616 public:
617 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700618
Jack Palevich22305132009-05-13 10:58:45 -0700619 virtual ~ARMCodeGenerator() {}
620
621 /* returns address to patch with local variable size
622 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700623 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700624 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700625 // sp -> arg4 arg5 ...
626 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700627 int regArgCount = calcRegArgCount(pDecl);
628 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700629 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700630 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700631 }
632 // sp -> arg0 arg1 ...
633 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700634 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700635 // sp, fp -> oldfp, retadr, arg0 arg1 ....
636 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700637 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700638 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700639 // We don't know how many local variables we are going to use,
640 // but we will round the allocation up to a multiple of
641 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700642 }
643
Jack Palevichb7718b92009-07-09 22:00:24 -0700644 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700645 // Round local variable size up to a multiple of stack alignment
646 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
647 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700648 // Patch local variable allocation code:
649 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700650 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700651 }
Jack Palevich69796b62009-05-14 15:42:26 -0700652 *(char*) (localVariableAddress) = localVariableSize;
653
654 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
655 o4(0xE1A0E00B); // mov lr, fp
656 o4(0xE59BB000); // ldr fp, [fp]
657 o4(0xE28ED004); // add sp, lr, #4
658 // sp -> retadr, arg0, ...
659 o4(0xE8BD4000); // ldmfd sp!, {lr}
660 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700661
662 // We store the PC into the lr so we can adjust the sp before
663 // returning. We need to pull off the registers we pushed
664 // earlier. We don't need to actually store them anywhere,
665 // just adjust the stack.
666 int regArgCount = calcRegArgCount(pDecl);
667 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700668 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
669 }
670 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700671 }
672
673 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700674 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700675 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700676 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700677 }
678
Jack Palevich1a539db2009-07-08 13:04:41 -0700679 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700680 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700681 // Global, absolute address
682 o4(0xE59F0000); // ldr r0, .L1
683 o4(0xEA000000); // b .L99
684 o4(address); // .L1: .word ea
685 // .L99:
686
687 switch (pType->tag) {
688 case TY_FLOAT:
689 o4(0xE5900000); // ldr r0, [r0]
690 break;
691 case TY_DOUBLE:
692 o4(0xE1C000D0); // ldrd r0, [r0]
693 break;
694 default:
695 assert(false);
696 break;
697 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700698 }
699
Jack Palevich22305132009-05-13 10:58:45 -0700700 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700701 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700702 }
703
704 /* l = 0: je, l == 1: jne */
705 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700706 Type* pR0Type = getR0Type();
707 TypeTag tagR0 = pR0Type->tag;
708 switch(tagR0) {
709 case TY_FLOAT:
710 callRuntime((void*) runtime_is_non_zero_f);
711 break;
712 case TY_DOUBLE:
713 callRuntime((void*) runtime_is_non_zero_d);
714 break;
715 default:
716 break;
717 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700718 o4(0xE3500000); // cmp r0,#0
719 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
720 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700721 }
722
Jack Palevich58c30ee2009-07-17 16:35:23 -0700723 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700724 Type* pR0Type = getR0Type();
725 Type* pTOSType = getTOSType();
726 TypeTag tagR0 = collapseType(pR0Type->tag);
727 TypeTag tagTOS = collapseType(pTOSType->tag);
728 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700729 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700730 o4(0xE1510000); // cmp r1, r1
731 switch(op) {
732 case OP_EQUALS:
733 o4(0x03A00001); // moveq r0,#1
734 o4(0x13A00000); // movne r0,#0
735 break;
736 case OP_NOT_EQUALS:
737 o4(0x03A00000); // moveq r0,#0
738 o4(0x13A00001); // movne r0,#1
739 break;
740 case OP_LESS_EQUAL:
741 o4(0xD3A00001); // movle r0,#1
742 o4(0xC3A00000); // movgt r0,#0
743 break;
744 case OP_GREATER:
745 o4(0xD3A00000); // movle r0,#0
746 o4(0xC3A00001); // movgt r0,#1
747 break;
748 case OP_GREATER_EQUAL:
749 o4(0xA3A00001); // movge r0,#1
750 o4(0xB3A00000); // movlt r0,#0
751 break;
752 case OP_LESS:
753 o4(0xA3A00000); // movge r0,#0
754 o4(0xB3A00001); // movlt r0,#1
755 break;
756 default:
757 error("Unknown comparison op %d", op);
758 break;
759 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700760 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
761 setupDoubleArgs();
762 switch(op) {
763 case OP_EQUALS:
764 callRuntime((void*) runtime_cmp_eq_dd);
765 break;
766 case OP_NOT_EQUALS:
767 callRuntime((void*) runtime_cmp_ne_dd);
768 break;
769 case OP_LESS_EQUAL:
770 callRuntime((void*) runtime_cmp_le_dd);
771 break;
772 case OP_GREATER:
773 callRuntime((void*) runtime_cmp_gt_dd);
774 break;
775 case OP_GREATER_EQUAL:
776 callRuntime((void*) runtime_cmp_ge_dd);
777 break;
778 case OP_LESS:
779 callRuntime((void*) runtime_cmp_lt_dd);
780 break;
781 default:
782 error("Unknown comparison op %d", op);
783 break;
784 }
785 } else {
786 setupFloatArgs();
787 switch(op) {
788 case OP_EQUALS:
789 callRuntime((void*) runtime_cmp_eq_ff);
790 break;
791 case OP_NOT_EQUALS:
792 callRuntime((void*) runtime_cmp_ne_ff);
793 break;
794 case OP_LESS_EQUAL:
795 callRuntime((void*) runtime_cmp_le_ff);
796 break;
797 case OP_GREATER:
798 callRuntime((void*) runtime_cmp_gt_ff);
799 break;
800 case OP_GREATER_EQUAL:
801 callRuntime((void*) runtime_cmp_ge_ff);
802 break;
803 case OP_LESS:
804 callRuntime((void*) runtime_cmp_lt_ff);
805 break;
806 default:
807 error("Unknown comparison op %d", op);
808 break;
809 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700810 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700811 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700812 }
813
Jack Palevich546b2242009-05-13 15:10:04 -0700814 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700815 Type* pR0Type = getR0Type();
816 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700817 TypeTag tagR0 = pR0Type->tag;
818 TypeTag tagTOS = pTOSType->tag;
819 bool isFloatR0 = isFloatTag(tagR0);
820 bool isFloatTOS = isFloatTag(tagTOS);
821 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700822 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700823 bool isPtrR0 = tagR0 == TY_POINTER;
824 bool isPtrTOS = tagTOS == TY_POINTER;
825 if (isPtrR0 || isPtrTOS) {
826 if (isPtrR0 && isPtrTOS) {
827 if (op != OP_MINUS) {
828 error("Unsupported pointer-pointer operation %d.", op);
829 }
830 if (! typeEqual(pR0Type, pTOSType)) {
831 error("Incompatible pointer types for subtraction.");
832 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700833 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700834 setR0Type(mkpInt);
835 int size = sizeOf(pR0Type->pHead);
836 if (size != 1) {
837 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700838 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700839 // TODO: Optimize for power-of-two.
840 genOp(OP_DIV);
841 }
842 } else {
843 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
844 error("Unsupported pointer-scalar operation %d", op);
845 }
846 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700847 int size = sizeOf(pPtrType->pHead);
848 if (size != 1) {
849 // TODO: Optimize for power-of-two.
850 liReg(size, 2);
851 if (isPtrR0) {
852 o4(0x0E0010192); // mul r1,r2,r1
853 } else {
854 o4(0x0E0000092); // mul r0,r2,r0
855 }
856 }
857 switch(op) {
858 case OP_PLUS:
859 o4(0xE0810000); // add r0,r1,r0
860 break;
861 case OP_MINUS:
862 o4(0xE0410000); // sub r0,r1,r0
863 break;
864 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700865 setR0Type(pPtrType);
866 }
867 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700868 switch(op) {
869 case OP_MUL:
870 o4(0x0E0000091); // mul r0,r1,r0
871 break;
872 case OP_DIV:
873 callRuntime((void*) runtime_DIV);
874 break;
875 case OP_MOD:
876 callRuntime((void*) runtime_MOD);
877 break;
878 case OP_PLUS:
879 o4(0xE0810000); // add r0,r1,r0
880 break;
881 case OP_MINUS:
882 o4(0xE0410000); // sub r0,r1,r0
883 break;
884 case OP_SHIFT_LEFT:
885 o4(0xE1A00011); // lsl r0,r1,r0
886 break;
887 case OP_SHIFT_RIGHT:
888 o4(0xE1A00051); // asr r0,r1,r0
889 break;
890 case OP_BIT_AND:
891 o4(0xE0010000); // and r0,r1,r0
892 break;
893 case OP_BIT_XOR:
894 o4(0xE0210000); // eor r0,r1,r0
895 break;
896 case OP_BIT_OR:
897 o4(0xE1810000); // orr r0,r1,r0
898 break;
899 case OP_BIT_NOT:
900 o4(0xE1E00000); // mvn r0, r0
901 break;
902 default:
903 error("Unimplemented op %d\n", op);
904 break;
905 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700906 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700907 } else {
908 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
909 if (pResultType->tag == TY_DOUBLE) {
910 setupDoubleArgs();
911 switch(op) {
912 case OP_MUL:
913 callRuntime((void*) runtime_op_mul_dd);
914 break;
915 case OP_DIV:
916 callRuntime((void*) runtime_op_div_dd);
917 break;
918 case OP_PLUS:
919 callRuntime((void*) runtime_op_add_dd);
920 break;
921 case OP_MINUS:
922 callRuntime((void*) runtime_op_sub_dd);
923 break;
924 default:
925 error("Unsupported binary floating operation %d\n", op);
926 break;
927 }
928 } else {
929 setupFloatArgs();
930 switch(op) {
931 case OP_MUL:
932 callRuntime((void*) runtime_op_mul_ff);
933 break;
934 case OP_DIV:
935 callRuntime((void*) runtime_op_div_ff);
936 break;
937 case OP_PLUS:
938 callRuntime((void*) runtime_op_add_ff);
939 break;
940 case OP_MINUS:
941 callRuntime((void*) runtime_op_sub_ff);
942 break;
943 default:
944 error("Unsupported binary floating operation %d\n", op);
945 break;
946 }
947 }
948 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700949 }
Jack Palevich22305132009-05-13 10:58:45 -0700950 }
951
Jack Palevich58c30ee2009-07-17 16:35:23 -0700952 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700953 if (op != OP_LOGICAL_NOT) {
954 error("Unknown unary cmp %d", op);
955 } else {
956 Type* pR0Type = getR0Type();
957 TypeTag tag = collapseType(pR0Type->tag);
958 switch(tag) {
959 case TY_INT:
960 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700961 o4(0xE1510000); // cmp r1, r0
962 o4(0x03A00001); // moveq r0,#1
963 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700964 break;
965 case TY_FLOAT:
966 callRuntime((void*) runtime_is_zero_f);
967 break;
968 case TY_DOUBLE:
969 callRuntime((void*) runtime_is_zero_d);
970 break;
971 default:
972 error("gUnaryCmp unsupported type");
973 break;
974 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700975 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700976 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700977 }
978
979 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700980 Type* pR0Type = getR0Type();
981 TypeTag tag = collapseType(pR0Type->tag);
982 switch(tag) {
983 case TY_INT:
984 switch(op) {
985 case OP_MINUS:
986 o4(0xE3A01000); // mov r1, #0
987 o4(0xE0410000); // sub r0,r1,r0
988 break;
989 case OP_BIT_NOT:
990 o4(0xE1E00000); // mvn r0, r0
991 break;
992 default:
993 error("Unknown unary op %d\n", op);
994 break;
995 }
996 break;
997 case TY_FLOAT:
998 case TY_DOUBLE:
999 switch (op) {
1000 case OP_MINUS:
1001 if (tag == TY_FLOAT) {
1002 callRuntime((void*) runtime_op_neg_f);
1003 } else {
1004 callRuntime((void*) runtime_op_neg_d);
1005 }
1006 break;
1007 case OP_BIT_NOT:
1008 error("Can't apply '~' operator to a float or double.");
1009 break;
1010 default:
1011 error("Unknown unary op %d\n", op);
1012 break;
1013 }
1014 break;
1015 default:
1016 error("genUnaryOp unsupported type");
1017 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001018 }
Jack Palevich22305132009-05-13 10:58:45 -07001019 }
1020
Jack Palevich1cdef202009-05-22 12:06:27 -07001021 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001022 Type* pR0Type = getR0Type();
1023 TypeTag r0ct = collapseType(pR0Type->tag);
1024 if (r0ct != TY_DOUBLE) {
1025 o4(0xE92D0001); // stmfd sp!,{r0}
1026 mStackUse += 4;
1027 } else {
1028 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1029 mStackUse += 8;
1030 }
Jack Palevich8df46192009-07-07 14:48:51 -07001031 pushType();
-b master422972c2009-06-17 19:13:52 -07001032 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001033 }
1034
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001035 virtual void over() {
1036 // We know it's only used for int-ptr ops (++/--)
1037
1038 Type* pR0Type = getR0Type();
1039 TypeTag r0ct = collapseType(pR0Type->tag);
1040
1041 Type* pTOSType = getTOSType();
1042 TypeTag tosct = collapseType(pTOSType->tag);
1043
1044 assert (r0ct == TY_INT && tosct == TY_INT);
1045
1046 o4(0xE8BD0002); // ldmfd sp!,{r1}
1047 o4(0xE92D0001); // stmfd sp!,{r0}
1048 o4(0xE92D0002); // stmfd sp!,{r1}
1049 overType();
1050 mStackUse += 4;
1051 }
1052
Jack Palevich58c30ee2009-07-17 16:35:23 -07001053 virtual void popR0() {
1054 Type* pTOSType = getTOSType();
1055 switch (collapseType(pTOSType->tag)){
1056 case TY_INT:
1057 case TY_FLOAT:
1058 o4(0xE8BD0001); // ldmfd sp!,{r0}
1059 mStackUse -= 4;
1060 break;
1061 case TY_DOUBLE:
1062 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1063 mStackUse -= 8;
1064 break;
1065 default:
1066 error("Can't pop this type.");
1067 break;
1068 }
1069 popType();
1070 LOG_STACK("popR0: %d\n", mStackUse);
1071 }
1072
1073 virtual void storeR0ToTOS() {
1074 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001075 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001076 o4(0xE8BD0004); // ldmfd sp!,{r2}
1077 popType();
-b master422972c2009-06-17 19:13:52 -07001078 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001079 switch (pPointerType->pHead->tag) {
1080 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001081 case TY_FLOAT:
1082 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001083 break;
1084 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001085 o4(0xE5C20000); // strb r0, [r2]
1086 break;
1087 case TY_DOUBLE:
1088 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001089 break;
1090 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001091 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001092 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001093 }
Jack Palevich22305132009-05-13 10:58:45 -07001094 }
1095
Jack Palevich58c30ee2009-07-17 16:35:23 -07001096 virtual void loadR0FromR0() {
1097 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001098 assert(pPointerType->tag == TY_POINTER);
1099 switch (pPointerType->pHead->tag) {
1100 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001101 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001102 o4(0xE5900000); // ldr r0, [r0]
1103 break;
1104 case TY_CHAR:
1105 o4(0xE5D00000); // ldrb r0, [r0]
1106 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001107 case TY_DOUBLE:
1108 o4(0xE1C000D0); // ldrd r0, [r0]
1109 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001110 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001111 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001112 break;
1113 }
Jack Palevich8df46192009-07-07 14:48:51 -07001114 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001115 }
1116
Jack Palevich8df46192009-07-07 14:48:51 -07001117 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001118 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001119 // Local, fp relative
1120 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1121 error("Offset out of range: %08x", ea);
1122 }
1123 if (ea < 0) {
1124 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1125 } else {
1126 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1127 }
Jack Palevichbd894902009-05-14 19:35:31 -07001128 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001129 // Global, absolute.
1130 o4(0xE59F0000); // ldr r0, .L1
1131 o4(0xEA000000); // b .L99
1132 o4(ea); // .L1: .word 0
1133 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001134 }
Jack Palevich8df46192009-07-07 14:48:51 -07001135 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001136 }
1137
Jack Palevich9cbd2262009-07-08 16:48:41 -07001138 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001139 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001140 TypeTag tag = pType->tag;
1141 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001142 case TY_CHAR:
1143 if (ea > -LOCAL && ea < LOCAL) {
1144 // Local, fp relative
1145 if (ea < -4095 || ea > 4095) {
1146 error("Offset out of range: %08x", ea);
1147 }
1148 if (ea < 0) {
1149 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1150 } else {
1151 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1152 }
1153 } else{
1154 // Global, absolute
1155 o4(0xE59F1000); // ldr r1, .L1
1156 o4(0xEA000000); // b .L99
1157 o4(ea); // .L1: .word 0
1158 o4(0xE5C10000); // .L99: strb r0, [r1]
1159 }
1160 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001161 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001162 case TY_INT:
1163 case TY_FLOAT:
1164 if (ea > -LOCAL && ea < LOCAL) {
1165 // Local, fp relative
1166 if (ea < -4095 || ea > 4095) {
1167 error("Offset out of range: %08x", ea);
1168 }
1169 if (ea < 0) {
1170 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1171 } else {
1172 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1173 }
1174 } else{
1175 // Global, absolute
1176 o4(0xE59F1000); // ldr r1, .L1
1177 o4(0xEA000000); // b .L99
1178 o4(ea); // .L1: .word 0
1179 o4(0xE5810000); // .L99: str r0, [r1]
1180 }
1181 break;
1182 case TY_DOUBLE:
1183 if ((ea & 0x7) != 0) {
1184 error("double address is not aligned: %d", ea);
1185 }
1186 if (ea > -LOCAL && ea < LOCAL) {
1187 // Local, fp relative
1188 if (ea < -4095 || ea > 4095) {
1189 error("Offset out of range: %08x", ea);
1190 }
1191 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001192 o4(0xE50B0000 | (0xfff & (4-ea))); // str r0, [fp,#-ea]
1193 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001194#if 0
1195 // strd doesn't seem to work. Is encoding wrong?
1196 } else if (ea < 0) {
1197 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1198 } else if (ea < 256) {
1199 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1200#endif
1201 } else {
1202 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1203 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1204 }
1205 } else{
1206 // Global, absolute
1207 o4(0xE59F2000); // ldr r2, .L1
1208 o4(0xEA000000); // b .L99
1209 o4(ea); // .L1: .word 0
1210 o4(0xE1C200F0); // .L99: strd r0, [r2]
1211 }
1212 break;
1213 default:
1214 error("Unable to store to type %d", tag);
1215 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001216 }
Jack Palevich22305132009-05-13 10:58:45 -07001217 }
1218
Jack Palevich58c30ee2009-07-17 16:35:23 -07001219 virtual void loadR0(int ea, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001220 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001221 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001222 case TY_CHAR:
1223 if (ea < LOCAL) {
1224 // Local, fp relative
1225 if (ea < -4095 || ea > 4095) {
1226 error("Offset out of range: %08x", ea);
1227 }
1228 if (ea < 0) {
1229 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1230 } else {
1231 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1232 }
1233 } else {
1234 // Global, absolute
1235 o4(0xE59F2000); // ldr r2, .L1
1236 o4(0xEA000000); // b .L99
1237 o4(ea); // .L1: .word ea
1238 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1239 }
Jack Palevich25c0cca2009-07-13 16:56:28 -07001240 break;
1241 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001242 case TY_INT:
1243 case TY_FLOAT:
1244 if (ea < LOCAL) {
1245 // Local, fp relative
1246 if (ea < -4095 || ea > 4095) {
1247 error("Offset out of range: %08x", ea);
1248 }
1249 if (ea < 0) {
1250 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1251 } else {
1252 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1253 }
1254 } else {
1255 // Global, absolute
1256 o4(0xE59F2000); // ldr r2, .L1
1257 o4(0xEA000000); // b .L99
1258 o4(ea); // .L1: .word ea
1259 o4(0xE5920000); // .L99: ldr r0, [r2]
1260 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001261 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001262 case TY_DOUBLE:
1263 if ((ea & 0x7) != 0) {
1264 error("double address is not aligned: %d", ea);
1265 }
1266 if (ea < LOCAL) {
1267 // Local, fp relative
1268 if (ea < -4095 || ea > 4095) {
1269 error("Offset out of range: %08x", ea);
1270 }
1271 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001272 o4(0xE51B0000 | (0xfff & (4-ea))); // ldr r0, [fp,#-ea]
1273 o4(0xE51B1000 | (0xfff & (-ea))); // ldr r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001274 } else {
1275 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1276 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1277 }
1278 } else {
1279 // Global, absolute
1280 o4(0xE59F2000); // ldr r2, .L1
1281 o4(0xEA000000); // b .L99
1282 o4(ea); // .L1: .word ea
1283 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1284 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001285 break;
1286 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001287 error("Unable to load type %d", tag);
1288 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001289 }
Jack Palevich8df46192009-07-07 14:48:51 -07001290 setR0Type(pType);
1291 }
1292
1293 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001294 Type* pR0Type = getR0Type();
1295 if (bitsSame(pType, pR0Type)) {
1296 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001297 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001298 TypeTag r0Tag = collapseType(pR0Type->tag);
1299 TypeTag destTag = collapseType(pType->tag);
1300 if (r0Tag == TY_INT) {
1301 if (destTag == TY_FLOAT) {
1302 callRuntime((void*) runtime_int_to_float);
1303 } else {
1304 assert(destTag == TY_DOUBLE);
1305 callRuntime((void*) runtime_int_to_double);
1306 }
1307 } else if (r0Tag == TY_FLOAT) {
1308 if (destTag == TY_INT) {
1309 callRuntime((void*) runtime_float_to_int);
1310 } else {
1311 assert(destTag == TY_DOUBLE);
1312 callRuntime((void*) runtime_float_to_double);
1313 }
1314 } else {
1315 assert (r0Tag == TY_DOUBLE);
1316 if (destTag == TY_INT) {
1317 callRuntime((void*) runtime_double_to_int);
1318 } else {
1319 assert(destTag == TY_FLOAT);
1320 callRuntime((void*) runtime_double_to_float);
1321 }
1322 }
Jack Palevich8df46192009-07-07 14:48:51 -07001323 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001324 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001325 }
1326
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001327 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001328 return o4(0xE24DDF00); // Placeholder
1329 }
1330
Jack Palevich8148c5b2009-07-16 18:24:47 -07001331 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001332 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001333 Type* pR0Type = getR0Type();
1334 TypeTag r0ct = collapseType(pR0Type->tag);
1335 switch(r0ct) {
1336 case TY_INT:
1337 case TY_FLOAT:
1338 if (l < 0 || l > 4096-4) {
1339 error("l out of range for stack offset: 0x%08x", l);
1340 }
1341 o4(0xE58D0000 + l); // str r0, [sp, #l]
1342 return 4;
1343 case TY_DOUBLE: {
1344 // Align to 8 byte boundary
1345 int l2 = (l + 7) & ~7;
1346 if (l2 < 0 || l2 > 4096-8) {
1347 error("l out of range for stack offset: 0x%08x", l);
1348 }
1349 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1350 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1351 return (l2 - l) + 8;
1352 }
1353 default:
1354 assert(false);
1355 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001356 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001357 }
1358
Jack Palevichb7718b92009-07-09 22:00:24 -07001359 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001360 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001361 // Have to calculate register arg count from actual stack size,
1362 // in order to properly handle ... functions.
1363 int regArgCount = l >> 2;
1364 if (regArgCount > 4) {
1365 regArgCount = 4;
1366 }
1367 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001368 argumentStackUse -= regArgCount * 4;
1369 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1370 }
1371 mStackUse += argumentStackUse;
1372
1373 // Align stack.
1374 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1375 * STACK_ALIGNMENT);
1376 mStackAlignmentAdjustment = 0;
1377 if (missalignment > 0) {
1378 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1379 }
1380 l += mStackAlignmentAdjustment;
1381
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001382 if (l < 0 || l > 0x3FC) {
1383 error("L out of range for stack adjustment: 0x%08x", l);
1384 }
1385 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001386 mStackUse += mStackAlignmentAdjustment;
1387 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1388 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001389 }
1390
Jack Palevich8df46192009-07-07 14:48:51 -07001391 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001392 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001393 // Forward calls are always short (local)
1394 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001395 }
1396
Jack Palevich8df46192009-07-07 14:48:51 -07001397 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001398 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001399 int abs = t + getPC() + jumpOffset();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001400 if (t >= - (1 << 25) && t < (1 << 25)) {
1401 o4(0xEB000000 | encodeAddress(t));
1402 } else {
1403 // Long call.
1404 o4(0xE59FC000); // ldr r12, .L1
1405 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001406 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001407 o4(0xE08CC00F); // .L99: add r12,pc
1408 o4(0xE12FFF3C); // blx r12
1409 }
Jack Palevich22305132009-05-13 10:58:45 -07001410 }
1411
Jack Palevich8df46192009-07-07 14:48:51 -07001412 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001413 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001414 int argCount = l >> 2;
1415 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001416 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001417 if (adjustedL < 0 || adjustedL > 4096-4) {
1418 error("l out of range for stack offset: 0x%08x", l);
1419 }
1420 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1421 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001422 }
1423
Jack Palevichb7718b92009-07-09 22:00:24 -07001424 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001425 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001426 // Have to calculate register arg count from actual stack size,
1427 // in order to properly handle ... functions.
1428 int regArgCount = l >> 2;
1429 if (regArgCount > 4) {
1430 regArgCount = 4;
1431 }
1432 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001433 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1434 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001435 if (stackUse) {
1436 if (stackUse < 0 || stackUse > 255) {
1437 error("L out of range for stack adjustment: 0x%08x", l);
1438 }
1439 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001440 mStackUse -= stackUse * 4;
1441 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001442 }
Jack Palevich22305132009-05-13 10:58:45 -07001443 }
1444
Jack Palevicha6535612009-05-13 16:24:17 -07001445 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001446 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001447 }
1448
1449 /* output a symbol and patch all calls to it */
1450 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001451 int n;
1452 int base = getBase();
1453 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001454 while (t) {
1455 int data = * (int*) t;
1456 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1457 if (decodedOffset == 0) {
1458 n = 0;
1459 } else {
1460 n = base + decodedOffset; /* next value */
1461 }
1462 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1463 | encodeRelAddress(pc - t - 8);
1464 t = n;
1465 }
1466 }
1467
Jack Palevich1cdef202009-05-22 12:06:27 -07001468 virtual int finishCompile() {
1469#if defined(__arm__)
1470 const long base = long(getBase());
1471 const long curr = long(getPC());
1472 int err = cacheflush(base, curr, 0);
1473 return err;
1474#else
1475 return 0;
1476#endif
1477 }
1478
Jack Palevicha6535612009-05-13 16:24:17 -07001479 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001480#ifdef ENABLE_ARM_DISASSEMBLY
1481 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001482 disasm_interface_t di;
1483 di.di_readword = disassemble_readword;
1484 di.di_printaddr = disassemble_printaddr;
1485 di.di_printf = disassemble_printf;
1486
1487 int base = getBase();
1488 int pc = getPC();
1489 for(int i = base; i < pc; i += 4) {
1490 fprintf(out, "%08x: %08x ", i, *(int*) i);
1491 ::disasm(&di, i, 0);
1492 }
Jack Palevich09555c72009-05-27 12:25:55 -07001493#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001494 return 0;
1495 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001496
Jack Palevich9eed7a22009-07-06 17:24:34 -07001497 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001498 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001499 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001500 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001501 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001502 case TY_CHAR:
1503 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001504 case TY_DOUBLE:
1505 return 8;
1506 default:
1507 return 4;
1508 }
1509 }
1510
1511 /**
1512 * Array element alignment (in bytes) for this type of data.
1513 */
1514 virtual size_t sizeOf(Type* pType){
1515 switch(pType->tag) {
1516 case TY_INT:
1517 return 4;
1518 case TY_CHAR:
1519 return 1;
1520 default:
1521 return 0;
1522 case TY_FLOAT:
1523 return 4;
1524 case TY_DOUBLE:
1525 return 8;
1526 case TY_POINTER:
1527 return 4;
1528 }
1529 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001530
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001531 virtual size_t stackAlignmentOf(Type* pType) {
1532 switch(pType->tag) {
1533 case TY_DOUBLE:
1534 return 8;
1535 default:
1536 return 4;
1537 }
1538 }
1539
Jack Palevich9cbd2262009-07-08 16:48:41 -07001540 virtual size_t stackSizeOf(Type* pType) {
1541 switch(pType->tag) {
1542 case TY_DOUBLE:
1543 return 8;
1544 default:
1545 return 4;
1546 }
1547 }
1548
Jack Palevich22305132009-05-13 10:58:45 -07001549 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001550 static FILE* disasmOut;
1551
1552 static u_int
1553 disassemble_readword(u_int address)
1554 {
1555 return(*((u_int *)address));
1556 }
1557
1558 static void
1559 disassemble_printaddr(u_int address)
1560 {
1561 fprintf(disasmOut, "0x%08x", address);
1562 }
1563
1564 static void
1565 disassemble_printf(const char *fmt, ...) {
1566 va_list ap;
1567 va_start(ap, fmt);
1568 vfprintf(disasmOut, fmt, ap);
1569 va_end(ap);
1570 }
1571
1572 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1573
1574 /** Encode a relative address that might also be
1575 * a label.
1576 */
1577 int encodeAddress(int value) {
1578 int base = getBase();
1579 if (value >= base && value <= getPC() ) {
1580 // This is a label, encode it relative to the base.
1581 value = value - base;
1582 }
1583 return encodeRelAddress(value);
1584 }
1585
1586 int encodeRelAddress(int value) {
1587 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1588 }
Jack Palevich22305132009-05-13 10:58:45 -07001589
Jack Palevichb7718b92009-07-09 22:00:24 -07001590 int calcRegArgCount(Type* pDecl) {
1591 int reg = 0;
1592 Type* pArgs = pDecl->pTail;
1593 while (pArgs && reg < 4) {
1594 Type* pArg = pArgs->pHead;
1595 if ( pArg->tag == TY_DOUBLE) {
1596 int evenReg = (reg + 1) & ~1;
1597 if (evenReg >= 4) {
1598 break;
1599 }
1600 reg = evenReg + 2;
1601 } else {
1602 reg++;
1603 }
1604 pArgs = pArgs->pTail;
1605 }
1606 return reg;
1607 }
1608
Jack Palevich58c30ee2009-07-17 16:35:23 -07001609 void setupIntPtrArgs() {
1610 o4(0xE8BD0002); // ldmfd sp!,{r1}
1611 mStackUse -= 4;
1612 popType();
1613 }
1614
Jack Palevichb7718b92009-07-09 22:00:24 -07001615 /* Pop TOS to R1
1616 * Make sure both R0 and TOS are floats. (Could be ints)
1617 * We know that at least one of R0 and TOS is already a float
1618 */
1619 void setupFloatArgs() {
1620 Type* pR0Type = getR0Type();
1621 Type* pTOSType = getTOSType();
1622 TypeTag tagR0 = collapseType(pR0Type->tag);
1623 TypeTag tagTOS = collapseType(pTOSType->tag);
1624 if (tagR0 != TY_FLOAT) {
1625 assert(tagR0 == TY_INT);
1626 callRuntime((void*) runtime_int_to_float);
1627 }
1628 if (tagTOS != TY_FLOAT) {
1629 assert(tagTOS == TY_INT);
1630 assert(tagR0 == TY_FLOAT);
1631 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1632 o4(0xE59D0004); // ldr r0, [sp, #4]
1633 callRuntime((void*) runtime_int_to_float);
1634 o4(0xE1A01000); // mov r1, r0
1635 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1636 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1637 } else {
1638 // Pop TOS
1639 o4(0xE8BD0002); // ldmfd sp!,{r1}
1640 }
1641 mStackUse -= 4;
1642 popType();
1643 }
1644
1645 /* Pop TOS into R2..R3
1646 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1647 * We know that at least one of R0 and TOS are already a double.
1648 */
1649
1650 void setupDoubleArgs() {
1651 Type* pR0Type = getR0Type();
1652 Type* pTOSType = getTOSType();
1653 TypeTag tagR0 = collapseType(pR0Type->tag);
1654 TypeTag tagTOS = collapseType(pTOSType->tag);
1655 if (tagR0 != TY_DOUBLE) {
1656 if (tagR0 == TY_INT) {
1657 callRuntime((void*) runtime_int_to_double);
1658 } else {
1659 assert(tagR0 == TY_FLOAT);
1660 callRuntime((void*) runtime_float_to_double);
1661 }
1662 }
1663 if (tagTOS != TY_DOUBLE) {
1664 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1665 o4(0xE59D0008); // ldr r0, [sp, #8]
1666 if (tagTOS == TY_INT) {
1667 callRuntime((void*) runtime_int_to_double);
1668 } else {
1669 assert(tagTOS == TY_FLOAT);
1670 callRuntime((void*) runtime_float_to_double);
1671 }
1672 o4(0xE1A02000); // mov r2, r0
1673 o4(0xE1A03001); // mov r3, r1
1674 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1675 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1676 mStackUse -= 4;
1677 } else {
1678 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1679 mStackUse -= 8;
1680 }
1681 popType();
1682 }
1683
Jack Palevicha8f427f2009-07-13 18:40:08 -07001684 void liReg(int t, int reg) {
1685 assert(reg >= 0 && reg < 16);
1686 int rN = (reg & 0xf) << 12;
1687 if (t >= 0 && t < 255) {
1688 o4((0xE3A00000 + t) | rN); // mov rN, #0
1689 } else if (t >= -256 && t < 0) {
1690 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001691 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001692 } else {
1693 o4(0xE51F0000 | rN); // ldr rN, .L3
1694 o4(0xEA000000); // b .L99
1695 o4(t); // .L3: .word 0
1696 // .L99:
1697 }
1698 }
1699
Jack Palevichb7718b92009-07-09 22:00:24 -07001700 void callRuntime(void* fn) {
1701 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001702 o4(0xEA000000); // b .L99
1703 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001704 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001705 }
1706
Jack Palevichb7718b92009-07-09 22:00:24 -07001707 // Integer math:
1708
1709 static int runtime_DIV(int b, int a) {
1710 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001711 }
1712
Jack Palevichb7718b92009-07-09 22:00:24 -07001713 static int runtime_MOD(int b, int a) {
1714 return a % b;
1715 }
1716
1717 // Comparison to zero
1718
1719 static int runtime_is_non_zero_f(float a) {
1720 return a != 0;
1721 }
1722
1723 static int runtime_is_non_zero_d(double a) {
1724 return a != 0;
1725 }
1726
1727 // Comparison to zero
1728
1729 static int runtime_is_zero_f(float a) {
1730 return a == 0;
1731 }
1732
1733 static int runtime_is_zero_d(double a) {
1734 return a == 0;
1735 }
1736
1737 // Type conversion
1738
1739 static int runtime_float_to_int(float a) {
1740 return (int) a;
1741 }
1742
1743 static double runtime_float_to_double(float a) {
1744 return (double) a;
1745 }
1746
1747 static int runtime_double_to_int(double a) {
1748 return (int) a;
1749 }
1750
1751 static float runtime_double_to_float(double a) {
1752 return (float) a;
1753 }
1754
1755 static float runtime_int_to_float(int a) {
1756 return (float) a;
1757 }
1758
1759 static double runtime_int_to_double(int a) {
1760 return (double) a;
1761 }
1762
1763 // Comparisons float
1764
1765 static int runtime_cmp_eq_ff(float b, float a) {
1766 return a == b;
1767 }
1768
1769 static int runtime_cmp_ne_ff(float b, float a) {
1770 return a != b;
1771 }
1772
1773 static int runtime_cmp_lt_ff(float b, float a) {
1774 return a < b;
1775 }
1776
1777 static int runtime_cmp_le_ff(float b, float a) {
1778 return a <= b;
1779 }
1780
1781 static int runtime_cmp_ge_ff(float b, float a) {
1782 return a >= b;
1783 }
1784
1785 static int runtime_cmp_gt_ff(float b, float a) {
1786 return a > b;
1787 }
1788
1789 // Comparisons double
1790
1791 static int runtime_cmp_eq_dd(double b, double a) {
1792 return a == b;
1793 }
1794
1795 static int runtime_cmp_ne_dd(double b, double a) {
1796 return a != b;
1797 }
1798
1799 static int runtime_cmp_lt_dd(double b, double a) {
1800 return a < b;
1801 }
1802
1803 static int runtime_cmp_le_dd(double b, double a) {
1804 return a <= b;
1805 }
1806
1807 static int runtime_cmp_ge_dd(double b, double a) {
1808 return a >= b;
1809 }
1810
1811 static int runtime_cmp_gt_dd(double b, double a) {
1812 return a > b;
1813 }
1814
1815 // Math float
1816
1817 static float runtime_op_add_ff(float b, float a) {
1818 return a + b;
1819 }
1820
1821 static float runtime_op_sub_ff(float b, float a) {
1822 return a - b;
1823 }
1824
1825 static float runtime_op_mul_ff(float b, float a) {
1826 return a * b;
1827 }
1828
1829 static float runtime_op_div_ff(float b, float a) {
1830 return a / b;
1831 }
1832
1833 static float runtime_op_neg_f(float a) {
1834 return -a;
1835 }
1836
1837 // Math double
1838
1839 static double runtime_op_add_dd(double b, double a) {
1840 return a + b;
1841 }
1842
1843 static double runtime_op_sub_dd(double b, double a) {
1844 return a - b;
1845 }
1846
1847 static double runtime_op_mul_dd(double b, double a) {
1848 return a * b;
1849 }
1850
1851 static double runtime_op_div_dd(double b, double a) {
1852 return a / b;
1853 }
1854
1855 static double runtime_op_neg_d(double a) {
1856 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001857 }
-b master422972c2009-06-17 19:13:52 -07001858
1859 static const int STACK_ALIGNMENT = 8;
1860 int mStackUse;
1861 // This variable holds the amount we adjusted the stack in the most
1862 // recent endFunctionCallArguments call. It's examined by the
1863 // following adjustStackAfterCall call.
1864 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001865 };
1866
Jack Palevich09555c72009-05-27 12:25:55 -07001867#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001868
1869#ifdef PROVIDE_X86_CODEGEN
1870
Jack Palevich21a15a22009-05-11 14:49:29 -07001871 class X86CodeGenerator : public CodeGenerator {
1872 public:
1873 X86CodeGenerator() {}
1874 virtual ~X86CodeGenerator() {}
1875
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001876 /* returns address to patch with local variable size
1877 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001878 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001879 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1880 return oad(0xec81, 0); /* sub $xxx, %esp */
1881 }
1882
Jack Palevichb7718b92009-07-09 22:00:24 -07001883 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001884 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001885 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001886 }
1887
Jack Palevich21a15a22009-05-11 14:49:29 -07001888 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001889 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001890 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001891 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001892 }
1893
Jack Palevich1a539db2009-07-08 13:04:41 -07001894 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001895 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001896 switch (pType->tag) {
1897 case TY_FLOAT:
1898 oad(0x05D9, address); // flds
1899 break;
1900 case TY_DOUBLE:
1901 oad(0x05DD, address); // fldl
1902 break;
1903 default:
1904 assert(false);
1905 break;
1906 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001907 }
1908
Jack Palevich22305132009-05-13 10:58:45 -07001909 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001910 return psym(0xe9, t);
1911 }
1912
1913 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001914 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001915 Type* pR0Type = getR0Type();
1916 TypeTag tagR0 = pR0Type->tag;
1917 bool isFloatR0 = isFloatTag(tagR0);
1918 if (isFloatR0) {
1919 o(0xeed9); // fldz
1920 o(0xe9da); // fucompp
1921 o(0xe0df); // fnstsw %ax
1922 o(0x9e); // sahf
1923 } else {
1924 o(0xc085); // test %eax, %eax
1925 }
1926 // Use two output statements to generate one instruction.
1927 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001928 return psym(0x84 + l, t);
1929 }
1930
Jack Palevich58c30ee2009-07-17 16:35:23 -07001931 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001932 Type* pR0Type = getR0Type();
1933 Type* pTOSType = getTOSType();
1934 TypeTag tagR0 = pR0Type->tag;
1935 TypeTag tagTOS = pTOSType->tag;
1936 bool isFloatR0 = isFloatTag(tagR0);
1937 bool isFloatTOS = isFloatTag(tagTOS);
1938 if (!isFloatR0 && !isFloatTOS) {
1939 int t = decodeOp(op);
1940 o(0x59); /* pop %ecx */
1941 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001942 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001943 o(0x0f); /* setxx %al */
1944 o(t + 0x90);
1945 o(0xc0);
1946 popType();
1947 } else {
1948 setupFloatOperands();
1949 switch (op) {
1950 case OP_EQUALS:
1951 o(0xe9da); // fucompp
1952 o(0xe0df); // fnstsw %ax
1953 o(0x9e); // sahf
1954 o(0xc0940f); // sete %al
1955 o(0xc29b0f); // setnp %dl
1956 o(0xd021); // andl %edx, %eax
1957 break;
1958 case OP_NOT_EQUALS:
1959 o(0xe9da); // fucompp
1960 o(0xe0df); // fnstsw %ax
1961 o(0x9e); // sahf
1962 o(0xc0950f); // setne %al
1963 o(0xc29a0f); // setp %dl
1964 o(0xd009); // orl %edx, %eax
1965 break;
1966 case OP_GREATER_EQUAL:
1967 o(0xe9da); // fucompp
1968 o(0xe0df); // fnstsw %ax
1969 o(0x05c4f6); // testb $5, %ah
1970 o(0xc0940f); // sete %al
1971 break;
1972 case OP_LESS:
1973 o(0xc9d9); // fxch %st(1)
1974 o(0xe9da); // fucompp
1975 o(0xe0df); // fnstsw %ax
1976 o(0x9e); // sahf
1977 o(0xc0970f); // seta %al
1978 break;
1979 case OP_LESS_EQUAL:
1980 o(0xc9d9); // fxch %st(1)
1981 o(0xe9da); // fucompp
1982 o(0xe0df); // fnstsw %ax
1983 o(0x9e); // sahf
1984 o(0xc0930f); // setea %al
1985 break;
1986 case OP_GREATER:
1987 o(0xe9da); // fucompp
1988 o(0xe0df); // fnstsw %ax
1989 o(0x45c4f6); // testb $69, %ah
1990 o(0xc0940f); // sete %al
1991 break;
1992 default:
1993 error("Unknown comparison op");
1994 }
1995 o(0xc0b60f); // movzbl %al, %eax
1996 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001997 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001998 }
1999
Jack Palevich546b2242009-05-13 15:10:04 -07002000 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002001 Type* pR0Type = getR0Type();
2002 Type* pTOSType = getTOSType();
2003 TypeTag tagR0 = pR0Type->tag;
2004 TypeTag tagTOS = pTOSType->tag;
2005 bool isFloatR0 = isFloatTag(tagR0);
2006 bool isFloatTOS = isFloatTag(tagTOS);
2007 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002008 bool isPtrR0 = tagR0 == TY_POINTER;
2009 bool isPtrTOS = tagTOS == TY_POINTER;
2010 if (isPtrR0 || isPtrTOS) {
2011 if (isPtrR0 && isPtrTOS) {
2012 if (op != OP_MINUS) {
2013 error("Unsupported pointer-pointer operation %d.", op);
2014 }
2015 if (! typeEqual(pR0Type, pTOSType)) {
2016 error("Incompatible pointer types for subtraction.");
2017 }
2018 o(0x59); /* pop %ecx */
2019 o(decodeOp(op));
2020 popType();
2021 setR0Type(mkpInt);
2022 int size = sizeOf(pR0Type->pHead);
2023 if (size != 1) {
2024 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002025 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002026 // TODO: Optimize for power-of-two.
2027 genOp(OP_DIV);
2028 }
2029 } else {
2030 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2031 error("Unsupported pointer-scalar operation %d", op);
2032 }
2033 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
2034 o(0x59); /* pop %ecx */
2035 int size = sizeOf(pPtrType->pHead);
2036 if (size != 1) {
2037 // TODO: Optimize for power-of-two.
2038 if (isPtrR0) {
2039 oad(0xC969, size); // imull $size, %ecx
2040 } else {
2041 oad(0xC069, size); // mul $size, %eax
2042 }
2043 }
2044 o(decodeOp(op));
2045 popType();
2046 setR0Type(pPtrType);
2047 }
2048 } else {
2049 o(0x59); /* pop %ecx */
2050 o(decodeOp(op));
2051 if (op == OP_MOD)
2052 o(0x92); /* xchg %edx, %eax */
2053 popType();
2054 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002055 } else {
2056 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2057 setupFloatOperands();
2058 // Both float. x87 R0 == left hand, x87 R1 == right hand
2059 switch (op) {
2060 case OP_MUL:
2061 o(0xc9de); // fmulp
2062 break;
2063 case OP_DIV:
2064 o(0xf1de); // fdivp
2065 break;
2066 case OP_PLUS:
2067 o(0xc1de); // faddp
2068 break;
2069 case OP_MINUS:
2070 o(0xe1de); // fsubp
2071 break;
2072 default:
2073 error("Unsupported binary floating operation.");
2074 break;
2075 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002076 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002077 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002078 }
2079
Jack Palevich58c30ee2009-07-17 16:35:23 -07002080 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002081 if (op != OP_LOGICAL_NOT) {
2082 error("Unknown unary cmp %d", op);
2083 } else {
2084 Type* pR0Type = getR0Type();
2085 TypeTag tag = collapseType(pR0Type->tag);
2086 switch(tag) {
2087 case TY_INT: {
2088 oad(0xb9, 0); /* movl $0, %ecx */
2089 int t = decodeOp(op);
2090 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002091 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002092 o(0x0f); /* setxx %al */
2093 o(t + 0x90);
2094 o(0xc0);
2095 }
2096 break;
2097 case TY_FLOAT:
2098 case TY_DOUBLE:
2099 o(0xeed9); // fldz
2100 o(0xe9da); // fucompp
2101 o(0xe0df); // fnstsw %ax
2102 o(0x9e); // sahf
2103 o(0xc0950f); // setne %al
2104 o(0xc29a0f); // setp %dl
2105 o(0xd009); // orl %edx, %eax
2106 o(0xc0b60f); // movzbl %al, %eax
2107 o(0x01f083); // xorl $1, %eax
2108 break;
2109 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002110 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002111 break;
2112 }
2113 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002114 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002115 }
2116
2117 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002118 Type* pR0Type = getR0Type();
2119 TypeTag tag = collapseType(pR0Type->tag);
2120 switch(tag) {
2121 case TY_INT:
2122 oad(0xb9, 0); /* movl $0, %ecx */
2123 o(decodeOp(op));
2124 break;
2125 case TY_FLOAT:
2126 case TY_DOUBLE:
2127 switch (op) {
2128 case OP_MINUS:
2129 o(0xe0d9); // fchs
2130 break;
2131 case OP_BIT_NOT:
2132 error("Can't apply '~' operator to a float or double.");
2133 break;
2134 default:
2135 error("Unknown unary op %d\n", op);
2136 break;
2137 }
2138 break;
2139 default:
2140 error("genUnaryOp unsupported type");
2141 break;
2142 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002143 }
2144
Jack Palevich1cdef202009-05-22 12:06:27 -07002145 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002146 Type* pR0Type = getR0Type();
2147 TypeTag r0ct = collapseType(pR0Type->tag);
2148 switch(r0ct) {
2149 case TY_INT:
2150 o(0x50); /* push %eax */
2151 break;
2152 case TY_FLOAT:
2153 o(0x50); /* push %eax */
2154 o(0x241cd9); // fstps 0(%esp)
2155 break;
2156 case TY_DOUBLE:
2157 o(0x50); /* push %eax */
2158 o(0x50); /* push %eax */
2159 o(0x241cdd); // fstpl 0(%esp)
2160 break;
2161 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002162 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002163 break;
2164 }
Jack Palevich8df46192009-07-07 14:48:51 -07002165 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002166 }
2167
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002168 virtual void over() {
2169 // We know it's only used for int-ptr ops (++/--)
2170
2171 Type* pR0Type = getR0Type();
2172 TypeTag r0ct = collapseType(pR0Type->tag);
2173
2174 Type* pTOSType = getTOSType();
2175 TypeTag tosct = collapseType(pTOSType->tag);
2176
2177 assert (r0ct == TY_INT && tosct == TY_INT);
2178
2179 o(0x59); /* pop %ecx */
2180 o(0x50); /* push %eax */
2181 o(0x51); /* push %ecx */
2182
2183 overType();
2184 }
2185
Jack Palevich58c30ee2009-07-17 16:35:23 -07002186 virtual void popR0() {
2187 Type* pR0Type = getR0Type();
2188 TypeTag r0ct = collapseType(pR0Type->tag);
2189 switch(r0ct) {
2190 case TY_INT:
2191 o(0x58); /* popl %eax */
2192 break;
2193 case TY_FLOAT:
2194 o(0x2404d9); // flds (%esp)
2195 o(0x58); /* popl %eax */
2196 break;
2197 case TY_DOUBLE:
2198 o(0x2404dd); // fldl (%esp)
2199 o(0x58); /* popl %eax */
2200 o(0x58); /* popl %eax */
2201 break;
2202 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002203 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002204 break;
2205 }
2206 popType();
2207 }
2208
2209 virtual void storeR0ToTOS() {
2210 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002211 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002212 Type* pTargetType = pPointerType->pHead;
2213 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002214 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002215 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002216 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002217 case TY_INT:
2218 o(0x0189); /* movl %eax/%al, (%ecx) */
2219 break;
2220 case TY_CHAR:
2221 o(0x0188); /* movl %eax/%al, (%ecx) */
2222 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002223 case TY_FLOAT:
2224 o(0x19d9); /* fstps (%ecx) */
2225 break;
2226 case TY_DOUBLE:
2227 o(0x19dd); /* fstpl (%ecx) */
2228 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002229 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002230 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002231 break;
2232 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002233 }
2234
Jack Palevich58c30ee2009-07-17 16:35:23 -07002235 virtual void loadR0FromR0() {
2236 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002237 assert(pPointerType->tag == TY_POINTER);
2238 switch (pPointerType->pHead->tag) {
2239 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002240 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002241 break;
2242 case TY_CHAR:
2243 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002244 ob(0); /* add zero in code */
2245 break;
2246 case TY_FLOAT:
2247 o2(0x00d9); // flds (%eax)
2248 break;
2249 case TY_DOUBLE:
2250 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002251 break;
2252 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002253 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002254 break;
2255 }
Jack Palevich8df46192009-07-07 14:48:51 -07002256 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002257 }
2258
Jack Palevich8df46192009-07-07 14:48:51 -07002259 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002260 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002261 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002262 }
2263
Jack Palevich9cbd2262009-07-08 16:48:41 -07002264 virtual void storeR0(int ea, Type* pType) {
2265 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002266 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002267 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002268 case TY_CHAR:
2269 if (ea < -LOCAL || ea > LOCAL) {
2270 oad(0xa2, ea); // movb %al,ea
2271 } else {
2272 oad(0x8588, ea); // movb %al,ea(%ebp)
2273 }
2274 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002275 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002276 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002277 gmov(6, ea); /* mov %eax, EA */
2278 break;
2279 case TY_FLOAT:
2280 if (ea < -LOCAL || ea > LOCAL) {
2281 oad(0x1dd9, ea); // fstps ea
2282 } else {
2283 oad(0x9dd9, ea); // fstps ea(%ebp)
2284 }
2285 break;
2286 case TY_DOUBLE:
2287 if (ea < -LOCAL || ea > LOCAL) {
2288 oad(0x1ddd, ea); // fstpl ea
2289 } else {
2290 oad(0x9ddd, ea); // fstpl ea(%ebp)
2291 }
2292 break;
2293 default:
2294 error("Unable to store to type %d", tag);
2295 break;
2296 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002297 }
2298
Jack Palevich58c30ee2009-07-17 16:35:23 -07002299 virtual void loadR0(int ea, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002300 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002301 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002302 case TY_CHAR:
2303 if (ea < -LOCAL || ea > LOCAL) {
2304 oad(0x05BE0F, ea); // movsbl ea,%eax
2305 } else {
2306 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2307 }
Jack Palevich25c0cca2009-07-13 16:56:28 -07002308 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002309 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002310 case TY_POINTER:
Jack Palevich58c30ee2009-07-17 16:35:23 -07002311 gmov(8, ea); /* mov EA, %eax */
Jack Palevich128ad2d2009-07-08 14:51:31 -07002312 break;
2313 case TY_FLOAT:
2314 if (ea < -LOCAL || ea > LOCAL) {
2315 oad(0x05d9, ea); // flds ea
2316 } else {
2317 oad(0x85d9, ea); // flds ea(%ebp)
2318 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002319 break;
2320 case TY_DOUBLE:
2321 if (ea < -LOCAL || ea > LOCAL) {
2322 oad(0x05dd, ea); // fldl ea
2323 } else {
2324 oad(0x85dd, ea); // fldl ea(%ebp)
2325 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002326 break;
2327 default:
2328 error("Unable to load type %d", tag);
2329 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002330 }
Jack Palevich8df46192009-07-07 14:48:51 -07002331 setR0Type(pType);
2332 }
2333
2334 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002335 Type* pR0Type = getR0Type();
2336 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002337 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002338 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002339 return;
2340 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002341 if (bitsSame(pType, pR0Type)) {
2342 // do nothing special
2343 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2344 // do nothing special, both held in same register on x87.
2345 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002346 TypeTag r0Tag = collapseType(pR0Type->tag);
2347 TypeTag destTag = collapseType(pType->tag);
2348 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2349 // Convert R0 from int to float
2350 o(0x50); // push %eax
2351 o(0x2404DB); // fildl 0(%esp)
2352 o(0x58); // pop %eax
2353 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2354 // Convert R0 from float to int. Complicated because
2355 // need to save and restore the rounding mode.
2356 o(0x50); // push %eax
2357 o(0x50); // push %eax
2358 o(0x02247cD9); // fnstcw 2(%esp)
2359 o(0x2444b70f); // movzwl 2(%esp), %eax
2360 o(0x02);
2361 o(0x0cb4); // movb $12, %ah
2362 o(0x24048966); // movw %ax, 0(%esp)
2363 o(0x242cd9); // fldcw 0(%esp)
2364 o(0x04245cdb); // fistpl 4(%esp)
2365 o(0x02246cd9); // fldcw 2(%esp)
2366 o(0x58); // pop %eax
2367 o(0x58); // pop %eax
2368 } else {
2369 error("Incompatible types old: %d new: %d",
2370 pR0Type->tag, pType->tag);
2371 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002372 }
2373 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002374 }
2375
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002376 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002377 return oad(0xec81, 0); /* sub $xxx, %esp */
2378 }
2379
Jack Palevich8148c5b2009-07-16 18:24:47 -07002380 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2381 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002382 Type* pR0Type = getR0Type();
2383 TypeTag r0ct = collapseType(pR0Type->tag);
2384 switch(r0ct) {
2385 case TY_INT:
2386 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2387 return 4;
2388 case TY_FLOAT:
2389 oad(0x249CD9, l); /* fstps xxx(%esp) */
2390 return 4;
2391 case TY_DOUBLE:
2392 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2393 return 8;
2394 default:
2395 assert(false);
2396 return 0;
2397 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002398 }
2399
Jack Palevichb7718b92009-07-09 22:00:24 -07002400 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002401 * (int*) a = l;
2402 }
2403
Jack Palevich8df46192009-07-07 14:48:51 -07002404 virtual int callForward(int symbol, Type* pFunc) {
2405 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002406 return psym(0xe8, symbol); /* call xxx */
2407 }
2408
Jack Palevich8df46192009-07-07 14:48:51 -07002409 virtual void callRelative(int t, Type* pFunc) {
2410 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002411 psym(0xe8, t); /* call xxx */
2412 }
2413
Jack Palevich8df46192009-07-07 14:48:51 -07002414 virtual void callIndirect(int l, Type* pFunc) {
2415 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002416 oad(0x2494ff, l); /* call *xxx(%esp) */
2417 }
2418
Jack Palevichb7718b92009-07-09 22:00:24 -07002419 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002420 if (isIndirect) {
2421 l += 4;
2422 }
-b master422972c2009-06-17 19:13:52 -07002423 if (l > 0) {
2424 oad(0xc481, l); /* add $xxx, %esp */
2425 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002426 }
2427
Jack Palevicha6535612009-05-13 16:24:17 -07002428 virtual int jumpOffset() {
2429 return 5;
2430 }
2431
2432 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002433 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002434 }
2435
Jack Paleviche7b59062009-05-19 17:12:17 -07002436 /* output a symbol and patch all calls to it */
2437 virtual void gsym(int t) {
2438 int n;
2439 int pc = getPC();
2440 while (t) {
2441 n = *(int *) t; /* next value */
2442 *(int *) t = pc - t - 4;
2443 t = n;
2444 }
2445 }
2446
Jack Palevich1cdef202009-05-22 12:06:27 -07002447 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002448 size_t pagesize = 4096;
2449 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2450 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2451 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2452 if (err) {
2453 error("mprotect() failed: %d", errno);
2454 }
2455 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002456 }
2457
Jack Palevich9eed7a22009-07-06 17:24:34 -07002458 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002459 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002460 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002461 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002462 switch (pType->tag) {
2463 case TY_CHAR:
2464 return 1;
2465 default:
2466 return 4;
2467 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002468 }
2469
2470 /**
2471 * Array element alignment (in bytes) for this type of data.
2472 */
2473 virtual size_t sizeOf(Type* pType){
2474 switch(pType->tag) {
2475 case TY_INT:
2476 return 4;
2477 case TY_CHAR:
2478 return 1;
2479 default:
2480 return 0;
2481 case TY_FLOAT:
2482 return 4;
2483 case TY_DOUBLE:
2484 return 8;
2485 case TY_POINTER:
2486 return 4;
2487 }
2488 }
2489
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002490 virtual size_t stackAlignmentOf(Type* pType){
2491 return 4;
2492 }
2493
Jack Palevich9cbd2262009-07-08 16:48:41 -07002494 virtual size_t stackSizeOf(Type* pType) {
2495 switch(pType->tag) {
2496 case TY_DOUBLE:
2497 return 8;
2498 default:
2499 return 4;
2500 }
2501 }
2502
Jack Palevich21a15a22009-05-11 14:49:29 -07002503 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002504
2505 /** Output 1 to 4 bytes.
2506 *
2507 */
2508 void o(int n) {
2509 /* cannot use unsigned, so we must do a hack */
2510 while (n && n != -1) {
2511 ob(n & 0xff);
2512 n = n >> 8;
2513 }
2514 }
2515
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002516 /* Output exactly 2 bytes
2517 */
2518 void o2(int n) {
2519 ob(n & 0xff);
2520 ob(0xff & (n >> 8));
2521 }
2522
Jack Paleviche7b59062009-05-19 17:12:17 -07002523 /* psym is used to put an instruction with a data field which is a
2524 reference to a symbol. It is in fact the same as oad ! */
2525 int psym(int n, int t) {
2526 return oad(n, t);
2527 }
2528
2529 /* instruction + address */
2530 int oad(int n, int t) {
2531 o(n);
2532 int result = getPC();
2533 o4(t);
2534 return result;
2535 }
2536
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002537 static const int operatorHelper[];
2538
2539 int decodeOp(int op) {
2540 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002541 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002542 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002543 }
2544 return operatorHelper[op];
2545 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002546
Jack Palevich546b2242009-05-13 15:10:04 -07002547 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002548 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002549 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002550 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002551
2552 void setupFloatOperands() {
2553 Type* pR0Type = getR0Type();
2554 Type* pTOSType = getTOSType();
2555 TypeTag tagR0 = pR0Type->tag;
2556 TypeTag tagTOS = pTOSType->tag;
2557 bool isFloatR0 = isFloatTag(tagR0);
2558 bool isFloatTOS = isFloatTag(tagTOS);
2559 if (! isFloatR0) {
2560 // Convert R0 from int to float
2561 o(0x50); // push %eax
2562 o(0x2404DB); // fildl 0(%esp)
2563 o(0x58); // pop %eax
2564 }
2565 if (! isFloatTOS){
2566 o(0x2404DB); // fildl 0(%esp);
2567 o(0x58); // pop %eax
2568 } else {
2569 if (tagTOS == TY_FLOAT) {
2570 o(0x2404d9); // flds (%esp)
2571 o(0x58); // pop %eax
2572 } else {
2573 o(0x2404dd); // fldl (%esp)
2574 o(0x58); // pop %eax
2575 o(0x58); // pop %eax
2576 }
2577 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002578 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002579 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002580 };
2581
Jack Paleviche7b59062009-05-19 17:12:17 -07002582#endif // PROVIDE_X86_CODEGEN
2583
Jack Palevichb67b18f2009-06-11 21:12:23 -07002584#ifdef PROVIDE_TRACE_CODEGEN
2585 class TraceCodeGenerator : public CodeGenerator {
2586 private:
2587 CodeGenerator* mpBase;
2588
2589 public:
2590 TraceCodeGenerator(CodeGenerator* pBase) {
2591 mpBase = pBase;
2592 }
2593
2594 virtual ~TraceCodeGenerator() {
2595 delete mpBase;
2596 }
2597
2598 virtual void init(CodeBuf* pCodeBuf) {
2599 mpBase->init(pCodeBuf);
2600 }
2601
2602 void setErrorSink(ErrorSink* pErrorSink) {
2603 mpBase->setErrorSink(pErrorSink);
2604 }
2605
2606 /* returns address to patch with local variable size
2607 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002608 virtual int functionEntry(Type* pDecl) {
2609 int result = mpBase->functionEntry(pDecl);
2610 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002611 return result;
2612 }
2613
Jack Palevichb7718b92009-07-09 22:00:24 -07002614 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2615 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2616 localVariableAddress, localVariableSize);
2617 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002618 }
2619
2620 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002621 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002622 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002623 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002624 }
2625
Jack Palevich1a539db2009-07-08 13:04:41 -07002626 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002627 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002628 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002629 }
2630
Jack Palevichb67b18f2009-06-11 21:12:23 -07002631 virtual int gjmp(int t) {
2632 int result = mpBase->gjmp(t);
2633 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2634 return result;
2635 }
2636
2637 /* l = 0: je, l == 1: jne */
2638 virtual int gtst(bool l, int t) {
2639 int result = mpBase->gtst(l, t);
2640 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2641 return result;
2642 }
2643
Jack Palevich58c30ee2009-07-17 16:35:23 -07002644 virtual void gcmp(int op) {
2645 fprintf(stderr, "gcmp(%d)\n", op);
2646 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002647 }
2648
2649 virtual void genOp(int op) {
2650 fprintf(stderr, "genOp(%d)\n", op);
2651 mpBase->genOp(op);
2652 }
2653
Jack Palevich9eed7a22009-07-06 17:24:34 -07002654
Jack Palevich58c30ee2009-07-17 16:35:23 -07002655 virtual void gUnaryCmp(int op) {
2656 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2657 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002658 }
2659
2660 virtual void genUnaryOp(int op) {
2661 fprintf(stderr, "genUnaryOp(%d)\n", op);
2662 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002663 }
2664
2665 virtual void pushR0() {
2666 fprintf(stderr, "pushR0()\n");
2667 mpBase->pushR0();
2668 }
2669
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002670 virtual void over() {
2671 fprintf(stderr, "over()\n");
2672 mpBase->over();
2673 }
2674
Jack Palevich58c30ee2009-07-17 16:35:23 -07002675 virtual void popR0() {
2676 fprintf(stderr, "popR0()\n");
2677 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002678 }
2679
Jack Palevich58c30ee2009-07-17 16:35:23 -07002680 virtual void storeR0ToTOS() {
2681 fprintf(stderr, "storeR0ToTOS()\n");
2682 mpBase->storeR0ToTOS();
2683 }
2684
2685 virtual void loadR0FromR0() {
2686 fprintf(stderr, "loadR0FromR0()\n");
2687 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002688 }
2689
Jack Palevich8df46192009-07-07 14:48:51 -07002690 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002691 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002692 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002693 }
2694
Jack Palevich9cbd2262009-07-08 16:48:41 -07002695 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002696 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002697 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002698 }
2699
Jack Palevich58c30ee2009-07-17 16:35:23 -07002700 virtual void loadR0(int ea, Type* pType) {
2701 fprintf(stderr, "loadR0(%d, pType)\n", ea);
2702 mpBase->loadR0(ea, pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002703 }
2704
2705 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002706 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002707 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002708 }
2709
2710 virtual int beginFunctionCallArguments() {
2711 int result = mpBase->beginFunctionCallArguments();
2712 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2713 return result;
2714 }
2715
Jack Palevich8148c5b2009-07-16 18:24:47 -07002716 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2717 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2718 pArgType->tag);
2719 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002720 }
2721
Jack Palevichb7718b92009-07-09 22:00:24 -07002722 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002723 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002724 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002725 }
2726
Jack Palevich8df46192009-07-07 14:48:51 -07002727 virtual int callForward(int symbol, Type* pFunc) {
2728 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002729 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2730 return result;
2731 }
2732
Jack Palevich8df46192009-07-07 14:48:51 -07002733 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002734 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002735 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002736 }
2737
Jack Palevich8df46192009-07-07 14:48:51 -07002738 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002739 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002740 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002741 }
2742
Jack Palevichb7718b92009-07-09 22:00:24 -07002743 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2744 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2745 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002746 }
2747
2748 virtual int jumpOffset() {
2749 return mpBase->jumpOffset();
2750 }
2751
2752 virtual int disassemble(FILE* out) {
2753 return mpBase->disassemble(out);
2754 }
2755
2756 /* output a symbol and patch all calls to it */
2757 virtual void gsym(int t) {
2758 fprintf(stderr, "gsym(%d)\n", t);
2759 mpBase->gsym(t);
2760 }
2761
2762 virtual int finishCompile() {
2763 int result = mpBase->finishCompile();
2764 fprintf(stderr, "finishCompile() = %d\n", result);
2765 return result;
2766 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002767
2768 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002769 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002770 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002771 virtual size_t alignmentOf(Type* pType){
2772 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002773 }
2774
2775 /**
2776 * Array element alignment (in bytes) for this type of data.
2777 */
2778 virtual size_t sizeOf(Type* pType){
2779 return mpBase->sizeOf(pType);
2780 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002781
Jack Palevich9cbd2262009-07-08 16:48:41 -07002782
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002783 virtual size_t stackAlignmentOf(Type* pType) {
2784 return mpBase->stackAlignmentOf(pType);
2785 }
2786
2787
Jack Palevich9cbd2262009-07-08 16:48:41 -07002788 virtual size_t stackSizeOf(Type* pType) {
2789 return mpBase->stackSizeOf(pType);
2790 }
2791
Jack Palevich1a539db2009-07-08 13:04:41 -07002792 virtual Type* getR0Type() {
2793 return mpBase->getR0Type();
2794 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002795
2796 virtual ExpressionType getR0ExpressionType() {
2797 return mpBase->getR0ExpressionType();
2798 }
2799
2800 virtual void setR0ExpressionType(ExpressionType et) {
2801 mpBase->setR0ExpressionType(et);
2802 }
2803
2804 virtual size_t getExpressionStackDepth() {
2805 return mpBase->getExpressionStackDepth();
2806 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002807 };
2808
2809#endif // PROVIDE_TRACE_CODEGEN
2810
Jack Palevich569f1352009-06-29 14:29:08 -07002811 class Arena {
2812 public:
2813 // Used to record a given allocation amount.
2814 // Used:
2815 // Mark mark = arena.mark();
2816 // ... lots of arena.allocate()
2817 // arena.free(mark);
2818
2819 struct Mark {
2820 size_t chunk;
2821 size_t offset;
2822 };
2823
2824 Arena() {
2825 mCurrentChunk = 0;
2826 Chunk start(CHUNK_SIZE);
2827 mData.push_back(start);
2828 }
2829
2830 ~Arena() {
2831 for(size_t i = 0; i < mData.size(); i++) {
2832 mData[i].free();
2833 }
2834 }
2835
2836 // Alloc using the standard alignment size safe for any variable
2837 void* alloc(size_t size) {
2838 return alloc(size, 8);
2839 }
2840
2841 Mark mark(){
2842 Mark result;
2843 result.chunk = mCurrentChunk;
2844 result.offset = mData[mCurrentChunk].mOffset;
2845 return result;
2846 }
2847
2848 void freeToMark(const Mark& mark) {
2849 mCurrentChunk = mark.chunk;
2850 mData[mCurrentChunk].mOffset = mark.offset;
2851 }
2852
2853 private:
2854 // Allocate memory aligned to a given size
2855 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2856 // Memory is not zero filled.
2857
2858 void* alloc(size_t size, size_t alignment) {
2859 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2860 if (mCurrentChunk + 1 < mData.size()) {
2861 mCurrentChunk++;
2862 } else {
2863 size_t allocSize = CHUNK_SIZE;
2864 if (allocSize < size + alignment - 1) {
2865 allocSize = size + alignment - 1;
2866 }
2867 Chunk chunk(allocSize);
2868 mData.push_back(chunk);
2869 mCurrentChunk++;
2870 }
2871 }
2872 return mData[mCurrentChunk].allocate(size, alignment);
2873 }
2874
2875 static const size_t CHUNK_SIZE = 128*1024;
2876 // Note: this class does not deallocate its
2877 // memory when it's destroyed. It depends upon
2878 // its parent to deallocate the memory.
2879 struct Chunk {
2880 Chunk() {
2881 mpData = 0;
2882 mSize = 0;
2883 mOffset = 0;
2884 }
2885
2886 Chunk(size_t size) {
2887 mSize = size;
2888 mpData = (char*) malloc(size);
2889 mOffset = 0;
2890 }
2891
2892 ~Chunk() {
2893 // Doesn't deallocate memory.
2894 }
2895
2896 void* allocate(size_t size, size_t alignment) {
2897 size_t alignedOffset = aligned(mOffset, alignment);
2898 void* result = mpData + alignedOffset;
2899 mOffset = alignedOffset + size;
2900 return result;
2901 }
2902
2903 void free() {
2904 if (mpData) {
2905 ::free(mpData);
2906 mpData = 0;
2907 }
2908 }
2909
2910 size_t remainingCapacity(size_t alignment) {
2911 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2912 }
2913
2914 // Assume alignment is a power of two
2915 inline size_t aligned(size_t v, size_t alignment) {
2916 size_t mask = alignment-1;
2917 return (v + mask) & ~mask;
2918 }
2919
2920 char* mpData;
2921 size_t mSize;
2922 size_t mOffset;
2923 };
2924
2925 size_t mCurrentChunk;
2926
2927 Vector<Chunk> mData;
2928 };
2929
Jack Palevich569f1352009-06-29 14:29:08 -07002930 struct VariableInfo;
2931
2932 struct Token {
2933 int hash;
2934 size_t length;
2935 char* pText;
2936 tokenid_t id;
2937
2938 // Current values for the token
2939 char* mpMacroDefinition;
2940 VariableInfo* mpVariableInfo;
2941 };
2942
2943 class TokenTable {
2944 public:
2945 // Don't use 0..0xff, allows characters and operators to be tokens too.
2946
2947 static const int TOKEN_BASE = 0x100;
2948 TokenTable() {
2949 mpMap = hashmapCreate(128, hashFn, equalsFn);
2950 }
2951
2952 ~TokenTable() {
2953 hashmapFree(mpMap);
2954 }
2955
2956 void setArena(Arena* pArena) {
2957 mpArena = pArena;
2958 }
2959
2960 // Returns a token for a given string of characters.
2961 tokenid_t intern(const char* pText, size_t length) {
2962 Token probe;
2963 int hash = hashmapHash((void*) pText, length);
2964 {
2965 Token probe;
2966 probe.hash = hash;
2967 probe.length = length;
2968 probe.pText = (char*) pText;
2969 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2970 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002971 return pValue->id;
2972 }
2973 }
2974
2975 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2976 memset(pToken, 0, sizeof(*pToken));
2977 pToken->hash = hash;
2978 pToken->length = length;
2979 pToken->pText = (char*) mpArena->alloc(length + 1);
2980 memcpy(pToken->pText, pText, length);
2981 pToken->pText[length] = 0;
2982 pToken->id = mTokens.size() + TOKEN_BASE;
2983 mTokens.push_back(pToken);
2984 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002985 return pToken->id;
2986 }
2987
2988 // Return the Token for a given tokenid.
2989 Token& operator[](tokenid_t id) {
2990 return *mTokens[id - TOKEN_BASE];
2991 }
2992
2993 inline size_t size() {
2994 return mTokens.size();
2995 }
2996
2997 private:
2998
2999 static int hashFn(void* pKey) {
3000 Token* pToken = (Token*) pKey;
3001 return pToken->hash;
3002 }
3003
3004 static bool equalsFn(void* keyA, void* keyB) {
3005 Token* pTokenA = (Token*) keyA;
3006 Token* pTokenB = (Token*) keyB;
3007 // Don't need to compare hash values, they should always be equal
3008 return pTokenA->length == pTokenB->length
3009 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3010 }
3011
3012 Hashmap* mpMap;
3013 Vector<Token*> mTokens;
3014 Arena* mpArena;
3015 };
3016
Jack Palevich1cdef202009-05-22 12:06:27 -07003017 class InputStream {
3018 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003019 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003020 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003021 };
3022
3023 class TextInputStream : public InputStream {
3024 public:
3025 TextInputStream(const char* text, size_t textLength)
3026 : pText(text), mTextLength(textLength), mPosition(0) {
3027 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003028
Jack Palevichdc456462009-07-16 16:50:56 -07003029 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003030 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3031 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003032
Jack Palevichdc456462009-07-16 16:50:56 -07003033 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003034 const char* pText;
3035 size_t mTextLength;
3036 size_t mPosition;
3037 };
3038
Jack Palevicheedf9d22009-06-04 16:23:40 -07003039 class String {
3040 public:
3041 String() {
3042 mpBase = 0;
3043 mUsed = 0;
3044 mSize = 0;
3045 }
3046
Jack Palevich303d8ff2009-06-11 19:06:24 -07003047 String(const char* item, int len, bool adopt) {
3048 if (len < 0) {
3049 len = strlen(item);
3050 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003051 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003052 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003053 mUsed = len;
3054 mSize = len + 1;
3055 } else {
3056 mpBase = 0;
3057 mUsed = 0;
3058 mSize = 0;
3059 appendBytes(item, len);
3060 }
3061 }
3062
Jack Palevich303d8ff2009-06-11 19:06:24 -07003063 String(const String& other) {
3064 mpBase = 0;
3065 mUsed = 0;
3066 mSize = 0;
3067 appendBytes(other.getUnwrapped(), other.len());
3068 }
3069
Jack Palevicheedf9d22009-06-04 16:23:40 -07003070 ~String() {
3071 if (mpBase) {
3072 free(mpBase);
3073 }
3074 }
3075
Jack Palevicha6baa232009-06-12 11:25:59 -07003076 String& operator=(const String& other) {
3077 clear();
3078 appendBytes(other.getUnwrapped(), other.len());
3079 return *this;
3080 }
3081
Jack Palevich303d8ff2009-06-11 19:06:24 -07003082 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003083 return mpBase;
3084 }
3085
Jack Palevich303d8ff2009-06-11 19:06:24 -07003086 void clear() {
3087 mUsed = 0;
3088 if (mSize > 0) {
3089 mpBase[0] = 0;
3090 }
3091 }
3092
Jack Palevicheedf9d22009-06-04 16:23:40 -07003093 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003094 appendBytes(s, strlen(s));
3095 }
3096
3097 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003098 memcpy(ensure(n), s, n + 1);
3099 }
3100
3101 void append(char c) {
3102 * ensure(1) = c;
3103 }
3104
Jack Palevich86351982009-06-30 18:09:56 -07003105 void append(String& other) {
3106 appendBytes(other.getUnwrapped(), other.len());
3107 }
3108
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003109 char* orphan() {
3110 char* result = mpBase;
3111 mpBase = 0;
3112 mUsed = 0;
3113 mSize = 0;
3114 return result;
3115 }
3116
Jack Palevicheedf9d22009-06-04 16:23:40 -07003117 void printf(const char* fmt,...) {
3118 va_list ap;
3119 va_start(ap, fmt);
3120 vprintf(fmt, ap);
3121 va_end(ap);
3122 }
3123
3124 void vprintf(const char* fmt, va_list ap) {
3125 char* temp;
3126 int numChars = vasprintf(&temp, fmt, ap);
3127 memcpy(ensure(numChars), temp, numChars+1);
3128 free(temp);
3129 }
3130
Jack Palevich303d8ff2009-06-11 19:06:24 -07003131 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003132 return mUsed;
3133 }
3134
3135 private:
3136 char* ensure(int n) {
3137 size_t newUsed = mUsed + n;
3138 if (newUsed > mSize) {
3139 size_t newSize = mSize * 2 + 10;
3140 if (newSize < newUsed) {
3141 newSize = newUsed;
3142 }
3143 mpBase = (char*) realloc(mpBase, newSize + 1);
3144 mSize = newSize;
3145 }
3146 mpBase[newUsed] = '\0';
3147 char* result = mpBase + mUsed;
3148 mUsed = newUsed;
3149 return result;
3150 }
3151
3152 char* mpBase;
3153 size_t mUsed;
3154 size_t mSize;
3155 };
3156
Jack Palevich569f1352009-06-29 14:29:08 -07003157 void internKeywords() {
3158 // Note: order has to match TOK_ constants
3159 static const char* keywords[] = {
3160 "int",
3161 "char",
3162 "void",
3163 "if",
3164 "else",
3165 "while",
3166 "break",
3167 "return",
3168 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003169 "auto",
3170 "case",
3171 "const",
3172 "continue",
3173 "default",
3174 "do",
3175 "double",
3176 "enum",
3177 "extern",
3178 "float",
3179 "goto",
3180 "long",
3181 "register",
3182 "short",
3183 "signed",
3184 "sizeof",
3185 "static",
3186 "struct",
3187 "switch",
3188 "typedef",
3189 "union",
3190 "unsigned",
3191 "volatile",
3192 "_Bool",
3193 "_Complex",
3194 "_Imaginary",
3195 "inline",
3196 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003197
3198 // predefined tokens that can also be symbols start here:
3199 "pragma",
3200 "define",
3201 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003202 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003203
Jack Palevich569f1352009-06-29 14:29:08 -07003204 for(int i = 0; keywords[i]; i++) {
3205 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003206 }
Jack Palevich569f1352009-06-29 14:29:08 -07003207 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003208
Jack Palevich36d94142009-06-08 15:55:32 -07003209 struct InputState {
3210 InputStream* pStream;
3211 int oldCh;
3212 };
3213
Jack Palevich2db168f2009-06-11 14:29:47 -07003214 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003215 void* pAddress;
3216 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003217 tokenid_t tok;
3218 size_t level;
3219 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003220 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003221 };
3222
Jack Palevich303d8ff2009-06-11 19:06:24 -07003223 class SymbolStack {
3224 public:
3225 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003226 mpArena = 0;
3227 mpTokenTable = 0;
3228 }
3229
3230 void setArena(Arena* pArena) {
3231 mpArena = pArena;
3232 }
3233
3234 void setTokenTable(TokenTable* pTokenTable) {
3235 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003236 }
3237
3238 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003239 Mark mark;
3240 mark.mArenaMark = mpArena->mark();
3241 mark.mSymbolHead = mStack.size();
3242 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003243 }
3244
3245 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003246 // Undo any shadowing that was done:
3247 Mark mark = mLevelStack.back();
3248 mLevelStack.pop_back();
3249 while (mStack.size() > mark.mSymbolHead) {
3250 VariableInfo* pV = mStack.back();
3251 mStack.pop_back();
3252 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003253 }
Jack Palevich569f1352009-06-29 14:29:08 -07003254 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003255 }
3256
Jack Palevich569f1352009-06-29 14:29:08 -07003257 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3258 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3259 return pV && pV->level == level();
3260 }
3261
3262 VariableInfo* add(tokenid_t tok) {
3263 Token& token = (*mpTokenTable)[tok];
3264 VariableInfo* pOldV = token.mpVariableInfo;
3265 VariableInfo* pNewV =
3266 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3267 memset(pNewV, 0, sizeof(VariableInfo));
3268 pNewV->tok = tok;
3269 pNewV->level = level();
3270 pNewV->pOldDefinition = pOldV;
3271 token.mpVariableInfo = pNewV;
3272 mStack.push_back(pNewV);
3273 return pNewV;
3274 }
3275
Jack Palevich86351982009-06-30 18:09:56 -07003276 VariableInfo* add(Type* pType) {
3277 VariableInfo* pVI = add(pType->id);
3278 pVI->pType = pType;
3279 return pVI;
3280 }
3281
Jack Palevich569f1352009-06-29 14:29:08 -07003282 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3283 for (size_t i = 0; i < mStack.size(); i++) {
3284 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003285 break;
3286 }
3287 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003288 }
3289
Jack Palevich303d8ff2009-06-11 19:06:24 -07003290 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003291 inline size_t level() {
3292 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003293 }
3294
Jack Palevich569f1352009-06-29 14:29:08 -07003295 struct Mark {
3296 Arena::Mark mArenaMark;
3297 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003298 };
3299
Jack Palevich569f1352009-06-29 14:29:08 -07003300 Arena* mpArena;
3301 TokenTable* mpTokenTable;
3302 Vector<VariableInfo*> mStack;
3303 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003304 };
Jack Palevich36d94142009-06-08 15:55:32 -07003305
3306 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003307 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003308 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003309 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003310 int tokl; // token operator level
3311 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003312 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003313 intptr_t loc; // local variable index
3314 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003315 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003316 char* dptr; // Macro state: Points to macro text during macro playback.
3317 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003318 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003319 ACCSymbolLookupFn mpSymbolLookupFn;
3320 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003321
3322 // Arena for the duration of the compile
3323 Arena mGlobalArena;
3324 // Arena for data that's only needed when compiling a single function
3325 Arena mLocalArena;
3326
Jack Palevich2ff5c222009-07-23 15:11:22 -07003327 Arena* mpCurrentArena;
3328
Jack Palevich569f1352009-06-29 14:29:08 -07003329 TokenTable mTokenTable;
3330 SymbolStack mGlobals;
3331 SymbolStack mLocals;
3332
Jack Palevich40600de2009-07-01 15:32:35 -07003333 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003334 Type* mkpInt; // int
3335 Type* mkpChar; // char
3336 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003337 Type* mkpFloat;
3338 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003339 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003340 Type* mkpIntPtr;
3341 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003342 Type* mkpFloatPtr;
3343 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003344 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003345
Jack Palevich36d94142009-06-08 15:55:32 -07003346 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003347 int mLineNumber;
3348 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003349
3350 CodeBuf codeBuf;
3351 CodeGenerator* pGen;
3352
Jack Palevicheedf9d22009-06-04 16:23:40 -07003353 String mErrorBuf;
3354
Jack Palevicheedf9d22009-06-04 16:23:40 -07003355 String mPragmas;
3356 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003357 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003358
Jack Palevich21a15a22009-05-11 14:49:29 -07003359 static const int ALLOC_SIZE = 99999;
3360
Jack Palevich303d8ff2009-06-11 19:06:24 -07003361 static const int TOK_DUMMY = 1;
3362 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003363 static const int TOK_NUM_FLOAT = 3;
3364 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003365
3366 // 3..255 are character and/or operators
3367
Jack Palevich2db168f2009-06-11 14:29:47 -07003368 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003369 // Order has to match string list in "internKeywords".
3370 enum {
3371 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3372 TOK_INT = TOK_KEYWORD,
3373 TOK_CHAR,
3374 TOK_VOID,
3375 TOK_IF,
3376 TOK_ELSE,
3377 TOK_WHILE,
3378 TOK_BREAK,
3379 TOK_RETURN,
3380 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003381 TOK_AUTO,
3382 TOK_CASE,
3383 TOK_CONST,
3384 TOK_CONTINUE,
3385 TOK_DEFAULT,
3386 TOK_DO,
3387 TOK_DOUBLE,
3388 TOK_ENUM,
3389 TOK_EXTERN,
3390 TOK_FLOAT,
3391 TOK_GOTO,
3392 TOK_LONG,
3393 TOK_REGISTER,
3394 TOK_SHORT,
3395 TOK_SIGNED,
3396 TOK_SIZEOF,
3397 TOK_STATIC,
3398 TOK_STRUCT,
3399 TOK_SWITCH,
3400 TOK_TYPEDEF,
3401 TOK_UNION,
3402 TOK_UNSIGNED,
3403 TOK_VOLATILE,
3404 TOK__BOOL,
3405 TOK__COMPLEX,
3406 TOK__IMAGINARY,
3407 TOK_INLINE,
3408 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003409
3410 // Symbols start after keywords
3411
3412 TOK_SYMBOL,
3413 TOK_PRAGMA = TOK_SYMBOL,
3414 TOK_DEFINE,
3415 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003416 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003417
3418 static const int LOCAL = 0x200;
3419
3420 static const int SYM_FORWARD = 0;
3421 static const int SYM_DEFINE = 1;
3422
3423 /* tokens in string heap */
3424 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003425
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003426 static const int OP_INCREMENT = 0;
3427 static const int OP_DECREMENT = 1;
3428 static const int OP_MUL = 2;
3429 static const int OP_DIV = 3;
3430 static const int OP_MOD = 4;
3431 static const int OP_PLUS = 5;
3432 static const int OP_MINUS = 6;
3433 static const int OP_SHIFT_LEFT = 7;
3434 static const int OP_SHIFT_RIGHT = 8;
3435 static const int OP_LESS_EQUAL = 9;
3436 static const int OP_GREATER_EQUAL = 10;
3437 static const int OP_LESS = 11;
3438 static const int OP_GREATER = 12;
3439 static const int OP_EQUALS = 13;
3440 static const int OP_NOT_EQUALS = 14;
3441 static const int OP_LOGICAL_AND = 15;
3442 static const int OP_LOGICAL_OR = 16;
3443 static const int OP_BIT_AND = 17;
3444 static const int OP_BIT_XOR = 18;
3445 static const int OP_BIT_OR = 19;
3446 static const int OP_BIT_NOT = 20;
3447 static const int OP_LOGICAL_NOT = 21;
3448 static const int OP_COUNT = 22;
3449
3450 /* Operators are searched from front, the two-character operators appear
3451 * before the single-character operators with the same first character.
3452 * @ is used to pad out single-character operators.
3453 */
3454 static const char* operatorChars;
3455 static const char operatorLevel[];
3456
Jack Palevich569f1352009-06-29 14:29:08 -07003457 /* Called when we detect an internal problem. Does nothing in production.
3458 *
3459 */
3460 void internalError() {
3461 * (char*) 0 = 0;
3462 }
3463
Jack Palevich86351982009-06-30 18:09:56 -07003464 void assert(bool isTrue) {
3465 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003466 internalError();
3467 }
Jack Palevich86351982009-06-30 18:09:56 -07003468 }
3469
Jack Palevich40600de2009-07-01 15:32:35 -07003470 bool isSymbol(tokenid_t t) {
3471 return t >= TOK_SYMBOL &&
3472 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3473 }
3474
3475 bool isSymbolOrKeyword(tokenid_t t) {
3476 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003477 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003478 }
3479
Jack Palevich86351982009-06-30 18:09:56 -07003480 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003481 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003482 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3483 if (pV && pV->tok != t) {
3484 internalError();
3485 }
3486 return pV;
3487 }
3488
3489 inline bool isDefined(tokenid_t t) {
3490 return t >= TOK_SYMBOL && VI(t) != 0;
3491 }
3492
Jack Palevich40600de2009-07-01 15:32:35 -07003493 const char* nameof(tokenid_t t) {
3494 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003495 return mTokenTable[t].pText;
3496 }
3497
Jack Palevich21a15a22009-05-11 14:49:29 -07003498 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003499 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003500 }
3501
3502 void inp() {
3503 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003504 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003505 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003506 dptr = 0;
3507 ch = dch;
3508 }
Jack Palevichdc456462009-07-16 16:50:56 -07003509 } else {
3510 if (mbBumpLine) {
3511 mLineNumber++;
3512 mbBumpLine = false;
3513 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003514 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003515 if (ch == '\n') {
3516 mbBumpLine = true;
3517 }
3518 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003519#if 0
3520 printf("ch='%c' 0x%x\n", ch, ch);
3521#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003522 }
3523
3524 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003525 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003526 }
3527
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003528 int decodeHex(int c) {
3529 if (isdigit(c)) {
3530 c -= '0';
3531 } else if (c <= 'F') {
3532 c = c - 'A' + 10;
3533 } else {
3534 c =c - 'a' + 10;
3535 }
3536 return c;
3537 }
3538
Jack Palevichb4758ff2009-06-12 12:49:14 -07003539 /* read a character constant, advances ch to after end of constant */
3540 int getq() {
3541 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003542 if (ch == '\\') {
3543 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003544 if (isoctal(ch)) {
3545 // 1 to 3 octal characters.
3546 val = 0;
3547 for(int i = 0; i < 3; i++) {
3548 if (isoctal(ch)) {
3549 val = (val << 3) + ch - '0';
3550 inp();
3551 }
3552 }
3553 return val;
3554 } else if (ch == 'x' || ch == 'X') {
3555 // N hex chars
3556 inp();
3557 if (! isxdigit(ch)) {
3558 error("'x' character escape requires at least one digit.");
3559 } else {
3560 val = 0;
3561 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003562 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003563 inp();
3564 }
3565 }
3566 } else {
3567 int val = ch;
3568 switch (ch) {
3569 case 'a':
3570 val = '\a';
3571 break;
3572 case 'b':
3573 val = '\b';
3574 break;
3575 case 'f':
3576 val = '\f';
3577 break;
3578 case 'n':
3579 val = '\n';
3580 break;
3581 case 'r':
3582 val = '\r';
3583 break;
3584 case 't':
3585 val = '\t';
3586 break;
3587 case 'v':
3588 val = '\v';
3589 break;
3590 case '\\':
3591 val = '\\';
3592 break;
3593 case '\'':
3594 val = '\'';
3595 break;
3596 case '"':
3597 val = '"';
3598 break;
3599 case '?':
3600 val = '?';
3601 break;
3602 default:
3603 error("Undefined character escape %c", ch);
3604 break;
3605 }
3606 inp();
3607 return val;
3608 }
3609 } else {
3610 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003611 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003612 return val;
3613 }
3614
3615 static bool isoctal(int ch) {
3616 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003617 }
3618
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003619 bool acceptCh(int c) {
3620 bool result = c == ch;
3621 if (result) {
3622 pdef(ch);
3623 inp();
3624 }
3625 return result;
3626 }
3627
3628 bool acceptDigitsCh() {
3629 bool result = false;
3630 while (isdigit(ch)) {
3631 result = true;
3632 pdef(ch);
3633 inp();
3634 }
3635 return result;
3636 }
3637
3638 void parseFloat() {
3639 tok = TOK_NUM_DOUBLE;
3640 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003641 if(mTokenString.len() == 0) {
3642 mTokenString.append('0');
3643 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003644 acceptCh('.');
3645 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003646 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003647 acceptCh('-') || acceptCh('+');
3648 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003649 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003650 if (ch == 'f' || ch == 'F') {
3651 tok = TOK_NUM_FLOAT;
3652 inp();
3653 } else if (ch == 'l' || ch == 'L') {
3654 inp();
3655 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003656 }
3657 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003658 char* pEnd = pText + strlen(pText);
3659 char* pEndPtr = 0;
3660 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003661 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003662 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003663 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003664 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003665 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003666 if (errno || pEndPtr != pEnd) {
3667 error("Can't parse constant: %s", pText);
3668 }
3669 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003670 }
3671
Jack Palevich21a15a22009-05-11 14:49:29 -07003672 void next() {
3673 int l, a;
3674
Jack Palevich546b2242009-05-13 15:10:04 -07003675 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003676 if (ch == '#') {
3677 inp();
3678 next();
3679 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003680 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003681 } else if (tok == TOK_PRAGMA) {
3682 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003683 } else if (tok == TOK_LINE) {
3684 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003685 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003686 error("Unsupported preprocessor directive \"%s\"",
3687 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003688 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003689 }
3690 inp();
3691 }
3692 tokl = 0;
3693 tok = ch;
3694 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003695 if (isdigit(ch) || ch == '.') {
3696 // Start of a numeric constant. Could be integer, float, or
3697 // double, won't know until we look further.
3698 mTokenString.clear();
3699 pdef(ch);
3700 inp();
3701 int base = 10;
3702 if (tok == '0') {
3703 if (ch == 'x' || ch == 'X') {
3704 base = 16;
3705 tok = TOK_NUM;
3706 tokc = 0;
3707 inp();
3708 while ( isxdigit(ch) ) {
3709 tokc = (tokc << 4) + decodeHex(ch);
3710 inp();
3711 }
3712 } else if (isoctal(ch)){
3713 base = 8;
3714 tok = TOK_NUM;
3715 tokc = 0;
3716 while ( isoctal(ch) ) {
3717 tokc = (tokc << 3) + (ch - '0');
3718 inp();
3719 }
3720 }
3721 } else if (isdigit(tok)){
3722 acceptDigitsCh();
3723 }
3724 if (base == 10) {
3725 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3726 parseFloat();
3727 } else {
3728 // It's an integer constant
3729 char* pText = mTokenString.getUnwrapped();
3730 char* pEnd = pText + strlen(pText);
3731 char* pEndPtr = 0;
3732 errno = 0;
3733 tokc = strtol(pText, &pEndPtr, base);
3734 if (errno || pEndPtr != pEnd) {
3735 error("Can't parse constant: %s %d %d", pText, base, errno);
3736 }
3737 tok = TOK_NUM;
3738 }
3739 }
3740 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003741 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003742 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003743 pdef(ch);
3744 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003745 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003746 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3747 // Is this a macro?
3748 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3749 if (pMacroDefinition) {
3750 // Yes, it is a macro
3751 dptr = pMacroDefinition;
3752 dch = ch;
3753 inp();
3754 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003755 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003756 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003757 inp();
3758 if (tok == '\'') {
3759 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003760 tokc = getq();
3761 if (ch != '\'') {
3762 error("Expected a ' character, got %c", ch);
3763 } else {
3764 inp();
3765 }
Jack Palevich546b2242009-05-13 15:10:04 -07003766 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003767 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003768 while (ch && ch != EOF) {
3769 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003770 inp();
3771 inp();
3772 if (ch == '/')
3773 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003774 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003775 if (ch == EOF) {
3776 error("End of file inside comment.");
3777 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003778 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003779 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003780 } else if ((tok == '/') & (ch == '/')) {
3781 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003782 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003783 inp();
3784 }
3785 inp();
3786 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003787 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003788 const char* t = operatorChars;
3789 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003790 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003791 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003792 tokl = operatorLevel[opIndex];
3793 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003794 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003795#if 0
3796 printf("%c%c -> tokl=%d tokc=0x%x\n",
3797 l, a, tokl, tokc);
3798#endif
3799 if (a == ch) {
3800 inp();
3801 tok = TOK_DUMMY; /* dummy token for double tokens */
3802 }
3803 break;
3804 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003805 opIndex++;
3806 }
3807 if (l == 0) {
3808 tokl = 0;
3809 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003810 }
3811 }
3812 }
3813#if 0
3814 {
Jack Palevich569f1352009-06-29 14:29:08 -07003815 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003816 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003817 fprintf(stderr, "%s\n", buf.getUnwrapped());
3818 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003819#endif
3820 }
3821
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003822 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003823 next();
3824 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003825 String* pName = new String();
3826 while (isspace(ch)) {
3827 inp();
3828 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003829 if (ch == '(') {
3830 delete pName;
3831 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003832 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003833 }
3834 while (isspace(ch)) {
3835 inp();
3836 }
Jack Palevich569f1352009-06-29 14:29:08 -07003837 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003838 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003839 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003840 inp();
3841 }
Jack Palevich569f1352009-06-29 14:29:08 -07003842 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3843 memcpy(pDefn, value.getUnwrapped(), value.len());
3844 pDefn[value.len()] = 0;
3845 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003846 }
3847
Jack Palevicheedf9d22009-06-04 16:23:40 -07003848 void doPragma() {
3849 // # pragma name(val)
3850 int state = 0;
3851 while(ch != EOF && ch != '\n' && state < 10) {
3852 switch(state) {
3853 case 0:
3854 if (isspace(ch)) {
3855 inp();
3856 } else {
3857 state++;
3858 }
3859 break;
3860 case 1:
3861 if (isalnum(ch)) {
3862 mPragmas.append(ch);
3863 inp();
3864 } else if (ch == '(') {
3865 mPragmas.append(0);
3866 inp();
3867 state++;
3868 } else {
3869 state = 11;
3870 }
3871 break;
3872 case 2:
3873 if (isalnum(ch)) {
3874 mPragmas.append(ch);
3875 inp();
3876 } else if (ch == ')') {
3877 mPragmas.append(0);
3878 inp();
3879 state = 10;
3880 } else {
3881 state = 11;
3882 }
3883 break;
3884 }
3885 }
3886 if(state != 10) {
3887 error("Unexpected pragma syntax");
3888 }
3889 mPragmaStringCount += 2;
3890 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003891
Jack Palevichdc456462009-07-16 16:50:56 -07003892 void doLine() {
3893 // # line number { "filename "}
3894 next();
3895 if (tok != TOK_NUM) {
3896 error("Expected a line-number");
3897 } else {
3898 mLineNumber = tokc-1; // The end-of-line will increment it.
3899 }
3900 while(ch != EOF && ch != '\n') {
3901 inp();
3902 }
3903 }
3904
Jack Palevichac0e95e2009-05-29 13:53:44 -07003905 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003906 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003907 mErrorBuf.vprintf(fmt, ap);
3908 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003909 }
3910
Jack Palevich8b0624c2009-05-20 12:12:06 -07003911 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 if (tok != c) {
3913 error("'%c' expected", c);
3914 }
3915 next();
3916 }
3917
Jack Palevich86351982009-06-30 18:09:56 -07003918 bool accept(intptr_t c) {
3919 if (tok == c) {
3920 next();
3921 return true;
3922 }
3923 return false;
3924 }
3925
Jack Palevich40600de2009-07-01 15:32:35 -07003926 bool acceptStringLiteral() {
3927 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003928 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003929 // This while loop merges multiple adjacent string constants.
3930 while (tok == '"') {
3931 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003932 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003933 }
3934 if (ch != '"') {
3935 error("Unterminated string constant.");
3936 }
3937 inp();
3938 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003939 }
Jack Palevich40600de2009-07-01 15:32:35 -07003940 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003941 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003942 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003943 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003944
3945 return true;
3946 }
3947 return false;
3948 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003949
Jack Palevichb1544ca2009-07-16 15:09:20 -07003950 void linkGlobal(tokenid_t t, bool isFunction) {
3951 VariableInfo* pVI = VI(t);
3952 void* n = NULL;
3953 if (mpSymbolLookupFn) {
3954 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3955 }
3956 if (pVI->pType == NULL) {
3957 if (isFunction) {
3958 pVI->pType = mkpIntFn;
3959 } else {
3960 pVI->pType = mkpInt;
3961 }
3962 }
3963 pVI->pAddress = n;
3964 }
3965
Jack Palevich40600de2009-07-01 15:32:35 -07003966 /* Parse and evaluate a unary expression.
3967 * allowAssignment is true if '=' parsing wanted (quick hack)
3968 */
3969 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003970 tokenid_t t;
3971 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003972 t = 0;
3973 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3974 if (acceptStringLiteral()) {
3975 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003976 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003977 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003978 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003979 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003980 t = tok;
3981 next();
3982 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003983 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003984 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003985 // Align to 4-byte boundary
3986 glo = (char*) (((intptr_t) glo + 3) & -4);
3987 * (float*) glo = (float) ad;
3988 pGen->loadFloat((int) glo, mkpFloat);
3989 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003990 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003991 // Align to 8-byte boundary
3992 glo = (char*) (((intptr_t) glo + 7) & -8);
3993 * (double*) glo = ad;
3994 pGen->loadFloat((int) glo, mkpDouble);
3995 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003996 } else if (c == 2) {
3997 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003998 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003999 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004000 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004001 else if (t == '+') {
4002 // ignore unary plus.
4003 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004004 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004005 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004006 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004007 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004008 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004009 if (pCast) {
4010 skip(')');
4011 unary(false);
4012 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004013 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004014 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004015 skip(')');
4016 }
4017 } else if (t == '*') {
4018 /* This is a pointer dereference.
4019 */
4020 unary(false);
4021 Type* pR0Type = pGen->getR0Type();
4022 if (pR0Type->tag != TY_POINTER) {
4023 error("Expected a pointer type.");
4024 } else {
4025 if (pR0Type->pHead->tag == TY_FUNC) {
4026 t = 0;
4027 }
4028 if (accept('=')) {
4029 pGen->pushR0();
4030 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07004031 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07004032 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004033 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07004034 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 }
Jack Palevich3f226492009-07-02 14:46:19 -07004036 // Else we fall through to the function call below, with
4037 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004039 VariableInfo* pVI = VI(tok);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004040 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType));
Jack Palevich21a15a22009-05-11 14:49:29 -07004041 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004042 } else if (t == EOF ) {
4043 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004044 } else if (t == ';') {
4045 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004046 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004047 // Don't have to do anything special here, the error
4048 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004049 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004050 if (!isDefined(t)) {
4051 mGlobals.add(t);
4052 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004053 }
Jack Palevich8df46192009-07-07 14:48:51 -07004054 VariableInfo* pVI = VI(t);
4055 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004056 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004057 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004058 linkGlobal(t, tok == '(');
4059 n = (intptr_t) pVI->pAddress;
4060 if (!n && tok != '(') {
4061 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004062 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004063 }
Jack Palevich40600de2009-07-01 15:32:35 -07004064 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004065 /* assignment */
4066 next();
4067 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004068 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004069 } else if (tok != '(') {
4070 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07004071 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004072 linkGlobal(t, false);
4073 n = (intptr_t) pVI->pAddress;
4074 if (!n) {
4075 error("Undeclared variable %s\n", nameof(t));
4076 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004077 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07004078 // load a variable
Jack Palevich21a15a22009-05-11 14:49:29 -07004079 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004080 // post inc / post dec
Jack Palevichddf7c9c2009-07-29 10:28:18 -07004081 pGen->leaR0(n, createPtrType(pVI->pType));
4082
Jack Palevich58c30ee2009-07-17 16:35:23 -07004083 pGen->pushR0();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07004084 pGen->loadR0FromR0();
4085 pGen->over();
4086 int lit = 1;
4087 if (tokc == OP_DECREMENT) {
4088 lit = -1;
4089 }
4090 switch (pVI->pType->tag) {
4091 case TY_INT:
4092 case TY_CHAR:
4093 case TY_POINTER:
4094 pGen->pushR0();
4095 pGen->li(lit);
4096 pGen->genOp(OP_PLUS);
4097 break;
4098 default:
4099 error("++/-- illegal for this type.");
4100 break;
4101 }
4102
4103 pGen->storeR0ToTOS();
Jack Palevich58c30ee2009-07-17 16:35:23 -07004104 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07004105 next();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07004106 } else {
4107 pGen->loadR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004108 }
4109 }
4110 }
4111 }
4112
4113 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07004114 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07004115 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07004116 VariableInfo* pVI = NULL;
4117 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07004118 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07004119 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07004120 } else {
4121 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07004122 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07004123 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004124 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07004125 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07004126 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004127 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07004128 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004129 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004130 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004131 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004132 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004133 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004134 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004135 Type* pTargetType;
4136 if (pArgList) {
4137 pTargetType = pArgList->pHead;
4138 pArgList = pArgList->pTail;
4139 } else {
4140 pTargetType = pGen->getR0Type();
4141 if (pTargetType->tag == TY_FLOAT) {
4142 pTargetType = mkpDouble;
4143 }
4144 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004145 if (pTargetType->tag == TY_VOID) {
4146 error("Can't pass void value for argument %d",
4147 argCount + 1);
4148 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004149 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004150 }
Jack Palevich95727a02009-07-06 12:07:15 -07004151 if (accept(',')) {
4152 // fine
4153 } else if ( tok != ')') {
4154 error("Expected ',' or ')'");
4155 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004156 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004157 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004158 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004159 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004160 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004161 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004162 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004163 if (!n) {
4164 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004165 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4166 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004167 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004168 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004169 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004170 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4171 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004172 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004173 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004174 }
4175 }
4176
Jack Palevich40600de2009-07-01 15:32:35 -07004177 /* Recursive descent parser for binary operations.
4178 */
4179 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004180 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004181 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004182 if (level-- == 1)
4183 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004184 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004185 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004186 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004187 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004188 t = tokc;
4189 next();
4190
Jack Palevich40600de2009-07-01 15:32:35 -07004191 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004192 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004193 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004194 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004195 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004196 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004197 // Check for syntax error.
4198 if (pGen->getR0Type() == NULL) {
4199 // We failed to parse a right-hand argument.
4200 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004201 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004202 }
Jack Palevich40600de2009-07-01 15:32:35 -07004203 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004204 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004205 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004206 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004207 }
4208 }
4209 }
4210 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004211 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004212 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004213 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07004214 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004215 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004216 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07004217 }
4218 }
4219 }
4220
4221 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004222 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004223 }
4224
4225 int test_expr() {
4226 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004227 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004228 }
4229
Jack Palevicha6baa232009-06-12 11:25:59 -07004230 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004231 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004232
Jack Palevich95727a02009-07-06 12:07:15 -07004233 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004234 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004235 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004236 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004237 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004238 next();
4239 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004240 a = test_expr();
4241 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004242 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004243 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004244 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004245 n = pGen->gjmp(0); /* jmp */
4246 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004247 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004248 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004249 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004250 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004251 }
Jack Palevich546b2242009-05-13 15:10:04 -07004252 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004253 t = tok;
4254 next();
4255 skip('(');
4256 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004257 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004258 a = test_expr();
4259 } else {
4260 if (tok != ';')
4261 expr();
4262 skip(';');
4263 n = codeBuf.getPC();
4264 a = 0;
4265 if (tok != ';')
4266 a = test_expr();
4267 skip(';');
4268 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004269 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004270 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004271 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004272 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004273 n = t + 4;
4274 }
4275 }
4276 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004277 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004278 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004279 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004280 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004281 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004282 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004283 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004284 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004285 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004286 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004287 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004288 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004289 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004290 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004291 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004292 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004293 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004294 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004295 if (pReturnType->tag == TY_VOID) {
4296 error("Must not return a value from a void function");
4297 } else {
4298 pGen->convertR0(pReturnType);
4299 }
4300 } else {
4301 if (pReturnType->tag != TY_VOID) {
4302 error("Must specify a value here");
4303 }
Jack Palevich8df46192009-07-07 14:48:51 -07004304 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004305 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004306 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004307 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004308 } else if (tok != ';')
4309 expr();
4310 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004311 }
4312 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004313
Jack Palevicha8f427f2009-07-13 18:40:08 -07004314 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004315 if (a == b) {
4316 return true;
4317 }
4318 if (a == NULL || b == NULL) {
4319 return false;
4320 }
4321 TypeTag at = a->tag;
4322 if (at != b->tag) {
4323 return false;
4324 }
4325 if (at == TY_POINTER) {
4326 return typeEqual(a->pHead, b->pHead);
4327 } else if (at == TY_FUNC || at == TY_PARAM) {
4328 return typeEqual(a->pHead, b->pHead)
4329 && typeEqual(a->pTail, b->pTail);
4330 }
4331 return true;
4332 }
4333
Jack Palevich2ff5c222009-07-23 15:11:22 -07004334 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004335 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004336 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004337 memset(pType, 0, sizeof(*pType));
4338 pType->tag = tag;
4339 pType->pHead = pHead;
4340 pType->pTail = pTail;
4341 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004342 }
4343
Jack Palevich2ff5c222009-07-23 15:11:22 -07004344 Type* createPtrType(Type* pType) {
4345 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004346 }
4347
4348 /**
4349 * Try to print a type in declaration order
4350 */
Jack Palevich86351982009-06-30 18:09:56 -07004351 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004352 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004353 if (pType == NULL) {
4354 buffer.appendCStr("null");
4355 return;
4356 }
Jack Palevich3f226492009-07-02 14:46:19 -07004357 decodeTypeImp(buffer, pType);
4358 }
4359
4360 void decodeTypeImp(String& buffer, Type* pType) {
4361 decodeTypeImpPrefix(buffer, pType);
4362
Jack Palevich86351982009-06-30 18:09:56 -07004363 String temp;
4364 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004365 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004366 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004367 }
4368
4369 decodeTypeImpPostfix(buffer, pType);
4370 }
4371
4372 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4373 TypeTag tag = pType->tag;
4374
Jack Palevich37c54bd2009-07-14 18:35:36 -07004375 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004376 switch (tag) {
4377 case TY_INT:
4378 buffer.appendCStr("int");
4379 break;
4380 case TY_CHAR:
4381 buffer.appendCStr("char");
4382 break;
4383 case TY_VOID:
4384 buffer.appendCStr("void");
4385 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004386 case TY_FLOAT:
4387 buffer.appendCStr("float");
4388 break;
4389 case TY_DOUBLE:
4390 buffer.appendCStr("double");
4391 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004392 default:
4393 break;
4394 }
Jack Palevich86351982009-06-30 18:09:56 -07004395 buffer.append(' ');
4396 }
Jack Palevich3f226492009-07-02 14:46:19 -07004397
4398 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004399 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004400 break;
4401 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004402 break;
4403 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004404 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004405 case TY_FLOAT:
4406 break;
4407 case TY_DOUBLE:
4408 break;
Jack Palevich86351982009-06-30 18:09:56 -07004409 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004410 decodeTypeImpPrefix(buffer, pType->pHead);
4411 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4412 buffer.append('(');
4413 }
4414 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004415 break;
4416 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004417 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004418 break;
4419 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004420 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004421 break;
4422 default:
4423 String temp;
4424 temp.printf("Unknown tag %d", pType->tag);
4425 buffer.append(temp);
4426 break;
4427 }
Jack Palevich3f226492009-07-02 14:46:19 -07004428 }
4429
4430 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4431 TypeTag tag = pType->tag;
4432
4433 switch(tag) {
4434 case TY_POINTER:
4435 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4436 buffer.append(')');
4437 }
4438 decodeTypeImpPostfix(buffer, pType->pHead);
4439 break;
4440 case TY_FUNC:
4441 buffer.append('(');
4442 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4443 decodeTypeImp(buffer, pArg);
4444 if (pArg->pTail) {
4445 buffer.appendCStr(", ");
4446 }
4447 }
4448 buffer.append(')');
4449 break;
4450 default:
4451 break;
Jack Palevich86351982009-06-30 18:09:56 -07004452 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004453 }
4454
Jack Palevich86351982009-06-30 18:09:56 -07004455 void printType(Type* pType) {
4456 String buffer;
4457 decodeType(buffer, pType);
4458 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004459 }
4460
Jack Palevich2ff5c222009-07-23 15:11:22 -07004461 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004462 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004463 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004464 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004465 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004466 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004467 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004468 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004469 } else if (tok == TOK_FLOAT) {
4470 pType = mkpFloat;
4471 } else if (tok == TOK_DOUBLE) {
4472 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004473 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004474 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004475 }
4476 next();
Jack Palevich86351982009-06-30 18:09:56 -07004477 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004478 }
4479
Jack Palevich2ff5c222009-07-23 15:11:22 -07004480 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004481 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004482 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004483 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004484 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004485 if (declName) {
4486 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004487 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004488
Jack Palevich86351982009-06-30 18:09:56 -07004489 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004490 }
Jack Palevich3f226492009-07-02 14:46:19 -07004491 // fprintf(stderr, "Parsed a declaration: ");
4492 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004493 if (reportFailure) {
4494 return NULL;
4495 }
Jack Palevich86351982009-06-30 18:09:56 -07004496 return pType;
4497 }
4498
Jack Palevich2ff5c222009-07-23 15:11:22 -07004499 Type* expectDeclaration(Type* pBaseType) {
4500 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004501 if (! pType) {
4502 error("Expected a declaration");
4503 }
4504 return pType;
4505 }
4506
Jack Palevich3f226492009-07-02 14:46:19 -07004507 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004508 Type* acceptCastTypeDeclaration() {
4509 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004510 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004511 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004512 }
Jack Palevich86351982009-06-30 18:09:56 -07004513 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004514 }
4515
Jack Palevich2ff5c222009-07-23 15:11:22 -07004516 Type* expectCastTypeDeclaration() {
4517 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004518 if (! pType) {
4519 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004520 }
Jack Palevich3f226492009-07-02 14:46:19 -07004521 return pType;
4522 }
4523
4524 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004525 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004526 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004527 int ptrCounter = 0;
4528 while (accept('*')) {
4529 ptrCounter++;
4530 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004531 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004532 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004533 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004534 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004535 }
4536 return pType;
4537 }
4538
4539 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004540 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004541 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004542 // direct-dcl :
4543 // name
4544 // (dcl)
4545 // direct-dcl()
4546 // direct-dcl[]
4547 Type* pNewHead = NULL;
4548 if (accept('(')) {
4549 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004550 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004551 skip(')');
4552 } else if ((declName = acceptSymbol()) != 0) {
4553 if (nameAllowed == false && declName) {
4554 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004555 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004556 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004557 } else if (nameRequired && ! declName) {
4558 String temp;
4559 decodeToken(temp, tok, true);
4560 error("Expected name. Got %s", temp.getUnwrapped());
4561 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004562 }
4563 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004564 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004565 Type* pTail = acceptArgs(nameAllowed);
4566 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004567 skip(')');
4568 }
Jack Palevich3f226492009-07-02 14:46:19 -07004569
4570 if (pNewHead) {
4571 Type* pA = pNewHead;
4572 while (pA->pHead) {
4573 pA = pA->pHead;
4574 }
4575 pA->pHead = pType;
4576 pType = pNewHead;
4577 }
Jack Palevich86351982009-06-30 18:09:56 -07004578 return pType;
4579 }
4580
Jack Palevich2ff5c222009-07-23 15:11:22 -07004581 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004582 Type* pHead = NULL;
4583 Type* pTail = NULL;
4584 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004585 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004586 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004587 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004588 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004589 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004590 if (!pHead) {
4591 pHead = pParam;
4592 pTail = pParam;
4593 } else {
4594 pTail->pTail = pParam;
4595 pTail = pParam;
4596 }
4597 }
4598 }
4599 if (! accept(',')) {
4600 break;
4601 }
4602 }
4603 return pHead;
4604 }
4605
Jack Palevich2ff5c222009-07-23 15:11:22 -07004606 Type* expectPrimitiveType() {
4607 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004608 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004609 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004610 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004611 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004612 }
Jack Palevich86351982009-06-30 18:09:56 -07004613 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004614 }
4615
Jack Palevich86351982009-06-30 18:09:56 -07004616 void addGlobalSymbol(Type* pDecl) {
4617 tokenid_t t = pDecl->id;
4618 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004619 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004620 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004621 }
Jack Palevich86351982009-06-30 18:09:56 -07004622 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004623 }
4624
Jack Palevich86351982009-06-30 18:09:56 -07004625 void reportDuplicate(tokenid_t t) {
4626 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004627 }
4628
Jack Palevich86351982009-06-30 18:09:56 -07004629 void addLocalSymbol(Type* pDecl) {
4630 tokenid_t t = pDecl->id;
4631 if (mLocals.isDefinedAtCurrentLevel(t)) {
4632 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004633 }
Jack Palevich86351982009-06-30 18:09:56 -07004634 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004635 }
4636
Jack Palevich95727a02009-07-06 12:07:15 -07004637 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004638 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004639
Jack Palevich95727a02009-07-06 12:07:15 -07004640 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004641 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004642 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004643 if (!pDecl) {
4644 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004645 }
Jack Palevich86351982009-06-30 18:09:56 -07004646 int variableAddress = 0;
4647 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004648 size_t alignment = pGen->stackAlignmentOf(pDecl);
4649 size_t alignmentMask = ~ (alignment - 1);
4650 size_t sizeOf = pGen->sizeOf(pDecl);
4651 loc = (loc + alignment - 1) & alignmentMask;
4652 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4653 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004654 variableAddress = -loc;
4655 VI(pDecl->id)->pAddress = (void*) variableAddress;
4656 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004657 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004658 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004659 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004660 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004661 if (tok == ',')
4662 next();
4663 }
4664 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004665 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004666 }
4667 }
4668
Jack Palevichf1728be2009-06-12 13:53:51 -07004669 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004670 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004671 }
4672
Jack Palevich37c54bd2009-07-14 18:35:36 -07004673 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004674 if (token == EOF ) {
4675 buffer.printf("EOF");
4676 } else if (token == TOK_NUM) {
4677 buffer.printf("numeric constant");
4678 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004679 if (token < 32) {
4680 buffer.printf("'\\x%02x'", token);
4681 } else {
4682 buffer.printf("'%c'", token);
4683 }
Jack Palevich569f1352009-06-29 14:29:08 -07004684 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004685 if (quote) {
4686 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4687 buffer.printf("keyword \"%s\"", nameof(token));
4688 } else {
4689 buffer.printf("symbol \"%s\"", nameof(token));
4690 }
4691 } else {
4692 buffer.printf("%s", nameof(token));
4693 }
Jack Palevich569f1352009-06-29 14:29:08 -07004694 }
4695 }
4696
Jack Palevich40600de2009-07-01 15:32:35 -07004697 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004698 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004699 if (!result) {
4700 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004701 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004702 error("Expected symbol. Got %s", temp.getUnwrapped());
4703 }
4704 return result;
4705 }
4706
Jack Palevich86351982009-06-30 18:09:56 -07004707 tokenid_t acceptSymbol() {
4708 tokenid_t result = 0;
4709 if (tok >= TOK_SYMBOL) {
4710 result = tok;
4711 next();
Jack Palevich86351982009-06-30 18:09:56 -07004712 }
4713 return result;
4714 }
4715
Jack Palevichb7c81e92009-06-04 19:56:13 -07004716 void globalDeclarations() {
4717 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004718 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004719 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004720 break;
4721 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004722 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004723 if (!pDecl) {
4724 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004725 }
Jack Palevich86351982009-06-30 18:09:56 -07004726 if (! isDefined(pDecl->id)) {
4727 addGlobalSymbol(pDecl);
4728 }
4729 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004730 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004731 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004732 }
Jack Palevich86351982009-06-30 18:09:56 -07004733 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004734 // it's a variable declaration
4735 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004736 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004737 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004738 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004739 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004740 }
Jack Palevich86351982009-06-30 18:09:56 -07004741 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004742 if (tok == TOK_NUM) {
4743 if (name) {
4744 * (int*) name->pAddress = tokc;
4745 }
4746 next();
4747 } else {
4748 error("Expected an integer constant");
4749 }
4750 }
Jack Palevich86351982009-06-30 18:09:56 -07004751 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004752 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004753 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004754 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004755 if (!pDecl) {
4756 break;
4757 }
4758 if (! isDefined(pDecl->id)) {
4759 addGlobalSymbol(pDecl);
4760 }
4761 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004762 }
4763 skip(';');
4764 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004765 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004766 if (accept(';')) {
4767 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004768 } else if (tok != '{') {
4769 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004770 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004771 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004772 if (name) {
4773 /* patch forward references (XXX: does not work for function
4774 pointers) */
4775 pGen->gsym((int) name->pForward);
4776 /* put function address */
4777 name->pAddress = (void*) codeBuf.getPC();
4778 }
4779 // Calculate stack offsets for parameters
4780 mLocals.pushLevel();
4781 intptr_t a = 8;
4782 int argCount = 0;
4783 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4784 Type* pArg = pP->pHead;
4785 addLocalSymbol(pArg);
4786 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004787 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004788 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004789 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004790 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004791 argCount++;
4792 }
4793 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004794 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004795 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004796 block(0, true);
4797 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004798 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004799 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004800 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004801 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004802 }
4803 }
4804 }
4805
Jack Palevich9cbd2262009-07-08 16:48:41 -07004806 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4807 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4808 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004809 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004810 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004811 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004812 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004813 char* result = (char*) base;
4814 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004815 return result;
4816 }
4817
Jack Palevich21a15a22009-05-11 14:49:29 -07004818 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004819 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004820 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004821 pGlobalBase = 0;
4822 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004823 if (pGen) {
4824 delete pGen;
4825 pGen = 0;
4826 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004827 if (file) {
4828 delete file;
4829 file = 0;
4830 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004831 }
4832
Jack Palevich8c246a92009-07-14 21:14:10 -07004833 // One-time initialization, when class is constructed.
4834 void init() {
4835 mpSymbolLookupFn = 0;
4836 mpSymbolLookupContext = 0;
4837 }
4838
Jack Palevich21a15a22009-05-11 14:49:29 -07004839 void clear() {
4840 tok = 0;
4841 tokc = 0;
4842 tokl = 0;
4843 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004844 rsym = 0;
4845 loc = 0;
4846 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004847 dptr = 0;
4848 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004849 file = 0;
4850 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004851 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004852 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004853 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004854 mLineNumber = 1;
4855 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004856 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004857
Jack Palevich22305132009-05-13 10:58:45 -07004858 void setArchitecture(const char* architecture) {
4859 delete pGen;
4860 pGen = 0;
4861
4862 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004863#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004864 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004865 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004866 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004867#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004868#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004869 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004870 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004871 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004872#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004873 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004874 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004875 }
4876 }
4877
4878 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004879#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004880 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004881#elif defined(DEFAULT_X86_CODEGEN)
4882 pGen = new X86CodeGenerator();
4883#endif
4884 }
4885 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004886 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004887 } else {
4888 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004889 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004890 }
4891 }
4892
Jack Palevich77ae76e2009-05-10 19:59:24 -07004893public:
Jack Palevich22305132009-05-13 10:58:45 -07004894 struct args {
4895 args() {
4896 architecture = 0;
4897 }
4898 const char* architecture;
4899 };
4900
Jack Paleviche7b59062009-05-19 17:12:17 -07004901 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004902 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004903 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004904 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004905
Jack Paleviche7b59062009-05-19 17:12:17 -07004906 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004907 cleanup();
4908 }
4909
Jack Palevich8c246a92009-07-14 21:14:10 -07004910 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4911 mpSymbolLookupFn = pFn;
4912 mpSymbolLookupContext = pContext;
4913 }
4914
Jack Palevich1cdef202009-05-22 12:06:27 -07004915 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004916 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004917
Jack Palevich2ff5c222009-07-23 15:11:22 -07004918 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004919 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004920 cleanup();
4921 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004922 mTokenTable.setArena(&mGlobalArena);
4923 mGlobals.setArena(&mGlobalArena);
4924 mGlobals.setTokenTable(&mTokenTable);
4925 mLocals.setArena(&mLocalArena);
4926 mLocals.setTokenTable(&mTokenTable);
4927
4928 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004929 codeBuf.init(ALLOC_SIZE);
4930 setArchitecture(NULL);
4931 if (!pGen) {
4932 return -1;
4933 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004934#ifdef PROVIDE_TRACE_CODEGEN
4935 pGen = new TraceCodeGenerator(pGen);
4936#endif
4937 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004938 pGen->init(&codeBuf);
4939 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004940 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4941 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004942 inp();
4943 next();
4944 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004945 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004946 result = pGen->finishCompile();
4947 if (result == 0) {
4948 if (mErrorBuf.len()) {
4949 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004950 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004951 }
Jack Palevichce105a92009-07-16 14:30:33 -07004952 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004953 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004954 }
4955
Jack Palevich86351982009-06-30 18:09:56 -07004956 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004957 mkpInt = createType(TY_INT, NULL, NULL);
4958 mkpChar = createType(TY_CHAR, NULL, NULL);
4959 mkpVoid = createType(TY_VOID, NULL, NULL);
4960 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4961 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4962 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4963 mkpIntPtr = createPtrType(mkpInt);
4964 mkpCharPtr = createPtrType(mkpChar);
4965 mkpFloatPtr = createPtrType(mkpFloat);
4966 mkpDoublePtr = createPtrType(mkpDouble);
4967 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004968 }
4969
Jack Palevicha6baa232009-06-12 11:25:59 -07004970 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004971 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004972 }
4973
Jack Palevich569f1352009-06-29 14:29:08 -07004974 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004975 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004976 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004977 }
4978
Jack Palevich569f1352009-06-29 14:29:08 -07004979 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004980 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004981 error("Undefined forward reference: %s",
4982 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004983 }
4984 return true;
4985 }
4986
Jack Palevich21a15a22009-05-11 14:49:29 -07004987 int dump(FILE* out) {
4988 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4989 return 0;
4990 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004991
Jack Palevicha6535612009-05-13 16:24:17 -07004992 int disassemble(FILE* out) {
4993 return pGen->disassemble(out);
4994 }
4995
Jack Palevich1cdef202009-05-22 12:06:27 -07004996 /* Look through the symbol table to find a symbol.
4997 * If found, return its value.
4998 */
4999 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005000 if (mCompileResult == 0) {
5001 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5002 VariableInfo* pVariableInfo = VI(tok);
5003 if (pVariableInfo) {
5004 return pVariableInfo->pAddress;
5005 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005006 }
5007 return NULL;
5008 }
5009
Jack Palevicheedf9d22009-06-04 16:23:40 -07005010 void getPragmas(ACCsizei* actualStringCount,
5011 ACCsizei maxStringCount, ACCchar** strings) {
5012 int stringCount = mPragmaStringCount;
5013 if (actualStringCount) {
5014 *actualStringCount = stringCount;
5015 }
5016 if (stringCount > maxStringCount) {
5017 stringCount = maxStringCount;
5018 }
5019 if (strings) {
5020 char* pPragmas = mPragmas.getUnwrapped();
5021 while (stringCount-- > 0) {
5022 *strings++ = pPragmas;
5023 pPragmas += strlen(pPragmas) + 1;
5024 }
5025 }
5026 }
5027
Jack Palevichac0e95e2009-05-29 13:53:44 -07005028 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005029 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005030 }
5031
Jack Palevich77ae76e2009-05-10 19:59:24 -07005032};
5033
Jack Paleviche7b59062009-05-19 17:12:17 -07005034const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005035 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5036
Jack Paleviche7b59062009-05-19 17:12:17 -07005037const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005038 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5039 5, 5, /* ==, != */
5040 9, 10, /* &&, || */
5041 6, 7, 8, /* & ^ | */
5042 2, 2 /* ~ ! */
5043 };
5044
Jack Palevich8b0624c2009-05-20 12:12:06 -07005045#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005046FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005047#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005048
Jack Palevich8b0624c2009-05-20 12:12:06 -07005049#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005050const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005051 0x1, // ++
5052 0xff, // --
5053 0xc1af0f, // *
5054 0xf9f79991, // /
5055 0xf9f79991, // % (With manual assist to swap results)
5056 0xc801, // +
5057 0xd8f7c829, // -
5058 0xe0d391, // <<
5059 0xf8d391, // >>
5060 0xe, // <=
5061 0xd, // >=
5062 0xc, // <
5063 0xf, // >
5064 0x4, // ==
5065 0x5, // !=
5066 0x0, // &&
5067 0x1, // ||
5068 0xc821, // &
5069 0xc831, // ^
5070 0xc809, // |
5071 0xd0f7, // ~
5072 0x4 // !
5073};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005074#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005075
Jack Palevich1cdef202009-05-22 12:06:27 -07005076struct ACCscript {
5077 ACCscript() {
5078 text = 0;
5079 textLength = 0;
5080 accError = ACC_NO_ERROR;
5081 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005082
Jack Palevich1cdef202009-05-22 12:06:27 -07005083 ~ACCscript() {
5084 delete text;
5085 }
Jack Palevich546b2242009-05-13 15:10:04 -07005086
Jack Palevich8c246a92009-07-14 21:14:10 -07005087 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5088 compiler.registerSymbolCallback(pFn, pContext);
5089 }
5090
Jack Palevich1cdef202009-05-22 12:06:27 -07005091 void setError(ACCenum error) {
5092 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5093 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005094 }
5095 }
5096
Jack Palevich1cdef202009-05-22 12:06:27 -07005097 ACCenum getError() {
5098 ACCenum result = accError;
5099 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005100 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005101 }
5102
Jack Palevich1cdef202009-05-22 12:06:27 -07005103 Compiler compiler;
5104 char* text;
5105 int textLength;
5106 ACCenum accError;
5107};
5108
5109
5110extern "C"
5111ACCscript* accCreateScript() {
5112 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005113}
Jack Palevich1cdef202009-05-22 12:06:27 -07005114
5115extern "C"
5116ACCenum accGetError( ACCscript* script ) {
5117 return script->getError();
5118}
5119
5120extern "C"
5121void accDeleteScript(ACCscript* script) {
5122 delete script;
5123}
5124
5125extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005126void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5127 ACCvoid* pContext) {
5128 script->registerSymbolCallback(pFn, pContext);
5129}
5130
5131extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005132void accScriptSource(ACCscript* script,
5133 ACCsizei count,
5134 const ACCchar ** string,
5135 const ACCint * length) {
5136 int totalLength = 0;
5137 for(int i = 0; i < count; i++) {
5138 int len = -1;
5139 const ACCchar* s = string[i];
5140 if (length) {
5141 len = length[i];
5142 }
5143 if (len < 0) {
5144 len = strlen(s);
5145 }
5146 totalLength += len;
5147 }
5148 delete script->text;
5149 char* text = new char[totalLength + 1];
5150 script->text = text;
5151 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005152 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005153 for(int i = 0; i < count; i++) {
5154 int len = -1;
5155 const ACCchar* s = string[i];
5156 if (length) {
5157 len = length[i];
5158 }
5159 if (len < 0) {
5160 len = strlen(s);
5161 }
Jack Palevich09555c72009-05-27 12:25:55 -07005162 memcpy(dest, s, len);
5163 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005164 }
5165 text[totalLength] = '\0';
5166}
5167
5168extern "C"
5169void accCompileScript(ACCscript* script) {
5170 int result = script->compiler.compile(script->text, script->textLength);
5171 if (result) {
5172 script->setError(ACC_INVALID_OPERATION);
5173 }
5174}
5175
5176extern "C"
5177void accGetScriptiv(ACCscript* script,
5178 ACCenum pname,
5179 ACCint * params) {
5180 switch (pname) {
5181 case ACC_INFO_LOG_LENGTH:
5182 *params = 0;
5183 break;
5184 }
5185}
5186
5187extern "C"
5188void accGetScriptInfoLog(ACCscript* script,
5189 ACCsizei maxLength,
5190 ACCsizei * length,
5191 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005192 char* message = script->compiler.getErrorMessage();
5193 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005194 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005195 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005196 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005197 if (infoLog && maxLength > 0) {
5198 int trimmedLength = maxLength < messageLength ?
5199 maxLength : messageLength;
5200 memcpy(infoLog, message, trimmedLength);
5201 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005202 }
5203}
5204
5205extern "C"
5206void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5207 ACCvoid ** address) {
5208 void* value = script->compiler.lookup(name);
5209 if (value) {
5210 *address = value;
5211 } else {
5212 script->setError(ACC_INVALID_VALUE);
5213 }
5214}
5215
Jack Palevicheedf9d22009-06-04 16:23:40 -07005216extern "C"
5217void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5218 ACCsizei maxStringCount, ACCchar** strings){
5219 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5220}
5221
-b master422972c2009-06-17 19:13:52 -07005222extern "C"
5223void accDisassemble(ACCscript* script) {
5224 script->compiler.disassemble(stderr);
5225}
5226
Jack Palevicheedf9d22009-06-04 16:23:40 -07005227
Jack Palevich1cdef202009-05-22 12:06:27 -07005228} // namespace acc
5229