blob: da703a705870d29cba7a1e3e5d84b216749b9be3 [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
Jack Palevich9f51a262009-07-29 16:22:26 -070051#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.
Jack Palevich9f51a262009-07-29 16:22:26 -0700384 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700385 * et is ET_RVALUE for things like string constants, ET_LVALUE for
386 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700388 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich9f51a262009-07-29 16:22:26 -0700390 /* Load the pc-relative address of a forward-referenced variable to R0.
391 * Return the address of the 4-byte constant so that it can be filled
392 * in later.
393 */
394 virtual int leaForward(int ea, Type* pPointerType) = 0;
395
Jack Palevich8df46192009-07-07 14:48:51 -0700396 /**
397 * Convert R0 to the given type.
398 */
399 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700400
Jack Palevich1cdef202009-05-22 12:06:27 -0700401 /* Emit code to adjust the stack for a function call. Return the
402 * label for the address of the instruction that adjusts the
403 * stack size. This will be passed as argument "a" to
404 * endFunctionCallArguments.
405 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700406 virtual int beginFunctionCallArguments() = 0;
407
Jack Palevich1cdef202009-05-22 12:06:27 -0700408 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700409 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700411 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700412
Jack Palevich1cdef202009-05-22 12:06:27 -0700413 /* Patch the function call preamble.
414 * a is the address returned from beginFunctionCallArguments
415 * l is the number of bytes the arguments took on the stack.
416 * Typically you would also emit code to convert the argument
417 * list into whatever the native function calling convention is.
418 * On ARM for example you would pop the first 5 arguments into
419 * R0..R4
420 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700421 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700422
Jack Palevich1cdef202009-05-22 12:06:27 -0700423 /* Emit a call to an unknown function. The argument "symbol" needs to
424 * be stored in the location where the address should go. It forms
425 * a chain. The address will be patched later.
426 * Return the address of the word that has to be patched.
427 */
Jack Palevich8df46192009-07-07 14:48:51 -0700428 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700429
Jack Palevich1cdef202009-05-22 12:06:27 -0700430 /* Call a function pointer. L is the number of bytes the arguments
431 * take on the stack. The address of the function is stored at
432 * location SP + l.
433 */
Jack Palevich8df46192009-07-07 14:48:51 -0700434 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700435
Jack Palevich1cdef202009-05-22 12:06:27 -0700436 /* Adjust SP after returning from a function call. l is the
437 * number of bytes of arguments stored on the stack. isIndirect
438 * is true if this was an indirect call. (In which case the
439 * address of the function is stored at location SP + l.)
440 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700441 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700442
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 /* Print a disassembly of the assembled code to out. Return
444 * non-zero if there is an error.
445 */
Jack Palevicha6535612009-05-13 16:24:17 -0700446 virtual int disassemble(FILE* out) = 0;
447
Jack Palevich1cdef202009-05-22 12:06:27 -0700448 /* Generate a symbol at the current PC. t is the head of a
449 * linked list of addresses to patch.
450 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700451 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700452
Jack Palevich9f51a262009-07-29 16:22:26 -0700453 /* Resolve a forward reference function at the current PC.
454 * t is the head of a
455 * linked list of addresses to patch.
456 * (Like gsym, but using absolute address, not PC relative address.)
457 */
458 virtual void resolveForward(int t) = 0;
459
Jack Palevich1cdef202009-05-22 12:06:27 -0700460 /*
461 * Do any cleanup work required at the end of a compile.
462 * For example, an instruction cache might need to be
463 * invalidated.
464 * Return non-zero if there is an error.
465 */
466 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700467
Jack Palevicha6535612009-05-13 16:24:17 -0700468 /**
469 * Adjust relative branches by this amount.
470 */
471 virtual int jumpOffset() = 0;
472
Jack Palevich9eed7a22009-07-06 17:24:34 -0700473 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700474 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700475 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700476 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700477
478 /**
479 * Array element alignment (in bytes) for this type of data.
480 */
481 virtual size_t sizeOf(Type* type) = 0;
482
Jack Palevich9cbd2262009-07-08 16:48:41 -0700483 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700484 * Stack alignment of this type of data
485 */
486 virtual size_t stackAlignmentOf(Type* pType) = 0;
487
488 /**
489 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700490 */
491 virtual size_t stackSizeOf(Type* pType) = 0;
492
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700493 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700494 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700495 }
496
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700497 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700498 return mExpressionStack.back().et;
499 }
500
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700501 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700502 mExpressionStack.back().et = et;
503 }
504
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700505 virtual size_t getExpressionStackDepth() {
506 return mExpressionStack.size();
507 }
508
Jack Palevichb5e33312009-07-30 19:06:34 -0700509 virtual void forceR0RVal() {
510 if (getR0ExpressionType() == ET_LVALUE) {
511 loadR0FromR0();
512 }
513 }
514
Jack Palevich21a15a22009-05-11 14:49:29 -0700515 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700516 /*
517 * Output a byte. Handles all values, 0..ff.
518 */
519 void ob(int n) {
520 pCodeBuf->ob(n);
521 }
522
Jack Palevich8b0624c2009-05-20 12:12:06 -0700523 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700524 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700525 }
526
Jack Palevich8b0624c2009-05-20 12:12:06 -0700527 intptr_t getBase() {
528 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700529 }
530
Jack Palevich8b0624c2009-05-20 12:12:06 -0700531 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700532 return pCodeBuf->getPC();
533 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700534
535 intptr_t getSize() {
536 return pCodeBuf->getSize();
537 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700538
539 void error(const char* fmt,...) {
540 va_list ap;
541 va_start(ap, fmt);
542 mErrorSink->verror(fmt, ap);
543 va_end(ap);
544 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700545
546 void assert(bool test) {
547 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700548 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700549 error("code generator assertion failed.");
550 }
551 }
Jack Palevich8df46192009-07-07 14:48:51 -0700552
553 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700554 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700555 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700556 mExpressionStack.back().et = ET_RVALUE;
557 }
558
559 void setR0Type(Type* pType, ExpressionType et) {
560 assert(pType != NULL);
561 mExpressionStack.back().pType = pType;
562 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700563 }
564
Jack Palevich8df46192009-07-07 14:48:51 -0700565 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700566 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700567 }
568
569 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700570 if (mExpressionStack.size()) {
571 mExpressionStack.push_back(mExpressionStack.back());
572 } else {
573 mExpressionStack.push_back(ExpressionValue());
574 }
575
Jack Palevich8df46192009-07-07 14:48:51 -0700576 }
577
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700578 void overType() {
579 size_t size = mExpressionStack.size();
580 if (size >= 2) {
581 mExpressionStack.push_back(mExpressionStack.back());
582 mExpressionStack[size-1] = mExpressionStack[size-2];
583 mExpressionStack[size-2] = mExpressionStack[size];
584 }
585 }
586
Jack Palevich8df46192009-07-07 14:48:51 -0700587 void popType() {
588 mExpressionStack.pop_back();
589 }
590
591 bool bitsSame(Type* pA, Type* pB) {
592 return collapseType(pA->tag) == collapseType(pB->tag);
593 }
594
595 TypeTag collapseType(TypeTag tag) {
596 static const TypeTag collapsedTag[] = {
597 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
598 TY_VOID, TY_VOID};
599 return collapsedTag[tag];
600 }
601
Jack Palevich1a539db2009-07-08 13:04:41 -0700602 TypeTag collapseTypeR0() {
603 return collapseType(getR0Type()->tag);
604 }
605
606 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700607 return isFloatTag(pType->tag);
608 }
609
610 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700611 return tag == TY_FLOAT || tag == TY_DOUBLE;
612 }
613
Jack Palevicha8f427f2009-07-13 18:40:08 -0700614 Type* mkpInt;
615
Jack Palevich21a15a22009-05-11 14:49:29 -0700616 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700617 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700618 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700619 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700620 };
621
Jack Paleviche7b59062009-05-19 17:12:17 -0700622#ifdef PROVIDE_ARM_CODEGEN
623
Jack Palevich22305132009-05-13 10:58:45 -0700624 class ARMCodeGenerator : public CodeGenerator {
625 public:
626 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700627
Jack Palevich22305132009-05-13 10:58:45 -0700628 virtual ~ARMCodeGenerator() {}
629
630 /* returns address to patch with local variable size
631 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700632 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700633 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700634 // sp -> arg4 arg5 ...
635 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700636 int regArgCount = calcRegArgCount(pDecl);
637 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700638 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700639 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700640 }
641 // sp -> arg0 arg1 ...
642 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700643 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700644 // sp, fp -> oldfp, retadr, arg0 arg1 ....
645 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700646 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700647 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700648 // We don't know how many local variables we are going to use,
649 // but we will round the allocation up to a multiple of
650 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700651 }
652
Jack Palevichb7718b92009-07-09 22:00:24 -0700653 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700654 // Round local variable size up to a multiple of stack alignment
655 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
656 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700657 // Patch local variable allocation code:
658 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700659 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700660 }
Jack Palevich69796b62009-05-14 15:42:26 -0700661 *(char*) (localVariableAddress) = localVariableSize;
662
663 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
664 o4(0xE1A0E00B); // mov lr, fp
665 o4(0xE59BB000); // ldr fp, [fp]
666 o4(0xE28ED004); // add sp, lr, #4
667 // sp -> retadr, arg0, ...
668 o4(0xE8BD4000); // ldmfd sp!, {lr}
669 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700670
671 // We store the PC into the lr so we can adjust the sp before
672 // returning. We need to pull off the registers we pushed
673 // earlier. We don't need to actually store them anywhere,
674 // just adjust the stack.
675 int regArgCount = calcRegArgCount(pDecl);
676 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700677 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
678 }
679 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700680 }
681
682 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700683 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700684 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700685 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700686 }
687
Jack Palevich1a539db2009-07-08 13:04:41 -0700688 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700689 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700690 // Global, absolute address
691 o4(0xE59F0000); // ldr r0, .L1
692 o4(0xEA000000); // b .L99
693 o4(address); // .L1: .word ea
694 // .L99:
695
696 switch (pType->tag) {
697 case TY_FLOAT:
698 o4(0xE5900000); // ldr r0, [r0]
699 break;
700 case TY_DOUBLE:
701 o4(0xE1C000D0); // ldrd r0, [r0]
702 break;
703 default:
704 assert(false);
705 break;
706 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700707 }
708
Jack Palevich22305132009-05-13 10:58:45 -0700709 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700710 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700711 }
712
713 /* l = 0: je, l == 1: jne */
714 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700715 Type* pR0Type = getR0Type();
716 TypeTag tagR0 = pR0Type->tag;
717 switch(tagR0) {
718 case TY_FLOAT:
719 callRuntime((void*) runtime_is_non_zero_f);
720 break;
721 case TY_DOUBLE:
722 callRuntime((void*) runtime_is_non_zero_d);
723 break;
724 default:
725 break;
726 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700727 o4(0xE3500000); // cmp r0,#0
728 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
729 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700730 }
731
Jack Palevich58c30ee2009-07-17 16:35:23 -0700732 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700733 Type* pR0Type = getR0Type();
734 Type* pTOSType = getTOSType();
735 TypeTag tagR0 = collapseType(pR0Type->tag);
736 TypeTag tagTOS = collapseType(pTOSType->tag);
737 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700738 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700739 o4(0xE1510000); // cmp r1, r1
740 switch(op) {
741 case OP_EQUALS:
742 o4(0x03A00001); // moveq r0,#1
743 o4(0x13A00000); // movne r0,#0
744 break;
745 case OP_NOT_EQUALS:
746 o4(0x03A00000); // moveq r0,#0
747 o4(0x13A00001); // movne r0,#1
748 break;
749 case OP_LESS_EQUAL:
750 o4(0xD3A00001); // movle r0,#1
751 o4(0xC3A00000); // movgt r0,#0
752 break;
753 case OP_GREATER:
754 o4(0xD3A00000); // movle r0,#0
755 o4(0xC3A00001); // movgt r0,#1
756 break;
757 case OP_GREATER_EQUAL:
758 o4(0xA3A00001); // movge r0,#1
759 o4(0xB3A00000); // movlt r0,#0
760 break;
761 case OP_LESS:
762 o4(0xA3A00000); // movge r0,#0
763 o4(0xB3A00001); // movlt r0,#1
764 break;
765 default:
766 error("Unknown comparison op %d", op);
767 break;
768 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700769 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
770 setupDoubleArgs();
771 switch(op) {
772 case OP_EQUALS:
773 callRuntime((void*) runtime_cmp_eq_dd);
774 break;
775 case OP_NOT_EQUALS:
776 callRuntime((void*) runtime_cmp_ne_dd);
777 break;
778 case OP_LESS_EQUAL:
779 callRuntime((void*) runtime_cmp_le_dd);
780 break;
781 case OP_GREATER:
782 callRuntime((void*) runtime_cmp_gt_dd);
783 break;
784 case OP_GREATER_EQUAL:
785 callRuntime((void*) runtime_cmp_ge_dd);
786 break;
787 case OP_LESS:
788 callRuntime((void*) runtime_cmp_lt_dd);
789 break;
790 default:
791 error("Unknown comparison op %d", op);
792 break;
793 }
794 } else {
795 setupFloatArgs();
796 switch(op) {
797 case OP_EQUALS:
798 callRuntime((void*) runtime_cmp_eq_ff);
799 break;
800 case OP_NOT_EQUALS:
801 callRuntime((void*) runtime_cmp_ne_ff);
802 break;
803 case OP_LESS_EQUAL:
804 callRuntime((void*) runtime_cmp_le_ff);
805 break;
806 case OP_GREATER:
807 callRuntime((void*) runtime_cmp_gt_ff);
808 break;
809 case OP_GREATER_EQUAL:
810 callRuntime((void*) runtime_cmp_ge_ff);
811 break;
812 case OP_LESS:
813 callRuntime((void*) runtime_cmp_lt_ff);
814 break;
815 default:
816 error("Unknown comparison op %d", op);
817 break;
818 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700819 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700820 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700821 }
822
Jack Palevich546b2242009-05-13 15:10:04 -0700823 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700824 Type* pR0Type = getR0Type();
825 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700826 TypeTag tagR0 = pR0Type->tag;
827 TypeTag tagTOS = pTOSType->tag;
828 bool isFloatR0 = isFloatTag(tagR0);
829 bool isFloatTOS = isFloatTag(tagTOS);
830 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700831 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700832 bool isPtrR0 = tagR0 == TY_POINTER;
833 bool isPtrTOS = tagTOS == TY_POINTER;
834 if (isPtrR0 || isPtrTOS) {
835 if (isPtrR0 && isPtrTOS) {
836 if (op != OP_MINUS) {
837 error("Unsupported pointer-pointer operation %d.", op);
838 }
839 if (! typeEqual(pR0Type, pTOSType)) {
840 error("Incompatible pointer types for subtraction.");
841 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700842 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700843 setR0Type(mkpInt);
844 int size = sizeOf(pR0Type->pHead);
845 if (size != 1) {
846 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700847 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700848 // TODO: Optimize for power-of-two.
849 genOp(OP_DIV);
850 }
851 } else {
852 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
853 error("Unsupported pointer-scalar operation %d", op);
854 }
855 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700856 int size = sizeOf(pPtrType->pHead);
857 if (size != 1) {
858 // TODO: Optimize for power-of-two.
859 liReg(size, 2);
860 if (isPtrR0) {
861 o4(0x0E0010192); // mul r1,r2,r1
862 } else {
863 o4(0x0E0000092); // mul r0,r2,r0
864 }
865 }
866 switch(op) {
867 case OP_PLUS:
868 o4(0xE0810000); // add r0,r1,r0
869 break;
870 case OP_MINUS:
871 o4(0xE0410000); // sub r0,r1,r0
872 break;
873 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700874 setR0Type(pPtrType);
875 }
876 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700877 switch(op) {
878 case OP_MUL:
879 o4(0x0E0000091); // mul r0,r1,r0
880 break;
881 case OP_DIV:
882 callRuntime((void*) runtime_DIV);
883 break;
884 case OP_MOD:
885 callRuntime((void*) runtime_MOD);
886 break;
887 case OP_PLUS:
888 o4(0xE0810000); // add r0,r1,r0
889 break;
890 case OP_MINUS:
891 o4(0xE0410000); // sub r0,r1,r0
892 break;
893 case OP_SHIFT_LEFT:
894 o4(0xE1A00011); // lsl r0,r1,r0
895 break;
896 case OP_SHIFT_RIGHT:
897 o4(0xE1A00051); // asr r0,r1,r0
898 break;
899 case OP_BIT_AND:
900 o4(0xE0010000); // and r0,r1,r0
901 break;
902 case OP_BIT_XOR:
903 o4(0xE0210000); // eor r0,r1,r0
904 break;
905 case OP_BIT_OR:
906 o4(0xE1810000); // orr r0,r1,r0
907 break;
908 case OP_BIT_NOT:
909 o4(0xE1E00000); // mvn r0, r0
910 break;
911 default:
912 error("Unimplemented op %d\n", op);
913 break;
914 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700915 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700916 } else {
917 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
918 if (pResultType->tag == TY_DOUBLE) {
919 setupDoubleArgs();
920 switch(op) {
921 case OP_MUL:
922 callRuntime((void*) runtime_op_mul_dd);
923 break;
924 case OP_DIV:
925 callRuntime((void*) runtime_op_div_dd);
926 break;
927 case OP_PLUS:
928 callRuntime((void*) runtime_op_add_dd);
929 break;
930 case OP_MINUS:
931 callRuntime((void*) runtime_op_sub_dd);
932 break;
933 default:
934 error("Unsupported binary floating operation %d\n", op);
935 break;
936 }
937 } else {
938 setupFloatArgs();
939 switch(op) {
940 case OP_MUL:
941 callRuntime((void*) runtime_op_mul_ff);
942 break;
943 case OP_DIV:
944 callRuntime((void*) runtime_op_div_ff);
945 break;
946 case OP_PLUS:
947 callRuntime((void*) runtime_op_add_ff);
948 break;
949 case OP_MINUS:
950 callRuntime((void*) runtime_op_sub_ff);
951 break;
952 default:
953 error("Unsupported binary floating operation %d\n", op);
954 break;
955 }
956 }
957 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700958 }
Jack Palevich22305132009-05-13 10:58:45 -0700959 }
960
Jack Palevich58c30ee2009-07-17 16:35:23 -0700961 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700962 if (op != OP_LOGICAL_NOT) {
963 error("Unknown unary cmp %d", op);
964 } else {
965 Type* pR0Type = getR0Type();
966 TypeTag tag = collapseType(pR0Type->tag);
967 switch(tag) {
968 case TY_INT:
969 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700970 o4(0xE1510000); // cmp r1, r0
971 o4(0x03A00001); // moveq r0,#1
972 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700973 break;
974 case TY_FLOAT:
975 callRuntime((void*) runtime_is_zero_f);
976 break;
977 case TY_DOUBLE:
978 callRuntime((void*) runtime_is_zero_d);
979 break;
980 default:
981 error("gUnaryCmp unsupported type");
982 break;
983 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700984 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700985 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700986 }
987
988 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700989 Type* pR0Type = getR0Type();
990 TypeTag tag = collapseType(pR0Type->tag);
991 switch(tag) {
992 case TY_INT:
993 switch(op) {
994 case OP_MINUS:
995 o4(0xE3A01000); // mov r1, #0
996 o4(0xE0410000); // sub r0,r1,r0
997 break;
998 case OP_BIT_NOT:
999 o4(0xE1E00000); // mvn r0, r0
1000 break;
1001 default:
1002 error("Unknown unary op %d\n", op);
1003 break;
1004 }
1005 break;
1006 case TY_FLOAT:
1007 case TY_DOUBLE:
1008 switch (op) {
1009 case OP_MINUS:
1010 if (tag == TY_FLOAT) {
1011 callRuntime((void*) runtime_op_neg_f);
1012 } else {
1013 callRuntime((void*) runtime_op_neg_d);
1014 }
1015 break;
1016 case OP_BIT_NOT:
1017 error("Can't apply '~' operator to a float or double.");
1018 break;
1019 default:
1020 error("Unknown unary op %d\n", op);
1021 break;
1022 }
1023 break;
1024 default:
1025 error("genUnaryOp unsupported type");
1026 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001027 }
Jack Palevich22305132009-05-13 10:58:45 -07001028 }
1029
Jack Palevich1cdef202009-05-22 12:06:27 -07001030 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001031 Type* pR0Type = getR0Type();
1032 TypeTag r0ct = collapseType(pR0Type->tag);
1033 if (r0ct != TY_DOUBLE) {
1034 o4(0xE92D0001); // stmfd sp!,{r0}
1035 mStackUse += 4;
1036 } else {
1037 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1038 mStackUse += 8;
1039 }
Jack Palevich8df46192009-07-07 14:48:51 -07001040 pushType();
-b master422972c2009-06-17 19:13:52 -07001041 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001042 }
1043
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001044 virtual void over() {
1045 // We know it's only used for int-ptr ops (++/--)
1046
1047 Type* pR0Type = getR0Type();
1048 TypeTag r0ct = collapseType(pR0Type->tag);
1049
1050 Type* pTOSType = getTOSType();
1051 TypeTag tosct = collapseType(pTOSType->tag);
1052
1053 assert (r0ct == TY_INT && tosct == TY_INT);
1054
1055 o4(0xE8BD0002); // ldmfd sp!,{r1}
1056 o4(0xE92D0001); // stmfd sp!,{r0}
1057 o4(0xE92D0002); // stmfd sp!,{r1}
1058 overType();
1059 mStackUse += 4;
1060 }
1061
Jack Palevich58c30ee2009-07-17 16:35:23 -07001062 virtual void popR0() {
1063 Type* pTOSType = getTOSType();
1064 switch (collapseType(pTOSType->tag)){
1065 case TY_INT:
1066 case TY_FLOAT:
1067 o4(0xE8BD0001); // ldmfd sp!,{r0}
1068 mStackUse -= 4;
1069 break;
1070 case TY_DOUBLE:
1071 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1072 mStackUse -= 8;
1073 break;
1074 default:
1075 error("Can't pop this type.");
1076 break;
1077 }
1078 popType();
1079 LOG_STACK("popR0: %d\n", mStackUse);
1080 }
1081
1082 virtual void storeR0ToTOS() {
1083 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001084 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001085 Type* pDestType = pPointerType->pHead;
1086 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001087 o4(0xE8BD0004); // ldmfd sp!,{r2}
1088 popType();
-b master422972c2009-06-17 19:13:52 -07001089 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001090 switch (pDestType->tag) {
1091 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001092 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001093 case TY_FLOAT:
1094 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001095 break;
1096 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001097 o4(0xE5C20000); // strb r0, [r2]
1098 break;
1099 case TY_DOUBLE:
1100 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001101 break;
1102 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001103 error("storeR0ToTOS: unimplemented type %d",
1104 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001105 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001106 }
Jack Palevich22305132009-05-13 10:58:45 -07001107 }
1108
Jack Palevich58c30ee2009-07-17 16:35:23 -07001109 virtual void loadR0FromR0() {
1110 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001111 assert(pPointerType->tag == TY_POINTER);
1112 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001113 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001114 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001115 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001116 o4(0xE5900000); // ldr r0, [r0]
1117 break;
1118 case TY_CHAR:
1119 o4(0xE5D00000); // ldrb r0, [r0]
1120 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001121 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001122 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001123 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001124 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001125 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001126 break;
1127 }
Jack Palevich8df46192009-07-07 14:48:51 -07001128 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001129 }
1130
Jack Palevichb5e33312009-07-30 19:06:34 -07001131 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001132 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001133 // Local, fp relative
1134 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1135 error("Offset out of range: %08x", ea);
1136 }
1137 if (ea < 0) {
1138 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1139 } else {
1140 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1141 }
Jack Palevichbd894902009-05-14 19:35:31 -07001142 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001143 // Global, absolute.
1144 o4(0xE59F0000); // ldr r0, .L1
1145 o4(0xEA000000); // b .L99
1146 o4(ea); // .L1: .word 0
1147 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001148 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001149 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001150 }
1151
Jack Palevich9f51a262009-07-29 16:22:26 -07001152 virtual int leaForward(int ea, Type* pPointerType) {
1153 setR0Type(pPointerType);
1154 int result = ea;
1155 int pc = getPC();
1156 int offset = 0;
1157 if (ea) {
1158 offset = (pc - ea - 8) >> 2;
1159 if ((offset & 0xffff) != offset) {
1160 error("function forward reference out of bounds");
1161 }
1162 } else {
1163 offset = 0;
1164 }
1165 o4(0xE59F0000 | offset); // ldr r0, .L1
1166
1167 if (ea == 0) {
1168 o4(0xEA000000); // b .L99
1169 result = o4(ea); // .L1: .word 0
1170 // .L99:
1171 }
1172 return result;
1173 }
1174
Jack Palevich8df46192009-07-07 14:48:51 -07001175 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001176 Type* pR0Type = getR0Type();
1177 if (bitsSame(pType, pR0Type)) {
1178 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001179 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001180 TypeTag r0Tag = collapseType(pR0Type->tag);
1181 TypeTag destTag = collapseType(pType->tag);
1182 if (r0Tag == TY_INT) {
1183 if (destTag == TY_FLOAT) {
1184 callRuntime((void*) runtime_int_to_float);
1185 } else {
1186 assert(destTag == TY_DOUBLE);
1187 callRuntime((void*) runtime_int_to_double);
1188 }
1189 } else if (r0Tag == TY_FLOAT) {
1190 if (destTag == TY_INT) {
1191 callRuntime((void*) runtime_float_to_int);
1192 } else {
1193 assert(destTag == TY_DOUBLE);
1194 callRuntime((void*) runtime_float_to_double);
1195 }
1196 } else {
1197 assert (r0Tag == TY_DOUBLE);
1198 if (destTag == TY_INT) {
1199 callRuntime((void*) runtime_double_to_int);
1200 } else {
1201 assert(destTag == TY_FLOAT);
1202 callRuntime((void*) runtime_double_to_float);
1203 }
1204 }
Jack Palevich8df46192009-07-07 14:48:51 -07001205 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001206 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001207 }
1208
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001209 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001210 return o4(0xE24DDF00); // Placeholder
1211 }
1212
Jack Palevich8148c5b2009-07-16 18:24:47 -07001213 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001214 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001215 Type* pR0Type = getR0Type();
1216 TypeTag r0ct = collapseType(pR0Type->tag);
1217 switch(r0ct) {
1218 case TY_INT:
1219 case TY_FLOAT:
1220 if (l < 0 || l > 4096-4) {
1221 error("l out of range for stack offset: 0x%08x", l);
1222 }
1223 o4(0xE58D0000 + l); // str r0, [sp, #l]
1224 return 4;
1225 case TY_DOUBLE: {
1226 // Align to 8 byte boundary
1227 int l2 = (l + 7) & ~7;
1228 if (l2 < 0 || l2 > 4096-8) {
1229 error("l out of range for stack offset: 0x%08x", l);
1230 }
1231 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1232 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1233 return (l2 - l) + 8;
1234 }
1235 default:
1236 assert(false);
1237 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001238 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001239 }
1240
Jack Palevichb7718b92009-07-09 22:00:24 -07001241 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001242 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001243 // Have to calculate register arg count from actual stack size,
1244 // in order to properly handle ... functions.
1245 int regArgCount = l >> 2;
1246 if (regArgCount > 4) {
1247 regArgCount = 4;
1248 }
1249 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001250 argumentStackUse -= regArgCount * 4;
1251 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1252 }
1253 mStackUse += argumentStackUse;
1254
1255 // Align stack.
1256 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1257 * STACK_ALIGNMENT);
1258 mStackAlignmentAdjustment = 0;
1259 if (missalignment > 0) {
1260 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1261 }
1262 l += mStackAlignmentAdjustment;
1263
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001264 if (l < 0 || l > 0x3FC) {
1265 error("L out of range for stack adjustment: 0x%08x", l);
1266 }
1267 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001268 mStackUse += mStackAlignmentAdjustment;
1269 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1270 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001271 }
1272
Jack Palevich8df46192009-07-07 14:48:51 -07001273 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001274 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001275 // Forward calls are always short (local)
1276 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001277 }
1278
Jack Palevich8df46192009-07-07 14:48:51 -07001279 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001280 assert(pFunc->tag == TY_FUNC);
1281 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001282 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001283 int argCount = l >> 2;
1284 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001285 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001286 if (adjustedL < 0 || adjustedL > 4096-4) {
1287 error("l out of range for stack offset: 0x%08x", l);
1288 }
1289 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1290 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001291 }
1292
Jack Palevichb7718b92009-07-09 22:00:24 -07001293 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001294 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001295 // Have to calculate register arg count from actual stack size,
1296 // in order to properly handle ... functions.
1297 int regArgCount = l >> 2;
1298 if (regArgCount > 4) {
1299 regArgCount = 4;
1300 }
1301 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001302 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1303 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001304 if (stackUse) {
1305 if (stackUse < 0 || stackUse > 255) {
1306 error("L out of range for stack adjustment: 0x%08x", l);
1307 }
1308 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001309 mStackUse -= stackUse * 4;
1310 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001311 }
Jack Palevich22305132009-05-13 10:58:45 -07001312 }
1313
Jack Palevicha6535612009-05-13 16:24:17 -07001314 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001315 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001316 }
1317
1318 /* output a symbol and patch all calls to it */
1319 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001320 int n;
1321 int base = getBase();
1322 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001323 while (t) {
1324 int data = * (int*) t;
1325 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1326 if (decodedOffset == 0) {
1327 n = 0;
1328 } else {
1329 n = base + decodedOffset; /* next value */
1330 }
1331 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1332 | encodeRelAddress(pc - t - 8);
1333 t = n;
1334 }
1335 }
1336
Jack Palevich9f51a262009-07-29 16:22:26 -07001337 /* output a symbol and patch all calls to it */
1338 virtual void resolveForward(int t) {
1339 if (t) {
1340 int pc = getPC();
1341 *(int *) t = pc;
1342 }
1343 }
1344
Jack Palevich1cdef202009-05-22 12:06:27 -07001345 virtual int finishCompile() {
1346#if defined(__arm__)
1347 const long base = long(getBase());
1348 const long curr = long(getPC());
1349 int err = cacheflush(base, curr, 0);
1350 return err;
1351#else
1352 return 0;
1353#endif
1354 }
1355
Jack Palevicha6535612009-05-13 16:24:17 -07001356 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001357#ifdef ENABLE_ARM_DISASSEMBLY
1358 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001359 disasm_interface_t di;
1360 di.di_readword = disassemble_readword;
1361 di.di_printaddr = disassemble_printaddr;
1362 di.di_printf = disassemble_printf;
1363
1364 int base = getBase();
1365 int pc = getPC();
1366 for(int i = base; i < pc; i += 4) {
1367 fprintf(out, "%08x: %08x ", i, *(int*) i);
1368 ::disasm(&di, i, 0);
1369 }
Jack Palevich09555c72009-05-27 12:25:55 -07001370#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001371 return 0;
1372 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001373
Jack Palevich9eed7a22009-07-06 17:24:34 -07001374 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001375 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001376 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001377 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001378 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001379 case TY_CHAR:
1380 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001381 case TY_DOUBLE:
1382 return 8;
1383 default:
1384 return 4;
1385 }
1386 }
1387
1388 /**
1389 * Array element alignment (in bytes) for this type of data.
1390 */
1391 virtual size_t sizeOf(Type* pType){
1392 switch(pType->tag) {
1393 case TY_INT:
1394 return 4;
1395 case TY_CHAR:
1396 return 1;
1397 default:
1398 return 0;
1399 case TY_FLOAT:
1400 return 4;
1401 case TY_DOUBLE:
1402 return 8;
1403 case TY_POINTER:
1404 return 4;
1405 }
1406 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001407
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001408 virtual size_t stackAlignmentOf(Type* pType) {
1409 switch(pType->tag) {
1410 case TY_DOUBLE:
1411 return 8;
1412 default:
1413 return 4;
1414 }
1415 }
1416
Jack Palevich9cbd2262009-07-08 16:48:41 -07001417 virtual size_t stackSizeOf(Type* pType) {
1418 switch(pType->tag) {
1419 case TY_DOUBLE:
1420 return 8;
1421 default:
1422 return 4;
1423 }
1424 }
1425
Jack Palevich22305132009-05-13 10:58:45 -07001426 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001427 static FILE* disasmOut;
1428
1429 static u_int
1430 disassemble_readword(u_int address)
1431 {
1432 return(*((u_int *)address));
1433 }
1434
1435 static void
1436 disassemble_printaddr(u_int address)
1437 {
1438 fprintf(disasmOut, "0x%08x", address);
1439 }
1440
1441 static void
1442 disassemble_printf(const char *fmt, ...) {
1443 va_list ap;
1444 va_start(ap, fmt);
1445 vfprintf(disasmOut, fmt, ap);
1446 va_end(ap);
1447 }
1448
1449 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1450
1451 /** Encode a relative address that might also be
1452 * a label.
1453 */
1454 int encodeAddress(int value) {
1455 int base = getBase();
1456 if (value >= base && value <= getPC() ) {
1457 // This is a label, encode it relative to the base.
1458 value = value - base;
1459 }
1460 return encodeRelAddress(value);
1461 }
1462
1463 int encodeRelAddress(int value) {
1464 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1465 }
Jack Palevich22305132009-05-13 10:58:45 -07001466
Jack Palevichb7718b92009-07-09 22:00:24 -07001467 int calcRegArgCount(Type* pDecl) {
1468 int reg = 0;
1469 Type* pArgs = pDecl->pTail;
1470 while (pArgs && reg < 4) {
1471 Type* pArg = pArgs->pHead;
1472 if ( pArg->tag == TY_DOUBLE) {
1473 int evenReg = (reg + 1) & ~1;
1474 if (evenReg >= 4) {
1475 break;
1476 }
1477 reg = evenReg + 2;
1478 } else {
1479 reg++;
1480 }
1481 pArgs = pArgs->pTail;
1482 }
1483 return reg;
1484 }
1485
Jack Palevich58c30ee2009-07-17 16:35:23 -07001486 void setupIntPtrArgs() {
1487 o4(0xE8BD0002); // ldmfd sp!,{r1}
1488 mStackUse -= 4;
1489 popType();
1490 }
1491
Jack Palevichb7718b92009-07-09 22:00:24 -07001492 /* Pop TOS to R1
1493 * Make sure both R0 and TOS are floats. (Could be ints)
1494 * We know that at least one of R0 and TOS is already a float
1495 */
1496 void setupFloatArgs() {
1497 Type* pR0Type = getR0Type();
1498 Type* pTOSType = getTOSType();
1499 TypeTag tagR0 = collapseType(pR0Type->tag);
1500 TypeTag tagTOS = collapseType(pTOSType->tag);
1501 if (tagR0 != TY_FLOAT) {
1502 assert(tagR0 == TY_INT);
1503 callRuntime((void*) runtime_int_to_float);
1504 }
1505 if (tagTOS != TY_FLOAT) {
1506 assert(tagTOS == TY_INT);
1507 assert(tagR0 == TY_FLOAT);
1508 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1509 o4(0xE59D0004); // ldr r0, [sp, #4]
1510 callRuntime((void*) runtime_int_to_float);
1511 o4(0xE1A01000); // mov r1, r0
1512 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1513 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1514 } else {
1515 // Pop TOS
1516 o4(0xE8BD0002); // ldmfd sp!,{r1}
1517 }
1518 mStackUse -= 4;
1519 popType();
1520 }
1521
1522 /* Pop TOS into R2..R3
1523 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1524 * We know that at least one of R0 and TOS are already a double.
1525 */
1526
1527 void setupDoubleArgs() {
1528 Type* pR0Type = getR0Type();
1529 Type* pTOSType = getTOSType();
1530 TypeTag tagR0 = collapseType(pR0Type->tag);
1531 TypeTag tagTOS = collapseType(pTOSType->tag);
1532 if (tagR0 != TY_DOUBLE) {
1533 if (tagR0 == TY_INT) {
1534 callRuntime((void*) runtime_int_to_double);
1535 } else {
1536 assert(tagR0 == TY_FLOAT);
1537 callRuntime((void*) runtime_float_to_double);
1538 }
1539 }
1540 if (tagTOS != TY_DOUBLE) {
1541 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1542 o4(0xE59D0008); // ldr r0, [sp, #8]
1543 if (tagTOS == TY_INT) {
1544 callRuntime((void*) runtime_int_to_double);
1545 } else {
1546 assert(tagTOS == TY_FLOAT);
1547 callRuntime((void*) runtime_float_to_double);
1548 }
1549 o4(0xE1A02000); // mov r2, r0
1550 o4(0xE1A03001); // mov r3, r1
1551 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1552 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1553 mStackUse -= 4;
1554 } else {
1555 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1556 mStackUse -= 8;
1557 }
1558 popType();
1559 }
1560
Jack Palevicha8f427f2009-07-13 18:40:08 -07001561 void liReg(int t, int reg) {
1562 assert(reg >= 0 && reg < 16);
1563 int rN = (reg & 0xf) << 12;
1564 if (t >= 0 && t < 255) {
1565 o4((0xE3A00000 + t) | rN); // mov rN, #0
1566 } else if (t >= -256 && t < 0) {
1567 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001568 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001569 } else {
1570 o4(0xE51F0000 | rN); // ldr rN, .L3
1571 o4(0xEA000000); // b .L99
1572 o4(t); // .L3: .word 0
1573 // .L99:
1574 }
1575 }
1576
Jack Palevichb7718b92009-07-09 22:00:24 -07001577 void callRuntime(void* fn) {
1578 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001579 o4(0xEA000000); // b .L99
1580 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001581 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001582 }
1583
Jack Palevichb7718b92009-07-09 22:00:24 -07001584 // Integer math:
1585
1586 static int runtime_DIV(int b, int a) {
1587 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001588 }
1589
Jack Palevichb7718b92009-07-09 22:00:24 -07001590 static int runtime_MOD(int b, int a) {
1591 return a % b;
1592 }
1593
1594 // Comparison to zero
1595
1596 static int runtime_is_non_zero_f(float a) {
1597 return a != 0;
1598 }
1599
1600 static int runtime_is_non_zero_d(double a) {
1601 return a != 0;
1602 }
1603
1604 // Comparison to zero
1605
1606 static int runtime_is_zero_f(float a) {
1607 return a == 0;
1608 }
1609
1610 static int runtime_is_zero_d(double a) {
1611 return a == 0;
1612 }
1613
1614 // Type conversion
1615
1616 static int runtime_float_to_int(float a) {
1617 return (int) a;
1618 }
1619
1620 static double runtime_float_to_double(float a) {
1621 return (double) a;
1622 }
1623
1624 static int runtime_double_to_int(double a) {
1625 return (int) a;
1626 }
1627
1628 static float runtime_double_to_float(double a) {
1629 return (float) a;
1630 }
1631
1632 static float runtime_int_to_float(int a) {
1633 return (float) a;
1634 }
1635
1636 static double runtime_int_to_double(int a) {
1637 return (double) a;
1638 }
1639
1640 // Comparisons float
1641
1642 static int runtime_cmp_eq_ff(float b, float a) {
1643 return a == b;
1644 }
1645
1646 static int runtime_cmp_ne_ff(float b, float a) {
1647 return a != b;
1648 }
1649
1650 static int runtime_cmp_lt_ff(float b, float a) {
1651 return a < b;
1652 }
1653
1654 static int runtime_cmp_le_ff(float b, float a) {
1655 return a <= b;
1656 }
1657
1658 static int runtime_cmp_ge_ff(float b, float a) {
1659 return a >= b;
1660 }
1661
1662 static int runtime_cmp_gt_ff(float b, float a) {
1663 return a > b;
1664 }
1665
1666 // Comparisons double
1667
1668 static int runtime_cmp_eq_dd(double b, double a) {
1669 return a == b;
1670 }
1671
1672 static int runtime_cmp_ne_dd(double b, double a) {
1673 return a != b;
1674 }
1675
1676 static int runtime_cmp_lt_dd(double b, double a) {
1677 return a < b;
1678 }
1679
1680 static int runtime_cmp_le_dd(double b, double a) {
1681 return a <= b;
1682 }
1683
1684 static int runtime_cmp_ge_dd(double b, double a) {
1685 return a >= b;
1686 }
1687
1688 static int runtime_cmp_gt_dd(double b, double a) {
1689 return a > b;
1690 }
1691
1692 // Math float
1693
1694 static float runtime_op_add_ff(float b, float a) {
1695 return a + b;
1696 }
1697
1698 static float runtime_op_sub_ff(float b, float a) {
1699 return a - b;
1700 }
1701
1702 static float runtime_op_mul_ff(float b, float a) {
1703 return a * b;
1704 }
1705
1706 static float runtime_op_div_ff(float b, float a) {
1707 return a / b;
1708 }
1709
1710 static float runtime_op_neg_f(float a) {
1711 return -a;
1712 }
1713
1714 // Math double
1715
1716 static double runtime_op_add_dd(double b, double a) {
1717 return a + b;
1718 }
1719
1720 static double runtime_op_sub_dd(double b, double a) {
1721 return a - b;
1722 }
1723
1724 static double runtime_op_mul_dd(double b, double a) {
1725 return a * b;
1726 }
1727
1728 static double runtime_op_div_dd(double b, double a) {
1729 return a / b;
1730 }
1731
1732 static double runtime_op_neg_d(double a) {
1733 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001734 }
-b master422972c2009-06-17 19:13:52 -07001735
1736 static const int STACK_ALIGNMENT = 8;
1737 int mStackUse;
1738 // This variable holds the amount we adjusted the stack in the most
1739 // recent endFunctionCallArguments call. It's examined by the
1740 // following adjustStackAfterCall call.
1741 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001742 };
1743
Jack Palevich09555c72009-05-27 12:25:55 -07001744#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001745
1746#ifdef PROVIDE_X86_CODEGEN
1747
Jack Palevich21a15a22009-05-11 14:49:29 -07001748 class X86CodeGenerator : public CodeGenerator {
1749 public:
1750 X86CodeGenerator() {}
1751 virtual ~X86CodeGenerator() {}
1752
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001753 /* returns address to patch with local variable size
1754 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001755 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001756 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1757 return oad(0xec81, 0); /* sub $xxx, %esp */
1758 }
1759
Jack Palevichb7718b92009-07-09 22:00:24 -07001760 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001761 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001762 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001763 }
1764
Jack Palevich21a15a22009-05-11 14:49:29 -07001765 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001766 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001767 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001768 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001769 }
1770
Jack Palevich1a539db2009-07-08 13:04:41 -07001771 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001772 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001773 switch (pType->tag) {
1774 case TY_FLOAT:
1775 oad(0x05D9, address); // flds
1776 break;
1777 case TY_DOUBLE:
1778 oad(0x05DD, address); // fldl
1779 break;
1780 default:
1781 assert(false);
1782 break;
1783 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001784 }
1785
Jack Palevich22305132009-05-13 10:58:45 -07001786 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001787 return psym(0xe9, t);
1788 }
1789
1790 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001791 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001792 Type* pR0Type = getR0Type();
1793 TypeTag tagR0 = pR0Type->tag;
1794 bool isFloatR0 = isFloatTag(tagR0);
1795 if (isFloatR0) {
1796 o(0xeed9); // fldz
1797 o(0xe9da); // fucompp
1798 o(0xe0df); // fnstsw %ax
1799 o(0x9e); // sahf
1800 } else {
1801 o(0xc085); // test %eax, %eax
1802 }
1803 // Use two output statements to generate one instruction.
1804 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001805 return psym(0x84 + l, t);
1806 }
1807
Jack Palevich58c30ee2009-07-17 16:35:23 -07001808 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001809 Type* pR0Type = getR0Type();
1810 Type* pTOSType = getTOSType();
1811 TypeTag tagR0 = pR0Type->tag;
1812 TypeTag tagTOS = pTOSType->tag;
1813 bool isFloatR0 = isFloatTag(tagR0);
1814 bool isFloatTOS = isFloatTag(tagTOS);
1815 if (!isFloatR0 && !isFloatTOS) {
1816 int t = decodeOp(op);
1817 o(0x59); /* pop %ecx */
1818 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001819 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001820 o(0x0f); /* setxx %al */
1821 o(t + 0x90);
1822 o(0xc0);
1823 popType();
1824 } else {
1825 setupFloatOperands();
1826 switch (op) {
1827 case OP_EQUALS:
1828 o(0xe9da); // fucompp
1829 o(0xe0df); // fnstsw %ax
1830 o(0x9e); // sahf
1831 o(0xc0940f); // sete %al
1832 o(0xc29b0f); // setnp %dl
1833 o(0xd021); // andl %edx, %eax
1834 break;
1835 case OP_NOT_EQUALS:
1836 o(0xe9da); // fucompp
1837 o(0xe0df); // fnstsw %ax
1838 o(0x9e); // sahf
1839 o(0xc0950f); // setne %al
1840 o(0xc29a0f); // setp %dl
1841 o(0xd009); // orl %edx, %eax
1842 break;
1843 case OP_GREATER_EQUAL:
1844 o(0xe9da); // fucompp
1845 o(0xe0df); // fnstsw %ax
1846 o(0x05c4f6); // testb $5, %ah
1847 o(0xc0940f); // sete %al
1848 break;
1849 case OP_LESS:
1850 o(0xc9d9); // fxch %st(1)
1851 o(0xe9da); // fucompp
1852 o(0xe0df); // fnstsw %ax
1853 o(0x9e); // sahf
1854 o(0xc0970f); // seta %al
1855 break;
1856 case OP_LESS_EQUAL:
1857 o(0xc9d9); // fxch %st(1)
1858 o(0xe9da); // fucompp
1859 o(0xe0df); // fnstsw %ax
1860 o(0x9e); // sahf
1861 o(0xc0930f); // setea %al
1862 break;
1863 case OP_GREATER:
1864 o(0xe9da); // fucompp
1865 o(0xe0df); // fnstsw %ax
1866 o(0x45c4f6); // testb $69, %ah
1867 o(0xc0940f); // sete %al
1868 break;
1869 default:
1870 error("Unknown comparison op");
1871 }
1872 o(0xc0b60f); // movzbl %al, %eax
1873 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001874 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001875 }
1876
Jack Palevich546b2242009-05-13 15:10:04 -07001877 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001878 Type* pR0Type = getR0Type();
1879 Type* pTOSType = getTOSType();
1880 TypeTag tagR0 = pR0Type->tag;
1881 TypeTag tagTOS = pTOSType->tag;
1882 bool isFloatR0 = isFloatTag(tagR0);
1883 bool isFloatTOS = isFloatTag(tagTOS);
1884 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001885 bool isPtrR0 = tagR0 == TY_POINTER;
1886 bool isPtrTOS = tagTOS == TY_POINTER;
1887 if (isPtrR0 || isPtrTOS) {
1888 if (isPtrR0 && isPtrTOS) {
1889 if (op != OP_MINUS) {
1890 error("Unsupported pointer-pointer operation %d.", op);
1891 }
1892 if (! typeEqual(pR0Type, pTOSType)) {
1893 error("Incompatible pointer types for subtraction.");
1894 }
1895 o(0x59); /* pop %ecx */
1896 o(decodeOp(op));
1897 popType();
1898 setR0Type(mkpInt);
1899 int size = sizeOf(pR0Type->pHead);
1900 if (size != 1) {
1901 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001902 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001903 // TODO: Optimize for power-of-two.
1904 genOp(OP_DIV);
1905 }
1906 } else {
1907 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1908 error("Unsupported pointer-scalar operation %d", op);
1909 }
1910 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1911 o(0x59); /* pop %ecx */
1912 int size = sizeOf(pPtrType->pHead);
1913 if (size != 1) {
1914 // TODO: Optimize for power-of-two.
1915 if (isPtrR0) {
1916 oad(0xC969, size); // imull $size, %ecx
1917 } else {
1918 oad(0xC069, size); // mul $size, %eax
1919 }
1920 }
1921 o(decodeOp(op));
1922 popType();
1923 setR0Type(pPtrType);
1924 }
1925 } else {
1926 o(0x59); /* pop %ecx */
1927 o(decodeOp(op));
1928 if (op == OP_MOD)
1929 o(0x92); /* xchg %edx, %eax */
1930 popType();
1931 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001932 } else {
1933 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1934 setupFloatOperands();
1935 // Both float. x87 R0 == left hand, x87 R1 == right hand
1936 switch (op) {
1937 case OP_MUL:
1938 o(0xc9de); // fmulp
1939 break;
1940 case OP_DIV:
1941 o(0xf1de); // fdivp
1942 break;
1943 case OP_PLUS:
1944 o(0xc1de); // faddp
1945 break;
1946 case OP_MINUS:
1947 o(0xe1de); // fsubp
1948 break;
1949 default:
1950 error("Unsupported binary floating operation.");
1951 break;
1952 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001953 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001954 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001955 }
1956
Jack Palevich58c30ee2009-07-17 16:35:23 -07001957 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001958 if (op != OP_LOGICAL_NOT) {
1959 error("Unknown unary cmp %d", op);
1960 } else {
1961 Type* pR0Type = getR0Type();
1962 TypeTag tag = collapseType(pR0Type->tag);
1963 switch(tag) {
1964 case TY_INT: {
1965 oad(0xb9, 0); /* movl $0, %ecx */
1966 int t = decodeOp(op);
1967 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001968 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001969 o(0x0f); /* setxx %al */
1970 o(t + 0x90);
1971 o(0xc0);
1972 }
1973 break;
1974 case TY_FLOAT:
1975 case TY_DOUBLE:
1976 o(0xeed9); // fldz
1977 o(0xe9da); // fucompp
1978 o(0xe0df); // fnstsw %ax
1979 o(0x9e); // sahf
1980 o(0xc0950f); // setne %al
1981 o(0xc29a0f); // setp %dl
1982 o(0xd009); // orl %edx, %eax
1983 o(0xc0b60f); // movzbl %al, %eax
1984 o(0x01f083); // xorl $1, %eax
1985 break;
1986 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001987 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07001988 break;
1989 }
1990 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001991 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001992 }
1993
1994 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001995 Type* pR0Type = getR0Type();
1996 TypeTag tag = collapseType(pR0Type->tag);
1997 switch(tag) {
1998 case TY_INT:
1999 oad(0xb9, 0); /* movl $0, %ecx */
2000 o(decodeOp(op));
2001 break;
2002 case TY_FLOAT:
2003 case TY_DOUBLE:
2004 switch (op) {
2005 case OP_MINUS:
2006 o(0xe0d9); // fchs
2007 break;
2008 case OP_BIT_NOT:
2009 error("Can't apply '~' operator to a float or double.");
2010 break;
2011 default:
2012 error("Unknown unary op %d\n", op);
2013 break;
2014 }
2015 break;
2016 default:
2017 error("genUnaryOp unsupported type");
2018 break;
2019 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002020 }
2021
Jack Palevich1cdef202009-05-22 12:06:27 -07002022 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002023 Type* pR0Type = getR0Type();
2024 TypeTag r0ct = collapseType(pR0Type->tag);
2025 switch(r0ct) {
2026 case TY_INT:
2027 o(0x50); /* push %eax */
2028 break;
2029 case TY_FLOAT:
2030 o(0x50); /* push %eax */
2031 o(0x241cd9); // fstps 0(%esp)
2032 break;
2033 case TY_DOUBLE:
2034 o(0x50); /* push %eax */
2035 o(0x50); /* push %eax */
2036 o(0x241cdd); // fstpl 0(%esp)
2037 break;
2038 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002039 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002040 break;
2041 }
Jack Palevich8df46192009-07-07 14:48:51 -07002042 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002043 }
2044
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002045 virtual void over() {
2046 // We know it's only used for int-ptr ops (++/--)
2047
2048 Type* pR0Type = getR0Type();
2049 TypeTag r0ct = collapseType(pR0Type->tag);
2050
2051 Type* pTOSType = getTOSType();
2052 TypeTag tosct = collapseType(pTOSType->tag);
2053
2054 assert (r0ct == TY_INT && tosct == TY_INT);
2055
2056 o(0x59); /* pop %ecx */
2057 o(0x50); /* push %eax */
2058 o(0x51); /* push %ecx */
2059
2060 overType();
2061 }
2062
Jack Palevich58c30ee2009-07-17 16:35:23 -07002063 virtual void popR0() {
2064 Type* pR0Type = getR0Type();
2065 TypeTag r0ct = collapseType(pR0Type->tag);
2066 switch(r0ct) {
2067 case TY_INT:
2068 o(0x58); /* popl %eax */
2069 break;
2070 case TY_FLOAT:
2071 o(0x2404d9); // flds (%esp)
2072 o(0x58); /* popl %eax */
2073 break;
2074 case TY_DOUBLE:
2075 o(0x2404dd); // fldl (%esp)
2076 o(0x58); /* popl %eax */
2077 o(0x58); /* popl %eax */
2078 break;
2079 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002080 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002081 break;
2082 }
2083 popType();
2084 }
2085
2086 virtual void storeR0ToTOS() {
2087 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002088 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002089 Type* pTargetType = pPointerType->pHead;
2090 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002091 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002092 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002093 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002094 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002095 case TY_INT:
2096 o(0x0189); /* movl %eax/%al, (%ecx) */
2097 break;
2098 case TY_CHAR:
2099 o(0x0188); /* movl %eax/%al, (%ecx) */
2100 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002101 case TY_FLOAT:
2102 o(0x19d9); /* fstps (%ecx) */
2103 break;
2104 case TY_DOUBLE:
2105 o(0x19dd); /* fstpl (%ecx) */
2106 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002107 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002108 error("storeR0ToTOS: unsupported type %d",
2109 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002110 break;
2111 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002112 }
2113
Jack Palevich58c30ee2009-07-17 16:35:23 -07002114 virtual void loadR0FromR0() {
2115 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002116 assert(pPointerType->tag == TY_POINTER);
2117 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002118 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002119 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002120 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002121 break;
2122 case TY_CHAR:
2123 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002124 ob(0); /* add zero in code */
2125 break;
2126 case TY_FLOAT:
2127 o2(0x00d9); // flds (%eax)
2128 break;
2129 case TY_DOUBLE:
2130 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002131 break;
2132 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002133 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002134 break;
2135 }
Jack Palevich8df46192009-07-07 14:48:51 -07002136 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002137 }
2138
Jack Palevichb5e33312009-07-30 19:06:34 -07002139 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002140 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002141 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002142 }
2143
Jack Palevich9f51a262009-07-29 16:22:26 -07002144 virtual int leaForward(int ea, Type* pPointerType) {
2145 oad(0xb8, ea); /* mov $xx, %eax */
2146 setR0Type(pPointerType);
2147 return getPC() - 4;
2148 }
2149
Jack Palevich8df46192009-07-07 14:48:51 -07002150 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002151 Type* pR0Type = getR0Type();
2152 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002153 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002154 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002155 return;
2156 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002157 if (bitsSame(pType, pR0Type)) {
2158 // do nothing special
2159 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2160 // do nothing special, both held in same register on x87.
2161 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002162 TypeTag r0Tag = collapseType(pR0Type->tag);
2163 TypeTag destTag = collapseType(pType->tag);
2164 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2165 // Convert R0 from int to float
2166 o(0x50); // push %eax
2167 o(0x2404DB); // fildl 0(%esp)
2168 o(0x58); // pop %eax
2169 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2170 // Convert R0 from float to int. Complicated because
2171 // need to save and restore the rounding mode.
2172 o(0x50); // push %eax
2173 o(0x50); // push %eax
2174 o(0x02247cD9); // fnstcw 2(%esp)
2175 o(0x2444b70f); // movzwl 2(%esp), %eax
2176 o(0x02);
2177 o(0x0cb4); // movb $12, %ah
2178 o(0x24048966); // movw %ax, 0(%esp)
2179 o(0x242cd9); // fldcw 0(%esp)
2180 o(0x04245cdb); // fistpl 4(%esp)
2181 o(0x02246cd9); // fldcw 2(%esp)
2182 o(0x58); // pop %eax
2183 o(0x58); // pop %eax
2184 } else {
2185 error("Incompatible types old: %d new: %d",
2186 pR0Type->tag, pType->tag);
2187 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002188 }
2189 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002190 }
2191
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002192 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002193 return oad(0xec81, 0); /* sub $xxx, %esp */
2194 }
2195
Jack Palevich8148c5b2009-07-16 18:24:47 -07002196 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2197 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002198 Type* pR0Type = getR0Type();
2199 TypeTag r0ct = collapseType(pR0Type->tag);
2200 switch(r0ct) {
2201 case TY_INT:
2202 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2203 return 4;
2204 case TY_FLOAT:
2205 oad(0x249CD9, l); /* fstps xxx(%esp) */
2206 return 4;
2207 case TY_DOUBLE:
2208 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2209 return 8;
2210 default:
2211 assert(false);
2212 return 0;
2213 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002214 }
2215
Jack Palevichb7718b92009-07-09 22:00:24 -07002216 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002217 * (int*) a = l;
2218 }
2219
Jack Palevich8df46192009-07-07 14:48:51 -07002220 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002221 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002222 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002223 return psym(0xe8, symbol); /* call xxx */
2224 }
2225
Jack Palevich8df46192009-07-07 14:48:51 -07002226 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002227 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002228 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002229 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002230 oad(0x2494ff, l); /* call *xxx(%esp) */
2231 }
2232
Jack Palevichb7718b92009-07-09 22:00:24 -07002233 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002234 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002235 if (isIndirect) {
2236 l += 4;
2237 }
-b master422972c2009-06-17 19:13:52 -07002238 if (l > 0) {
2239 oad(0xc481, l); /* add $xxx, %esp */
2240 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002241 }
2242
Jack Palevicha6535612009-05-13 16:24:17 -07002243 virtual int jumpOffset() {
2244 return 5;
2245 }
2246
2247 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002248 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002249 }
2250
Jack Paleviche7b59062009-05-19 17:12:17 -07002251 /* output a symbol and patch all calls to it */
2252 virtual void gsym(int t) {
2253 int n;
2254 int pc = getPC();
2255 while (t) {
2256 n = *(int *) t; /* next value */
2257 *(int *) t = pc - t - 4;
2258 t = n;
2259 }
2260 }
2261
Jack Palevich9f51a262009-07-29 16:22:26 -07002262 /* output a symbol and patch all calls to it, using absolute address */
2263 virtual void resolveForward(int t) {
2264 int n;
2265 int pc = getPC();
2266 while (t) {
2267 n = *(int *) t; /* next value */
2268 *(int *) t = pc;
2269 t = n;
2270 }
2271 }
2272
Jack Palevich1cdef202009-05-22 12:06:27 -07002273 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002274 size_t pagesize = 4096;
2275 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2276 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2277 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2278 if (err) {
2279 error("mprotect() failed: %d", errno);
2280 }
2281 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002282 }
2283
Jack Palevich9eed7a22009-07-06 17:24:34 -07002284 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002285 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002286 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002287 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002288 switch (pType->tag) {
2289 case TY_CHAR:
2290 return 1;
2291 default:
2292 return 4;
2293 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002294 }
2295
2296 /**
2297 * Array element alignment (in bytes) for this type of data.
2298 */
2299 virtual size_t sizeOf(Type* pType){
2300 switch(pType->tag) {
2301 case TY_INT:
2302 return 4;
2303 case TY_CHAR:
2304 return 1;
2305 default:
2306 return 0;
2307 case TY_FLOAT:
2308 return 4;
2309 case TY_DOUBLE:
2310 return 8;
2311 case TY_POINTER:
2312 return 4;
2313 }
2314 }
2315
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002316 virtual size_t stackAlignmentOf(Type* pType){
2317 return 4;
2318 }
2319
Jack Palevich9cbd2262009-07-08 16:48:41 -07002320 virtual size_t stackSizeOf(Type* pType) {
2321 switch(pType->tag) {
2322 case TY_DOUBLE:
2323 return 8;
2324 default:
2325 return 4;
2326 }
2327 }
2328
Jack Palevich21a15a22009-05-11 14:49:29 -07002329 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002330
2331 /** Output 1 to 4 bytes.
2332 *
2333 */
2334 void o(int n) {
2335 /* cannot use unsigned, so we must do a hack */
2336 while (n && n != -1) {
2337 ob(n & 0xff);
2338 n = n >> 8;
2339 }
2340 }
2341
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002342 /* Output exactly 2 bytes
2343 */
2344 void o2(int n) {
2345 ob(n & 0xff);
2346 ob(0xff & (n >> 8));
2347 }
2348
Jack Paleviche7b59062009-05-19 17:12:17 -07002349 /* psym is used to put an instruction with a data field which is a
2350 reference to a symbol. It is in fact the same as oad ! */
2351 int psym(int n, int t) {
2352 return oad(n, t);
2353 }
2354
2355 /* instruction + address */
2356 int oad(int n, int t) {
2357 o(n);
2358 int result = getPC();
2359 o4(t);
2360 return result;
2361 }
2362
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002363 static const int operatorHelper[];
2364
2365 int decodeOp(int op) {
2366 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002367 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002368 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002369 }
2370 return operatorHelper[op];
2371 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002372
Jack Palevich546b2242009-05-13 15:10:04 -07002373 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002374 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002375 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002376 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002377
2378 void setupFloatOperands() {
2379 Type* pR0Type = getR0Type();
2380 Type* pTOSType = getTOSType();
2381 TypeTag tagR0 = pR0Type->tag;
2382 TypeTag tagTOS = pTOSType->tag;
2383 bool isFloatR0 = isFloatTag(tagR0);
2384 bool isFloatTOS = isFloatTag(tagTOS);
2385 if (! isFloatR0) {
2386 // Convert R0 from int to float
2387 o(0x50); // push %eax
2388 o(0x2404DB); // fildl 0(%esp)
2389 o(0x58); // pop %eax
2390 }
2391 if (! isFloatTOS){
2392 o(0x2404DB); // fildl 0(%esp);
2393 o(0x58); // pop %eax
2394 } else {
2395 if (tagTOS == TY_FLOAT) {
2396 o(0x2404d9); // flds (%esp)
2397 o(0x58); // pop %eax
2398 } else {
2399 o(0x2404dd); // fldl (%esp)
2400 o(0x58); // pop %eax
2401 o(0x58); // pop %eax
2402 }
2403 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002404 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002405 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002406 };
2407
Jack Paleviche7b59062009-05-19 17:12:17 -07002408#endif // PROVIDE_X86_CODEGEN
2409
Jack Palevichb67b18f2009-06-11 21:12:23 -07002410#ifdef PROVIDE_TRACE_CODEGEN
2411 class TraceCodeGenerator : public CodeGenerator {
2412 private:
2413 CodeGenerator* mpBase;
2414
2415 public:
2416 TraceCodeGenerator(CodeGenerator* pBase) {
2417 mpBase = pBase;
2418 }
2419
2420 virtual ~TraceCodeGenerator() {
2421 delete mpBase;
2422 }
2423
2424 virtual void init(CodeBuf* pCodeBuf) {
2425 mpBase->init(pCodeBuf);
2426 }
2427
2428 void setErrorSink(ErrorSink* pErrorSink) {
2429 mpBase->setErrorSink(pErrorSink);
2430 }
2431
2432 /* returns address to patch with local variable size
2433 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002434 virtual int functionEntry(Type* pDecl) {
2435 int result = mpBase->functionEntry(pDecl);
2436 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002437 return result;
2438 }
2439
Jack Palevichb7718b92009-07-09 22:00:24 -07002440 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2441 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2442 localVariableAddress, localVariableSize);
2443 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002444 }
2445
2446 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002447 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002448 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002449 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002450 }
2451
Jack Palevich1a539db2009-07-08 13:04:41 -07002452 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002453 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002454 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002455 }
2456
Jack Palevichb67b18f2009-06-11 21:12:23 -07002457 virtual int gjmp(int t) {
2458 int result = mpBase->gjmp(t);
2459 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2460 return result;
2461 }
2462
2463 /* l = 0: je, l == 1: jne */
2464 virtual int gtst(bool l, int t) {
2465 int result = mpBase->gtst(l, t);
2466 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2467 return result;
2468 }
2469
Jack Palevich58c30ee2009-07-17 16:35:23 -07002470 virtual void gcmp(int op) {
2471 fprintf(stderr, "gcmp(%d)\n", op);
2472 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002473 }
2474
2475 virtual void genOp(int op) {
2476 fprintf(stderr, "genOp(%d)\n", op);
2477 mpBase->genOp(op);
2478 }
2479
Jack Palevich9eed7a22009-07-06 17:24:34 -07002480
Jack Palevich58c30ee2009-07-17 16:35:23 -07002481 virtual void gUnaryCmp(int op) {
2482 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2483 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002484 }
2485
2486 virtual void genUnaryOp(int op) {
2487 fprintf(stderr, "genUnaryOp(%d)\n", op);
2488 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002489 }
2490
2491 virtual void pushR0() {
2492 fprintf(stderr, "pushR0()\n");
2493 mpBase->pushR0();
2494 }
2495
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002496 virtual void over() {
2497 fprintf(stderr, "over()\n");
2498 mpBase->over();
2499 }
2500
Jack Palevich58c30ee2009-07-17 16:35:23 -07002501 virtual void popR0() {
2502 fprintf(stderr, "popR0()\n");
2503 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002504 }
2505
Jack Palevich58c30ee2009-07-17 16:35:23 -07002506 virtual void storeR0ToTOS() {
2507 fprintf(stderr, "storeR0ToTOS()\n");
2508 mpBase->storeR0ToTOS();
2509 }
2510
2511 virtual void loadR0FromR0() {
2512 fprintf(stderr, "loadR0FromR0()\n");
2513 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002514 }
2515
Jack Palevichb5e33312009-07-30 19:06:34 -07002516 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2517 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
2518 pPointerType->pHead->tag, et);
2519 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002520 }
2521
Jack Palevich9f51a262009-07-29 16:22:26 -07002522 virtual int leaForward(int ea, Type* pPointerType) {
2523 fprintf(stderr, "leaForward(%d)\n", ea);
2524 return mpBase->leaForward(ea, pPointerType);
2525 }
2526
Jack Palevich8df46192009-07-07 14:48:51 -07002527 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002528 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002529 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002530 }
2531
2532 virtual int beginFunctionCallArguments() {
2533 int result = mpBase->beginFunctionCallArguments();
2534 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2535 return result;
2536 }
2537
Jack Palevich8148c5b2009-07-16 18:24:47 -07002538 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2539 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2540 pArgType->tag);
2541 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002542 }
2543
Jack Palevichb7718b92009-07-09 22:00:24 -07002544 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002545 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002546 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002547 }
2548
Jack Palevich8df46192009-07-07 14:48:51 -07002549 virtual int callForward(int symbol, Type* pFunc) {
2550 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002551 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2552 return result;
2553 }
2554
Jack Palevich8df46192009-07-07 14:48:51 -07002555 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002556 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2557 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002558 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002559 }
2560
Jack Palevichb7718b92009-07-09 22:00:24 -07002561 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2562 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2563 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002564 }
2565
2566 virtual int jumpOffset() {
2567 return mpBase->jumpOffset();
2568 }
2569
2570 virtual int disassemble(FILE* out) {
2571 return mpBase->disassemble(out);
2572 }
2573
2574 /* output a symbol and patch all calls to it */
2575 virtual void gsym(int t) {
2576 fprintf(stderr, "gsym(%d)\n", t);
2577 mpBase->gsym(t);
2578 }
2579
Jack Palevich9f51a262009-07-29 16:22:26 -07002580 virtual void resolveForward(int t) {
2581 mpBase->resolveForward(t);
2582 }
2583
Jack Palevichb67b18f2009-06-11 21:12:23 -07002584 virtual int finishCompile() {
2585 int result = mpBase->finishCompile();
2586 fprintf(stderr, "finishCompile() = %d\n", result);
2587 return result;
2588 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002589
2590 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002591 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002592 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002593 virtual size_t alignmentOf(Type* pType){
2594 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002595 }
2596
2597 /**
2598 * Array element alignment (in bytes) for this type of data.
2599 */
2600 virtual size_t sizeOf(Type* pType){
2601 return mpBase->sizeOf(pType);
2602 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002603
Jack Palevich9cbd2262009-07-08 16:48:41 -07002604
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002605 virtual size_t stackAlignmentOf(Type* pType) {
2606 return mpBase->stackAlignmentOf(pType);
2607 }
2608
2609
Jack Palevich9cbd2262009-07-08 16:48:41 -07002610 virtual size_t stackSizeOf(Type* pType) {
2611 return mpBase->stackSizeOf(pType);
2612 }
2613
Jack Palevich1a539db2009-07-08 13:04:41 -07002614 virtual Type* getR0Type() {
2615 return mpBase->getR0Type();
2616 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002617
2618 virtual ExpressionType getR0ExpressionType() {
2619 return mpBase->getR0ExpressionType();
2620 }
2621
2622 virtual void setR0ExpressionType(ExpressionType et) {
2623 mpBase->setR0ExpressionType(et);
2624 }
2625
2626 virtual size_t getExpressionStackDepth() {
2627 return mpBase->getExpressionStackDepth();
2628 }
Jack Palevichb5e33312009-07-30 19:06:34 -07002629
2630 virtual void forceR0RVal() {
2631 return mpBase->forceR0RVal();
2632 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002633 };
2634
2635#endif // PROVIDE_TRACE_CODEGEN
2636
Jack Palevich569f1352009-06-29 14:29:08 -07002637 class Arena {
2638 public:
2639 // Used to record a given allocation amount.
2640 // Used:
2641 // Mark mark = arena.mark();
2642 // ... lots of arena.allocate()
2643 // arena.free(mark);
2644
2645 struct Mark {
2646 size_t chunk;
2647 size_t offset;
2648 };
2649
2650 Arena() {
2651 mCurrentChunk = 0;
2652 Chunk start(CHUNK_SIZE);
2653 mData.push_back(start);
2654 }
2655
2656 ~Arena() {
2657 for(size_t i = 0; i < mData.size(); i++) {
2658 mData[i].free();
2659 }
2660 }
2661
2662 // Alloc using the standard alignment size safe for any variable
2663 void* alloc(size_t size) {
2664 return alloc(size, 8);
2665 }
2666
2667 Mark mark(){
2668 Mark result;
2669 result.chunk = mCurrentChunk;
2670 result.offset = mData[mCurrentChunk].mOffset;
2671 return result;
2672 }
2673
2674 void freeToMark(const Mark& mark) {
2675 mCurrentChunk = mark.chunk;
2676 mData[mCurrentChunk].mOffset = mark.offset;
2677 }
2678
2679 private:
2680 // Allocate memory aligned to a given size
2681 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2682 // Memory is not zero filled.
2683
2684 void* alloc(size_t size, size_t alignment) {
2685 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2686 if (mCurrentChunk + 1 < mData.size()) {
2687 mCurrentChunk++;
2688 } else {
2689 size_t allocSize = CHUNK_SIZE;
2690 if (allocSize < size + alignment - 1) {
2691 allocSize = size + alignment - 1;
2692 }
2693 Chunk chunk(allocSize);
2694 mData.push_back(chunk);
2695 mCurrentChunk++;
2696 }
2697 }
2698 return mData[mCurrentChunk].allocate(size, alignment);
2699 }
2700
2701 static const size_t CHUNK_SIZE = 128*1024;
2702 // Note: this class does not deallocate its
2703 // memory when it's destroyed. It depends upon
2704 // its parent to deallocate the memory.
2705 struct Chunk {
2706 Chunk() {
2707 mpData = 0;
2708 mSize = 0;
2709 mOffset = 0;
2710 }
2711
2712 Chunk(size_t size) {
2713 mSize = size;
2714 mpData = (char*) malloc(size);
2715 mOffset = 0;
2716 }
2717
2718 ~Chunk() {
2719 // Doesn't deallocate memory.
2720 }
2721
2722 void* allocate(size_t size, size_t alignment) {
2723 size_t alignedOffset = aligned(mOffset, alignment);
2724 void* result = mpData + alignedOffset;
2725 mOffset = alignedOffset + size;
2726 return result;
2727 }
2728
2729 void free() {
2730 if (mpData) {
2731 ::free(mpData);
2732 mpData = 0;
2733 }
2734 }
2735
2736 size_t remainingCapacity(size_t alignment) {
2737 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2738 }
2739
2740 // Assume alignment is a power of two
2741 inline size_t aligned(size_t v, size_t alignment) {
2742 size_t mask = alignment-1;
2743 return (v + mask) & ~mask;
2744 }
2745
2746 char* mpData;
2747 size_t mSize;
2748 size_t mOffset;
2749 };
2750
2751 size_t mCurrentChunk;
2752
2753 Vector<Chunk> mData;
2754 };
2755
Jack Palevich569f1352009-06-29 14:29:08 -07002756 struct VariableInfo;
2757
2758 struct Token {
2759 int hash;
2760 size_t length;
2761 char* pText;
2762 tokenid_t id;
2763
2764 // Current values for the token
2765 char* mpMacroDefinition;
2766 VariableInfo* mpVariableInfo;
2767 };
2768
2769 class TokenTable {
2770 public:
2771 // Don't use 0..0xff, allows characters and operators to be tokens too.
2772
2773 static const int TOKEN_BASE = 0x100;
2774 TokenTable() {
2775 mpMap = hashmapCreate(128, hashFn, equalsFn);
2776 }
2777
2778 ~TokenTable() {
2779 hashmapFree(mpMap);
2780 }
2781
2782 void setArena(Arena* pArena) {
2783 mpArena = pArena;
2784 }
2785
2786 // Returns a token for a given string of characters.
2787 tokenid_t intern(const char* pText, size_t length) {
2788 Token probe;
2789 int hash = hashmapHash((void*) pText, length);
2790 {
2791 Token probe;
2792 probe.hash = hash;
2793 probe.length = length;
2794 probe.pText = (char*) pText;
2795 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2796 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002797 return pValue->id;
2798 }
2799 }
2800
2801 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2802 memset(pToken, 0, sizeof(*pToken));
2803 pToken->hash = hash;
2804 pToken->length = length;
2805 pToken->pText = (char*) mpArena->alloc(length + 1);
2806 memcpy(pToken->pText, pText, length);
2807 pToken->pText[length] = 0;
2808 pToken->id = mTokens.size() + TOKEN_BASE;
2809 mTokens.push_back(pToken);
2810 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002811 return pToken->id;
2812 }
2813
2814 // Return the Token for a given tokenid.
2815 Token& operator[](tokenid_t id) {
2816 return *mTokens[id - TOKEN_BASE];
2817 }
2818
2819 inline size_t size() {
2820 return mTokens.size();
2821 }
2822
2823 private:
2824
2825 static int hashFn(void* pKey) {
2826 Token* pToken = (Token*) pKey;
2827 return pToken->hash;
2828 }
2829
2830 static bool equalsFn(void* keyA, void* keyB) {
2831 Token* pTokenA = (Token*) keyA;
2832 Token* pTokenB = (Token*) keyB;
2833 // Don't need to compare hash values, they should always be equal
2834 return pTokenA->length == pTokenB->length
2835 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2836 }
2837
2838 Hashmap* mpMap;
2839 Vector<Token*> mTokens;
2840 Arena* mpArena;
2841 };
2842
Jack Palevich1cdef202009-05-22 12:06:27 -07002843 class InputStream {
2844 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002845 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002846 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002847 };
2848
2849 class TextInputStream : public InputStream {
2850 public:
2851 TextInputStream(const char* text, size_t textLength)
2852 : pText(text), mTextLength(textLength), mPosition(0) {
2853 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002854
Jack Palevichdc456462009-07-16 16:50:56 -07002855 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002856 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2857 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002858
Jack Palevichdc456462009-07-16 16:50:56 -07002859 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002860 const char* pText;
2861 size_t mTextLength;
2862 size_t mPosition;
2863 };
2864
Jack Palevicheedf9d22009-06-04 16:23:40 -07002865 class String {
2866 public:
2867 String() {
2868 mpBase = 0;
2869 mUsed = 0;
2870 mSize = 0;
2871 }
2872
Jack Palevich303d8ff2009-06-11 19:06:24 -07002873 String(const char* item, int len, bool adopt) {
2874 if (len < 0) {
2875 len = strlen(item);
2876 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002877 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002878 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002879 mUsed = len;
2880 mSize = len + 1;
2881 } else {
2882 mpBase = 0;
2883 mUsed = 0;
2884 mSize = 0;
2885 appendBytes(item, len);
2886 }
2887 }
2888
Jack Palevich303d8ff2009-06-11 19:06:24 -07002889 String(const String& other) {
2890 mpBase = 0;
2891 mUsed = 0;
2892 mSize = 0;
2893 appendBytes(other.getUnwrapped(), other.len());
2894 }
2895
Jack Palevicheedf9d22009-06-04 16:23:40 -07002896 ~String() {
2897 if (mpBase) {
2898 free(mpBase);
2899 }
2900 }
2901
Jack Palevicha6baa232009-06-12 11:25:59 -07002902 String& operator=(const String& other) {
2903 clear();
2904 appendBytes(other.getUnwrapped(), other.len());
2905 return *this;
2906 }
2907
Jack Palevich303d8ff2009-06-11 19:06:24 -07002908 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002909 return mpBase;
2910 }
2911
Jack Palevich303d8ff2009-06-11 19:06:24 -07002912 void clear() {
2913 mUsed = 0;
2914 if (mSize > 0) {
2915 mpBase[0] = 0;
2916 }
2917 }
2918
Jack Palevicheedf9d22009-06-04 16:23:40 -07002919 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002920 appendBytes(s, strlen(s));
2921 }
2922
2923 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002924 memcpy(ensure(n), s, n + 1);
2925 }
2926
2927 void append(char c) {
2928 * ensure(1) = c;
2929 }
2930
Jack Palevich86351982009-06-30 18:09:56 -07002931 void append(String& other) {
2932 appendBytes(other.getUnwrapped(), other.len());
2933 }
2934
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002935 char* orphan() {
2936 char* result = mpBase;
2937 mpBase = 0;
2938 mUsed = 0;
2939 mSize = 0;
2940 return result;
2941 }
2942
Jack Palevicheedf9d22009-06-04 16:23:40 -07002943 void printf(const char* fmt,...) {
2944 va_list ap;
2945 va_start(ap, fmt);
2946 vprintf(fmt, ap);
2947 va_end(ap);
2948 }
2949
2950 void vprintf(const char* fmt, va_list ap) {
2951 char* temp;
2952 int numChars = vasprintf(&temp, fmt, ap);
2953 memcpy(ensure(numChars), temp, numChars+1);
2954 free(temp);
2955 }
2956
Jack Palevich303d8ff2009-06-11 19:06:24 -07002957 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002958 return mUsed;
2959 }
2960
2961 private:
2962 char* ensure(int n) {
2963 size_t newUsed = mUsed + n;
2964 if (newUsed > mSize) {
2965 size_t newSize = mSize * 2 + 10;
2966 if (newSize < newUsed) {
2967 newSize = newUsed;
2968 }
2969 mpBase = (char*) realloc(mpBase, newSize + 1);
2970 mSize = newSize;
2971 }
2972 mpBase[newUsed] = '\0';
2973 char* result = mpBase + mUsed;
2974 mUsed = newUsed;
2975 return result;
2976 }
2977
2978 char* mpBase;
2979 size_t mUsed;
2980 size_t mSize;
2981 };
2982
Jack Palevich569f1352009-06-29 14:29:08 -07002983 void internKeywords() {
2984 // Note: order has to match TOK_ constants
2985 static const char* keywords[] = {
2986 "int",
2987 "char",
2988 "void",
2989 "if",
2990 "else",
2991 "while",
2992 "break",
2993 "return",
2994 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07002995 "auto",
2996 "case",
2997 "const",
2998 "continue",
2999 "default",
3000 "do",
3001 "double",
3002 "enum",
3003 "extern",
3004 "float",
3005 "goto",
3006 "long",
3007 "register",
3008 "short",
3009 "signed",
3010 "sizeof",
3011 "static",
3012 "struct",
3013 "switch",
3014 "typedef",
3015 "union",
3016 "unsigned",
3017 "volatile",
3018 "_Bool",
3019 "_Complex",
3020 "_Imaginary",
3021 "inline",
3022 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003023
3024 // predefined tokens that can also be symbols start here:
3025 "pragma",
3026 "define",
3027 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003028 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003029
Jack Palevich569f1352009-06-29 14:29:08 -07003030 for(int i = 0; keywords[i]; i++) {
3031 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003032 }
Jack Palevich569f1352009-06-29 14:29:08 -07003033 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003034
Jack Palevich36d94142009-06-08 15:55:32 -07003035 struct InputState {
3036 InputStream* pStream;
3037 int oldCh;
3038 };
3039
Jack Palevich2db168f2009-06-11 14:29:47 -07003040 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003041 void* pAddress;
3042 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003043 tokenid_t tok;
3044 size_t level;
3045 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003046 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003047 };
3048
Jack Palevich303d8ff2009-06-11 19:06:24 -07003049 class SymbolStack {
3050 public:
3051 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003052 mpArena = 0;
3053 mpTokenTable = 0;
3054 }
3055
3056 void setArena(Arena* pArena) {
3057 mpArena = pArena;
3058 }
3059
3060 void setTokenTable(TokenTable* pTokenTable) {
3061 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003062 }
3063
3064 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003065 Mark mark;
3066 mark.mArenaMark = mpArena->mark();
3067 mark.mSymbolHead = mStack.size();
3068 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003069 }
3070
3071 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003072 // Undo any shadowing that was done:
3073 Mark mark = mLevelStack.back();
3074 mLevelStack.pop_back();
3075 while (mStack.size() > mark.mSymbolHead) {
3076 VariableInfo* pV = mStack.back();
3077 mStack.pop_back();
3078 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003079 }
Jack Palevich569f1352009-06-29 14:29:08 -07003080 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003081 }
3082
Jack Palevich569f1352009-06-29 14:29:08 -07003083 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3084 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3085 return pV && pV->level == level();
3086 }
3087
3088 VariableInfo* add(tokenid_t tok) {
3089 Token& token = (*mpTokenTable)[tok];
3090 VariableInfo* pOldV = token.mpVariableInfo;
3091 VariableInfo* pNewV =
3092 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3093 memset(pNewV, 0, sizeof(VariableInfo));
3094 pNewV->tok = tok;
3095 pNewV->level = level();
3096 pNewV->pOldDefinition = pOldV;
3097 token.mpVariableInfo = pNewV;
3098 mStack.push_back(pNewV);
3099 return pNewV;
3100 }
3101
Jack Palevich86351982009-06-30 18:09:56 -07003102 VariableInfo* add(Type* pType) {
3103 VariableInfo* pVI = add(pType->id);
3104 pVI->pType = pType;
3105 return pVI;
3106 }
3107
Jack Palevich569f1352009-06-29 14:29:08 -07003108 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3109 for (size_t i = 0; i < mStack.size(); i++) {
3110 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003111 break;
3112 }
3113 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003114 }
3115
Jack Palevich303d8ff2009-06-11 19:06:24 -07003116 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003117 inline size_t level() {
3118 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003119 }
3120
Jack Palevich569f1352009-06-29 14:29:08 -07003121 struct Mark {
3122 Arena::Mark mArenaMark;
3123 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003124 };
3125
Jack Palevich569f1352009-06-29 14:29:08 -07003126 Arena* mpArena;
3127 TokenTable* mpTokenTable;
3128 Vector<VariableInfo*> mStack;
3129 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003130 };
Jack Palevich36d94142009-06-08 15:55:32 -07003131
3132 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003133 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003134 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003135 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003136 int tokl; // token operator level
3137 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003138 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003139 intptr_t loc; // local variable index
3140 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003141 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003142 char* dptr; // Macro state: Points to macro text during macro playback.
3143 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003144 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003145 ACCSymbolLookupFn mpSymbolLookupFn;
3146 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003147
3148 // Arena for the duration of the compile
3149 Arena mGlobalArena;
3150 // Arena for data that's only needed when compiling a single function
3151 Arena mLocalArena;
3152
Jack Palevich2ff5c222009-07-23 15:11:22 -07003153 Arena* mpCurrentArena;
3154
Jack Palevich569f1352009-06-29 14:29:08 -07003155 TokenTable mTokenTable;
3156 SymbolStack mGlobals;
3157 SymbolStack mLocals;
3158
Jack Palevich40600de2009-07-01 15:32:35 -07003159 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003160 Type* mkpInt; // int
3161 Type* mkpChar; // char
3162 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003163 Type* mkpFloat;
3164 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003165 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003166 Type* mkpIntPtr;
3167 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003168 Type* mkpFloatPtr;
3169 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003170 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003171
Jack Palevich36d94142009-06-08 15:55:32 -07003172 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003173 int mLineNumber;
3174 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003175
3176 CodeBuf codeBuf;
3177 CodeGenerator* pGen;
3178
Jack Palevicheedf9d22009-06-04 16:23:40 -07003179 String mErrorBuf;
3180
Jack Palevicheedf9d22009-06-04 16:23:40 -07003181 String mPragmas;
3182 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003183 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003184
Jack Palevich21a15a22009-05-11 14:49:29 -07003185 static const int ALLOC_SIZE = 99999;
3186
Jack Palevich303d8ff2009-06-11 19:06:24 -07003187 static const int TOK_DUMMY = 1;
3188 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003189 static const int TOK_NUM_FLOAT = 3;
3190 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003191 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003192
3193 // 3..255 are character and/or operators
3194
Jack Palevich2db168f2009-06-11 14:29:47 -07003195 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003196 // Order has to match string list in "internKeywords".
3197 enum {
3198 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3199 TOK_INT = TOK_KEYWORD,
3200 TOK_CHAR,
3201 TOK_VOID,
3202 TOK_IF,
3203 TOK_ELSE,
3204 TOK_WHILE,
3205 TOK_BREAK,
3206 TOK_RETURN,
3207 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003208 TOK_AUTO,
3209 TOK_CASE,
3210 TOK_CONST,
3211 TOK_CONTINUE,
3212 TOK_DEFAULT,
3213 TOK_DO,
3214 TOK_DOUBLE,
3215 TOK_ENUM,
3216 TOK_EXTERN,
3217 TOK_FLOAT,
3218 TOK_GOTO,
3219 TOK_LONG,
3220 TOK_REGISTER,
3221 TOK_SHORT,
3222 TOK_SIGNED,
3223 TOK_SIZEOF,
3224 TOK_STATIC,
3225 TOK_STRUCT,
3226 TOK_SWITCH,
3227 TOK_TYPEDEF,
3228 TOK_UNION,
3229 TOK_UNSIGNED,
3230 TOK_VOLATILE,
3231 TOK__BOOL,
3232 TOK__COMPLEX,
3233 TOK__IMAGINARY,
3234 TOK_INLINE,
3235 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003236
3237 // Symbols start after keywords
3238
3239 TOK_SYMBOL,
3240 TOK_PRAGMA = TOK_SYMBOL,
3241 TOK_DEFINE,
3242 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003243 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003244
3245 static const int LOCAL = 0x200;
3246
3247 static const int SYM_FORWARD = 0;
3248 static const int SYM_DEFINE = 1;
3249
3250 /* tokens in string heap */
3251 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003252
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003253 static const int OP_INCREMENT = 0;
3254 static const int OP_DECREMENT = 1;
3255 static const int OP_MUL = 2;
3256 static const int OP_DIV = 3;
3257 static const int OP_MOD = 4;
3258 static const int OP_PLUS = 5;
3259 static const int OP_MINUS = 6;
3260 static const int OP_SHIFT_LEFT = 7;
3261 static const int OP_SHIFT_RIGHT = 8;
3262 static const int OP_LESS_EQUAL = 9;
3263 static const int OP_GREATER_EQUAL = 10;
3264 static const int OP_LESS = 11;
3265 static const int OP_GREATER = 12;
3266 static const int OP_EQUALS = 13;
3267 static const int OP_NOT_EQUALS = 14;
3268 static const int OP_LOGICAL_AND = 15;
3269 static const int OP_LOGICAL_OR = 16;
3270 static const int OP_BIT_AND = 17;
3271 static const int OP_BIT_XOR = 18;
3272 static const int OP_BIT_OR = 19;
3273 static const int OP_BIT_NOT = 20;
3274 static const int OP_LOGICAL_NOT = 21;
3275 static const int OP_COUNT = 22;
3276
3277 /* Operators are searched from front, the two-character operators appear
3278 * before the single-character operators with the same first character.
3279 * @ is used to pad out single-character operators.
3280 */
3281 static const char* operatorChars;
3282 static const char operatorLevel[];
3283
Jack Palevich569f1352009-06-29 14:29:08 -07003284 /* Called when we detect an internal problem. Does nothing in production.
3285 *
3286 */
3287 void internalError() {
3288 * (char*) 0 = 0;
3289 }
3290
Jack Palevich86351982009-06-30 18:09:56 -07003291 void assert(bool isTrue) {
3292 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003293 internalError();
3294 }
Jack Palevich86351982009-06-30 18:09:56 -07003295 }
3296
Jack Palevich40600de2009-07-01 15:32:35 -07003297 bool isSymbol(tokenid_t t) {
3298 return t >= TOK_SYMBOL &&
3299 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3300 }
3301
3302 bool isSymbolOrKeyword(tokenid_t t) {
3303 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003304 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003305 }
3306
Jack Palevich86351982009-06-30 18:09:56 -07003307 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003308 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003309 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3310 if (pV && pV->tok != t) {
3311 internalError();
3312 }
3313 return pV;
3314 }
3315
3316 inline bool isDefined(tokenid_t t) {
3317 return t >= TOK_SYMBOL && VI(t) != 0;
3318 }
3319
Jack Palevich40600de2009-07-01 15:32:35 -07003320 const char* nameof(tokenid_t t) {
3321 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003322 return mTokenTable[t].pText;
3323 }
3324
Jack Palevich21a15a22009-05-11 14:49:29 -07003325 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003326 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003327 }
3328
3329 void inp() {
3330 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003331 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003332 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003333 dptr = 0;
3334 ch = dch;
3335 }
Jack Palevichdc456462009-07-16 16:50:56 -07003336 } else {
3337 if (mbBumpLine) {
3338 mLineNumber++;
3339 mbBumpLine = false;
3340 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003341 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003342 if (ch == '\n') {
3343 mbBumpLine = true;
3344 }
3345 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003346#if 0
3347 printf("ch='%c' 0x%x\n", ch, ch);
3348#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003349 }
3350
3351 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003352 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003353 }
3354
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003355 int decodeHex(int c) {
3356 if (isdigit(c)) {
3357 c -= '0';
3358 } else if (c <= 'F') {
3359 c = c - 'A' + 10;
3360 } else {
3361 c =c - 'a' + 10;
3362 }
3363 return c;
3364 }
3365
Jack Palevichb4758ff2009-06-12 12:49:14 -07003366 /* read a character constant, advances ch to after end of constant */
3367 int getq() {
3368 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003369 if (ch == '\\') {
3370 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003371 if (isoctal(ch)) {
3372 // 1 to 3 octal characters.
3373 val = 0;
3374 for(int i = 0; i < 3; i++) {
3375 if (isoctal(ch)) {
3376 val = (val << 3) + ch - '0';
3377 inp();
3378 }
3379 }
3380 return val;
3381 } else if (ch == 'x' || ch == 'X') {
3382 // N hex chars
3383 inp();
3384 if (! isxdigit(ch)) {
3385 error("'x' character escape requires at least one digit.");
3386 } else {
3387 val = 0;
3388 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003389 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003390 inp();
3391 }
3392 }
3393 } else {
3394 int val = ch;
3395 switch (ch) {
3396 case 'a':
3397 val = '\a';
3398 break;
3399 case 'b':
3400 val = '\b';
3401 break;
3402 case 'f':
3403 val = '\f';
3404 break;
3405 case 'n':
3406 val = '\n';
3407 break;
3408 case 'r':
3409 val = '\r';
3410 break;
3411 case 't':
3412 val = '\t';
3413 break;
3414 case 'v':
3415 val = '\v';
3416 break;
3417 case '\\':
3418 val = '\\';
3419 break;
3420 case '\'':
3421 val = '\'';
3422 break;
3423 case '"':
3424 val = '"';
3425 break;
3426 case '?':
3427 val = '?';
3428 break;
3429 default:
3430 error("Undefined character escape %c", ch);
3431 break;
3432 }
3433 inp();
3434 return val;
3435 }
3436 } else {
3437 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003438 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003439 return val;
3440 }
3441
3442 static bool isoctal(int ch) {
3443 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003444 }
3445
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003446 bool acceptCh(int c) {
3447 bool result = c == ch;
3448 if (result) {
3449 pdef(ch);
3450 inp();
3451 }
3452 return result;
3453 }
3454
3455 bool acceptDigitsCh() {
3456 bool result = false;
3457 while (isdigit(ch)) {
3458 result = true;
3459 pdef(ch);
3460 inp();
3461 }
3462 return result;
3463 }
3464
3465 void parseFloat() {
3466 tok = TOK_NUM_DOUBLE;
3467 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003468 if(mTokenString.len() == 0) {
3469 mTokenString.append('0');
3470 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003471 acceptCh('.');
3472 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003473 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003474 acceptCh('-') || acceptCh('+');
3475 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003476 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003477 if (ch == 'f' || ch == 'F') {
3478 tok = TOK_NUM_FLOAT;
3479 inp();
3480 } else if (ch == 'l' || ch == 'L') {
3481 inp();
3482 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003483 }
3484 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003485 char* pEnd = pText + strlen(pText);
3486 char* pEndPtr = 0;
3487 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003488 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003489 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003490 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003491 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003492 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003493 if (errno || pEndPtr != pEnd) {
3494 error("Can't parse constant: %s", pText);
3495 }
3496 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003497 }
3498
Jack Palevich21a15a22009-05-11 14:49:29 -07003499 void next() {
3500 int l, a;
3501
Jack Palevich546b2242009-05-13 15:10:04 -07003502 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003503 if (ch == '#') {
3504 inp();
3505 next();
3506 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003507 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003508 } else if (tok == TOK_PRAGMA) {
3509 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003510 } else if (tok == TOK_LINE) {
3511 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003512 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003513 error("Unsupported preprocessor directive \"%s\"",
3514 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003515 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003516 }
3517 inp();
3518 }
3519 tokl = 0;
3520 tok = ch;
3521 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003522 if (isdigit(ch) || ch == '.') {
3523 // Start of a numeric constant. Could be integer, float, or
3524 // double, won't know until we look further.
3525 mTokenString.clear();
3526 pdef(ch);
3527 inp();
3528 int base = 10;
3529 if (tok == '0') {
3530 if (ch == 'x' || ch == 'X') {
3531 base = 16;
3532 tok = TOK_NUM;
3533 tokc = 0;
3534 inp();
3535 while ( isxdigit(ch) ) {
3536 tokc = (tokc << 4) + decodeHex(ch);
3537 inp();
3538 }
3539 } else if (isoctal(ch)){
3540 base = 8;
3541 tok = TOK_NUM;
3542 tokc = 0;
3543 while ( isoctal(ch) ) {
3544 tokc = (tokc << 3) + (ch - '0');
3545 inp();
3546 }
3547 }
3548 } else if (isdigit(tok)){
3549 acceptDigitsCh();
3550 }
3551 if (base == 10) {
3552 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3553 parseFloat();
3554 } else {
3555 // It's an integer constant
3556 char* pText = mTokenString.getUnwrapped();
3557 char* pEnd = pText + strlen(pText);
3558 char* pEndPtr = 0;
3559 errno = 0;
3560 tokc = strtol(pText, &pEndPtr, base);
3561 if (errno || pEndPtr != pEnd) {
3562 error("Can't parse constant: %s %d %d", pText, base, errno);
3563 }
3564 tok = TOK_NUM;
3565 }
3566 }
3567 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003568 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003569 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003570 pdef(ch);
3571 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003572 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003573 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3574 // Is this a macro?
3575 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3576 if (pMacroDefinition) {
3577 // Yes, it is a macro
3578 dptr = pMacroDefinition;
3579 dch = ch;
3580 inp();
3581 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003582 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003583 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003584 inp();
3585 if (tok == '\'') {
3586 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003587 tokc = getq();
3588 if (ch != '\'') {
3589 error("Expected a ' character, got %c", ch);
3590 } else {
3591 inp();
3592 }
Jack Palevich546b2242009-05-13 15:10:04 -07003593 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003594 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003595 while (ch && ch != EOF) {
3596 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003597 inp();
3598 inp();
3599 if (ch == '/')
3600 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003601 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003602 if (ch == EOF) {
3603 error("End of file inside comment.");
3604 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003605 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003606 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003607 } else if ((tok == '/') & (ch == '/')) {
3608 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003609 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003610 inp();
3611 }
3612 inp();
3613 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003614 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003615 const char* t = operatorChars;
3616 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003617 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003618 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003619 tokl = operatorLevel[opIndex];
3620 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003621 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003622#if 0
3623 printf("%c%c -> tokl=%d tokc=0x%x\n",
3624 l, a, tokl, tokc);
3625#endif
3626 if (a == ch) {
3627 inp();
3628 tok = TOK_DUMMY; /* dummy token for double tokens */
3629 }
Jack Palevich0c017742009-07-31 12:00:39 -07003630 /* check for op=, valid for * / % + - << >> & ^ | */
3631 if (ch == '=' &&
3632 ((tokl >= 1 && tokl <= 3)
3633 || tokl >=6 && tokl <= 8) ) {
3634 inp();
3635 tok = TOK_OP_ASSIGNMENT;
3636 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003637 break;
3638 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003639 opIndex++;
3640 }
3641 if (l == 0) {
3642 tokl = 0;
3643 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003644 }
3645 }
3646 }
3647#if 0
3648 {
Jack Palevich569f1352009-06-29 14:29:08 -07003649 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003650 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003651 fprintf(stderr, "%s\n", buf.getUnwrapped());
3652 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003653#endif
3654 }
3655
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003656 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003657 next();
3658 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003659 String* pName = new String();
3660 while (isspace(ch)) {
3661 inp();
3662 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003663 if (ch == '(') {
3664 delete pName;
3665 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003666 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003667 }
3668 while (isspace(ch)) {
3669 inp();
3670 }
Jack Palevich569f1352009-06-29 14:29:08 -07003671 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003672 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003673 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003674 inp();
3675 }
Jack Palevich569f1352009-06-29 14:29:08 -07003676 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3677 memcpy(pDefn, value.getUnwrapped(), value.len());
3678 pDefn[value.len()] = 0;
3679 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003680 }
3681
Jack Palevicheedf9d22009-06-04 16:23:40 -07003682 void doPragma() {
3683 // # pragma name(val)
3684 int state = 0;
3685 while(ch != EOF && ch != '\n' && state < 10) {
3686 switch(state) {
3687 case 0:
3688 if (isspace(ch)) {
3689 inp();
3690 } else {
3691 state++;
3692 }
3693 break;
3694 case 1:
3695 if (isalnum(ch)) {
3696 mPragmas.append(ch);
3697 inp();
3698 } else if (ch == '(') {
3699 mPragmas.append(0);
3700 inp();
3701 state++;
3702 } else {
3703 state = 11;
3704 }
3705 break;
3706 case 2:
3707 if (isalnum(ch)) {
3708 mPragmas.append(ch);
3709 inp();
3710 } else if (ch == ')') {
3711 mPragmas.append(0);
3712 inp();
3713 state = 10;
3714 } else {
3715 state = 11;
3716 }
3717 break;
3718 }
3719 }
3720 if(state != 10) {
3721 error("Unexpected pragma syntax");
3722 }
3723 mPragmaStringCount += 2;
3724 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003725
Jack Palevichdc456462009-07-16 16:50:56 -07003726 void doLine() {
3727 // # line number { "filename "}
3728 next();
3729 if (tok != TOK_NUM) {
3730 error("Expected a line-number");
3731 } else {
3732 mLineNumber = tokc-1; // The end-of-line will increment it.
3733 }
3734 while(ch != EOF && ch != '\n') {
3735 inp();
3736 }
3737 }
3738
Jack Palevichac0e95e2009-05-29 13:53:44 -07003739 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003740 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003741 mErrorBuf.vprintf(fmt, ap);
3742 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003743 }
3744
Jack Palevich8b0624c2009-05-20 12:12:06 -07003745 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003746 if (tok != c) {
3747 error("'%c' expected", c);
3748 }
3749 next();
3750 }
3751
Jack Palevich86351982009-06-30 18:09:56 -07003752 bool accept(intptr_t c) {
3753 if (tok == c) {
3754 next();
3755 return true;
3756 }
3757 return false;
3758 }
3759
Jack Palevich40600de2009-07-01 15:32:35 -07003760 bool acceptStringLiteral() {
3761 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003762 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003763 // This while loop merges multiple adjacent string constants.
3764 while (tok == '"') {
3765 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003766 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003767 }
3768 if (ch != '"') {
3769 error("Unterminated string constant.");
3770 }
3771 inp();
3772 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003773 }
Jack Palevich40600de2009-07-01 15:32:35 -07003774 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003775 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003776 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003777 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003778
3779 return true;
3780 }
3781 return false;
3782 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003783
Jack Palevichb1544ca2009-07-16 15:09:20 -07003784 void linkGlobal(tokenid_t t, bool isFunction) {
3785 VariableInfo* pVI = VI(t);
3786 void* n = NULL;
3787 if (mpSymbolLookupFn) {
3788 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3789 }
3790 if (pVI->pType == NULL) {
3791 if (isFunction) {
3792 pVI->pType = mkpIntFn;
3793 } else {
3794 pVI->pType = mkpInt;
3795 }
3796 }
3797 pVI->pAddress = n;
3798 }
3799
Jack Palevich29daf572009-07-30 19:38:55 -07003800 void unaryOrAssignment() {
3801 unary();
3802 if (accept('=')) {
3803 checkLVal();
3804 pGen->pushR0();
3805 expr();
3806 pGen->forceR0RVal();
3807 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003808 } else if (tok == TOK_OP_ASSIGNMENT) {
3809 int t = tokc;
3810 next();
3811 checkLVal();
3812 pGen->pushR0();
3813 pGen->forceR0RVal();
3814 pGen->pushR0();
3815 expr();
3816 pGen->forceR0RVal();
3817 pGen->genOp(t);
3818 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003819 }
3820 }
3821
Jack Palevich40600de2009-07-01 15:32:35 -07003822 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003823 */
Jack Palevich29daf572009-07-30 19:38:55 -07003824 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003825 tokenid_t t;
3826 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003827 t = 0;
3828 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3829 if (acceptStringLiteral()) {
3830 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003831 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003832 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003833 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003834 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003835 t = tok;
3836 next();
3837 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003838 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003839 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003840 // Align to 4-byte boundary
3841 glo = (char*) (((intptr_t) glo + 3) & -4);
3842 * (float*) glo = (float) ad;
3843 pGen->loadFloat((int) glo, mkpFloat);
3844 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003845 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003846 // Align to 8-byte boundary
3847 glo = (char*) (((intptr_t) glo + 7) & -8);
3848 * (double*) glo = ad;
3849 pGen->loadFloat((int) glo, mkpDouble);
3850 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003851 } else if (c == 2) {
3852 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07003853 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07003854 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07003855 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003856 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003857 else if (t == '+') {
3858 // ignore unary plus.
3859 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003860 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003861 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003862 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003863 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003864 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003865 if (pCast) {
3866 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07003867 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07003868 pGen->forceR0RVal();
Jack Palevich45431bc2009-07-13 15:57:26 -07003869 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003870 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07003871 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003872 skip(')');
3873 }
3874 } else if (t == '*') {
3875 /* This is a pointer dereference.
3876 */
Jack Palevich29daf572009-07-30 19:38:55 -07003877 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07003878 pGen->forceR0RVal();
Jack Palevich45431bc2009-07-13 15:57:26 -07003879 Type* pR0Type = pGen->getR0Type();
3880 if (pR0Type->tag != TY_POINTER) {
3881 error("Expected a pointer type.");
3882 } else {
3883 if (pR0Type->pHead->tag == TY_FUNC) {
3884 t = 0;
3885 }
Jack Palevich29daf572009-07-30 19:38:55 -07003886 if (t) {
3887 pGen->setR0ExpressionType(ET_LVALUE);
Jack Palevich45431bc2009-07-13 15:57:26 -07003888 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003889 }
Jack Palevich3f226492009-07-02 14:46:19 -07003890 // Else we fall through to the function call below, with
3891 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003892 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003893 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07003894 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
3895 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07003896 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003897 } else if (t == EOF ) {
3898 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003899 } else if (t == ';') {
3900 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003901 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003902 // Don't have to do anything special here, the error
3903 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003904 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003905 if (!isDefined(t)) {
3906 mGlobals.add(t);
3907 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003908 }
Jack Palevich8df46192009-07-07 14:48:51 -07003909 VariableInfo* pVI = VI(t);
3910 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003911 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003912 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003913 linkGlobal(t, tok == '(');
3914 n = (intptr_t) pVI->pAddress;
3915 if (!n && tok != '(') {
3916 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003917 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003918 }
Jack Palevich29daf572009-07-30 19:38:55 -07003919 if (tok != '(') {
Jack Palevich21a15a22009-05-11 14:49:29 -07003920 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003921 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003922 linkGlobal(t, false);
3923 n = (intptr_t) pVI->pAddress;
3924 if (!n) {
3925 error("Undeclared variable %s\n", nameof(t));
3926 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003927 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07003928 // load a variable
Jack Palevich21a15a22009-05-11 14:49:29 -07003929 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003930 // post inc / post dec
Jack Palevichb5e33312009-07-30 19:06:34 -07003931 pGen->leaR0(n, createPtrType(pVI->pType), ET_LVALUE);
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003932
Jack Palevich58c30ee2009-07-17 16:35:23 -07003933 pGen->pushR0();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003934 pGen->loadR0FromR0();
3935 pGen->over();
3936 int lit = 1;
3937 if (tokc == OP_DECREMENT) {
3938 lit = -1;
3939 }
3940 switch (pVI->pType->tag) {
3941 case TY_INT:
3942 case TY_CHAR:
3943 case TY_POINTER:
3944 pGen->pushR0();
3945 pGen->li(lit);
3946 pGen->genOp(OP_PLUS);
3947 break;
3948 default:
3949 error("++/-- illegal for this type.");
3950 break;
3951 }
3952
3953 pGen->storeR0ToTOS();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003954 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003955 next();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003956 } else {
Jack Palevichb5e33312009-07-30 19:06:34 -07003957 pGen->leaR0(n, createPtrType(pVI->pType), ET_LVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07003958 }
3959 }
3960 }
3961 }
3962
3963 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003964 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003965 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003966 VariableInfo* pVI = NULL;
3967 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevich9f51a262009-07-29 16:22:26 -07003968 Type* pFn = pGen->getR0Type();
3969 assert(pFn->tag == TY_POINTER);
3970 assert(pFn->pHead->tag == TY_FUNC);
3971 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07003972 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003973 } else {
3974 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003975 pDecl = pVI->pType;
Jack Palevich9f51a262009-07-29 16:22:26 -07003976 Type* pFn = createPtrType(pDecl);
3977 if (n == 0) {
3978 pVI->pForward = (void*) pGen->leaForward(
3979 (int) pVI->pForward, pFn);
3980 } else {
Jack Palevichb5e33312009-07-30 19:06:34 -07003981 pGen->leaR0(n, pFn, ET_RVALUE);
Jack Palevich9f51a262009-07-29 16:22:26 -07003982 }
3983 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003984 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003985 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003986 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003987 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003988 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003989 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003990 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003991 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003992 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07003993 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07003994 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003995 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07003996 pGen->forceR0RVal();
Jack Palevich1a539db2009-07-08 13:04:41 -07003997 Type* pTargetType;
3998 if (pArgList) {
3999 pTargetType = pArgList->pHead;
4000 pArgList = pArgList->pTail;
4001 } else {
Jack Palevich9f51a262009-07-29 16:22:26 -07004002 // This is a ... function, just pass arguments in their
4003 // natural type.
Jack Palevich1a539db2009-07-08 13:04:41 -07004004 pTargetType = pGen->getR0Type();
4005 if (pTargetType->tag == TY_FLOAT) {
4006 pTargetType = mkpDouble;
4007 }
4008 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004009 if (pTargetType->tag == TY_VOID) {
4010 error("Can't pass void value for argument %d",
4011 argCount + 1);
4012 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004013 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004014 }
Jack Palevich95727a02009-07-06 12:07:15 -07004015 if (accept(',')) {
4016 // fine
4017 } else if ( tok != ')') {
4018 error("Expected ',' or ')'");
4019 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004020 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004021 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004022 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004023 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004024 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004025 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004026 skip(')');
Jack Palevich9f51a262009-07-29 16:22:26 -07004027 pGen->callIndirect(l, pDecl);
4028 pGen->adjustStackAfterCall(pDecl, l, true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004029 }
4030 }
4031
Jack Palevich40600de2009-07-01 15:32:35 -07004032 /* Recursive descent parser for binary operations.
4033 */
4034 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004035 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004036 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004037 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004038 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004039 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004040 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004041 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004042 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004043 t = tokc;
4044 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004045 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004046 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004047 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004048 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004049 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004050 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004051 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004052 // Check for syntax error.
4053 if (pGen->getR0Type() == NULL) {
4054 // We failed to parse a right-hand argument.
4055 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004056 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004057 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004058 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004059 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004060 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004061 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004062 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004063 }
4064 }
4065 }
4066 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004067 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004068 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004069 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004070 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004071 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004072 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004073 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004074 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 }
4076 }
4077 }
4078
Jack Palevich43aaee32009-07-31 14:01:37 -07004079 void commaExpr() {
4080 for(;;) {
4081 expr();
4082 if (!accept(',')) {
4083 break;
4084 }
4085 }
4086 }
4087
Jack Palevich21a15a22009-05-11 14:49:29 -07004088 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004089 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004090 }
4091
4092 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004093 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004094 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004095 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004096 }
4097
Jack Palevicha6baa232009-06-12 11:25:59 -07004098 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004099 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004100
Jack Palevich95727a02009-07-06 12:07:15 -07004101 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004102 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004103 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004104 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004105 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004106 next();
4107 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004108 a = test_expr();
4109 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004110 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004111 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004112 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004113 n = pGen->gjmp(0); /* jmp */
4114 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004115 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004116 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004117 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004118 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004119 }
Jack Palevich546b2242009-05-13 15:10:04 -07004120 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004121 t = tok;
4122 next();
4123 skip('(');
4124 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004125 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004126 a = test_expr();
4127 } else {
4128 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004129 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004130 skip(';');
4131 n = codeBuf.getPC();
4132 a = 0;
4133 if (tok != ';')
4134 a = test_expr();
4135 skip(';');
4136 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004137 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004138 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004139 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004140 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004141 n = t + 4;
4142 }
4143 }
4144 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004145 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004146 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004147 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004148 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004149 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004150 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004151 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004152 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004153 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004154 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004155 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004156 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004157 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004158 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004159 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004160 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004161 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004162 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004163 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004164 if (pReturnType->tag == TY_VOID) {
4165 error("Must not return a value from a void function");
4166 } else {
4167 pGen->convertR0(pReturnType);
4168 }
4169 } else {
4170 if (pReturnType->tag != TY_VOID) {
4171 error("Must specify a value here");
4172 }
Jack Palevich8df46192009-07-07 14:48:51 -07004173 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004174 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004175 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004176 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004177 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004178 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004179 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004180 }
4181 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004182
Jack Palevicha8f427f2009-07-13 18:40:08 -07004183 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004184 if (a == b) {
4185 return true;
4186 }
4187 if (a == NULL || b == NULL) {
4188 return false;
4189 }
4190 TypeTag at = a->tag;
4191 if (at != b->tag) {
4192 return false;
4193 }
4194 if (at == TY_POINTER) {
4195 return typeEqual(a->pHead, b->pHead);
4196 } else if (at == TY_FUNC || at == TY_PARAM) {
4197 return typeEqual(a->pHead, b->pHead)
4198 && typeEqual(a->pTail, b->pTail);
4199 }
4200 return true;
4201 }
4202
Jack Palevich2ff5c222009-07-23 15:11:22 -07004203 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004204 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004205 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004206 memset(pType, 0, sizeof(*pType));
4207 pType->tag = tag;
4208 pType->pHead = pHead;
4209 pType->pTail = pTail;
4210 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004211 }
4212
Jack Palevich2ff5c222009-07-23 15:11:22 -07004213 Type* createPtrType(Type* pType) {
4214 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004215 }
4216
4217 /**
4218 * Try to print a type in declaration order
4219 */
Jack Palevich86351982009-06-30 18:09:56 -07004220 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004221 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004222 if (pType == NULL) {
4223 buffer.appendCStr("null");
4224 return;
4225 }
Jack Palevich3f226492009-07-02 14:46:19 -07004226 decodeTypeImp(buffer, pType);
4227 }
4228
4229 void decodeTypeImp(String& buffer, Type* pType) {
4230 decodeTypeImpPrefix(buffer, pType);
4231
Jack Palevich86351982009-06-30 18:09:56 -07004232 String temp;
4233 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004234 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004235 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004236 }
4237
4238 decodeTypeImpPostfix(buffer, pType);
4239 }
4240
4241 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4242 TypeTag tag = pType->tag;
4243
Jack Palevich37c54bd2009-07-14 18:35:36 -07004244 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004245 switch (tag) {
4246 case TY_INT:
4247 buffer.appendCStr("int");
4248 break;
4249 case TY_CHAR:
4250 buffer.appendCStr("char");
4251 break;
4252 case TY_VOID:
4253 buffer.appendCStr("void");
4254 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004255 case TY_FLOAT:
4256 buffer.appendCStr("float");
4257 break;
4258 case TY_DOUBLE:
4259 buffer.appendCStr("double");
4260 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004261 default:
4262 break;
4263 }
Jack Palevich86351982009-06-30 18:09:56 -07004264 buffer.append(' ');
4265 }
Jack Palevich3f226492009-07-02 14:46:19 -07004266
4267 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004268 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004269 break;
4270 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004271 break;
4272 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004273 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004274 case TY_FLOAT:
4275 break;
4276 case TY_DOUBLE:
4277 break;
Jack Palevich86351982009-06-30 18:09:56 -07004278 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004279 decodeTypeImpPrefix(buffer, pType->pHead);
4280 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4281 buffer.append('(');
4282 }
4283 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004284 break;
4285 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004286 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004287 break;
4288 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004289 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004290 break;
4291 default:
4292 String temp;
4293 temp.printf("Unknown tag %d", pType->tag);
4294 buffer.append(temp);
4295 break;
4296 }
Jack Palevich3f226492009-07-02 14:46:19 -07004297 }
4298
4299 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4300 TypeTag tag = pType->tag;
4301
4302 switch(tag) {
4303 case TY_POINTER:
4304 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4305 buffer.append(')');
4306 }
4307 decodeTypeImpPostfix(buffer, pType->pHead);
4308 break;
4309 case TY_FUNC:
4310 buffer.append('(');
4311 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4312 decodeTypeImp(buffer, pArg);
4313 if (pArg->pTail) {
4314 buffer.appendCStr(", ");
4315 }
4316 }
4317 buffer.append(')');
4318 break;
4319 default:
4320 break;
Jack Palevich86351982009-06-30 18:09:56 -07004321 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004322 }
4323
Jack Palevich86351982009-06-30 18:09:56 -07004324 void printType(Type* pType) {
4325 String buffer;
4326 decodeType(buffer, pType);
4327 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004328 }
4329
Jack Palevich2ff5c222009-07-23 15:11:22 -07004330 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004331 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004332 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004333 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004334 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004335 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004336 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004337 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004338 } else if (tok == TOK_FLOAT) {
4339 pType = mkpFloat;
4340 } else if (tok == TOK_DOUBLE) {
4341 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004342 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004343 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004344 }
4345 next();
Jack Palevich86351982009-06-30 18:09:56 -07004346 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004347 }
4348
Jack Palevich2ff5c222009-07-23 15:11:22 -07004349 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004350 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004351 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004352 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004353 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004354 if (declName) {
4355 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004356 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004357
Jack Palevich86351982009-06-30 18:09:56 -07004358 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004359 }
Jack Palevich3f226492009-07-02 14:46:19 -07004360 // fprintf(stderr, "Parsed a declaration: ");
4361 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004362 if (reportFailure) {
4363 return NULL;
4364 }
Jack Palevich86351982009-06-30 18:09:56 -07004365 return pType;
4366 }
4367
Jack Palevich2ff5c222009-07-23 15:11:22 -07004368 Type* expectDeclaration(Type* pBaseType) {
4369 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004370 if (! pType) {
4371 error("Expected a declaration");
4372 }
4373 return pType;
4374 }
4375
Jack Palevich3f226492009-07-02 14:46:19 -07004376 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004377 Type* acceptCastTypeDeclaration() {
4378 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004379 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004380 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004381 }
Jack Palevich86351982009-06-30 18:09:56 -07004382 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004383 }
4384
Jack Palevich2ff5c222009-07-23 15:11:22 -07004385 Type* expectCastTypeDeclaration() {
4386 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004387 if (! pType) {
4388 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004389 }
Jack Palevich3f226492009-07-02 14:46:19 -07004390 return pType;
4391 }
4392
4393 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004394 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004395 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004396 int ptrCounter = 0;
4397 while (accept('*')) {
4398 ptrCounter++;
4399 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004400 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004401 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004402 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004403 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004404 }
4405 return pType;
4406 }
4407
4408 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004409 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004410 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004411 // direct-dcl :
4412 // name
4413 // (dcl)
4414 // direct-dcl()
4415 // direct-dcl[]
4416 Type* pNewHead = NULL;
4417 if (accept('(')) {
4418 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004419 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004420 skip(')');
4421 } else if ((declName = acceptSymbol()) != 0) {
4422 if (nameAllowed == false && declName) {
4423 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004424 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004425 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004426 } else if (nameRequired && ! declName) {
4427 String temp;
4428 decodeToken(temp, tok, true);
4429 error("Expected name. Got %s", temp.getUnwrapped());
4430 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004431 }
4432 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004433 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004434 Type* pTail = acceptArgs(nameAllowed);
4435 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004436 skip(')');
4437 }
Jack Palevich3f226492009-07-02 14:46:19 -07004438
4439 if (pNewHead) {
4440 Type* pA = pNewHead;
4441 while (pA->pHead) {
4442 pA = pA->pHead;
4443 }
4444 pA->pHead = pType;
4445 pType = pNewHead;
4446 }
Jack Palevich86351982009-06-30 18:09:56 -07004447 return pType;
4448 }
4449
Jack Palevich2ff5c222009-07-23 15:11:22 -07004450 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004451 Type* pHead = NULL;
4452 Type* pTail = NULL;
4453 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004454 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004455 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004456 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004457 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004458 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004459 if (!pHead) {
4460 pHead = pParam;
4461 pTail = pParam;
4462 } else {
4463 pTail->pTail = pParam;
4464 pTail = pParam;
4465 }
4466 }
4467 }
4468 if (! accept(',')) {
4469 break;
4470 }
4471 }
4472 return pHead;
4473 }
4474
Jack Palevich2ff5c222009-07-23 15:11:22 -07004475 Type* expectPrimitiveType() {
4476 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004477 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004478 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004479 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004480 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004481 }
Jack Palevich86351982009-06-30 18:09:56 -07004482 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004483 }
4484
Jack Palevichb5e33312009-07-30 19:06:34 -07004485 void checkLVal() {
4486 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4487 error("Expected an lval");
4488 }
4489 }
4490
Jack Palevich86351982009-06-30 18:09:56 -07004491 void addGlobalSymbol(Type* pDecl) {
4492 tokenid_t t = pDecl->id;
4493 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004494 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004495 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004496 }
Jack Palevich86351982009-06-30 18:09:56 -07004497 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004498 }
4499
Jack Palevich86351982009-06-30 18:09:56 -07004500 void reportDuplicate(tokenid_t t) {
4501 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004502 }
4503
Jack Palevich86351982009-06-30 18:09:56 -07004504 void addLocalSymbol(Type* pDecl) {
4505 tokenid_t t = pDecl->id;
4506 if (mLocals.isDefinedAtCurrentLevel(t)) {
4507 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004508 }
Jack Palevich86351982009-06-30 18:09:56 -07004509 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004510 }
4511
Jack Palevich95727a02009-07-06 12:07:15 -07004512 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004513 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004514
Jack Palevich95727a02009-07-06 12:07:15 -07004515 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004516 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004517 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004518 if (!pDecl) {
4519 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004520 }
Jack Palevich86351982009-06-30 18:09:56 -07004521 int variableAddress = 0;
4522 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004523 size_t alignment = pGen->stackAlignmentOf(pDecl);
4524 size_t alignmentMask = ~ (alignment - 1);
4525 size_t sizeOf = pGen->sizeOf(pDecl);
4526 loc = (loc + alignment - 1) & alignmentMask;
4527 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4528 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004529 variableAddress = -loc;
4530 VI(pDecl->id)->pAddress = (void*) variableAddress;
4531 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004532 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004533 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004534 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004535 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004536 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004537 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004538 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004539 if (tok == ',')
4540 next();
4541 }
4542 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004543 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004544 }
4545 }
4546
Jack Palevichf1728be2009-06-12 13:53:51 -07004547 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004548 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004549 }
4550
Jack Palevich37c54bd2009-07-14 18:35:36 -07004551 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004552 if (token == EOF ) {
4553 buffer.printf("EOF");
4554 } else if (token == TOK_NUM) {
4555 buffer.printf("numeric constant");
4556 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004557 if (token < 32) {
4558 buffer.printf("'\\x%02x'", token);
4559 } else {
4560 buffer.printf("'%c'", token);
4561 }
Jack Palevich569f1352009-06-29 14:29:08 -07004562 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004563 if (quote) {
4564 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4565 buffer.printf("keyword \"%s\"", nameof(token));
4566 } else {
4567 buffer.printf("symbol \"%s\"", nameof(token));
4568 }
4569 } else {
4570 buffer.printf("%s", nameof(token));
4571 }
Jack Palevich569f1352009-06-29 14:29:08 -07004572 }
4573 }
4574
Jack Palevich40600de2009-07-01 15:32:35 -07004575 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004576 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004577 if (!result) {
4578 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004579 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004580 error("Expected symbol. Got %s", temp.getUnwrapped());
4581 }
4582 return result;
4583 }
4584
Jack Palevich86351982009-06-30 18:09:56 -07004585 tokenid_t acceptSymbol() {
4586 tokenid_t result = 0;
4587 if (tok >= TOK_SYMBOL) {
4588 result = tok;
4589 next();
Jack Palevich86351982009-06-30 18:09:56 -07004590 }
4591 return result;
4592 }
4593
Jack Palevichb7c81e92009-06-04 19:56:13 -07004594 void globalDeclarations() {
4595 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004596 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004597 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004598 break;
4599 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004600 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004601 if (!pDecl) {
4602 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004603 }
Jack Palevich86351982009-06-30 18:09:56 -07004604 if (! isDefined(pDecl->id)) {
4605 addGlobalSymbol(pDecl);
4606 }
4607 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004608 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004609 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004610 }
Jack Palevich86351982009-06-30 18:09:56 -07004611 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004612 // it's a variable declaration
4613 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004614 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004615 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004616 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004617 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004618 }
Jack Palevich86351982009-06-30 18:09:56 -07004619 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004620 if (tok == TOK_NUM) {
4621 if (name) {
4622 * (int*) name->pAddress = tokc;
4623 }
4624 next();
4625 } else {
4626 error("Expected an integer constant");
4627 }
4628 }
Jack Palevich86351982009-06-30 18:09:56 -07004629 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004630 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004631 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004632 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004633 if (!pDecl) {
4634 break;
4635 }
4636 if (! isDefined(pDecl->id)) {
4637 addGlobalSymbol(pDecl);
4638 }
4639 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004640 }
4641 skip(';');
4642 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004643 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004644 if (accept(';')) {
4645 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004646 } else if (tok != '{') {
4647 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004648 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004649 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004650 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004651 /* patch forward references */
4652 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004653 /* put function address */
4654 name->pAddress = (void*) codeBuf.getPC();
4655 }
4656 // Calculate stack offsets for parameters
4657 mLocals.pushLevel();
4658 intptr_t a = 8;
4659 int argCount = 0;
4660 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4661 Type* pArg = pP->pHead;
4662 addLocalSymbol(pArg);
4663 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004664 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004665 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004666 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004667 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004668 argCount++;
4669 }
4670 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004671 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004672 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004673 block(0, true);
4674 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004675 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004676 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004677 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004678 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004679 }
4680 }
4681 }
4682
Jack Palevich9cbd2262009-07-08 16:48:41 -07004683 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4684 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4685 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004686 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004687 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004688 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004689 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004690 char* result = (char*) base;
4691 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004692 return result;
4693 }
4694
Jack Palevich21a15a22009-05-11 14:49:29 -07004695 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004696 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004697 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004698 pGlobalBase = 0;
4699 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004700 if (pGen) {
4701 delete pGen;
4702 pGen = 0;
4703 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004704 if (file) {
4705 delete file;
4706 file = 0;
4707 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 }
4709
Jack Palevich8c246a92009-07-14 21:14:10 -07004710 // One-time initialization, when class is constructed.
4711 void init() {
4712 mpSymbolLookupFn = 0;
4713 mpSymbolLookupContext = 0;
4714 }
4715
Jack Palevich21a15a22009-05-11 14:49:29 -07004716 void clear() {
4717 tok = 0;
4718 tokc = 0;
4719 tokl = 0;
4720 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004721 rsym = 0;
4722 loc = 0;
4723 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004724 dptr = 0;
4725 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004726 file = 0;
4727 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004728 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004729 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004730 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004731 mLineNumber = 1;
4732 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004733 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004734
Jack Palevich22305132009-05-13 10:58:45 -07004735 void setArchitecture(const char* architecture) {
4736 delete pGen;
4737 pGen = 0;
4738
4739 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004740#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004741 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004742 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004743 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004744#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004745#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004746 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004747 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004748 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004749#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004750 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004751 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004752 }
4753 }
4754
4755 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004756#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004757 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004758#elif defined(DEFAULT_X86_CODEGEN)
4759 pGen = new X86CodeGenerator();
4760#endif
4761 }
4762 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004763 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004764 } else {
4765 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004766 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004767 }
4768 }
4769
Jack Palevich77ae76e2009-05-10 19:59:24 -07004770public:
Jack Palevich22305132009-05-13 10:58:45 -07004771 struct args {
4772 args() {
4773 architecture = 0;
4774 }
4775 const char* architecture;
4776 };
4777
Jack Paleviche7b59062009-05-19 17:12:17 -07004778 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004779 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004780 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004781 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004782
Jack Paleviche7b59062009-05-19 17:12:17 -07004783 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004784 cleanup();
4785 }
4786
Jack Palevich8c246a92009-07-14 21:14:10 -07004787 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4788 mpSymbolLookupFn = pFn;
4789 mpSymbolLookupContext = pContext;
4790 }
4791
Jack Palevich1cdef202009-05-22 12:06:27 -07004792 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004793 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004794
Jack Palevich2ff5c222009-07-23 15:11:22 -07004795 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004796 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004797 cleanup();
4798 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004799 mTokenTable.setArena(&mGlobalArena);
4800 mGlobals.setArena(&mGlobalArena);
4801 mGlobals.setTokenTable(&mTokenTable);
4802 mLocals.setArena(&mLocalArena);
4803 mLocals.setTokenTable(&mTokenTable);
4804
4805 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004806 codeBuf.init(ALLOC_SIZE);
4807 setArchitecture(NULL);
4808 if (!pGen) {
4809 return -1;
4810 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004811#ifdef PROVIDE_TRACE_CODEGEN
4812 pGen = new TraceCodeGenerator(pGen);
4813#endif
4814 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004815 pGen->init(&codeBuf);
4816 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004817 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4818 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004819 inp();
4820 next();
4821 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004822 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004823 result = pGen->finishCompile();
4824 if (result == 0) {
4825 if (mErrorBuf.len()) {
4826 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004827 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004828 }
Jack Palevichce105a92009-07-16 14:30:33 -07004829 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004830 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004831 }
4832
Jack Palevich86351982009-06-30 18:09:56 -07004833 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004834 mkpInt = createType(TY_INT, NULL, NULL);
4835 mkpChar = createType(TY_CHAR, NULL, NULL);
4836 mkpVoid = createType(TY_VOID, NULL, NULL);
4837 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4838 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4839 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4840 mkpIntPtr = createPtrType(mkpInt);
4841 mkpCharPtr = createPtrType(mkpChar);
4842 mkpFloatPtr = createPtrType(mkpFloat);
4843 mkpDoublePtr = createPtrType(mkpDouble);
4844 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004845 }
4846
Jack Palevicha6baa232009-06-12 11:25:59 -07004847 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004848 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004849 }
4850
Jack Palevich569f1352009-06-29 14:29:08 -07004851 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004852 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004853 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004854 }
4855
Jack Palevich569f1352009-06-29 14:29:08 -07004856 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004857 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004858 error("Undefined forward reference: %s",
4859 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004860 }
4861 return true;
4862 }
4863
Jack Palevich21a15a22009-05-11 14:49:29 -07004864 int dump(FILE* out) {
4865 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4866 return 0;
4867 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004868
Jack Palevicha6535612009-05-13 16:24:17 -07004869 int disassemble(FILE* out) {
4870 return pGen->disassemble(out);
4871 }
4872
Jack Palevich1cdef202009-05-22 12:06:27 -07004873 /* Look through the symbol table to find a symbol.
4874 * If found, return its value.
4875 */
4876 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004877 if (mCompileResult == 0) {
4878 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4879 VariableInfo* pVariableInfo = VI(tok);
4880 if (pVariableInfo) {
4881 return pVariableInfo->pAddress;
4882 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004883 }
4884 return NULL;
4885 }
4886
Jack Palevicheedf9d22009-06-04 16:23:40 -07004887 void getPragmas(ACCsizei* actualStringCount,
4888 ACCsizei maxStringCount, ACCchar** strings) {
4889 int stringCount = mPragmaStringCount;
4890 if (actualStringCount) {
4891 *actualStringCount = stringCount;
4892 }
4893 if (stringCount > maxStringCount) {
4894 stringCount = maxStringCount;
4895 }
4896 if (strings) {
4897 char* pPragmas = mPragmas.getUnwrapped();
4898 while (stringCount-- > 0) {
4899 *strings++ = pPragmas;
4900 pPragmas += strlen(pPragmas) + 1;
4901 }
4902 }
4903 }
4904
Jack Palevichac0e95e2009-05-29 13:53:44 -07004905 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004906 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004907 }
4908
Jack Palevich77ae76e2009-05-10 19:59:24 -07004909};
4910
Jack Paleviche7b59062009-05-19 17:12:17 -07004911const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004912 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4913
Jack Paleviche7b59062009-05-19 17:12:17 -07004914const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004915 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4916 5, 5, /* ==, != */
4917 9, 10, /* &&, || */
4918 6, 7, 8, /* & ^ | */
4919 2, 2 /* ~ ! */
4920 };
4921
Jack Palevich8b0624c2009-05-20 12:12:06 -07004922#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004923FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004924#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004925
Jack Palevich8b0624c2009-05-20 12:12:06 -07004926#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004927const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004928 0x1, // ++
4929 0xff, // --
4930 0xc1af0f, // *
4931 0xf9f79991, // /
4932 0xf9f79991, // % (With manual assist to swap results)
4933 0xc801, // +
4934 0xd8f7c829, // -
4935 0xe0d391, // <<
4936 0xf8d391, // >>
4937 0xe, // <=
4938 0xd, // >=
4939 0xc, // <
4940 0xf, // >
4941 0x4, // ==
4942 0x5, // !=
4943 0x0, // &&
4944 0x1, // ||
4945 0xc821, // &
4946 0xc831, // ^
4947 0xc809, // |
4948 0xd0f7, // ~
4949 0x4 // !
4950};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004951#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004952
Jack Palevich1cdef202009-05-22 12:06:27 -07004953struct ACCscript {
4954 ACCscript() {
4955 text = 0;
4956 textLength = 0;
4957 accError = ACC_NO_ERROR;
4958 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004959
Jack Palevich1cdef202009-05-22 12:06:27 -07004960 ~ACCscript() {
4961 delete text;
4962 }
Jack Palevich546b2242009-05-13 15:10:04 -07004963
Jack Palevich8c246a92009-07-14 21:14:10 -07004964 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4965 compiler.registerSymbolCallback(pFn, pContext);
4966 }
4967
Jack Palevich1cdef202009-05-22 12:06:27 -07004968 void setError(ACCenum error) {
4969 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4970 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004971 }
4972 }
4973
Jack Palevich1cdef202009-05-22 12:06:27 -07004974 ACCenum getError() {
4975 ACCenum result = accError;
4976 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004977 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004978 }
4979
Jack Palevich1cdef202009-05-22 12:06:27 -07004980 Compiler compiler;
4981 char* text;
4982 int textLength;
4983 ACCenum accError;
4984};
4985
4986
4987extern "C"
4988ACCscript* accCreateScript() {
4989 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004990}
Jack Palevich1cdef202009-05-22 12:06:27 -07004991
4992extern "C"
4993ACCenum accGetError( ACCscript* script ) {
4994 return script->getError();
4995}
4996
4997extern "C"
4998void accDeleteScript(ACCscript* script) {
4999 delete script;
5000}
5001
5002extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005003void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5004 ACCvoid* pContext) {
5005 script->registerSymbolCallback(pFn, pContext);
5006}
5007
5008extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005009void accScriptSource(ACCscript* script,
5010 ACCsizei count,
5011 const ACCchar ** string,
5012 const ACCint * length) {
5013 int totalLength = 0;
5014 for(int i = 0; i < count; i++) {
5015 int len = -1;
5016 const ACCchar* s = string[i];
5017 if (length) {
5018 len = length[i];
5019 }
5020 if (len < 0) {
5021 len = strlen(s);
5022 }
5023 totalLength += len;
5024 }
5025 delete script->text;
5026 char* text = new char[totalLength + 1];
5027 script->text = text;
5028 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005029 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005030 for(int i = 0; i < count; i++) {
5031 int len = -1;
5032 const ACCchar* s = string[i];
5033 if (length) {
5034 len = length[i];
5035 }
5036 if (len < 0) {
5037 len = strlen(s);
5038 }
Jack Palevich09555c72009-05-27 12:25:55 -07005039 memcpy(dest, s, len);
5040 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005041 }
5042 text[totalLength] = '\0';
5043}
5044
5045extern "C"
5046void accCompileScript(ACCscript* script) {
5047 int result = script->compiler.compile(script->text, script->textLength);
5048 if (result) {
5049 script->setError(ACC_INVALID_OPERATION);
5050 }
5051}
5052
5053extern "C"
5054void accGetScriptiv(ACCscript* script,
5055 ACCenum pname,
5056 ACCint * params) {
5057 switch (pname) {
5058 case ACC_INFO_LOG_LENGTH:
5059 *params = 0;
5060 break;
5061 }
5062}
5063
5064extern "C"
5065void accGetScriptInfoLog(ACCscript* script,
5066 ACCsizei maxLength,
5067 ACCsizei * length,
5068 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005069 char* message = script->compiler.getErrorMessage();
5070 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005071 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005072 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005073 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005074 if (infoLog && maxLength > 0) {
5075 int trimmedLength = maxLength < messageLength ?
5076 maxLength : messageLength;
5077 memcpy(infoLog, message, trimmedLength);
5078 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005079 }
5080}
5081
5082extern "C"
5083void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5084 ACCvoid ** address) {
5085 void* value = script->compiler.lookup(name);
5086 if (value) {
5087 *address = value;
5088 } else {
5089 script->setError(ACC_INVALID_VALUE);
5090 }
5091}
5092
Jack Palevicheedf9d22009-06-04 16:23:40 -07005093extern "C"
5094void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5095 ACCsizei maxStringCount, ACCchar** strings){
5096 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5097}
5098
-b master422972c2009-06-17 19:13:52 -07005099extern "C"
5100void accDisassemble(ACCscript* script) {
5101 script->compiler.disassemble(stderr);
5102}
5103
Jack Palevicheedf9d22009-06-04 16:23:40 -07005104
Jack Palevich1cdef202009-05-22 12:06:27 -07005105} // namespace acc
5106