blob: e7f7d8d92822a0d4c5c5ceeec6d5331c23a5331a [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000012#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070014#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070015#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070016#include <stdlib.h>
17#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070018#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich8dc662e2009-06-09 22:53:47 +000020#if defined(__i386__)
21#include <sys/mman.h>
22#endif
23
Jack Palevich546b2242009-05-13 15:10:04 -070024#if defined(__arm__)
25#include <unistd.h>
26#endif
27
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Paleviche7b59062009-05-19 17:12:17 -070039#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070040#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
Jack Palevicha6535612009-05-13 16:24:17 -070042
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
51// #define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070052// #define PROVIDE_TRACE_CODEGEN
53
Jack Palevichbbf8ab52009-05-11 11:54:30 -070054namespace acc {
55
Jack Palevich8df46192009-07-07 14:48:51 -070056// Subset of STL vector.
57template<class E> class Vector {
58 public:
59 Vector() {
60 mpBase = 0;
61 mUsed = 0;
62 mSize = 0;
63 }
64
65 ~Vector() {
66 if (mpBase) {
67 for(size_t i = 0; i < mUsed; i++) {
68 mpBase[mUsed].~E();
69 }
70 free(mpBase);
71 }
72 }
73
74 inline E& operator[](size_t i) {
75 return mpBase[i];
76 }
77
78 inline E& front() {
79 return mpBase[0];
80 }
81
82 inline E& back() {
83 return mpBase[mUsed - 1];
84 }
85
86 void pop_back() {
87 mUsed -= 1;
88 mpBase[mUsed].~E();
89 }
90
91 void push_back(const E& item) {
92 * ensure(1) = item;
93 }
94
95 size_t size() {
96 return mUsed;
97 }
98
99private:
100 E* ensure(int n) {
101 size_t newUsed = mUsed + n;
102 if (newUsed > mSize) {
103 size_t newSize = mSize * 2 + 10;
104 if (newSize < newUsed) {
105 newSize = newUsed;
106 }
107 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
108 mSize = newSize;
109 }
110 E* result = mpBase + mUsed;
111 mUsed = newUsed;
112 return result;
113 }
114
115 E* mpBase;
116 size_t mUsed;
117 size_t mSize;
118};
119
Jack Palevichac0e95e2009-05-29 13:53:44 -0700120class ErrorSink {
121public:
122 void error(const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 verror(fmt, ap);
126 va_end(ap);
127 }
128
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700129 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
136 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
137 TY_POINTER, TY_FUNC, TY_PARAM
138 };
139
140 struct Type {
141 TypeTag tag;
142 tokenid_t id; // For function arguments
143 Type* pHead;
144 Type* pTail;
145 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700146
Jack Palevichba929a42009-07-17 10:20:32 -0700147 enum ExpressionType {
148 ET_RVALUE,
149 ET_LVALUE
150 };
151
152 struct ExpressionValue {
153 ExpressionValue() {
154 et = ET_RVALUE;
155 pType = NULL;
156 }
157 ExpressionType et;
158 Type* pType;
159 };
160
Jack Palevich21a15a22009-05-11 14:49:29 -0700161 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700162 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700163 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700164 ErrorSink* mErrorSink;
165 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700166 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700167
Jack Palevich21a15a22009-05-11 14:49:29 -0700168 void release() {
169 if (pProgramBase != 0) {
170 free(pProgramBase);
171 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700172 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 }
174
Jack Palevich0a280a02009-06-11 10:53:51 -0700175 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700176 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700177 bool overflow = newSize > mSize;
178 if (overflow && !mOverflowed) {
179 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700180 if (mErrorSink) {
181 mErrorSink->error("Code too large: %d bytes", newSize);
182 }
183 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700184 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 }
186
Jack Palevich21a15a22009-05-11 14:49:29 -0700187 public:
188 CodeBuf() {
189 pProgramBase = 0;
190 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700191 mErrorSink = 0;
192 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700193 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
196 ~CodeBuf() {
197 release();
198 }
199
200 void init(int size) {
201 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700202 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700203 pProgramBase = (char*) calloc(1, size);
204 ind = pProgramBase;
205 }
206
Jack Palevichac0e95e2009-05-29 13:53:44 -0700207 void setErrorSink(ErrorSink* pErrorSink) {
208 mErrorSink = pErrorSink;
209 }
210
Jack Palevich546b2242009-05-13 15:10:04 -0700211 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 if(check(4)) {
213 return 0;
214 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700215 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700216 * (int*) ind = n;
217 ind += 4;
218 return result;
219 }
220
Jack Palevich21a15a22009-05-11 14:49:29 -0700221 /*
222 * Output a byte. Handles all values, 0..ff.
223 */
224 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700225 if(check(1)) {
226 return;
227 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 *ind++ = n;
229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 inline void* getBase() {
232 return (void*) pProgramBase;
233 }
234
Jack Palevich8b0624c2009-05-20 12:12:06 -0700235 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700236 return ind - pProgramBase;
237 }
238
Jack Palevich8b0624c2009-05-20 12:12:06 -0700239 intptr_t getPC() {
240 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 }
242 };
243
Jack Palevich1cdef202009-05-22 12:06:27 -0700244 /**
245 * A code generator creates an in-memory program, generating the code on
246 * the fly. There is one code generator implementation for each supported
247 * architecture.
248 *
249 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700250 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700251 * FP - a frame pointer for accessing function arguments and local
252 * variables.
253 * SP - a stack pointer for storing intermediate results while evaluating
254 * expressions. The stack pointer grows downwards.
255 *
256 * The function calling convention is that all arguments are placed on the
257 * stack such that the first argument has the lowest address.
258 * After the call, the result is in R0. The caller is responsible for
259 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700260 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 * FP and SP registers are saved.
262 */
263
Jack Palevich21a15a22009-05-11 14:49:29 -0700264 class CodeGenerator {
265 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 CodeGenerator() {
267 mErrorSink = 0;
268 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700269 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700270 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700271 virtual ~CodeGenerator() {}
272
Jack Palevich22305132009-05-13 10:58:45 -0700273 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700275 pCodeBuf->setErrorSink(mErrorSink);
276 }
277
Jack Palevichb67b18f2009-06-11 21:12:23 -0700278 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700279 mErrorSink = pErrorSink;
280 if (pCodeBuf) {
281 pCodeBuf->setErrorSink(mErrorSink);
282 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
284
Jack Palevich58c30ee2009-07-17 16:35:23 -0700285 /* Give the code generator some utility types so it can
286 * use its own types as needed for the results of some
287 * operations like gcmp.
288 */
289
Jack Palevicha8f427f2009-07-13 18:40:08 -0700290 void setTypes(Type* pInt) {
291 mkpInt = pInt;
292 }
293
Jack Palevich1cdef202009-05-22 12:06:27 -0700294 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700295 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700296 * Save the old value of the FP.
297 * Set the new value of the FP.
298 * Convert from the native platform calling convention to
299 * our stack-based calling convention. This may require
300 * pushing arguments from registers to the stack.
301 * Allocate "N" bytes of stack space. N isn't known yet, so
302 * just emit the instructions for adjusting the stack, and return
303 * the address to patch up. The patching will be done in
304 * functionExit().
305 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700306 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700307 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700308
Jack Palevich1cdef202009-05-22 12:06:27 -0700309 /* Emit a function epilog.
310 * Restore the old SP and FP register values.
311 * Return to the calling function.
312 * argCount - the number of arguments to the function.
313 * localVariableAddress - returned from functionEntry()
314 * localVariableSize - the size in bytes of the local variables.
315 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700316 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700318
Jack Palevich1cdef202009-05-22 12:06:27 -0700319 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700320 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700321
Jack Palevich1a539db2009-07-08 13:04:41 -0700322 /* Load floating point value from global address. */
323 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Jump to a target, and return the address of the word that
326 * holds the target data, in case it needs to be fixed up later.
327 */
Jack Palevich22305132009-05-13 10:58:45 -0700328 virtual int gjmp(int t) = 0;
329
Jack Palevich1cdef202009-05-22 12:06:27 -0700330 /* Test R0 and jump to a target if the test succeeds.
331 * l = 0: je, l == 1: jne
332 * Return the address of the word that holds the targed data, in
333 * case it needs to be fixed up later.
334 */
Jack Palevich22305132009-05-13 10:58:45 -0700335 virtual int gtst(bool l, int t) = 0;
336
Jack Palevich9eed7a22009-07-06 17:24:34 -0700337 /* Compare TOS against R0, and store the boolean result in R0.
338 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 * op specifies the comparison.
340 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700341 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700342
Jack Palevich9eed7a22009-07-06 17:24:34 -0700343 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700345 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 */
Jack Palevich546b2242009-05-13 15:10:04 -0700347 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700348
Jack Palevich9eed7a22009-07-06 17:24:34 -0700349 /* Compare 0 against R0, and store the boolean result in R0.
350 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700352 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353
354 /* Perform the arithmetic op specified by op. 0 is the
355 * left argument, R0 is the right argument.
356 */
357 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700359 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 */
361 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700363 /* Turn R0, TOS into R0 TOS R0 */
364
365 virtual void over() = 0;
366
367 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700368 */
369 virtual void popR0() = 0;
370
Jack Palevich9eed7a22009-07-06 17:24:34 -0700371 /* Store R0 to the address stored in TOS.
372 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700373 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700374 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700378 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 /* Load the absolute address of a variable to R0.
381 * If ea <= LOCAL, then this is a local variable, or an
382 * argument, addressed relative to FP.
383 * else it is an absolute global address.
384 */
Jack Palevich8df46192009-07-07 14:48:51 -0700385 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700386
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 /* Store R0 to a variable.
388 * If ea <= LOCAL, then this is a local variable, or an
389 * argument, addressed relative to FP.
390 * else it is an absolute global address.
391 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700392 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700393
Jack Palevich8df46192009-07-07 14:48:51 -0700394 /**
395 * Convert R0 to the given type.
396 */
397 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700398
Jack Palevich1cdef202009-05-22 12:06:27 -0700399 /* Emit code to adjust the stack for a function call. Return the
400 * label for the address of the instruction that adjusts the
401 * stack size. This will be passed as argument "a" to
402 * endFunctionCallArguments.
403 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700404 virtual int beginFunctionCallArguments() = 0;
405
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700407 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700408 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700409 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700410
Jack Palevich1cdef202009-05-22 12:06:27 -0700411 /* Patch the function call preamble.
412 * a is the address returned from beginFunctionCallArguments
413 * l is the number of bytes the arguments took on the stack.
414 * Typically you would also emit code to convert the argument
415 * list into whatever the native function calling convention is.
416 * On ARM for example you would pop the first 5 arguments into
417 * R0..R4
418 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700419 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700420
Jack Palevich1cdef202009-05-22 12:06:27 -0700421 /* Emit a call to an unknown function. The argument "symbol" needs to
422 * be stored in the location where the address should go. It forms
423 * a chain. The address will be patched later.
424 * Return the address of the word that has to be patched.
425 */
Jack Palevich8df46192009-07-07 14:48:51 -0700426 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevich1cdef202009-05-22 12:06:27 -0700428 /* Call a function using PC-relative addressing. t is the PC-relative
429 * address of the function. It has already been adjusted for the
430 * architectural jump offset, so just store it as-is.
431 */
Jack Palevich8df46192009-07-07 14:48:51 -0700432 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Call a function pointer. L is the number of bytes the arguments
435 * take on the stack. The address of the function is stored at
436 * location SP + l.
437 */
Jack Palevich8df46192009-07-07 14:48:51 -0700438 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700439
Jack Palevich1cdef202009-05-22 12:06:27 -0700440 /* Adjust SP after returning from a function call. l is the
441 * number of bytes of arguments stored on the stack. isIndirect
442 * is true if this was an indirect call. (In which case the
443 * address of the function is stored at location SP + l.)
444 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700445 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700446
Jack Palevich1cdef202009-05-22 12:06:27 -0700447 /* Print a disassembly of the assembled code to out. Return
448 * non-zero if there is an error.
449 */
Jack Palevicha6535612009-05-13 16:24:17 -0700450 virtual int disassemble(FILE* out) = 0;
451
Jack Palevich1cdef202009-05-22 12:06:27 -0700452 /* Generate a symbol at the current PC. t is the head of a
453 * linked list of addresses to patch.
454 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700455 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700456
Jack Palevich1cdef202009-05-22 12:06:27 -0700457 /*
458 * Do any cleanup work required at the end of a compile.
459 * For example, an instruction cache might need to be
460 * invalidated.
461 * Return non-zero if there is an error.
462 */
463 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700464
Jack Palevicha6535612009-05-13 16:24:17 -0700465 /**
466 * Adjust relative branches by this amount.
467 */
468 virtual int jumpOffset() = 0;
469
Jack Palevich9eed7a22009-07-06 17:24:34 -0700470 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700471 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700472 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700473 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700474
475 /**
476 * Array element alignment (in bytes) for this type of data.
477 */
478 virtual size_t sizeOf(Type* type) = 0;
479
Jack Palevich9cbd2262009-07-08 16:48:41 -0700480 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700481 * Stack alignment of this type of data
482 */
483 virtual size_t stackAlignmentOf(Type* pType) = 0;
484
485 /**
486 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700487 */
488 virtual size_t stackSizeOf(Type* pType) = 0;
489
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700490 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700491 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700492 }
493
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700494 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700495 return mExpressionStack.back().et;
496 }
497
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700498 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700499 mExpressionStack.back().et = et;
500 }
501
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700502 virtual size_t getExpressionStackDepth() {
503 return mExpressionStack.size();
504 }
505
Jack Palevich21a15a22009-05-11 14:49:29 -0700506 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700507 /*
508 * Output a byte. Handles all values, 0..ff.
509 */
510 void ob(int n) {
511 pCodeBuf->ob(n);
512 }
513
Jack Palevich8b0624c2009-05-20 12:12:06 -0700514 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700515 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700516 }
517
Jack Palevich8b0624c2009-05-20 12:12:06 -0700518 intptr_t getBase() {
519 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700520 }
521
Jack Palevich8b0624c2009-05-20 12:12:06 -0700522 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700523 return pCodeBuf->getPC();
524 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700525
526 intptr_t getSize() {
527 return pCodeBuf->getSize();
528 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700529
530 void error(const char* fmt,...) {
531 va_list ap;
532 va_start(ap, fmt);
533 mErrorSink->verror(fmt, ap);
534 va_end(ap);
535 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700536
537 void assert(bool test) {
538 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700539 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700540 error("code generator assertion failed.");
541 }
542 }
Jack Palevich8df46192009-07-07 14:48:51 -0700543
544 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700545 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700546 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700547 }
548
Jack Palevich8df46192009-07-07 14:48:51 -0700549 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700550 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700551 }
552
553 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700554 if (mExpressionStack.size()) {
555 mExpressionStack.push_back(mExpressionStack.back());
556 } else {
557 mExpressionStack.push_back(ExpressionValue());
558 }
559
Jack Palevich8df46192009-07-07 14:48:51 -0700560 }
561
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700562 void overType() {
563 size_t size = mExpressionStack.size();
564 if (size >= 2) {
565 mExpressionStack.push_back(mExpressionStack.back());
566 mExpressionStack[size-1] = mExpressionStack[size-2];
567 mExpressionStack[size-2] = mExpressionStack[size];
568 }
569 }
570
Jack Palevich8df46192009-07-07 14:48:51 -0700571 void popType() {
572 mExpressionStack.pop_back();
573 }
574
575 bool bitsSame(Type* pA, Type* pB) {
576 return collapseType(pA->tag) == collapseType(pB->tag);
577 }
578
579 TypeTag collapseType(TypeTag tag) {
580 static const TypeTag collapsedTag[] = {
581 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
582 TY_VOID, TY_VOID};
583 return collapsedTag[tag];
584 }
585
Jack Palevich1a539db2009-07-08 13:04:41 -0700586 TypeTag collapseTypeR0() {
587 return collapseType(getR0Type()->tag);
588 }
589
590 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700591 return isFloatTag(pType->tag);
592 }
593
594 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700595 return tag == TY_FLOAT || tag == TY_DOUBLE;
596 }
597
Jack Palevicha8f427f2009-07-13 18:40:08 -0700598 Type* mkpInt;
599
Jack Palevich21a15a22009-05-11 14:49:29 -0700600 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700601 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700602 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700603 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700604 };
605
Jack Paleviche7b59062009-05-19 17:12:17 -0700606#ifdef PROVIDE_ARM_CODEGEN
607
Jack Palevich22305132009-05-13 10:58:45 -0700608 class ARMCodeGenerator : public CodeGenerator {
609 public:
610 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700611
Jack Palevich22305132009-05-13 10:58:45 -0700612 virtual ~ARMCodeGenerator() {}
613
614 /* returns address to patch with local variable size
615 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700616 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700617 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700618 // sp -> arg4 arg5 ...
619 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700620 int regArgCount = calcRegArgCount(pDecl);
621 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700622 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700623 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700624 }
625 // sp -> arg0 arg1 ...
626 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700627 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700628 // sp, fp -> oldfp, retadr, arg0 arg1 ....
629 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700630 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700631 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700632 // We don't know how many local variables we are going to use,
633 // but we will round the allocation up to a multiple of
634 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700635 }
636
Jack Palevichb7718b92009-07-09 22:00:24 -0700637 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700638 // Round local variable size up to a multiple of stack alignment
639 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
640 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700641 // Patch local variable allocation code:
642 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700643 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700644 }
Jack Palevich69796b62009-05-14 15:42:26 -0700645 *(char*) (localVariableAddress) = localVariableSize;
646
647 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
648 o4(0xE1A0E00B); // mov lr, fp
649 o4(0xE59BB000); // ldr fp, [fp]
650 o4(0xE28ED004); // add sp, lr, #4
651 // sp -> retadr, arg0, ...
652 o4(0xE8BD4000); // ldmfd sp!, {lr}
653 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700654
655 // We store the PC into the lr so we can adjust the sp before
656 // returning. We need to pull off the registers we pushed
657 // earlier. We don't need to actually store them anywhere,
658 // just adjust the stack.
659 int regArgCount = calcRegArgCount(pDecl);
660 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700661 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
662 }
663 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700664 }
665
666 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700667 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700668 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700669 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700670 }
671
Jack Palevich1a539db2009-07-08 13:04:41 -0700672 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700673 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700674 // Global, absolute address
675 o4(0xE59F0000); // ldr r0, .L1
676 o4(0xEA000000); // b .L99
677 o4(address); // .L1: .word ea
678 // .L99:
679
680 switch (pType->tag) {
681 case TY_FLOAT:
682 o4(0xE5900000); // ldr r0, [r0]
683 break;
684 case TY_DOUBLE:
685 o4(0xE1C000D0); // ldrd r0, [r0]
686 break;
687 default:
688 assert(false);
689 break;
690 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700691 }
692
Jack Palevich22305132009-05-13 10:58:45 -0700693 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700694 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700695 }
696
697 /* l = 0: je, l == 1: jne */
698 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700699 Type* pR0Type = getR0Type();
700 TypeTag tagR0 = pR0Type->tag;
701 switch(tagR0) {
702 case TY_FLOAT:
703 callRuntime((void*) runtime_is_non_zero_f);
704 break;
705 case TY_DOUBLE:
706 callRuntime((void*) runtime_is_non_zero_d);
707 break;
708 default:
709 break;
710 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700711 o4(0xE3500000); // cmp r0,#0
712 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
713 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700714 }
715
Jack Palevich58c30ee2009-07-17 16:35:23 -0700716 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700717 Type* pR0Type = getR0Type();
718 Type* pTOSType = getTOSType();
719 TypeTag tagR0 = collapseType(pR0Type->tag);
720 TypeTag tagTOS = collapseType(pTOSType->tag);
721 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700722 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700723 o4(0xE1510000); // cmp r1, r1
724 switch(op) {
725 case OP_EQUALS:
726 o4(0x03A00001); // moveq r0,#1
727 o4(0x13A00000); // movne r0,#0
728 break;
729 case OP_NOT_EQUALS:
730 o4(0x03A00000); // moveq r0,#0
731 o4(0x13A00001); // movne r0,#1
732 break;
733 case OP_LESS_EQUAL:
734 o4(0xD3A00001); // movle r0,#1
735 o4(0xC3A00000); // movgt r0,#0
736 break;
737 case OP_GREATER:
738 o4(0xD3A00000); // movle r0,#0
739 o4(0xC3A00001); // movgt r0,#1
740 break;
741 case OP_GREATER_EQUAL:
742 o4(0xA3A00001); // movge r0,#1
743 o4(0xB3A00000); // movlt r0,#0
744 break;
745 case OP_LESS:
746 o4(0xA3A00000); // movge r0,#0
747 o4(0xB3A00001); // movlt r0,#1
748 break;
749 default:
750 error("Unknown comparison op %d", op);
751 break;
752 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700753 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
754 setupDoubleArgs();
755 switch(op) {
756 case OP_EQUALS:
757 callRuntime((void*) runtime_cmp_eq_dd);
758 break;
759 case OP_NOT_EQUALS:
760 callRuntime((void*) runtime_cmp_ne_dd);
761 break;
762 case OP_LESS_EQUAL:
763 callRuntime((void*) runtime_cmp_le_dd);
764 break;
765 case OP_GREATER:
766 callRuntime((void*) runtime_cmp_gt_dd);
767 break;
768 case OP_GREATER_EQUAL:
769 callRuntime((void*) runtime_cmp_ge_dd);
770 break;
771 case OP_LESS:
772 callRuntime((void*) runtime_cmp_lt_dd);
773 break;
774 default:
775 error("Unknown comparison op %d", op);
776 break;
777 }
778 } else {
779 setupFloatArgs();
780 switch(op) {
781 case OP_EQUALS:
782 callRuntime((void*) runtime_cmp_eq_ff);
783 break;
784 case OP_NOT_EQUALS:
785 callRuntime((void*) runtime_cmp_ne_ff);
786 break;
787 case OP_LESS_EQUAL:
788 callRuntime((void*) runtime_cmp_le_ff);
789 break;
790 case OP_GREATER:
791 callRuntime((void*) runtime_cmp_gt_ff);
792 break;
793 case OP_GREATER_EQUAL:
794 callRuntime((void*) runtime_cmp_ge_ff);
795 break;
796 case OP_LESS:
797 callRuntime((void*) runtime_cmp_lt_ff);
798 break;
799 default:
800 error("Unknown comparison op %d", op);
801 break;
802 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700803 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700804 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700805 }
806
Jack Palevich546b2242009-05-13 15:10:04 -0700807 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700808 Type* pR0Type = getR0Type();
809 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700810 TypeTag tagR0 = pR0Type->tag;
811 TypeTag tagTOS = pTOSType->tag;
812 bool isFloatR0 = isFloatTag(tagR0);
813 bool isFloatTOS = isFloatTag(tagTOS);
814 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700815 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700816 bool isPtrR0 = tagR0 == TY_POINTER;
817 bool isPtrTOS = tagTOS == TY_POINTER;
818 if (isPtrR0 || isPtrTOS) {
819 if (isPtrR0 && isPtrTOS) {
820 if (op != OP_MINUS) {
821 error("Unsupported pointer-pointer operation %d.", op);
822 }
823 if (! typeEqual(pR0Type, pTOSType)) {
824 error("Incompatible pointer types for subtraction.");
825 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700826 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700827 setR0Type(mkpInt);
828 int size = sizeOf(pR0Type->pHead);
829 if (size != 1) {
830 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700831 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700832 // TODO: Optimize for power-of-two.
833 genOp(OP_DIV);
834 }
835 } else {
836 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
837 error("Unsupported pointer-scalar operation %d", op);
838 }
839 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700840 int size = sizeOf(pPtrType->pHead);
841 if (size != 1) {
842 // TODO: Optimize for power-of-two.
843 liReg(size, 2);
844 if (isPtrR0) {
845 o4(0x0E0010192); // mul r1,r2,r1
846 } else {
847 o4(0x0E0000092); // mul r0,r2,r0
848 }
849 }
850 switch(op) {
851 case OP_PLUS:
852 o4(0xE0810000); // add r0,r1,r0
853 break;
854 case OP_MINUS:
855 o4(0xE0410000); // sub r0,r1,r0
856 break;
857 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700858 setR0Type(pPtrType);
859 }
860 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700861 switch(op) {
862 case OP_MUL:
863 o4(0x0E0000091); // mul r0,r1,r0
864 break;
865 case OP_DIV:
866 callRuntime((void*) runtime_DIV);
867 break;
868 case OP_MOD:
869 callRuntime((void*) runtime_MOD);
870 break;
871 case OP_PLUS:
872 o4(0xE0810000); // add r0,r1,r0
873 break;
874 case OP_MINUS:
875 o4(0xE0410000); // sub r0,r1,r0
876 break;
877 case OP_SHIFT_LEFT:
878 o4(0xE1A00011); // lsl r0,r1,r0
879 break;
880 case OP_SHIFT_RIGHT:
881 o4(0xE1A00051); // asr r0,r1,r0
882 break;
883 case OP_BIT_AND:
884 o4(0xE0010000); // and r0,r1,r0
885 break;
886 case OP_BIT_XOR:
887 o4(0xE0210000); // eor r0,r1,r0
888 break;
889 case OP_BIT_OR:
890 o4(0xE1810000); // orr r0,r1,r0
891 break;
892 case OP_BIT_NOT:
893 o4(0xE1E00000); // mvn r0, r0
894 break;
895 default:
896 error("Unimplemented op %d\n", op);
897 break;
898 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700899 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700900 } else {
901 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
902 if (pResultType->tag == TY_DOUBLE) {
903 setupDoubleArgs();
904 switch(op) {
905 case OP_MUL:
906 callRuntime((void*) runtime_op_mul_dd);
907 break;
908 case OP_DIV:
909 callRuntime((void*) runtime_op_div_dd);
910 break;
911 case OP_PLUS:
912 callRuntime((void*) runtime_op_add_dd);
913 break;
914 case OP_MINUS:
915 callRuntime((void*) runtime_op_sub_dd);
916 break;
917 default:
918 error("Unsupported binary floating operation %d\n", op);
919 break;
920 }
921 } else {
922 setupFloatArgs();
923 switch(op) {
924 case OP_MUL:
925 callRuntime((void*) runtime_op_mul_ff);
926 break;
927 case OP_DIV:
928 callRuntime((void*) runtime_op_div_ff);
929 break;
930 case OP_PLUS:
931 callRuntime((void*) runtime_op_add_ff);
932 break;
933 case OP_MINUS:
934 callRuntime((void*) runtime_op_sub_ff);
935 break;
936 default:
937 error("Unsupported binary floating operation %d\n", op);
938 break;
939 }
940 }
941 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700942 }
Jack Palevich22305132009-05-13 10:58:45 -0700943 }
944
Jack Palevich58c30ee2009-07-17 16:35:23 -0700945 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700946 if (op != OP_LOGICAL_NOT) {
947 error("Unknown unary cmp %d", op);
948 } else {
949 Type* pR0Type = getR0Type();
950 TypeTag tag = collapseType(pR0Type->tag);
951 switch(tag) {
952 case TY_INT:
953 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700954 o4(0xE1510000); // cmp r1, r0
955 o4(0x03A00001); // moveq r0,#1
956 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700957 break;
958 case TY_FLOAT:
959 callRuntime((void*) runtime_is_zero_f);
960 break;
961 case TY_DOUBLE:
962 callRuntime((void*) runtime_is_zero_d);
963 break;
964 default:
965 error("gUnaryCmp unsupported type");
966 break;
967 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700968 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700969 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700970 }
971
972 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700973 Type* pR0Type = getR0Type();
974 TypeTag tag = collapseType(pR0Type->tag);
975 switch(tag) {
976 case TY_INT:
977 switch(op) {
978 case OP_MINUS:
979 o4(0xE3A01000); // mov r1, #0
980 o4(0xE0410000); // sub r0,r1,r0
981 break;
982 case OP_BIT_NOT:
983 o4(0xE1E00000); // mvn r0, r0
984 break;
985 default:
986 error("Unknown unary op %d\n", op);
987 break;
988 }
989 break;
990 case TY_FLOAT:
991 case TY_DOUBLE:
992 switch (op) {
993 case OP_MINUS:
994 if (tag == TY_FLOAT) {
995 callRuntime((void*) runtime_op_neg_f);
996 } else {
997 callRuntime((void*) runtime_op_neg_d);
998 }
999 break;
1000 case OP_BIT_NOT:
1001 error("Can't apply '~' operator to a float or double.");
1002 break;
1003 default:
1004 error("Unknown unary op %d\n", op);
1005 break;
1006 }
1007 break;
1008 default:
1009 error("genUnaryOp unsupported type");
1010 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001011 }
Jack Palevich22305132009-05-13 10:58:45 -07001012 }
1013
Jack Palevich1cdef202009-05-22 12:06:27 -07001014 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001015 Type* pR0Type = getR0Type();
1016 TypeTag r0ct = collapseType(pR0Type->tag);
1017 if (r0ct != TY_DOUBLE) {
1018 o4(0xE92D0001); // stmfd sp!,{r0}
1019 mStackUse += 4;
1020 } else {
1021 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1022 mStackUse += 8;
1023 }
Jack Palevich8df46192009-07-07 14:48:51 -07001024 pushType();
-b master422972c2009-06-17 19:13:52 -07001025 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001026 }
1027
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001028 virtual void over() {
1029 // We know it's only used for int-ptr ops (++/--)
1030
1031 Type* pR0Type = getR0Type();
1032 TypeTag r0ct = collapseType(pR0Type->tag);
1033
1034 Type* pTOSType = getTOSType();
1035 TypeTag tosct = collapseType(pTOSType->tag);
1036
1037 assert (r0ct == TY_INT && tosct == TY_INT);
1038
1039 o4(0xE8BD0002); // ldmfd sp!,{r1}
1040 o4(0xE92D0001); // stmfd sp!,{r0}
1041 o4(0xE92D0002); // stmfd sp!,{r1}
1042 overType();
1043 mStackUse += 4;
1044 }
1045
Jack Palevich58c30ee2009-07-17 16:35:23 -07001046 virtual void popR0() {
1047 Type* pTOSType = getTOSType();
1048 switch (collapseType(pTOSType->tag)){
1049 case TY_INT:
1050 case TY_FLOAT:
1051 o4(0xE8BD0001); // ldmfd sp!,{r0}
1052 mStackUse -= 4;
1053 break;
1054 case TY_DOUBLE:
1055 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1056 mStackUse -= 8;
1057 break;
1058 default:
1059 error("Can't pop this type.");
1060 break;
1061 }
1062 popType();
1063 LOG_STACK("popR0: %d\n", mStackUse);
1064 }
1065
1066 virtual void storeR0ToTOS() {
1067 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001068 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001069 o4(0xE8BD0004); // ldmfd sp!,{r2}
1070 popType();
-b master422972c2009-06-17 19:13:52 -07001071 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001072 switch (pPointerType->pHead->tag) {
1073 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001074 case TY_FLOAT:
1075 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001076 break;
1077 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001078 o4(0xE5C20000); // strb r0, [r2]
1079 break;
1080 case TY_DOUBLE:
1081 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001082 break;
1083 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001084 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001085 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001086 }
Jack Palevich22305132009-05-13 10:58:45 -07001087 }
1088
Jack Palevich58c30ee2009-07-17 16:35:23 -07001089 virtual void loadR0FromR0() {
1090 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001091 assert(pPointerType->tag == TY_POINTER);
1092 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001093 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001094 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001095 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001096 o4(0xE5900000); // ldr r0, [r0]
1097 break;
1098 case TY_CHAR:
1099 o4(0xE5D00000); // ldrb r0, [r0]
1100 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001101 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001102 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001103 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001104 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001105 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001106 break;
1107 }
Jack Palevich8df46192009-07-07 14:48:51 -07001108 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001109 }
1110
Jack Palevich8df46192009-07-07 14:48:51 -07001111 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001112 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001113 // Local, fp relative
1114 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1115 error("Offset out of range: %08x", ea);
1116 }
1117 if (ea < 0) {
1118 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1119 } else {
1120 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1121 }
Jack Palevichbd894902009-05-14 19:35:31 -07001122 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001123 // Global, absolute.
1124 o4(0xE59F0000); // ldr r0, .L1
1125 o4(0xEA000000); // b .L99
1126 o4(ea); // .L1: .word 0
1127 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001128 }
Jack Palevich8df46192009-07-07 14:48:51 -07001129 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001130 }
1131
Jack Palevich9cbd2262009-07-08 16:48:41 -07001132 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001133 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001134 TypeTag tag = pType->tag;
1135 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001136 case TY_CHAR:
1137 if (ea > -LOCAL && ea < LOCAL) {
1138 // Local, fp relative
1139 if (ea < -4095 || ea > 4095) {
1140 error("Offset out of range: %08x", ea);
1141 }
1142 if (ea < 0) {
1143 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1144 } else {
1145 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1146 }
1147 } else{
1148 // Global, absolute
1149 o4(0xE59F1000); // ldr r1, .L1
1150 o4(0xEA000000); // b .L99
1151 o4(ea); // .L1: .word 0
1152 o4(0xE5C10000); // .L99: strb r0, [r1]
1153 }
1154 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001155 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001156 case TY_INT:
1157 case TY_FLOAT:
1158 if (ea > -LOCAL && ea < LOCAL) {
1159 // Local, fp relative
1160 if (ea < -4095 || ea > 4095) {
1161 error("Offset out of range: %08x", ea);
1162 }
1163 if (ea < 0) {
1164 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1165 } else {
1166 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1167 }
1168 } else{
1169 // Global, absolute
1170 o4(0xE59F1000); // ldr r1, .L1
1171 o4(0xEA000000); // b .L99
1172 o4(ea); // .L1: .word 0
1173 o4(0xE5810000); // .L99: str r0, [r1]
1174 }
1175 break;
1176 case TY_DOUBLE:
1177 if ((ea & 0x7) != 0) {
1178 error("double address is not aligned: %d", ea);
1179 }
1180 if (ea > -LOCAL && ea < LOCAL) {
1181 // Local, fp relative
Jack Palevicha7813bd2009-07-29 11:36:04 -07001182 // Global, absolute
1183 o4(0xE59F2000); // ldr r2, .L1
1184 o4(0xEA000000); // b .L99
1185 o4(ea); // .L1: .word 0
1186 o4(0xE18B00F2); // .L99: strd r0, [fp,r2]
Jack Palevichb7718b92009-07-09 22:00:24 -07001187 } else{
1188 // Global, absolute
1189 o4(0xE59F2000); // ldr r2, .L1
1190 o4(0xEA000000); // b .L99
1191 o4(ea); // .L1: .word 0
1192 o4(0xE1C200F0); // .L99: strd r0, [r2]
1193 }
1194 break;
1195 default:
1196 error("Unable to store to type %d", tag);
1197 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001198 }
Jack Palevich22305132009-05-13 10:58:45 -07001199 }
1200
Jack Palevich8df46192009-07-07 14:48:51 -07001201 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001202 Type* pR0Type = getR0Type();
1203 if (bitsSame(pType, pR0Type)) {
1204 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001205 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001206 TypeTag r0Tag = collapseType(pR0Type->tag);
1207 TypeTag destTag = collapseType(pType->tag);
1208 if (r0Tag == TY_INT) {
1209 if (destTag == TY_FLOAT) {
1210 callRuntime((void*) runtime_int_to_float);
1211 } else {
1212 assert(destTag == TY_DOUBLE);
1213 callRuntime((void*) runtime_int_to_double);
1214 }
1215 } else if (r0Tag == TY_FLOAT) {
1216 if (destTag == TY_INT) {
1217 callRuntime((void*) runtime_float_to_int);
1218 } else {
1219 assert(destTag == TY_DOUBLE);
1220 callRuntime((void*) runtime_float_to_double);
1221 }
1222 } else {
1223 assert (r0Tag == TY_DOUBLE);
1224 if (destTag == TY_INT) {
1225 callRuntime((void*) runtime_double_to_int);
1226 } else {
1227 assert(destTag == TY_FLOAT);
1228 callRuntime((void*) runtime_double_to_float);
1229 }
1230 }
Jack Palevich8df46192009-07-07 14:48:51 -07001231 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001232 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001233 }
1234
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001235 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001236 return o4(0xE24DDF00); // Placeholder
1237 }
1238
Jack Palevich8148c5b2009-07-16 18:24:47 -07001239 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001240 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001241 Type* pR0Type = getR0Type();
1242 TypeTag r0ct = collapseType(pR0Type->tag);
1243 switch(r0ct) {
1244 case TY_INT:
1245 case TY_FLOAT:
1246 if (l < 0 || l > 4096-4) {
1247 error("l out of range for stack offset: 0x%08x", l);
1248 }
1249 o4(0xE58D0000 + l); // str r0, [sp, #l]
1250 return 4;
1251 case TY_DOUBLE: {
1252 // Align to 8 byte boundary
1253 int l2 = (l + 7) & ~7;
1254 if (l2 < 0 || l2 > 4096-8) {
1255 error("l out of range for stack offset: 0x%08x", l);
1256 }
1257 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1258 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1259 return (l2 - l) + 8;
1260 }
1261 default:
1262 assert(false);
1263 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001264 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001265 }
1266
Jack Palevichb7718b92009-07-09 22:00:24 -07001267 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001268 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001269 // Have to calculate register arg count from actual stack size,
1270 // in order to properly handle ... functions.
1271 int regArgCount = l >> 2;
1272 if (regArgCount > 4) {
1273 regArgCount = 4;
1274 }
1275 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001276 argumentStackUse -= regArgCount * 4;
1277 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1278 }
1279 mStackUse += argumentStackUse;
1280
1281 // Align stack.
1282 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1283 * STACK_ALIGNMENT);
1284 mStackAlignmentAdjustment = 0;
1285 if (missalignment > 0) {
1286 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1287 }
1288 l += mStackAlignmentAdjustment;
1289
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001290 if (l < 0 || l > 0x3FC) {
1291 error("L out of range for stack adjustment: 0x%08x", l);
1292 }
1293 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001294 mStackUse += mStackAlignmentAdjustment;
1295 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1296 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001297 }
1298
Jack Palevich8df46192009-07-07 14:48:51 -07001299 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001300 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001301 // Forward calls are always short (local)
1302 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001303 }
1304
Jack Palevich8df46192009-07-07 14:48:51 -07001305 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001306 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001307 int abs = t + getPC() + jumpOffset();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001308 if (t >= - (1 << 25) && t < (1 << 25)) {
1309 o4(0xEB000000 | encodeAddress(t));
1310 } else {
1311 // Long call.
1312 o4(0xE59FC000); // ldr r12, .L1
1313 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001314 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001315 o4(0xE08CC00F); // .L99: add r12,pc
1316 o4(0xE12FFF3C); // blx r12
1317 }
Jack Palevich22305132009-05-13 10:58:45 -07001318 }
1319
Jack Palevich8df46192009-07-07 14:48:51 -07001320 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001321 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001322 int argCount = l >> 2;
1323 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001324 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001325 if (adjustedL < 0 || adjustedL > 4096-4) {
1326 error("l out of range for stack offset: 0x%08x", l);
1327 }
1328 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1329 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001330 }
1331
Jack Palevichb7718b92009-07-09 22:00:24 -07001332 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001333 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001334 // Have to calculate register arg count from actual stack size,
1335 // in order to properly handle ... functions.
1336 int regArgCount = l >> 2;
1337 if (regArgCount > 4) {
1338 regArgCount = 4;
1339 }
1340 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001341 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1342 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001343 if (stackUse) {
1344 if (stackUse < 0 || stackUse > 255) {
1345 error("L out of range for stack adjustment: 0x%08x", l);
1346 }
1347 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001348 mStackUse -= stackUse * 4;
1349 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001350 }
Jack Palevich22305132009-05-13 10:58:45 -07001351 }
1352
Jack Palevicha6535612009-05-13 16:24:17 -07001353 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001354 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001355 }
1356
1357 /* output a symbol and patch all calls to it */
1358 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001359 int n;
1360 int base = getBase();
1361 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001362 while (t) {
1363 int data = * (int*) t;
1364 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1365 if (decodedOffset == 0) {
1366 n = 0;
1367 } else {
1368 n = base + decodedOffset; /* next value */
1369 }
1370 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1371 | encodeRelAddress(pc - t - 8);
1372 t = n;
1373 }
1374 }
1375
Jack Palevich1cdef202009-05-22 12:06:27 -07001376 virtual int finishCompile() {
1377#if defined(__arm__)
1378 const long base = long(getBase());
1379 const long curr = long(getPC());
1380 int err = cacheflush(base, curr, 0);
1381 return err;
1382#else
1383 return 0;
1384#endif
1385 }
1386
Jack Palevicha6535612009-05-13 16:24:17 -07001387 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001388#ifdef ENABLE_ARM_DISASSEMBLY
1389 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001390 disasm_interface_t di;
1391 di.di_readword = disassemble_readword;
1392 di.di_printaddr = disassemble_printaddr;
1393 di.di_printf = disassemble_printf;
1394
1395 int base = getBase();
1396 int pc = getPC();
1397 for(int i = base; i < pc; i += 4) {
1398 fprintf(out, "%08x: %08x ", i, *(int*) i);
1399 ::disasm(&di, i, 0);
1400 }
Jack Palevich09555c72009-05-27 12:25:55 -07001401#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001402 return 0;
1403 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001404
Jack Palevich9eed7a22009-07-06 17:24:34 -07001405 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001406 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001407 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001408 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001409 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001410 case TY_CHAR:
1411 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001412 case TY_DOUBLE:
1413 return 8;
1414 default:
1415 return 4;
1416 }
1417 }
1418
1419 /**
1420 * Array element alignment (in bytes) for this type of data.
1421 */
1422 virtual size_t sizeOf(Type* pType){
1423 switch(pType->tag) {
1424 case TY_INT:
1425 return 4;
1426 case TY_CHAR:
1427 return 1;
1428 default:
1429 return 0;
1430 case TY_FLOAT:
1431 return 4;
1432 case TY_DOUBLE:
1433 return 8;
1434 case TY_POINTER:
1435 return 4;
1436 }
1437 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001438
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001439 virtual size_t stackAlignmentOf(Type* pType) {
1440 switch(pType->tag) {
1441 case TY_DOUBLE:
1442 return 8;
1443 default:
1444 return 4;
1445 }
1446 }
1447
Jack Palevich9cbd2262009-07-08 16:48:41 -07001448 virtual size_t stackSizeOf(Type* pType) {
1449 switch(pType->tag) {
1450 case TY_DOUBLE:
1451 return 8;
1452 default:
1453 return 4;
1454 }
1455 }
1456
Jack Palevich22305132009-05-13 10:58:45 -07001457 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001458 static FILE* disasmOut;
1459
1460 static u_int
1461 disassemble_readword(u_int address)
1462 {
1463 return(*((u_int *)address));
1464 }
1465
1466 static void
1467 disassemble_printaddr(u_int address)
1468 {
1469 fprintf(disasmOut, "0x%08x", address);
1470 }
1471
1472 static void
1473 disassemble_printf(const char *fmt, ...) {
1474 va_list ap;
1475 va_start(ap, fmt);
1476 vfprintf(disasmOut, fmt, ap);
1477 va_end(ap);
1478 }
1479
1480 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1481
1482 /** Encode a relative address that might also be
1483 * a label.
1484 */
1485 int encodeAddress(int value) {
1486 int base = getBase();
1487 if (value >= base && value <= getPC() ) {
1488 // This is a label, encode it relative to the base.
1489 value = value - base;
1490 }
1491 return encodeRelAddress(value);
1492 }
1493
1494 int encodeRelAddress(int value) {
1495 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1496 }
Jack Palevich22305132009-05-13 10:58:45 -07001497
Jack Palevichb7718b92009-07-09 22:00:24 -07001498 int calcRegArgCount(Type* pDecl) {
1499 int reg = 0;
1500 Type* pArgs = pDecl->pTail;
1501 while (pArgs && reg < 4) {
1502 Type* pArg = pArgs->pHead;
1503 if ( pArg->tag == TY_DOUBLE) {
1504 int evenReg = (reg + 1) & ~1;
1505 if (evenReg >= 4) {
1506 break;
1507 }
1508 reg = evenReg + 2;
1509 } else {
1510 reg++;
1511 }
1512 pArgs = pArgs->pTail;
1513 }
1514 return reg;
1515 }
1516
Jack Palevich58c30ee2009-07-17 16:35:23 -07001517 void setupIntPtrArgs() {
1518 o4(0xE8BD0002); // ldmfd sp!,{r1}
1519 mStackUse -= 4;
1520 popType();
1521 }
1522
Jack Palevichb7718b92009-07-09 22:00:24 -07001523 /* Pop TOS to R1
1524 * Make sure both R0 and TOS are floats. (Could be ints)
1525 * We know that at least one of R0 and TOS is already a float
1526 */
1527 void setupFloatArgs() {
1528 Type* pR0Type = getR0Type();
1529 Type* pTOSType = getTOSType();
1530 TypeTag tagR0 = collapseType(pR0Type->tag);
1531 TypeTag tagTOS = collapseType(pTOSType->tag);
1532 if (tagR0 != TY_FLOAT) {
1533 assert(tagR0 == TY_INT);
1534 callRuntime((void*) runtime_int_to_float);
1535 }
1536 if (tagTOS != TY_FLOAT) {
1537 assert(tagTOS == TY_INT);
1538 assert(tagR0 == TY_FLOAT);
1539 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1540 o4(0xE59D0004); // ldr r0, [sp, #4]
1541 callRuntime((void*) runtime_int_to_float);
1542 o4(0xE1A01000); // mov r1, r0
1543 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1544 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1545 } else {
1546 // Pop TOS
1547 o4(0xE8BD0002); // ldmfd sp!,{r1}
1548 }
1549 mStackUse -= 4;
1550 popType();
1551 }
1552
1553 /* Pop TOS into R2..R3
1554 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1555 * We know that at least one of R0 and TOS are already a double.
1556 */
1557
1558 void setupDoubleArgs() {
1559 Type* pR0Type = getR0Type();
1560 Type* pTOSType = getTOSType();
1561 TypeTag tagR0 = collapseType(pR0Type->tag);
1562 TypeTag tagTOS = collapseType(pTOSType->tag);
1563 if (tagR0 != TY_DOUBLE) {
1564 if (tagR0 == TY_INT) {
1565 callRuntime((void*) runtime_int_to_double);
1566 } else {
1567 assert(tagR0 == TY_FLOAT);
1568 callRuntime((void*) runtime_float_to_double);
1569 }
1570 }
1571 if (tagTOS != TY_DOUBLE) {
1572 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1573 o4(0xE59D0008); // ldr r0, [sp, #8]
1574 if (tagTOS == TY_INT) {
1575 callRuntime((void*) runtime_int_to_double);
1576 } else {
1577 assert(tagTOS == TY_FLOAT);
1578 callRuntime((void*) runtime_float_to_double);
1579 }
1580 o4(0xE1A02000); // mov r2, r0
1581 o4(0xE1A03001); // mov r3, r1
1582 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1583 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1584 mStackUse -= 4;
1585 } else {
1586 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1587 mStackUse -= 8;
1588 }
1589 popType();
1590 }
1591
Jack Palevicha8f427f2009-07-13 18:40:08 -07001592 void liReg(int t, int reg) {
1593 assert(reg >= 0 && reg < 16);
1594 int rN = (reg & 0xf) << 12;
1595 if (t >= 0 && t < 255) {
1596 o4((0xE3A00000 + t) | rN); // mov rN, #0
1597 } else if (t >= -256 && t < 0) {
1598 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001599 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001600 } else {
1601 o4(0xE51F0000 | rN); // ldr rN, .L3
1602 o4(0xEA000000); // b .L99
1603 o4(t); // .L3: .word 0
1604 // .L99:
1605 }
1606 }
1607
Jack Palevichb7718b92009-07-09 22:00:24 -07001608 void callRuntime(void* fn) {
1609 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001610 o4(0xEA000000); // b .L99
1611 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001612 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001613 }
1614
Jack Palevichb7718b92009-07-09 22:00:24 -07001615 // Integer math:
1616
1617 static int runtime_DIV(int b, int a) {
1618 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001619 }
1620
Jack Palevichb7718b92009-07-09 22:00:24 -07001621 static int runtime_MOD(int b, int a) {
1622 return a % b;
1623 }
1624
1625 // Comparison to zero
1626
1627 static int runtime_is_non_zero_f(float a) {
1628 return a != 0;
1629 }
1630
1631 static int runtime_is_non_zero_d(double a) {
1632 return a != 0;
1633 }
1634
1635 // Comparison to zero
1636
1637 static int runtime_is_zero_f(float a) {
1638 return a == 0;
1639 }
1640
1641 static int runtime_is_zero_d(double a) {
1642 return a == 0;
1643 }
1644
1645 // Type conversion
1646
1647 static int runtime_float_to_int(float a) {
1648 return (int) a;
1649 }
1650
1651 static double runtime_float_to_double(float a) {
1652 return (double) a;
1653 }
1654
1655 static int runtime_double_to_int(double a) {
1656 return (int) a;
1657 }
1658
1659 static float runtime_double_to_float(double a) {
1660 return (float) a;
1661 }
1662
1663 static float runtime_int_to_float(int a) {
1664 return (float) a;
1665 }
1666
1667 static double runtime_int_to_double(int a) {
1668 return (double) a;
1669 }
1670
1671 // Comparisons float
1672
1673 static int runtime_cmp_eq_ff(float b, float a) {
1674 return a == b;
1675 }
1676
1677 static int runtime_cmp_ne_ff(float b, float a) {
1678 return a != b;
1679 }
1680
1681 static int runtime_cmp_lt_ff(float b, float a) {
1682 return a < b;
1683 }
1684
1685 static int runtime_cmp_le_ff(float b, float a) {
1686 return a <= b;
1687 }
1688
1689 static int runtime_cmp_ge_ff(float b, float a) {
1690 return a >= b;
1691 }
1692
1693 static int runtime_cmp_gt_ff(float b, float a) {
1694 return a > b;
1695 }
1696
1697 // Comparisons double
1698
1699 static int runtime_cmp_eq_dd(double b, double a) {
1700 return a == b;
1701 }
1702
1703 static int runtime_cmp_ne_dd(double b, double a) {
1704 return a != b;
1705 }
1706
1707 static int runtime_cmp_lt_dd(double b, double a) {
1708 return a < b;
1709 }
1710
1711 static int runtime_cmp_le_dd(double b, double a) {
1712 return a <= b;
1713 }
1714
1715 static int runtime_cmp_ge_dd(double b, double a) {
1716 return a >= b;
1717 }
1718
1719 static int runtime_cmp_gt_dd(double b, double a) {
1720 return a > b;
1721 }
1722
1723 // Math float
1724
1725 static float runtime_op_add_ff(float b, float a) {
1726 return a + b;
1727 }
1728
1729 static float runtime_op_sub_ff(float b, float a) {
1730 return a - b;
1731 }
1732
1733 static float runtime_op_mul_ff(float b, float a) {
1734 return a * b;
1735 }
1736
1737 static float runtime_op_div_ff(float b, float a) {
1738 return a / b;
1739 }
1740
1741 static float runtime_op_neg_f(float a) {
1742 return -a;
1743 }
1744
1745 // Math double
1746
1747 static double runtime_op_add_dd(double b, double a) {
1748 return a + b;
1749 }
1750
1751 static double runtime_op_sub_dd(double b, double a) {
1752 return a - b;
1753 }
1754
1755 static double runtime_op_mul_dd(double b, double a) {
1756 return a * b;
1757 }
1758
1759 static double runtime_op_div_dd(double b, double a) {
1760 return a / b;
1761 }
1762
1763 static double runtime_op_neg_d(double a) {
1764 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001765 }
-b master422972c2009-06-17 19:13:52 -07001766
1767 static const int STACK_ALIGNMENT = 8;
1768 int mStackUse;
1769 // This variable holds the amount we adjusted the stack in the most
1770 // recent endFunctionCallArguments call. It's examined by the
1771 // following adjustStackAfterCall call.
1772 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001773 };
1774
Jack Palevich09555c72009-05-27 12:25:55 -07001775#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001776
1777#ifdef PROVIDE_X86_CODEGEN
1778
Jack Palevich21a15a22009-05-11 14:49:29 -07001779 class X86CodeGenerator : public CodeGenerator {
1780 public:
1781 X86CodeGenerator() {}
1782 virtual ~X86CodeGenerator() {}
1783
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001784 /* returns address to patch with local variable size
1785 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001786 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001787 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1788 return oad(0xec81, 0); /* sub $xxx, %esp */
1789 }
1790
Jack Palevichb7718b92009-07-09 22:00:24 -07001791 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001792 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001793 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001794 }
1795
Jack Palevich21a15a22009-05-11 14:49:29 -07001796 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001797 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001798 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001799 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001800 }
1801
Jack Palevich1a539db2009-07-08 13:04:41 -07001802 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001803 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001804 switch (pType->tag) {
1805 case TY_FLOAT:
1806 oad(0x05D9, address); // flds
1807 break;
1808 case TY_DOUBLE:
1809 oad(0x05DD, address); // fldl
1810 break;
1811 default:
1812 assert(false);
1813 break;
1814 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001815 }
1816
Jack Palevich22305132009-05-13 10:58:45 -07001817 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001818 return psym(0xe9, t);
1819 }
1820
1821 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001822 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001823 Type* pR0Type = getR0Type();
1824 TypeTag tagR0 = pR0Type->tag;
1825 bool isFloatR0 = isFloatTag(tagR0);
1826 if (isFloatR0) {
1827 o(0xeed9); // fldz
1828 o(0xe9da); // fucompp
1829 o(0xe0df); // fnstsw %ax
1830 o(0x9e); // sahf
1831 } else {
1832 o(0xc085); // test %eax, %eax
1833 }
1834 // Use two output statements to generate one instruction.
1835 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001836 return psym(0x84 + l, t);
1837 }
1838
Jack Palevich58c30ee2009-07-17 16:35:23 -07001839 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001840 Type* pR0Type = getR0Type();
1841 Type* pTOSType = getTOSType();
1842 TypeTag tagR0 = pR0Type->tag;
1843 TypeTag tagTOS = pTOSType->tag;
1844 bool isFloatR0 = isFloatTag(tagR0);
1845 bool isFloatTOS = isFloatTag(tagTOS);
1846 if (!isFloatR0 && !isFloatTOS) {
1847 int t = decodeOp(op);
1848 o(0x59); /* pop %ecx */
1849 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001850 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001851 o(0x0f); /* setxx %al */
1852 o(t + 0x90);
1853 o(0xc0);
1854 popType();
1855 } else {
1856 setupFloatOperands();
1857 switch (op) {
1858 case OP_EQUALS:
1859 o(0xe9da); // fucompp
1860 o(0xe0df); // fnstsw %ax
1861 o(0x9e); // sahf
1862 o(0xc0940f); // sete %al
1863 o(0xc29b0f); // setnp %dl
1864 o(0xd021); // andl %edx, %eax
1865 break;
1866 case OP_NOT_EQUALS:
1867 o(0xe9da); // fucompp
1868 o(0xe0df); // fnstsw %ax
1869 o(0x9e); // sahf
1870 o(0xc0950f); // setne %al
1871 o(0xc29a0f); // setp %dl
1872 o(0xd009); // orl %edx, %eax
1873 break;
1874 case OP_GREATER_EQUAL:
1875 o(0xe9da); // fucompp
1876 o(0xe0df); // fnstsw %ax
1877 o(0x05c4f6); // testb $5, %ah
1878 o(0xc0940f); // sete %al
1879 break;
1880 case OP_LESS:
1881 o(0xc9d9); // fxch %st(1)
1882 o(0xe9da); // fucompp
1883 o(0xe0df); // fnstsw %ax
1884 o(0x9e); // sahf
1885 o(0xc0970f); // seta %al
1886 break;
1887 case OP_LESS_EQUAL:
1888 o(0xc9d9); // fxch %st(1)
1889 o(0xe9da); // fucompp
1890 o(0xe0df); // fnstsw %ax
1891 o(0x9e); // sahf
1892 o(0xc0930f); // setea %al
1893 break;
1894 case OP_GREATER:
1895 o(0xe9da); // fucompp
1896 o(0xe0df); // fnstsw %ax
1897 o(0x45c4f6); // testb $69, %ah
1898 o(0xc0940f); // sete %al
1899 break;
1900 default:
1901 error("Unknown comparison op");
1902 }
1903 o(0xc0b60f); // movzbl %al, %eax
1904 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001905 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001906 }
1907
Jack Palevich546b2242009-05-13 15:10:04 -07001908 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001909 Type* pR0Type = getR0Type();
1910 Type* pTOSType = getTOSType();
1911 TypeTag tagR0 = pR0Type->tag;
1912 TypeTag tagTOS = pTOSType->tag;
1913 bool isFloatR0 = isFloatTag(tagR0);
1914 bool isFloatTOS = isFloatTag(tagTOS);
1915 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001916 bool isPtrR0 = tagR0 == TY_POINTER;
1917 bool isPtrTOS = tagTOS == TY_POINTER;
1918 if (isPtrR0 || isPtrTOS) {
1919 if (isPtrR0 && isPtrTOS) {
1920 if (op != OP_MINUS) {
1921 error("Unsupported pointer-pointer operation %d.", op);
1922 }
1923 if (! typeEqual(pR0Type, pTOSType)) {
1924 error("Incompatible pointer types for subtraction.");
1925 }
1926 o(0x59); /* pop %ecx */
1927 o(decodeOp(op));
1928 popType();
1929 setR0Type(mkpInt);
1930 int size = sizeOf(pR0Type->pHead);
1931 if (size != 1) {
1932 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001933 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001934 // TODO: Optimize for power-of-two.
1935 genOp(OP_DIV);
1936 }
1937 } else {
1938 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1939 error("Unsupported pointer-scalar operation %d", op);
1940 }
1941 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1942 o(0x59); /* pop %ecx */
1943 int size = sizeOf(pPtrType->pHead);
1944 if (size != 1) {
1945 // TODO: Optimize for power-of-two.
1946 if (isPtrR0) {
1947 oad(0xC969, size); // imull $size, %ecx
1948 } else {
1949 oad(0xC069, size); // mul $size, %eax
1950 }
1951 }
1952 o(decodeOp(op));
1953 popType();
1954 setR0Type(pPtrType);
1955 }
1956 } else {
1957 o(0x59); /* pop %ecx */
1958 o(decodeOp(op));
1959 if (op == OP_MOD)
1960 o(0x92); /* xchg %edx, %eax */
1961 popType();
1962 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001963 } else {
1964 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1965 setupFloatOperands();
1966 // Both float. x87 R0 == left hand, x87 R1 == right hand
1967 switch (op) {
1968 case OP_MUL:
1969 o(0xc9de); // fmulp
1970 break;
1971 case OP_DIV:
1972 o(0xf1de); // fdivp
1973 break;
1974 case OP_PLUS:
1975 o(0xc1de); // faddp
1976 break;
1977 case OP_MINUS:
1978 o(0xe1de); // fsubp
1979 break;
1980 default:
1981 error("Unsupported binary floating operation.");
1982 break;
1983 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001984 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001985 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001986 }
1987
Jack Palevich58c30ee2009-07-17 16:35:23 -07001988 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001989 if (op != OP_LOGICAL_NOT) {
1990 error("Unknown unary cmp %d", op);
1991 } else {
1992 Type* pR0Type = getR0Type();
1993 TypeTag tag = collapseType(pR0Type->tag);
1994 switch(tag) {
1995 case TY_INT: {
1996 oad(0xb9, 0); /* movl $0, %ecx */
1997 int t = decodeOp(op);
1998 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001999 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002000 o(0x0f); /* setxx %al */
2001 o(t + 0x90);
2002 o(0xc0);
2003 }
2004 break;
2005 case TY_FLOAT:
2006 case TY_DOUBLE:
2007 o(0xeed9); // fldz
2008 o(0xe9da); // fucompp
2009 o(0xe0df); // fnstsw %ax
2010 o(0x9e); // sahf
2011 o(0xc0950f); // setne %al
2012 o(0xc29a0f); // setp %dl
2013 o(0xd009); // orl %edx, %eax
2014 o(0xc0b60f); // movzbl %al, %eax
2015 o(0x01f083); // xorl $1, %eax
2016 break;
2017 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002018 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002019 break;
2020 }
2021 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002022 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002023 }
2024
2025 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002026 Type* pR0Type = getR0Type();
2027 TypeTag tag = collapseType(pR0Type->tag);
2028 switch(tag) {
2029 case TY_INT:
2030 oad(0xb9, 0); /* movl $0, %ecx */
2031 o(decodeOp(op));
2032 break;
2033 case TY_FLOAT:
2034 case TY_DOUBLE:
2035 switch (op) {
2036 case OP_MINUS:
2037 o(0xe0d9); // fchs
2038 break;
2039 case OP_BIT_NOT:
2040 error("Can't apply '~' operator to a float or double.");
2041 break;
2042 default:
2043 error("Unknown unary op %d\n", op);
2044 break;
2045 }
2046 break;
2047 default:
2048 error("genUnaryOp unsupported type");
2049 break;
2050 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002051 }
2052
Jack Palevich1cdef202009-05-22 12:06:27 -07002053 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002054 Type* pR0Type = getR0Type();
2055 TypeTag r0ct = collapseType(pR0Type->tag);
2056 switch(r0ct) {
2057 case TY_INT:
2058 o(0x50); /* push %eax */
2059 break;
2060 case TY_FLOAT:
2061 o(0x50); /* push %eax */
2062 o(0x241cd9); // fstps 0(%esp)
2063 break;
2064 case TY_DOUBLE:
2065 o(0x50); /* push %eax */
2066 o(0x50); /* push %eax */
2067 o(0x241cdd); // fstpl 0(%esp)
2068 break;
2069 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002070 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002071 break;
2072 }
Jack Palevich8df46192009-07-07 14:48:51 -07002073 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002074 }
2075
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002076 virtual void over() {
2077 // We know it's only used for int-ptr ops (++/--)
2078
2079 Type* pR0Type = getR0Type();
2080 TypeTag r0ct = collapseType(pR0Type->tag);
2081
2082 Type* pTOSType = getTOSType();
2083 TypeTag tosct = collapseType(pTOSType->tag);
2084
2085 assert (r0ct == TY_INT && tosct == TY_INT);
2086
2087 o(0x59); /* pop %ecx */
2088 o(0x50); /* push %eax */
2089 o(0x51); /* push %ecx */
2090
2091 overType();
2092 }
2093
Jack Palevich58c30ee2009-07-17 16:35:23 -07002094 virtual void popR0() {
2095 Type* pR0Type = getR0Type();
2096 TypeTag r0ct = collapseType(pR0Type->tag);
2097 switch(r0ct) {
2098 case TY_INT:
2099 o(0x58); /* popl %eax */
2100 break;
2101 case TY_FLOAT:
2102 o(0x2404d9); // flds (%esp)
2103 o(0x58); /* popl %eax */
2104 break;
2105 case TY_DOUBLE:
2106 o(0x2404dd); // fldl (%esp)
2107 o(0x58); /* popl %eax */
2108 o(0x58); /* popl %eax */
2109 break;
2110 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002111 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002112 break;
2113 }
2114 popType();
2115 }
2116
2117 virtual void storeR0ToTOS() {
2118 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002119 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002120 Type* pTargetType = pPointerType->pHead;
2121 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002122 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002123 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002124 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002125 case TY_INT:
2126 o(0x0189); /* movl %eax/%al, (%ecx) */
2127 break;
2128 case TY_CHAR:
2129 o(0x0188); /* movl %eax/%al, (%ecx) */
2130 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002131 case TY_FLOAT:
2132 o(0x19d9); /* fstps (%ecx) */
2133 break;
2134 case TY_DOUBLE:
2135 o(0x19dd); /* fstpl (%ecx) */
2136 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002137 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002138 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002139 break;
2140 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002141 }
2142
Jack Palevich58c30ee2009-07-17 16:35:23 -07002143 virtual void loadR0FromR0() {
2144 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002145 assert(pPointerType->tag == TY_POINTER);
2146 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002147 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002148 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002149 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002150 break;
2151 case TY_CHAR:
2152 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002153 ob(0); /* add zero in code */
2154 break;
2155 case TY_FLOAT:
2156 o2(0x00d9); // flds (%eax)
2157 break;
2158 case TY_DOUBLE:
2159 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002160 break;
2161 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002162 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002163 break;
2164 }
Jack Palevich8df46192009-07-07 14:48:51 -07002165 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002166 }
2167
Jack Palevich8df46192009-07-07 14:48:51 -07002168 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002169 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002170 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002171 }
2172
Jack Palevich9cbd2262009-07-08 16:48:41 -07002173 virtual void storeR0(int ea, Type* pType) {
2174 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002175 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002176 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002177 case TY_CHAR:
2178 if (ea < -LOCAL || ea > LOCAL) {
2179 oad(0xa2, ea); // movb %al,ea
2180 } else {
2181 oad(0x8588, ea); // movb %al,ea(%ebp)
2182 }
2183 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002184 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002185 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002186 gmov(6, ea); /* mov %eax, EA */
2187 break;
2188 case TY_FLOAT:
2189 if (ea < -LOCAL || ea > LOCAL) {
2190 oad(0x1dd9, ea); // fstps ea
2191 } else {
2192 oad(0x9dd9, ea); // fstps ea(%ebp)
2193 }
2194 break;
2195 case TY_DOUBLE:
2196 if (ea < -LOCAL || ea > LOCAL) {
2197 oad(0x1ddd, ea); // fstpl ea
2198 } else {
2199 oad(0x9ddd, ea); // fstpl ea(%ebp)
2200 }
2201 break;
2202 default:
2203 error("Unable to store to type %d", tag);
2204 break;
2205 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 }
2207
Jack Palevich8df46192009-07-07 14:48:51 -07002208 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002209 Type* pR0Type = getR0Type();
2210 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002211 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002212 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002213 return;
2214 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002215 if (bitsSame(pType, pR0Type)) {
2216 // do nothing special
2217 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2218 // do nothing special, both held in same register on x87.
2219 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002220 TypeTag r0Tag = collapseType(pR0Type->tag);
2221 TypeTag destTag = collapseType(pType->tag);
2222 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2223 // Convert R0 from int to float
2224 o(0x50); // push %eax
2225 o(0x2404DB); // fildl 0(%esp)
2226 o(0x58); // pop %eax
2227 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2228 // Convert R0 from float to int. Complicated because
2229 // need to save and restore the rounding mode.
2230 o(0x50); // push %eax
2231 o(0x50); // push %eax
2232 o(0x02247cD9); // fnstcw 2(%esp)
2233 o(0x2444b70f); // movzwl 2(%esp), %eax
2234 o(0x02);
2235 o(0x0cb4); // movb $12, %ah
2236 o(0x24048966); // movw %ax, 0(%esp)
2237 o(0x242cd9); // fldcw 0(%esp)
2238 o(0x04245cdb); // fistpl 4(%esp)
2239 o(0x02246cd9); // fldcw 2(%esp)
2240 o(0x58); // pop %eax
2241 o(0x58); // pop %eax
2242 } else {
2243 error("Incompatible types old: %d new: %d",
2244 pR0Type->tag, pType->tag);
2245 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002246 }
2247 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002248 }
2249
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002250 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002251 return oad(0xec81, 0); /* sub $xxx, %esp */
2252 }
2253
Jack Palevich8148c5b2009-07-16 18:24:47 -07002254 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2255 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002256 Type* pR0Type = getR0Type();
2257 TypeTag r0ct = collapseType(pR0Type->tag);
2258 switch(r0ct) {
2259 case TY_INT:
2260 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2261 return 4;
2262 case TY_FLOAT:
2263 oad(0x249CD9, l); /* fstps xxx(%esp) */
2264 return 4;
2265 case TY_DOUBLE:
2266 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2267 return 8;
2268 default:
2269 assert(false);
2270 return 0;
2271 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002272 }
2273
Jack Palevichb7718b92009-07-09 22:00:24 -07002274 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002275 * (int*) a = l;
2276 }
2277
Jack Palevich8df46192009-07-07 14:48:51 -07002278 virtual int callForward(int symbol, Type* pFunc) {
2279 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002280 return psym(0xe8, symbol); /* call xxx */
2281 }
2282
Jack Palevich8df46192009-07-07 14:48:51 -07002283 virtual void callRelative(int t, Type* pFunc) {
2284 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002285 psym(0xe8, t); /* call xxx */
2286 }
2287
Jack Palevich8df46192009-07-07 14:48:51 -07002288 virtual void callIndirect(int l, Type* pFunc) {
2289 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002290 oad(0x2494ff, l); /* call *xxx(%esp) */
2291 }
2292
Jack Palevichb7718b92009-07-09 22:00:24 -07002293 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002294 if (isIndirect) {
2295 l += 4;
2296 }
-b master422972c2009-06-17 19:13:52 -07002297 if (l > 0) {
2298 oad(0xc481, l); /* add $xxx, %esp */
2299 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002300 }
2301
Jack Palevicha6535612009-05-13 16:24:17 -07002302 virtual int jumpOffset() {
2303 return 5;
2304 }
2305
2306 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002307 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002308 }
2309
Jack Paleviche7b59062009-05-19 17:12:17 -07002310 /* output a symbol and patch all calls to it */
2311 virtual void gsym(int t) {
2312 int n;
2313 int pc = getPC();
2314 while (t) {
2315 n = *(int *) t; /* next value */
2316 *(int *) t = pc - t - 4;
2317 t = n;
2318 }
2319 }
2320
Jack Palevich1cdef202009-05-22 12:06:27 -07002321 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002322 size_t pagesize = 4096;
2323 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2324 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2325 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2326 if (err) {
2327 error("mprotect() failed: %d", errno);
2328 }
2329 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002330 }
2331
Jack Palevich9eed7a22009-07-06 17:24:34 -07002332 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002333 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002334 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002335 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002336 switch (pType->tag) {
2337 case TY_CHAR:
2338 return 1;
2339 default:
2340 return 4;
2341 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002342 }
2343
2344 /**
2345 * Array element alignment (in bytes) for this type of data.
2346 */
2347 virtual size_t sizeOf(Type* pType){
2348 switch(pType->tag) {
2349 case TY_INT:
2350 return 4;
2351 case TY_CHAR:
2352 return 1;
2353 default:
2354 return 0;
2355 case TY_FLOAT:
2356 return 4;
2357 case TY_DOUBLE:
2358 return 8;
2359 case TY_POINTER:
2360 return 4;
2361 }
2362 }
2363
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002364 virtual size_t stackAlignmentOf(Type* pType){
2365 return 4;
2366 }
2367
Jack Palevich9cbd2262009-07-08 16:48:41 -07002368 virtual size_t stackSizeOf(Type* pType) {
2369 switch(pType->tag) {
2370 case TY_DOUBLE:
2371 return 8;
2372 default:
2373 return 4;
2374 }
2375 }
2376
Jack Palevich21a15a22009-05-11 14:49:29 -07002377 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002378
2379 /** Output 1 to 4 bytes.
2380 *
2381 */
2382 void o(int n) {
2383 /* cannot use unsigned, so we must do a hack */
2384 while (n && n != -1) {
2385 ob(n & 0xff);
2386 n = n >> 8;
2387 }
2388 }
2389
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002390 /* Output exactly 2 bytes
2391 */
2392 void o2(int n) {
2393 ob(n & 0xff);
2394 ob(0xff & (n >> 8));
2395 }
2396
Jack Paleviche7b59062009-05-19 17:12:17 -07002397 /* psym is used to put an instruction with a data field which is a
2398 reference to a symbol. It is in fact the same as oad ! */
2399 int psym(int n, int t) {
2400 return oad(n, t);
2401 }
2402
2403 /* instruction + address */
2404 int oad(int n, int t) {
2405 o(n);
2406 int result = getPC();
2407 o4(t);
2408 return result;
2409 }
2410
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002411 static const int operatorHelper[];
2412
2413 int decodeOp(int op) {
2414 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002415 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002416 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002417 }
2418 return operatorHelper[op];
2419 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002420
Jack Palevich546b2242009-05-13 15:10:04 -07002421 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002422 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002423 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002424 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002425
2426 void setupFloatOperands() {
2427 Type* pR0Type = getR0Type();
2428 Type* pTOSType = getTOSType();
2429 TypeTag tagR0 = pR0Type->tag;
2430 TypeTag tagTOS = pTOSType->tag;
2431 bool isFloatR0 = isFloatTag(tagR0);
2432 bool isFloatTOS = isFloatTag(tagTOS);
2433 if (! isFloatR0) {
2434 // Convert R0 from int to float
2435 o(0x50); // push %eax
2436 o(0x2404DB); // fildl 0(%esp)
2437 o(0x58); // pop %eax
2438 }
2439 if (! isFloatTOS){
2440 o(0x2404DB); // fildl 0(%esp);
2441 o(0x58); // pop %eax
2442 } else {
2443 if (tagTOS == TY_FLOAT) {
2444 o(0x2404d9); // flds (%esp)
2445 o(0x58); // pop %eax
2446 } else {
2447 o(0x2404dd); // fldl (%esp)
2448 o(0x58); // pop %eax
2449 o(0x58); // pop %eax
2450 }
2451 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002452 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002453 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002454 };
2455
Jack Paleviche7b59062009-05-19 17:12:17 -07002456#endif // PROVIDE_X86_CODEGEN
2457
Jack Palevichb67b18f2009-06-11 21:12:23 -07002458#ifdef PROVIDE_TRACE_CODEGEN
2459 class TraceCodeGenerator : public CodeGenerator {
2460 private:
2461 CodeGenerator* mpBase;
2462
2463 public:
2464 TraceCodeGenerator(CodeGenerator* pBase) {
2465 mpBase = pBase;
2466 }
2467
2468 virtual ~TraceCodeGenerator() {
2469 delete mpBase;
2470 }
2471
2472 virtual void init(CodeBuf* pCodeBuf) {
2473 mpBase->init(pCodeBuf);
2474 }
2475
2476 void setErrorSink(ErrorSink* pErrorSink) {
2477 mpBase->setErrorSink(pErrorSink);
2478 }
2479
2480 /* returns address to patch with local variable size
2481 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002482 virtual int functionEntry(Type* pDecl) {
2483 int result = mpBase->functionEntry(pDecl);
2484 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002485 return result;
2486 }
2487
Jack Palevichb7718b92009-07-09 22:00:24 -07002488 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2489 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2490 localVariableAddress, localVariableSize);
2491 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002492 }
2493
2494 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002495 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002496 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002497 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002498 }
2499
Jack Palevich1a539db2009-07-08 13:04:41 -07002500 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002501 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002502 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002503 }
2504
Jack Palevichb67b18f2009-06-11 21:12:23 -07002505 virtual int gjmp(int t) {
2506 int result = mpBase->gjmp(t);
2507 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2508 return result;
2509 }
2510
2511 /* l = 0: je, l == 1: jne */
2512 virtual int gtst(bool l, int t) {
2513 int result = mpBase->gtst(l, t);
2514 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2515 return result;
2516 }
2517
Jack Palevich58c30ee2009-07-17 16:35:23 -07002518 virtual void gcmp(int op) {
2519 fprintf(stderr, "gcmp(%d)\n", op);
2520 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002521 }
2522
2523 virtual void genOp(int op) {
2524 fprintf(stderr, "genOp(%d)\n", op);
2525 mpBase->genOp(op);
2526 }
2527
Jack Palevich9eed7a22009-07-06 17:24:34 -07002528
Jack Palevich58c30ee2009-07-17 16:35:23 -07002529 virtual void gUnaryCmp(int op) {
2530 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2531 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002532 }
2533
2534 virtual void genUnaryOp(int op) {
2535 fprintf(stderr, "genUnaryOp(%d)\n", op);
2536 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002537 }
2538
2539 virtual void pushR0() {
2540 fprintf(stderr, "pushR0()\n");
2541 mpBase->pushR0();
2542 }
2543
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002544 virtual void over() {
2545 fprintf(stderr, "over()\n");
2546 mpBase->over();
2547 }
2548
Jack Palevich58c30ee2009-07-17 16:35:23 -07002549 virtual void popR0() {
2550 fprintf(stderr, "popR0()\n");
2551 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002552 }
2553
Jack Palevich58c30ee2009-07-17 16:35:23 -07002554 virtual void storeR0ToTOS() {
2555 fprintf(stderr, "storeR0ToTOS()\n");
2556 mpBase->storeR0ToTOS();
2557 }
2558
2559 virtual void loadR0FromR0() {
2560 fprintf(stderr, "loadR0FromR0()\n");
2561 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002562 }
2563
Jack Palevich8df46192009-07-07 14:48:51 -07002564 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002565 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002566 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002567 }
2568
Jack Palevich9cbd2262009-07-08 16:48:41 -07002569 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002570 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002571 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002572 }
2573
Jack Palevich8df46192009-07-07 14:48:51 -07002574 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002575 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002576 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002577 }
2578
2579 virtual int beginFunctionCallArguments() {
2580 int result = mpBase->beginFunctionCallArguments();
2581 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2582 return result;
2583 }
2584
Jack Palevich8148c5b2009-07-16 18:24:47 -07002585 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2586 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2587 pArgType->tag);
2588 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002589 }
2590
Jack Palevichb7718b92009-07-09 22:00:24 -07002591 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002592 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002593 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002594 }
2595
Jack Palevich8df46192009-07-07 14:48:51 -07002596 virtual int callForward(int symbol, Type* pFunc) {
2597 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002598 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2599 return result;
2600 }
2601
Jack Palevich8df46192009-07-07 14:48:51 -07002602 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002603 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002604 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002605 }
2606
Jack Palevich8df46192009-07-07 14:48:51 -07002607 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002608 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002609 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002610 }
2611
Jack Palevichb7718b92009-07-09 22:00:24 -07002612 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2613 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2614 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002615 }
2616
2617 virtual int jumpOffset() {
2618 return mpBase->jumpOffset();
2619 }
2620
2621 virtual int disassemble(FILE* out) {
2622 return mpBase->disassemble(out);
2623 }
2624
2625 /* output a symbol and patch all calls to it */
2626 virtual void gsym(int t) {
2627 fprintf(stderr, "gsym(%d)\n", t);
2628 mpBase->gsym(t);
2629 }
2630
2631 virtual int finishCompile() {
2632 int result = mpBase->finishCompile();
2633 fprintf(stderr, "finishCompile() = %d\n", result);
2634 return result;
2635 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002636
2637 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002638 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002639 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002640 virtual size_t alignmentOf(Type* pType){
2641 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002642 }
2643
2644 /**
2645 * Array element alignment (in bytes) for this type of data.
2646 */
2647 virtual size_t sizeOf(Type* pType){
2648 return mpBase->sizeOf(pType);
2649 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002650
Jack Palevich9cbd2262009-07-08 16:48:41 -07002651
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002652 virtual size_t stackAlignmentOf(Type* pType) {
2653 return mpBase->stackAlignmentOf(pType);
2654 }
2655
2656
Jack Palevich9cbd2262009-07-08 16:48:41 -07002657 virtual size_t stackSizeOf(Type* pType) {
2658 return mpBase->stackSizeOf(pType);
2659 }
2660
Jack Palevich1a539db2009-07-08 13:04:41 -07002661 virtual Type* getR0Type() {
2662 return mpBase->getR0Type();
2663 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002664
2665 virtual ExpressionType getR0ExpressionType() {
2666 return mpBase->getR0ExpressionType();
2667 }
2668
2669 virtual void setR0ExpressionType(ExpressionType et) {
2670 mpBase->setR0ExpressionType(et);
2671 }
2672
2673 virtual size_t getExpressionStackDepth() {
2674 return mpBase->getExpressionStackDepth();
2675 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002676 };
2677
2678#endif // PROVIDE_TRACE_CODEGEN
2679
Jack Palevich569f1352009-06-29 14:29:08 -07002680 class Arena {
2681 public:
2682 // Used to record a given allocation amount.
2683 // Used:
2684 // Mark mark = arena.mark();
2685 // ... lots of arena.allocate()
2686 // arena.free(mark);
2687
2688 struct Mark {
2689 size_t chunk;
2690 size_t offset;
2691 };
2692
2693 Arena() {
2694 mCurrentChunk = 0;
2695 Chunk start(CHUNK_SIZE);
2696 mData.push_back(start);
2697 }
2698
2699 ~Arena() {
2700 for(size_t i = 0; i < mData.size(); i++) {
2701 mData[i].free();
2702 }
2703 }
2704
2705 // Alloc using the standard alignment size safe for any variable
2706 void* alloc(size_t size) {
2707 return alloc(size, 8);
2708 }
2709
2710 Mark mark(){
2711 Mark result;
2712 result.chunk = mCurrentChunk;
2713 result.offset = mData[mCurrentChunk].mOffset;
2714 return result;
2715 }
2716
2717 void freeToMark(const Mark& mark) {
2718 mCurrentChunk = mark.chunk;
2719 mData[mCurrentChunk].mOffset = mark.offset;
2720 }
2721
2722 private:
2723 // Allocate memory aligned to a given size
2724 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2725 // Memory is not zero filled.
2726
2727 void* alloc(size_t size, size_t alignment) {
2728 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2729 if (mCurrentChunk + 1 < mData.size()) {
2730 mCurrentChunk++;
2731 } else {
2732 size_t allocSize = CHUNK_SIZE;
2733 if (allocSize < size + alignment - 1) {
2734 allocSize = size + alignment - 1;
2735 }
2736 Chunk chunk(allocSize);
2737 mData.push_back(chunk);
2738 mCurrentChunk++;
2739 }
2740 }
2741 return mData[mCurrentChunk].allocate(size, alignment);
2742 }
2743
2744 static const size_t CHUNK_SIZE = 128*1024;
2745 // Note: this class does not deallocate its
2746 // memory when it's destroyed. It depends upon
2747 // its parent to deallocate the memory.
2748 struct Chunk {
2749 Chunk() {
2750 mpData = 0;
2751 mSize = 0;
2752 mOffset = 0;
2753 }
2754
2755 Chunk(size_t size) {
2756 mSize = size;
2757 mpData = (char*) malloc(size);
2758 mOffset = 0;
2759 }
2760
2761 ~Chunk() {
2762 // Doesn't deallocate memory.
2763 }
2764
2765 void* allocate(size_t size, size_t alignment) {
2766 size_t alignedOffset = aligned(mOffset, alignment);
2767 void* result = mpData + alignedOffset;
2768 mOffset = alignedOffset + size;
2769 return result;
2770 }
2771
2772 void free() {
2773 if (mpData) {
2774 ::free(mpData);
2775 mpData = 0;
2776 }
2777 }
2778
2779 size_t remainingCapacity(size_t alignment) {
2780 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2781 }
2782
2783 // Assume alignment is a power of two
2784 inline size_t aligned(size_t v, size_t alignment) {
2785 size_t mask = alignment-1;
2786 return (v + mask) & ~mask;
2787 }
2788
2789 char* mpData;
2790 size_t mSize;
2791 size_t mOffset;
2792 };
2793
2794 size_t mCurrentChunk;
2795
2796 Vector<Chunk> mData;
2797 };
2798
Jack Palevich569f1352009-06-29 14:29:08 -07002799 struct VariableInfo;
2800
2801 struct Token {
2802 int hash;
2803 size_t length;
2804 char* pText;
2805 tokenid_t id;
2806
2807 // Current values for the token
2808 char* mpMacroDefinition;
2809 VariableInfo* mpVariableInfo;
2810 };
2811
2812 class TokenTable {
2813 public:
2814 // Don't use 0..0xff, allows characters and operators to be tokens too.
2815
2816 static const int TOKEN_BASE = 0x100;
2817 TokenTable() {
2818 mpMap = hashmapCreate(128, hashFn, equalsFn);
2819 }
2820
2821 ~TokenTable() {
2822 hashmapFree(mpMap);
2823 }
2824
2825 void setArena(Arena* pArena) {
2826 mpArena = pArena;
2827 }
2828
2829 // Returns a token for a given string of characters.
2830 tokenid_t intern(const char* pText, size_t length) {
2831 Token probe;
2832 int hash = hashmapHash((void*) pText, length);
2833 {
2834 Token probe;
2835 probe.hash = hash;
2836 probe.length = length;
2837 probe.pText = (char*) pText;
2838 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2839 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002840 return pValue->id;
2841 }
2842 }
2843
2844 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2845 memset(pToken, 0, sizeof(*pToken));
2846 pToken->hash = hash;
2847 pToken->length = length;
2848 pToken->pText = (char*) mpArena->alloc(length + 1);
2849 memcpy(pToken->pText, pText, length);
2850 pToken->pText[length] = 0;
2851 pToken->id = mTokens.size() + TOKEN_BASE;
2852 mTokens.push_back(pToken);
2853 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002854 return pToken->id;
2855 }
2856
2857 // Return the Token for a given tokenid.
2858 Token& operator[](tokenid_t id) {
2859 return *mTokens[id - TOKEN_BASE];
2860 }
2861
2862 inline size_t size() {
2863 return mTokens.size();
2864 }
2865
2866 private:
2867
2868 static int hashFn(void* pKey) {
2869 Token* pToken = (Token*) pKey;
2870 return pToken->hash;
2871 }
2872
2873 static bool equalsFn(void* keyA, void* keyB) {
2874 Token* pTokenA = (Token*) keyA;
2875 Token* pTokenB = (Token*) keyB;
2876 // Don't need to compare hash values, they should always be equal
2877 return pTokenA->length == pTokenB->length
2878 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2879 }
2880
2881 Hashmap* mpMap;
2882 Vector<Token*> mTokens;
2883 Arena* mpArena;
2884 };
2885
Jack Palevich1cdef202009-05-22 12:06:27 -07002886 class InputStream {
2887 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002888 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002889 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002890 };
2891
2892 class TextInputStream : public InputStream {
2893 public:
2894 TextInputStream(const char* text, size_t textLength)
2895 : pText(text), mTextLength(textLength), mPosition(0) {
2896 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002897
Jack Palevichdc456462009-07-16 16:50:56 -07002898 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002899 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2900 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002901
Jack Palevichdc456462009-07-16 16:50:56 -07002902 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002903 const char* pText;
2904 size_t mTextLength;
2905 size_t mPosition;
2906 };
2907
Jack Palevicheedf9d22009-06-04 16:23:40 -07002908 class String {
2909 public:
2910 String() {
2911 mpBase = 0;
2912 mUsed = 0;
2913 mSize = 0;
2914 }
2915
Jack Palevich303d8ff2009-06-11 19:06:24 -07002916 String(const char* item, int len, bool adopt) {
2917 if (len < 0) {
2918 len = strlen(item);
2919 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002920 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002921 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002922 mUsed = len;
2923 mSize = len + 1;
2924 } else {
2925 mpBase = 0;
2926 mUsed = 0;
2927 mSize = 0;
2928 appendBytes(item, len);
2929 }
2930 }
2931
Jack Palevich303d8ff2009-06-11 19:06:24 -07002932 String(const String& other) {
2933 mpBase = 0;
2934 mUsed = 0;
2935 mSize = 0;
2936 appendBytes(other.getUnwrapped(), other.len());
2937 }
2938
Jack Palevicheedf9d22009-06-04 16:23:40 -07002939 ~String() {
2940 if (mpBase) {
2941 free(mpBase);
2942 }
2943 }
2944
Jack Palevicha6baa232009-06-12 11:25:59 -07002945 String& operator=(const String& other) {
2946 clear();
2947 appendBytes(other.getUnwrapped(), other.len());
2948 return *this;
2949 }
2950
Jack Palevich303d8ff2009-06-11 19:06:24 -07002951 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002952 return mpBase;
2953 }
2954
Jack Palevich303d8ff2009-06-11 19:06:24 -07002955 void clear() {
2956 mUsed = 0;
2957 if (mSize > 0) {
2958 mpBase[0] = 0;
2959 }
2960 }
2961
Jack Palevicheedf9d22009-06-04 16:23:40 -07002962 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002963 appendBytes(s, strlen(s));
2964 }
2965
2966 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002967 memcpy(ensure(n), s, n + 1);
2968 }
2969
2970 void append(char c) {
2971 * ensure(1) = c;
2972 }
2973
Jack Palevich86351982009-06-30 18:09:56 -07002974 void append(String& other) {
2975 appendBytes(other.getUnwrapped(), other.len());
2976 }
2977
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002978 char* orphan() {
2979 char* result = mpBase;
2980 mpBase = 0;
2981 mUsed = 0;
2982 mSize = 0;
2983 return result;
2984 }
2985
Jack Palevicheedf9d22009-06-04 16:23:40 -07002986 void printf(const char* fmt,...) {
2987 va_list ap;
2988 va_start(ap, fmt);
2989 vprintf(fmt, ap);
2990 va_end(ap);
2991 }
2992
2993 void vprintf(const char* fmt, va_list ap) {
2994 char* temp;
2995 int numChars = vasprintf(&temp, fmt, ap);
2996 memcpy(ensure(numChars), temp, numChars+1);
2997 free(temp);
2998 }
2999
Jack Palevich303d8ff2009-06-11 19:06:24 -07003000 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003001 return mUsed;
3002 }
3003
3004 private:
3005 char* ensure(int n) {
3006 size_t newUsed = mUsed + n;
3007 if (newUsed > mSize) {
3008 size_t newSize = mSize * 2 + 10;
3009 if (newSize < newUsed) {
3010 newSize = newUsed;
3011 }
3012 mpBase = (char*) realloc(mpBase, newSize + 1);
3013 mSize = newSize;
3014 }
3015 mpBase[newUsed] = '\0';
3016 char* result = mpBase + mUsed;
3017 mUsed = newUsed;
3018 return result;
3019 }
3020
3021 char* mpBase;
3022 size_t mUsed;
3023 size_t mSize;
3024 };
3025
Jack Palevich569f1352009-06-29 14:29:08 -07003026 void internKeywords() {
3027 // Note: order has to match TOK_ constants
3028 static const char* keywords[] = {
3029 "int",
3030 "char",
3031 "void",
3032 "if",
3033 "else",
3034 "while",
3035 "break",
3036 "return",
3037 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003038 "auto",
3039 "case",
3040 "const",
3041 "continue",
3042 "default",
3043 "do",
3044 "double",
3045 "enum",
3046 "extern",
3047 "float",
3048 "goto",
3049 "long",
3050 "register",
3051 "short",
3052 "signed",
3053 "sizeof",
3054 "static",
3055 "struct",
3056 "switch",
3057 "typedef",
3058 "union",
3059 "unsigned",
3060 "volatile",
3061 "_Bool",
3062 "_Complex",
3063 "_Imaginary",
3064 "inline",
3065 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003066
3067 // predefined tokens that can also be symbols start here:
3068 "pragma",
3069 "define",
3070 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003071 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003072
Jack Palevich569f1352009-06-29 14:29:08 -07003073 for(int i = 0; keywords[i]; i++) {
3074 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003075 }
Jack Palevich569f1352009-06-29 14:29:08 -07003076 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003077
Jack Palevich36d94142009-06-08 15:55:32 -07003078 struct InputState {
3079 InputStream* pStream;
3080 int oldCh;
3081 };
3082
Jack Palevich2db168f2009-06-11 14:29:47 -07003083 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003084 void* pAddress;
3085 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003086 tokenid_t tok;
3087 size_t level;
3088 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003089 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003090 };
3091
Jack Palevich303d8ff2009-06-11 19:06:24 -07003092 class SymbolStack {
3093 public:
3094 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003095 mpArena = 0;
3096 mpTokenTable = 0;
3097 }
3098
3099 void setArena(Arena* pArena) {
3100 mpArena = pArena;
3101 }
3102
3103 void setTokenTable(TokenTable* pTokenTable) {
3104 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003105 }
3106
3107 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003108 Mark mark;
3109 mark.mArenaMark = mpArena->mark();
3110 mark.mSymbolHead = mStack.size();
3111 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003112 }
3113
3114 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003115 // Undo any shadowing that was done:
3116 Mark mark = mLevelStack.back();
3117 mLevelStack.pop_back();
3118 while (mStack.size() > mark.mSymbolHead) {
3119 VariableInfo* pV = mStack.back();
3120 mStack.pop_back();
3121 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003122 }
Jack Palevich569f1352009-06-29 14:29:08 -07003123 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003124 }
3125
Jack Palevich569f1352009-06-29 14:29:08 -07003126 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3127 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3128 return pV && pV->level == level();
3129 }
3130
3131 VariableInfo* add(tokenid_t tok) {
3132 Token& token = (*mpTokenTable)[tok];
3133 VariableInfo* pOldV = token.mpVariableInfo;
3134 VariableInfo* pNewV =
3135 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3136 memset(pNewV, 0, sizeof(VariableInfo));
3137 pNewV->tok = tok;
3138 pNewV->level = level();
3139 pNewV->pOldDefinition = pOldV;
3140 token.mpVariableInfo = pNewV;
3141 mStack.push_back(pNewV);
3142 return pNewV;
3143 }
3144
Jack Palevich86351982009-06-30 18:09:56 -07003145 VariableInfo* add(Type* pType) {
3146 VariableInfo* pVI = add(pType->id);
3147 pVI->pType = pType;
3148 return pVI;
3149 }
3150
Jack Palevich569f1352009-06-29 14:29:08 -07003151 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3152 for (size_t i = 0; i < mStack.size(); i++) {
3153 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003154 break;
3155 }
3156 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003157 }
3158
Jack Palevich303d8ff2009-06-11 19:06:24 -07003159 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003160 inline size_t level() {
3161 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003162 }
3163
Jack Palevich569f1352009-06-29 14:29:08 -07003164 struct Mark {
3165 Arena::Mark mArenaMark;
3166 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003167 };
3168
Jack Palevich569f1352009-06-29 14:29:08 -07003169 Arena* mpArena;
3170 TokenTable* mpTokenTable;
3171 Vector<VariableInfo*> mStack;
3172 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003173 };
Jack Palevich36d94142009-06-08 15:55:32 -07003174
3175 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003176 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003177 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003178 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003179 int tokl; // token operator level
3180 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003181 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003182 intptr_t loc; // local variable index
3183 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003184 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003185 char* dptr; // Macro state: Points to macro text during macro playback.
3186 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003187 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003188 ACCSymbolLookupFn mpSymbolLookupFn;
3189 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003190
3191 // Arena for the duration of the compile
3192 Arena mGlobalArena;
3193 // Arena for data that's only needed when compiling a single function
3194 Arena mLocalArena;
3195
Jack Palevich2ff5c222009-07-23 15:11:22 -07003196 Arena* mpCurrentArena;
3197
Jack Palevich569f1352009-06-29 14:29:08 -07003198 TokenTable mTokenTable;
3199 SymbolStack mGlobals;
3200 SymbolStack mLocals;
3201
Jack Palevich40600de2009-07-01 15:32:35 -07003202 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003203 Type* mkpInt; // int
3204 Type* mkpChar; // char
3205 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003206 Type* mkpFloat;
3207 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003208 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003209 Type* mkpIntPtr;
3210 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003211 Type* mkpFloatPtr;
3212 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003213 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003214
Jack Palevich36d94142009-06-08 15:55:32 -07003215 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003216 int mLineNumber;
3217 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003218
3219 CodeBuf codeBuf;
3220 CodeGenerator* pGen;
3221
Jack Palevicheedf9d22009-06-04 16:23:40 -07003222 String mErrorBuf;
3223
Jack Palevicheedf9d22009-06-04 16:23:40 -07003224 String mPragmas;
3225 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003226 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003227
Jack Palevich21a15a22009-05-11 14:49:29 -07003228 static const int ALLOC_SIZE = 99999;
3229
Jack Palevich303d8ff2009-06-11 19:06:24 -07003230 static const int TOK_DUMMY = 1;
3231 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003232 static const int TOK_NUM_FLOAT = 3;
3233 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003234
3235 // 3..255 are character and/or operators
3236
Jack Palevich2db168f2009-06-11 14:29:47 -07003237 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003238 // Order has to match string list in "internKeywords".
3239 enum {
3240 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3241 TOK_INT = TOK_KEYWORD,
3242 TOK_CHAR,
3243 TOK_VOID,
3244 TOK_IF,
3245 TOK_ELSE,
3246 TOK_WHILE,
3247 TOK_BREAK,
3248 TOK_RETURN,
3249 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003250 TOK_AUTO,
3251 TOK_CASE,
3252 TOK_CONST,
3253 TOK_CONTINUE,
3254 TOK_DEFAULT,
3255 TOK_DO,
3256 TOK_DOUBLE,
3257 TOK_ENUM,
3258 TOK_EXTERN,
3259 TOK_FLOAT,
3260 TOK_GOTO,
3261 TOK_LONG,
3262 TOK_REGISTER,
3263 TOK_SHORT,
3264 TOK_SIGNED,
3265 TOK_SIZEOF,
3266 TOK_STATIC,
3267 TOK_STRUCT,
3268 TOK_SWITCH,
3269 TOK_TYPEDEF,
3270 TOK_UNION,
3271 TOK_UNSIGNED,
3272 TOK_VOLATILE,
3273 TOK__BOOL,
3274 TOK__COMPLEX,
3275 TOK__IMAGINARY,
3276 TOK_INLINE,
3277 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003278
3279 // Symbols start after keywords
3280
3281 TOK_SYMBOL,
3282 TOK_PRAGMA = TOK_SYMBOL,
3283 TOK_DEFINE,
3284 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003285 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003286
3287 static const int LOCAL = 0x200;
3288
3289 static const int SYM_FORWARD = 0;
3290 static const int SYM_DEFINE = 1;
3291
3292 /* tokens in string heap */
3293 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003294
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003295 static const int OP_INCREMENT = 0;
3296 static const int OP_DECREMENT = 1;
3297 static const int OP_MUL = 2;
3298 static const int OP_DIV = 3;
3299 static const int OP_MOD = 4;
3300 static const int OP_PLUS = 5;
3301 static const int OP_MINUS = 6;
3302 static const int OP_SHIFT_LEFT = 7;
3303 static const int OP_SHIFT_RIGHT = 8;
3304 static const int OP_LESS_EQUAL = 9;
3305 static const int OP_GREATER_EQUAL = 10;
3306 static const int OP_LESS = 11;
3307 static const int OP_GREATER = 12;
3308 static const int OP_EQUALS = 13;
3309 static const int OP_NOT_EQUALS = 14;
3310 static const int OP_LOGICAL_AND = 15;
3311 static const int OP_LOGICAL_OR = 16;
3312 static const int OP_BIT_AND = 17;
3313 static const int OP_BIT_XOR = 18;
3314 static const int OP_BIT_OR = 19;
3315 static const int OP_BIT_NOT = 20;
3316 static const int OP_LOGICAL_NOT = 21;
3317 static const int OP_COUNT = 22;
3318
3319 /* Operators are searched from front, the two-character operators appear
3320 * before the single-character operators with the same first character.
3321 * @ is used to pad out single-character operators.
3322 */
3323 static const char* operatorChars;
3324 static const char operatorLevel[];
3325
Jack Palevich569f1352009-06-29 14:29:08 -07003326 /* Called when we detect an internal problem. Does nothing in production.
3327 *
3328 */
3329 void internalError() {
3330 * (char*) 0 = 0;
3331 }
3332
Jack Palevich86351982009-06-30 18:09:56 -07003333 void assert(bool isTrue) {
3334 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003335 internalError();
3336 }
Jack Palevich86351982009-06-30 18:09:56 -07003337 }
3338
Jack Palevich40600de2009-07-01 15:32:35 -07003339 bool isSymbol(tokenid_t t) {
3340 return t >= TOK_SYMBOL &&
3341 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3342 }
3343
3344 bool isSymbolOrKeyword(tokenid_t t) {
3345 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003346 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003347 }
3348
Jack Palevich86351982009-06-30 18:09:56 -07003349 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003350 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003351 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3352 if (pV && pV->tok != t) {
3353 internalError();
3354 }
3355 return pV;
3356 }
3357
3358 inline bool isDefined(tokenid_t t) {
3359 return t >= TOK_SYMBOL && VI(t) != 0;
3360 }
3361
Jack Palevich40600de2009-07-01 15:32:35 -07003362 const char* nameof(tokenid_t t) {
3363 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003364 return mTokenTable[t].pText;
3365 }
3366
Jack Palevich21a15a22009-05-11 14:49:29 -07003367 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003368 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003369 }
3370
3371 void inp() {
3372 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003373 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003374 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003375 dptr = 0;
3376 ch = dch;
3377 }
Jack Palevichdc456462009-07-16 16:50:56 -07003378 } else {
3379 if (mbBumpLine) {
3380 mLineNumber++;
3381 mbBumpLine = false;
3382 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003383 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003384 if (ch == '\n') {
3385 mbBumpLine = true;
3386 }
3387 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003388#if 0
3389 printf("ch='%c' 0x%x\n", ch, ch);
3390#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003391 }
3392
3393 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003394 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003395 }
3396
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003397 int decodeHex(int c) {
3398 if (isdigit(c)) {
3399 c -= '0';
3400 } else if (c <= 'F') {
3401 c = c - 'A' + 10;
3402 } else {
3403 c =c - 'a' + 10;
3404 }
3405 return c;
3406 }
3407
Jack Palevichb4758ff2009-06-12 12:49:14 -07003408 /* read a character constant, advances ch to after end of constant */
3409 int getq() {
3410 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003411 if (ch == '\\') {
3412 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003413 if (isoctal(ch)) {
3414 // 1 to 3 octal characters.
3415 val = 0;
3416 for(int i = 0; i < 3; i++) {
3417 if (isoctal(ch)) {
3418 val = (val << 3) + ch - '0';
3419 inp();
3420 }
3421 }
3422 return val;
3423 } else if (ch == 'x' || ch == 'X') {
3424 // N hex chars
3425 inp();
3426 if (! isxdigit(ch)) {
3427 error("'x' character escape requires at least one digit.");
3428 } else {
3429 val = 0;
3430 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003431 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003432 inp();
3433 }
3434 }
3435 } else {
3436 int val = ch;
3437 switch (ch) {
3438 case 'a':
3439 val = '\a';
3440 break;
3441 case 'b':
3442 val = '\b';
3443 break;
3444 case 'f':
3445 val = '\f';
3446 break;
3447 case 'n':
3448 val = '\n';
3449 break;
3450 case 'r':
3451 val = '\r';
3452 break;
3453 case 't':
3454 val = '\t';
3455 break;
3456 case 'v':
3457 val = '\v';
3458 break;
3459 case '\\':
3460 val = '\\';
3461 break;
3462 case '\'':
3463 val = '\'';
3464 break;
3465 case '"':
3466 val = '"';
3467 break;
3468 case '?':
3469 val = '?';
3470 break;
3471 default:
3472 error("Undefined character escape %c", ch);
3473 break;
3474 }
3475 inp();
3476 return val;
3477 }
3478 } else {
3479 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003480 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003481 return val;
3482 }
3483
3484 static bool isoctal(int ch) {
3485 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003486 }
3487
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003488 bool acceptCh(int c) {
3489 bool result = c == ch;
3490 if (result) {
3491 pdef(ch);
3492 inp();
3493 }
3494 return result;
3495 }
3496
3497 bool acceptDigitsCh() {
3498 bool result = false;
3499 while (isdigit(ch)) {
3500 result = true;
3501 pdef(ch);
3502 inp();
3503 }
3504 return result;
3505 }
3506
3507 void parseFloat() {
3508 tok = TOK_NUM_DOUBLE;
3509 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003510 if(mTokenString.len() == 0) {
3511 mTokenString.append('0');
3512 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003513 acceptCh('.');
3514 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003515 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003516 acceptCh('-') || acceptCh('+');
3517 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003518 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003519 if (ch == 'f' || ch == 'F') {
3520 tok = TOK_NUM_FLOAT;
3521 inp();
3522 } else if (ch == 'l' || ch == 'L') {
3523 inp();
3524 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003525 }
3526 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003527 char* pEnd = pText + strlen(pText);
3528 char* pEndPtr = 0;
3529 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003530 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003531 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003532 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003533 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003534 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003535 if (errno || pEndPtr != pEnd) {
3536 error("Can't parse constant: %s", pText);
3537 }
3538 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003539 }
3540
Jack Palevich21a15a22009-05-11 14:49:29 -07003541 void next() {
3542 int l, a;
3543
Jack Palevich546b2242009-05-13 15:10:04 -07003544 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003545 if (ch == '#') {
3546 inp();
3547 next();
3548 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003549 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003550 } else if (tok == TOK_PRAGMA) {
3551 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003552 } else if (tok == TOK_LINE) {
3553 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003554 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003555 error("Unsupported preprocessor directive \"%s\"",
3556 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003557 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003558 }
3559 inp();
3560 }
3561 tokl = 0;
3562 tok = ch;
3563 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003564 if (isdigit(ch) || ch == '.') {
3565 // Start of a numeric constant. Could be integer, float, or
3566 // double, won't know until we look further.
3567 mTokenString.clear();
3568 pdef(ch);
3569 inp();
3570 int base = 10;
3571 if (tok == '0') {
3572 if (ch == 'x' || ch == 'X') {
3573 base = 16;
3574 tok = TOK_NUM;
3575 tokc = 0;
3576 inp();
3577 while ( isxdigit(ch) ) {
3578 tokc = (tokc << 4) + decodeHex(ch);
3579 inp();
3580 }
3581 } else if (isoctal(ch)){
3582 base = 8;
3583 tok = TOK_NUM;
3584 tokc = 0;
3585 while ( isoctal(ch) ) {
3586 tokc = (tokc << 3) + (ch - '0');
3587 inp();
3588 }
3589 }
3590 } else if (isdigit(tok)){
3591 acceptDigitsCh();
3592 }
3593 if (base == 10) {
3594 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3595 parseFloat();
3596 } else {
3597 // It's an integer constant
3598 char* pText = mTokenString.getUnwrapped();
3599 char* pEnd = pText + strlen(pText);
3600 char* pEndPtr = 0;
3601 errno = 0;
3602 tokc = strtol(pText, &pEndPtr, base);
3603 if (errno || pEndPtr != pEnd) {
3604 error("Can't parse constant: %s %d %d", pText, base, errno);
3605 }
3606 tok = TOK_NUM;
3607 }
3608 }
3609 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003610 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003611 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003612 pdef(ch);
3613 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003614 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003615 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3616 // Is this a macro?
3617 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3618 if (pMacroDefinition) {
3619 // Yes, it is a macro
3620 dptr = pMacroDefinition;
3621 dch = ch;
3622 inp();
3623 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003624 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003625 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003626 inp();
3627 if (tok == '\'') {
3628 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003629 tokc = getq();
3630 if (ch != '\'') {
3631 error("Expected a ' character, got %c", ch);
3632 } else {
3633 inp();
3634 }
Jack Palevich546b2242009-05-13 15:10:04 -07003635 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003636 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003637 while (ch && ch != EOF) {
3638 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003639 inp();
3640 inp();
3641 if (ch == '/')
3642 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003643 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003644 if (ch == EOF) {
3645 error("End of file inside comment.");
3646 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003647 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003648 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003649 } else if ((tok == '/') & (ch == '/')) {
3650 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003651 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003652 inp();
3653 }
3654 inp();
3655 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003656 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003657 const char* t = operatorChars;
3658 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003659 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003660 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003661 tokl = operatorLevel[opIndex];
3662 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003663 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003664#if 0
3665 printf("%c%c -> tokl=%d tokc=0x%x\n",
3666 l, a, tokl, tokc);
3667#endif
3668 if (a == ch) {
3669 inp();
3670 tok = TOK_DUMMY; /* dummy token for double tokens */
3671 }
3672 break;
3673 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003674 opIndex++;
3675 }
3676 if (l == 0) {
3677 tokl = 0;
3678 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003679 }
3680 }
3681 }
3682#if 0
3683 {
Jack Palevich569f1352009-06-29 14:29:08 -07003684 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003685 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003686 fprintf(stderr, "%s\n", buf.getUnwrapped());
3687 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003688#endif
3689 }
3690
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003691 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003692 next();
3693 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003694 String* pName = new String();
3695 while (isspace(ch)) {
3696 inp();
3697 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003698 if (ch == '(') {
3699 delete pName;
3700 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003701 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003702 }
3703 while (isspace(ch)) {
3704 inp();
3705 }
Jack Palevich569f1352009-06-29 14:29:08 -07003706 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003707 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003708 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003709 inp();
3710 }
Jack Palevich569f1352009-06-29 14:29:08 -07003711 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3712 memcpy(pDefn, value.getUnwrapped(), value.len());
3713 pDefn[value.len()] = 0;
3714 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003715 }
3716
Jack Palevicheedf9d22009-06-04 16:23:40 -07003717 void doPragma() {
3718 // # pragma name(val)
3719 int state = 0;
3720 while(ch != EOF && ch != '\n' && state < 10) {
3721 switch(state) {
3722 case 0:
3723 if (isspace(ch)) {
3724 inp();
3725 } else {
3726 state++;
3727 }
3728 break;
3729 case 1:
3730 if (isalnum(ch)) {
3731 mPragmas.append(ch);
3732 inp();
3733 } else if (ch == '(') {
3734 mPragmas.append(0);
3735 inp();
3736 state++;
3737 } else {
3738 state = 11;
3739 }
3740 break;
3741 case 2:
3742 if (isalnum(ch)) {
3743 mPragmas.append(ch);
3744 inp();
3745 } else if (ch == ')') {
3746 mPragmas.append(0);
3747 inp();
3748 state = 10;
3749 } else {
3750 state = 11;
3751 }
3752 break;
3753 }
3754 }
3755 if(state != 10) {
3756 error("Unexpected pragma syntax");
3757 }
3758 mPragmaStringCount += 2;
3759 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003760
Jack Palevichdc456462009-07-16 16:50:56 -07003761 void doLine() {
3762 // # line number { "filename "}
3763 next();
3764 if (tok != TOK_NUM) {
3765 error("Expected a line-number");
3766 } else {
3767 mLineNumber = tokc-1; // The end-of-line will increment it.
3768 }
3769 while(ch != EOF && ch != '\n') {
3770 inp();
3771 }
3772 }
3773
Jack Palevichac0e95e2009-05-29 13:53:44 -07003774 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003775 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003776 mErrorBuf.vprintf(fmt, ap);
3777 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003778 }
3779
Jack Palevich8b0624c2009-05-20 12:12:06 -07003780 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003781 if (tok != c) {
3782 error("'%c' expected", c);
3783 }
3784 next();
3785 }
3786
Jack Palevich86351982009-06-30 18:09:56 -07003787 bool accept(intptr_t c) {
3788 if (tok == c) {
3789 next();
3790 return true;
3791 }
3792 return false;
3793 }
3794
Jack Palevich40600de2009-07-01 15:32:35 -07003795 bool acceptStringLiteral() {
3796 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003797 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003798 // This while loop merges multiple adjacent string constants.
3799 while (tok == '"') {
3800 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003801 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003802 }
3803 if (ch != '"') {
3804 error("Unterminated string constant.");
3805 }
3806 inp();
3807 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003808 }
Jack Palevich40600de2009-07-01 15:32:35 -07003809 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003810 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003811 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003812 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003813
3814 return true;
3815 }
3816 return false;
3817 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003818
Jack Palevichb1544ca2009-07-16 15:09:20 -07003819 void linkGlobal(tokenid_t t, bool isFunction) {
3820 VariableInfo* pVI = VI(t);
3821 void* n = NULL;
3822 if (mpSymbolLookupFn) {
3823 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3824 }
3825 if (pVI->pType == NULL) {
3826 if (isFunction) {
3827 pVI->pType = mkpIntFn;
3828 } else {
3829 pVI->pType = mkpInt;
3830 }
3831 }
3832 pVI->pAddress = n;
3833 }
3834
Jack Palevich40600de2009-07-01 15:32:35 -07003835 /* Parse and evaluate a unary expression.
3836 * allowAssignment is true if '=' parsing wanted (quick hack)
3837 */
3838 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003839 tokenid_t t;
3840 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003841 t = 0;
3842 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3843 if (acceptStringLiteral()) {
3844 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003845 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003846 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003847 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003848 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003849 t = tok;
3850 next();
3851 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003852 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003853 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003854 // Align to 4-byte boundary
3855 glo = (char*) (((intptr_t) glo + 3) & -4);
3856 * (float*) glo = (float) ad;
3857 pGen->loadFloat((int) glo, mkpFloat);
3858 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003859 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003860 // Align to 8-byte boundary
3861 glo = (char*) (((intptr_t) glo + 7) & -8);
3862 * (double*) glo = ad;
3863 pGen->loadFloat((int) glo, mkpDouble);
3864 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003865 } else if (c == 2) {
3866 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003867 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003868 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003869 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003870 else if (t == '+') {
3871 // ignore unary plus.
3872 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003873 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003874 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003875 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003876 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003877 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003878 if (pCast) {
3879 skip(')');
3880 unary(false);
3881 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003882 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003883 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003884 skip(')');
3885 }
3886 } else if (t == '*') {
3887 /* This is a pointer dereference.
3888 */
3889 unary(false);
3890 Type* pR0Type = pGen->getR0Type();
3891 if (pR0Type->tag != TY_POINTER) {
3892 error("Expected a pointer type.");
3893 } else {
3894 if (pR0Type->pHead->tag == TY_FUNC) {
3895 t = 0;
3896 }
3897 if (accept('=')) {
3898 pGen->pushR0();
3899 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003900 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07003901 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003902 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07003903 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003904 }
Jack Palevich3f226492009-07-02 14:46:19 -07003905 // Else we fall through to the function call below, with
3906 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003907 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003908 VariableInfo* pVI = VI(tok);
Jack Palevich2ff5c222009-07-23 15:11:22 -07003909 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType));
Jack Palevich21a15a22009-05-11 14:49:29 -07003910 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003911 } else if (t == EOF ) {
3912 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003913 } else if (t == ';') {
3914 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003915 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003916 // Don't have to do anything special here, the error
3917 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003918 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003919 if (!isDefined(t)) {
3920 mGlobals.add(t);
3921 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003922 }
Jack Palevich8df46192009-07-07 14:48:51 -07003923 VariableInfo* pVI = VI(t);
3924 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003925 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003926 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003927 linkGlobal(t, tok == '(');
3928 n = (intptr_t) pVI->pAddress;
3929 if (!n && tok != '(') {
3930 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003931 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003932 }
Jack Palevich40600de2009-07-01 15:32:35 -07003933 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003934 /* assignment */
3935 next();
3936 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003937 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003938 } else if (tok != '(') {
3939 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003940 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003941 linkGlobal(t, false);
3942 n = (intptr_t) pVI->pAddress;
3943 if (!n) {
3944 error("Undeclared variable %s\n", nameof(t));
3945 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003946 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07003947 // load a variable
Jack Palevich21a15a22009-05-11 14:49:29 -07003948 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003949 // post inc / post dec
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003950 pGen->leaR0(n, createPtrType(pVI->pType));
3951
Jack Palevich58c30ee2009-07-17 16:35:23 -07003952 pGen->pushR0();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003953 pGen->loadR0FromR0();
3954 pGen->over();
3955 int lit = 1;
3956 if (tokc == OP_DECREMENT) {
3957 lit = -1;
3958 }
3959 switch (pVI->pType->tag) {
3960 case TY_INT:
3961 case TY_CHAR:
3962 case TY_POINTER:
3963 pGen->pushR0();
3964 pGen->li(lit);
3965 pGen->genOp(OP_PLUS);
3966 break;
3967 default:
3968 error("++/-- illegal for this type.");
3969 break;
3970 }
3971
3972 pGen->storeR0ToTOS();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003973 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003974 next();
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003975 } else {
Jack Palevicha7813bd2009-07-29 11:36:04 -07003976 pGen->leaR0(n, createPtrType(pVI->pType));
3977 pGen->loadR0FromR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003978 }
3979 }
3980 }
3981 }
3982
3983 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003984 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003985 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003986 VariableInfo* pVI = NULL;
3987 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003988 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003989 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003990 } else {
3991 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003992 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003993 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003994 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003995 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003996 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003997 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003998 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003999 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004000 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004001 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004002 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004003 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004004 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004005 Type* pTargetType;
4006 if (pArgList) {
4007 pTargetType = pArgList->pHead;
4008 pArgList = pArgList->pTail;
4009 } else {
4010 pTargetType = pGen->getR0Type();
4011 if (pTargetType->tag == TY_FLOAT) {
4012 pTargetType = mkpDouble;
4013 }
4014 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004015 if (pTargetType->tag == TY_VOID) {
4016 error("Can't pass void value for argument %d",
4017 argCount + 1);
4018 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004019 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004020 }
Jack Palevich95727a02009-07-06 12:07:15 -07004021 if (accept(',')) {
4022 // fine
4023 } else if ( tok != ')') {
4024 error("Expected ',' or ')'");
4025 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004026 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004027 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004028 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004029 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004030 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004031 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004032 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004033 if (!n) {
4034 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004035 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4036 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004037 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004038 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004039 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004040 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4041 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004042 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004043 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004044 }
4045 }
4046
Jack Palevich40600de2009-07-01 15:32:35 -07004047 /* Recursive descent parser for binary operations.
4048 */
4049 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004050 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004051 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004052 if (level-- == 1)
4053 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004054 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004055 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004057 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004058 t = tokc;
4059 next();
4060
Jack Palevich40600de2009-07-01 15:32:35 -07004061 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004062 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004063 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004064 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004065 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004066 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004067 // Check for syntax error.
4068 if (pGen->getR0Type() == NULL) {
4069 // We failed to parse a right-hand argument.
4070 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004071 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004072 }
Jack Palevich40600de2009-07-01 15:32:35 -07004073 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004074 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004076 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004077 }
4078 }
4079 }
4080 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004081 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004082 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004083 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07004084 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004085 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004086 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07004087 }
4088 }
4089 }
4090
4091 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004092 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004093 }
4094
4095 int test_expr() {
4096 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004097 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004098 }
4099
Jack Palevicha6baa232009-06-12 11:25:59 -07004100 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004101 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004102
Jack Palevich95727a02009-07-06 12:07:15 -07004103 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004104 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004105 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004106 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004107 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004108 next();
4109 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004110 a = test_expr();
4111 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004112 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004113 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004114 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004115 n = pGen->gjmp(0); /* jmp */
4116 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004117 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004118 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004119 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004120 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004121 }
Jack Palevich546b2242009-05-13 15:10:04 -07004122 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004123 t = tok;
4124 next();
4125 skip('(');
4126 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004127 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004128 a = test_expr();
4129 } else {
4130 if (tok != ';')
4131 expr();
4132 skip(';');
4133 n = codeBuf.getPC();
4134 a = 0;
4135 if (tok != ';')
4136 a = test_expr();
4137 skip(';');
4138 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004139 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004140 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004141 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004142 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004143 n = t + 4;
4144 }
4145 }
4146 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004147 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004148 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004149 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004150 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004151 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004152 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004153 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004155 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004156 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004157 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004158 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004159 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004160 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004161 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004162 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004163 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004164 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004165 if (pReturnType->tag == TY_VOID) {
4166 error("Must not return a value from a void function");
4167 } else {
4168 pGen->convertR0(pReturnType);
4169 }
4170 } else {
4171 if (pReturnType->tag != TY_VOID) {
4172 error("Must specify a value here");
4173 }
Jack Palevich8df46192009-07-07 14:48:51 -07004174 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004175 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004176 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004177 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004178 } else if (tok != ';')
4179 expr();
4180 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004181 }
4182 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004183
Jack Palevicha8f427f2009-07-13 18:40:08 -07004184 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004185 if (a == b) {
4186 return true;
4187 }
4188 if (a == NULL || b == NULL) {
4189 return false;
4190 }
4191 TypeTag at = a->tag;
4192 if (at != b->tag) {
4193 return false;
4194 }
4195 if (at == TY_POINTER) {
4196 return typeEqual(a->pHead, b->pHead);
4197 } else if (at == TY_FUNC || at == TY_PARAM) {
4198 return typeEqual(a->pHead, b->pHead)
4199 && typeEqual(a->pTail, b->pTail);
4200 }
4201 return true;
4202 }
4203
Jack Palevich2ff5c222009-07-23 15:11:22 -07004204 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004205 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004206 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004207 memset(pType, 0, sizeof(*pType));
4208 pType->tag = tag;
4209 pType->pHead = pHead;
4210 pType->pTail = pTail;
4211 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004212 }
4213
Jack Palevich2ff5c222009-07-23 15:11:22 -07004214 Type* createPtrType(Type* pType) {
4215 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004216 }
4217
4218 /**
4219 * Try to print a type in declaration order
4220 */
Jack Palevich86351982009-06-30 18:09:56 -07004221 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004222 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004223 if (pType == NULL) {
4224 buffer.appendCStr("null");
4225 return;
4226 }
Jack Palevich3f226492009-07-02 14:46:19 -07004227 decodeTypeImp(buffer, pType);
4228 }
4229
4230 void decodeTypeImp(String& buffer, Type* pType) {
4231 decodeTypeImpPrefix(buffer, pType);
4232
Jack Palevich86351982009-06-30 18:09:56 -07004233 String temp;
4234 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004235 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004236 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004237 }
4238
4239 decodeTypeImpPostfix(buffer, pType);
4240 }
4241
4242 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4243 TypeTag tag = pType->tag;
4244
Jack Palevich37c54bd2009-07-14 18:35:36 -07004245 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004246 switch (tag) {
4247 case TY_INT:
4248 buffer.appendCStr("int");
4249 break;
4250 case TY_CHAR:
4251 buffer.appendCStr("char");
4252 break;
4253 case TY_VOID:
4254 buffer.appendCStr("void");
4255 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004256 case TY_FLOAT:
4257 buffer.appendCStr("float");
4258 break;
4259 case TY_DOUBLE:
4260 buffer.appendCStr("double");
4261 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004262 default:
4263 break;
4264 }
Jack Palevich86351982009-06-30 18:09:56 -07004265 buffer.append(' ');
4266 }
Jack Palevich3f226492009-07-02 14:46:19 -07004267
4268 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004269 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004270 break;
4271 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004272 break;
4273 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004274 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004275 case TY_FLOAT:
4276 break;
4277 case TY_DOUBLE:
4278 break;
Jack Palevich86351982009-06-30 18:09:56 -07004279 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004280 decodeTypeImpPrefix(buffer, pType->pHead);
4281 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4282 buffer.append('(');
4283 }
4284 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004285 break;
4286 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004287 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004288 break;
4289 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004290 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004291 break;
4292 default:
4293 String temp;
4294 temp.printf("Unknown tag %d", pType->tag);
4295 buffer.append(temp);
4296 break;
4297 }
Jack Palevich3f226492009-07-02 14:46:19 -07004298 }
4299
4300 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4301 TypeTag tag = pType->tag;
4302
4303 switch(tag) {
4304 case TY_POINTER:
4305 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4306 buffer.append(')');
4307 }
4308 decodeTypeImpPostfix(buffer, pType->pHead);
4309 break;
4310 case TY_FUNC:
4311 buffer.append('(');
4312 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4313 decodeTypeImp(buffer, pArg);
4314 if (pArg->pTail) {
4315 buffer.appendCStr(", ");
4316 }
4317 }
4318 buffer.append(')');
4319 break;
4320 default:
4321 break;
Jack Palevich86351982009-06-30 18:09:56 -07004322 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004323 }
4324
Jack Palevich86351982009-06-30 18:09:56 -07004325 void printType(Type* pType) {
4326 String buffer;
4327 decodeType(buffer, pType);
4328 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004329 }
4330
Jack Palevich2ff5c222009-07-23 15:11:22 -07004331 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004332 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004333 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004334 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004335 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004336 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004337 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004338 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004339 } else if (tok == TOK_FLOAT) {
4340 pType = mkpFloat;
4341 } else if (tok == TOK_DOUBLE) {
4342 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004343 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004344 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004345 }
4346 next();
Jack Palevich86351982009-06-30 18:09:56 -07004347 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004348 }
4349
Jack Palevich2ff5c222009-07-23 15:11:22 -07004350 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004351 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004352 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004353 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004354 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004355 if (declName) {
4356 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004357 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004358
Jack Palevich86351982009-06-30 18:09:56 -07004359 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004360 }
Jack Palevich3f226492009-07-02 14:46:19 -07004361 // fprintf(stderr, "Parsed a declaration: ");
4362 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004363 if (reportFailure) {
4364 return NULL;
4365 }
Jack Palevich86351982009-06-30 18:09:56 -07004366 return pType;
4367 }
4368
Jack Palevich2ff5c222009-07-23 15:11:22 -07004369 Type* expectDeclaration(Type* pBaseType) {
4370 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004371 if (! pType) {
4372 error("Expected a declaration");
4373 }
4374 return pType;
4375 }
4376
Jack Palevich3f226492009-07-02 14:46:19 -07004377 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004378 Type* acceptCastTypeDeclaration() {
4379 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004380 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004381 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004382 }
Jack Palevich86351982009-06-30 18:09:56 -07004383 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004384 }
4385
Jack Palevich2ff5c222009-07-23 15:11:22 -07004386 Type* expectCastTypeDeclaration() {
4387 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004388 if (! pType) {
4389 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004390 }
Jack Palevich3f226492009-07-02 14:46:19 -07004391 return pType;
4392 }
4393
4394 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004395 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004396 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004397 int ptrCounter = 0;
4398 while (accept('*')) {
4399 ptrCounter++;
4400 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004401 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004402 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004403 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004404 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004405 }
4406 return pType;
4407 }
4408
4409 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004410 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004411 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004412 // direct-dcl :
4413 // name
4414 // (dcl)
4415 // direct-dcl()
4416 // direct-dcl[]
4417 Type* pNewHead = NULL;
4418 if (accept('(')) {
4419 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004420 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004421 skip(')');
4422 } else if ((declName = acceptSymbol()) != 0) {
4423 if (nameAllowed == false && declName) {
4424 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004425 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004426 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004427 } else if (nameRequired && ! declName) {
4428 String temp;
4429 decodeToken(temp, tok, true);
4430 error("Expected name. Got %s", temp.getUnwrapped());
4431 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004432 }
4433 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004434 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004435 Type* pTail = acceptArgs(nameAllowed);
4436 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004437 skip(')');
4438 }
Jack Palevich3f226492009-07-02 14:46:19 -07004439
4440 if (pNewHead) {
4441 Type* pA = pNewHead;
4442 while (pA->pHead) {
4443 pA = pA->pHead;
4444 }
4445 pA->pHead = pType;
4446 pType = pNewHead;
4447 }
Jack Palevich86351982009-06-30 18:09:56 -07004448 return pType;
4449 }
4450
Jack Palevich2ff5c222009-07-23 15:11:22 -07004451 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004452 Type* pHead = NULL;
4453 Type* pTail = NULL;
4454 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004455 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004456 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004457 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004458 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004459 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004460 if (!pHead) {
4461 pHead = pParam;
4462 pTail = pParam;
4463 } else {
4464 pTail->pTail = pParam;
4465 pTail = pParam;
4466 }
4467 }
4468 }
4469 if (! accept(',')) {
4470 break;
4471 }
4472 }
4473 return pHead;
4474 }
4475
Jack Palevich2ff5c222009-07-23 15:11:22 -07004476 Type* expectPrimitiveType() {
4477 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004478 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004479 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004480 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004481 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004482 }
Jack Palevich86351982009-06-30 18:09:56 -07004483 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004484 }
4485
Jack Palevich86351982009-06-30 18:09:56 -07004486 void addGlobalSymbol(Type* pDecl) {
4487 tokenid_t t = pDecl->id;
4488 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004489 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004490 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004491 }
Jack Palevich86351982009-06-30 18:09:56 -07004492 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004493 }
4494
Jack Palevich86351982009-06-30 18:09:56 -07004495 void reportDuplicate(tokenid_t t) {
4496 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004497 }
4498
Jack Palevich86351982009-06-30 18:09:56 -07004499 void addLocalSymbol(Type* pDecl) {
4500 tokenid_t t = pDecl->id;
4501 if (mLocals.isDefinedAtCurrentLevel(t)) {
4502 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004503 }
Jack Palevich86351982009-06-30 18:09:56 -07004504 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004505 }
4506
Jack Palevich95727a02009-07-06 12:07:15 -07004507 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004508 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004509
Jack Palevich95727a02009-07-06 12:07:15 -07004510 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004511 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004512 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004513 if (!pDecl) {
4514 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004515 }
Jack Palevich86351982009-06-30 18:09:56 -07004516 int variableAddress = 0;
4517 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004518 size_t alignment = pGen->stackAlignmentOf(pDecl);
4519 size_t alignmentMask = ~ (alignment - 1);
4520 size_t sizeOf = pGen->sizeOf(pDecl);
4521 loc = (loc + alignment - 1) & alignmentMask;
4522 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4523 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004524 variableAddress = -loc;
4525 VI(pDecl->id)->pAddress = (void*) variableAddress;
4526 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004527 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004528 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004529 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004530 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004531 if (tok == ',')
4532 next();
4533 }
4534 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004535 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004536 }
4537 }
4538
Jack Palevichf1728be2009-06-12 13:53:51 -07004539 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004540 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004541 }
4542
Jack Palevich37c54bd2009-07-14 18:35:36 -07004543 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004544 if (token == EOF ) {
4545 buffer.printf("EOF");
4546 } else if (token == TOK_NUM) {
4547 buffer.printf("numeric constant");
4548 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004549 if (token < 32) {
4550 buffer.printf("'\\x%02x'", token);
4551 } else {
4552 buffer.printf("'%c'", token);
4553 }
Jack Palevich569f1352009-06-29 14:29:08 -07004554 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004555 if (quote) {
4556 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4557 buffer.printf("keyword \"%s\"", nameof(token));
4558 } else {
4559 buffer.printf("symbol \"%s\"", nameof(token));
4560 }
4561 } else {
4562 buffer.printf("%s", nameof(token));
4563 }
Jack Palevich569f1352009-06-29 14:29:08 -07004564 }
4565 }
4566
Jack Palevich40600de2009-07-01 15:32:35 -07004567 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004568 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004569 if (!result) {
4570 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004571 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004572 error("Expected symbol. Got %s", temp.getUnwrapped());
4573 }
4574 return result;
4575 }
4576
Jack Palevich86351982009-06-30 18:09:56 -07004577 tokenid_t acceptSymbol() {
4578 tokenid_t result = 0;
4579 if (tok >= TOK_SYMBOL) {
4580 result = tok;
4581 next();
Jack Palevich86351982009-06-30 18:09:56 -07004582 }
4583 return result;
4584 }
4585
Jack Palevichb7c81e92009-06-04 19:56:13 -07004586 void globalDeclarations() {
4587 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004588 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004589 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004590 break;
4591 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004592 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004593 if (!pDecl) {
4594 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004595 }
Jack Palevich86351982009-06-30 18:09:56 -07004596 if (! isDefined(pDecl->id)) {
4597 addGlobalSymbol(pDecl);
4598 }
4599 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004600 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004601 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004602 }
Jack Palevich86351982009-06-30 18:09:56 -07004603 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004604 // it's a variable declaration
4605 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004606 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004607 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004608 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004609 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004610 }
Jack Palevich86351982009-06-30 18:09:56 -07004611 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004612 if (tok == TOK_NUM) {
4613 if (name) {
4614 * (int*) name->pAddress = tokc;
4615 }
4616 next();
4617 } else {
4618 error("Expected an integer constant");
4619 }
4620 }
Jack Palevich86351982009-06-30 18:09:56 -07004621 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004622 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004623 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004624 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004625 if (!pDecl) {
4626 break;
4627 }
4628 if (! isDefined(pDecl->id)) {
4629 addGlobalSymbol(pDecl);
4630 }
4631 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004632 }
4633 skip(';');
4634 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004635 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004636 if (accept(';')) {
4637 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004638 } else if (tok != '{') {
4639 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004640 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004641 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004642 if (name) {
4643 /* patch forward references (XXX: does not work for function
4644 pointers) */
4645 pGen->gsym((int) name->pForward);
4646 /* put function address */
4647 name->pAddress = (void*) codeBuf.getPC();
4648 }
4649 // Calculate stack offsets for parameters
4650 mLocals.pushLevel();
4651 intptr_t a = 8;
4652 int argCount = 0;
4653 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4654 Type* pArg = pP->pHead;
4655 addLocalSymbol(pArg);
4656 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004657 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004658 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004659 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004660 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004661 argCount++;
4662 }
4663 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004664 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004665 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004666 block(0, true);
4667 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004668 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004669 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004670 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004671 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004672 }
4673 }
4674 }
4675
Jack Palevich9cbd2262009-07-08 16:48:41 -07004676 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4677 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4678 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004679 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004680 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004681 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004682 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004683 char* result = (char*) base;
4684 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004685 return result;
4686 }
4687
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004689 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004690 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004691 pGlobalBase = 0;
4692 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004693 if (pGen) {
4694 delete pGen;
4695 pGen = 0;
4696 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004697 if (file) {
4698 delete file;
4699 file = 0;
4700 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004701 }
4702
Jack Palevich8c246a92009-07-14 21:14:10 -07004703 // One-time initialization, when class is constructed.
4704 void init() {
4705 mpSymbolLookupFn = 0;
4706 mpSymbolLookupContext = 0;
4707 }
4708
Jack Palevich21a15a22009-05-11 14:49:29 -07004709 void clear() {
4710 tok = 0;
4711 tokc = 0;
4712 tokl = 0;
4713 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004714 rsym = 0;
4715 loc = 0;
4716 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004717 dptr = 0;
4718 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004719 file = 0;
4720 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004721 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004722 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004723 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004724 mLineNumber = 1;
4725 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004726 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004727
Jack Palevich22305132009-05-13 10:58:45 -07004728 void setArchitecture(const char* architecture) {
4729 delete pGen;
4730 pGen = 0;
4731
4732 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004733#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004734 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004735 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004736 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004737#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004738#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004739 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004740 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004741 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004742#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004743 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004744 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004745 }
4746 }
4747
4748 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004749#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004750 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004751#elif defined(DEFAULT_X86_CODEGEN)
4752 pGen = new X86CodeGenerator();
4753#endif
4754 }
4755 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004756 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004757 } else {
4758 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004759 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004760 }
4761 }
4762
Jack Palevich77ae76e2009-05-10 19:59:24 -07004763public:
Jack Palevich22305132009-05-13 10:58:45 -07004764 struct args {
4765 args() {
4766 architecture = 0;
4767 }
4768 const char* architecture;
4769 };
4770
Jack Paleviche7b59062009-05-19 17:12:17 -07004771 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004772 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004773 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004774 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004775
Jack Paleviche7b59062009-05-19 17:12:17 -07004776 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004777 cleanup();
4778 }
4779
Jack Palevich8c246a92009-07-14 21:14:10 -07004780 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4781 mpSymbolLookupFn = pFn;
4782 mpSymbolLookupContext = pContext;
4783 }
4784
Jack Palevich1cdef202009-05-22 12:06:27 -07004785 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004786 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004787
Jack Palevich2ff5c222009-07-23 15:11:22 -07004788 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004789 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004790 cleanup();
4791 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004792 mTokenTable.setArena(&mGlobalArena);
4793 mGlobals.setArena(&mGlobalArena);
4794 mGlobals.setTokenTable(&mTokenTable);
4795 mLocals.setArena(&mLocalArena);
4796 mLocals.setTokenTable(&mTokenTable);
4797
4798 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004799 codeBuf.init(ALLOC_SIZE);
4800 setArchitecture(NULL);
4801 if (!pGen) {
4802 return -1;
4803 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004804#ifdef PROVIDE_TRACE_CODEGEN
4805 pGen = new TraceCodeGenerator(pGen);
4806#endif
4807 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004808 pGen->init(&codeBuf);
4809 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004810 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4811 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004812 inp();
4813 next();
4814 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004815 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004816 result = pGen->finishCompile();
4817 if (result == 0) {
4818 if (mErrorBuf.len()) {
4819 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004820 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004821 }
Jack Palevichce105a92009-07-16 14:30:33 -07004822 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004823 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004824 }
4825
Jack Palevich86351982009-06-30 18:09:56 -07004826 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004827 mkpInt = createType(TY_INT, NULL, NULL);
4828 mkpChar = createType(TY_CHAR, NULL, NULL);
4829 mkpVoid = createType(TY_VOID, NULL, NULL);
4830 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4831 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4832 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4833 mkpIntPtr = createPtrType(mkpInt);
4834 mkpCharPtr = createPtrType(mkpChar);
4835 mkpFloatPtr = createPtrType(mkpFloat);
4836 mkpDoublePtr = createPtrType(mkpDouble);
4837 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004838 }
4839
Jack Palevicha6baa232009-06-12 11:25:59 -07004840 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004841 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004842 }
4843
Jack Palevich569f1352009-06-29 14:29:08 -07004844 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004845 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004846 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004847 }
4848
Jack Palevich569f1352009-06-29 14:29:08 -07004849 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004850 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004851 error("Undefined forward reference: %s",
4852 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004853 }
4854 return true;
4855 }
4856
Jack Palevich21a15a22009-05-11 14:49:29 -07004857 int dump(FILE* out) {
4858 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4859 return 0;
4860 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004861
Jack Palevicha6535612009-05-13 16:24:17 -07004862 int disassemble(FILE* out) {
4863 return pGen->disassemble(out);
4864 }
4865
Jack Palevich1cdef202009-05-22 12:06:27 -07004866 /* Look through the symbol table to find a symbol.
4867 * If found, return its value.
4868 */
4869 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004870 if (mCompileResult == 0) {
4871 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4872 VariableInfo* pVariableInfo = VI(tok);
4873 if (pVariableInfo) {
4874 return pVariableInfo->pAddress;
4875 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004876 }
4877 return NULL;
4878 }
4879
Jack Palevicheedf9d22009-06-04 16:23:40 -07004880 void getPragmas(ACCsizei* actualStringCount,
4881 ACCsizei maxStringCount, ACCchar** strings) {
4882 int stringCount = mPragmaStringCount;
4883 if (actualStringCount) {
4884 *actualStringCount = stringCount;
4885 }
4886 if (stringCount > maxStringCount) {
4887 stringCount = maxStringCount;
4888 }
4889 if (strings) {
4890 char* pPragmas = mPragmas.getUnwrapped();
4891 while (stringCount-- > 0) {
4892 *strings++ = pPragmas;
4893 pPragmas += strlen(pPragmas) + 1;
4894 }
4895 }
4896 }
4897
Jack Palevichac0e95e2009-05-29 13:53:44 -07004898 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004899 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004900 }
4901
Jack Palevich77ae76e2009-05-10 19:59:24 -07004902};
4903
Jack Paleviche7b59062009-05-19 17:12:17 -07004904const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004905 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4906
Jack Paleviche7b59062009-05-19 17:12:17 -07004907const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004908 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4909 5, 5, /* ==, != */
4910 9, 10, /* &&, || */
4911 6, 7, 8, /* & ^ | */
4912 2, 2 /* ~ ! */
4913 };
4914
Jack Palevich8b0624c2009-05-20 12:12:06 -07004915#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004916FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004917#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004918
Jack Palevich8b0624c2009-05-20 12:12:06 -07004919#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004920const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004921 0x1, // ++
4922 0xff, // --
4923 0xc1af0f, // *
4924 0xf9f79991, // /
4925 0xf9f79991, // % (With manual assist to swap results)
4926 0xc801, // +
4927 0xd8f7c829, // -
4928 0xe0d391, // <<
4929 0xf8d391, // >>
4930 0xe, // <=
4931 0xd, // >=
4932 0xc, // <
4933 0xf, // >
4934 0x4, // ==
4935 0x5, // !=
4936 0x0, // &&
4937 0x1, // ||
4938 0xc821, // &
4939 0xc831, // ^
4940 0xc809, // |
4941 0xd0f7, // ~
4942 0x4 // !
4943};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004944#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004945
Jack Palevich1cdef202009-05-22 12:06:27 -07004946struct ACCscript {
4947 ACCscript() {
4948 text = 0;
4949 textLength = 0;
4950 accError = ACC_NO_ERROR;
4951 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004952
Jack Palevich1cdef202009-05-22 12:06:27 -07004953 ~ACCscript() {
4954 delete text;
4955 }
Jack Palevich546b2242009-05-13 15:10:04 -07004956
Jack Palevich8c246a92009-07-14 21:14:10 -07004957 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4958 compiler.registerSymbolCallback(pFn, pContext);
4959 }
4960
Jack Palevich1cdef202009-05-22 12:06:27 -07004961 void setError(ACCenum error) {
4962 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4963 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004964 }
4965 }
4966
Jack Palevich1cdef202009-05-22 12:06:27 -07004967 ACCenum getError() {
4968 ACCenum result = accError;
4969 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004970 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004971 }
4972
Jack Palevich1cdef202009-05-22 12:06:27 -07004973 Compiler compiler;
4974 char* text;
4975 int textLength;
4976 ACCenum accError;
4977};
4978
4979
4980extern "C"
4981ACCscript* accCreateScript() {
4982 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004983}
Jack Palevich1cdef202009-05-22 12:06:27 -07004984
4985extern "C"
4986ACCenum accGetError( ACCscript* script ) {
4987 return script->getError();
4988}
4989
4990extern "C"
4991void accDeleteScript(ACCscript* script) {
4992 delete script;
4993}
4994
4995extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004996void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4997 ACCvoid* pContext) {
4998 script->registerSymbolCallback(pFn, pContext);
4999}
5000
5001extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005002void accScriptSource(ACCscript* script,
5003 ACCsizei count,
5004 const ACCchar ** string,
5005 const ACCint * length) {
5006 int totalLength = 0;
5007 for(int i = 0; i < count; i++) {
5008 int len = -1;
5009 const ACCchar* s = string[i];
5010 if (length) {
5011 len = length[i];
5012 }
5013 if (len < 0) {
5014 len = strlen(s);
5015 }
5016 totalLength += len;
5017 }
5018 delete script->text;
5019 char* text = new char[totalLength + 1];
5020 script->text = text;
5021 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005022 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005023 for(int i = 0; i < count; i++) {
5024 int len = -1;
5025 const ACCchar* s = string[i];
5026 if (length) {
5027 len = length[i];
5028 }
5029 if (len < 0) {
5030 len = strlen(s);
5031 }
Jack Palevich09555c72009-05-27 12:25:55 -07005032 memcpy(dest, s, len);
5033 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005034 }
5035 text[totalLength] = '\0';
5036}
5037
5038extern "C"
5039void accCompileScript(ACCscript* script) {
5040 int result = script->compiler.compile(script->text, script->textLength);
5041 if (result) {
5042 script->setError(ACC_INVALID_OPERATION);
5043 }
5044}
5045
5046extern "C"
5047void accGetScriptiv(ACCscript* script,
5048 ACCenum pname,
5049 ACCint * params) {
5050 switch (pname) {
5051 case ACC_INFO_LOG_LENGTH:
5052 *params = 0;
5053 break;
5054 }
5055}
5056
5057extern "C"
5058void accGetScriptInfoLog(ACCscript* script,
5059 ACCsizei maxLength,
5060 ACCsizei * length,
5061 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005062 char* message = script->compiler.getErrorMessage();
5063 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005064 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005065 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005066 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005067 if (infoLog && maxLength > 0) {
5068 int trimmedLength = maxLength < messageLength ?
5069 maxLength : messageLength;
5070 memcpy(infoLog, message, trimmedLength);
5071 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005072 }
5073}
5074
5075extern "C"
5076void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5077 ACCvoid ** address) {
5078 void* value = script->compiler.lookup(name);
5079 if (value) {
5080 *address = value;
5081 } else {
5082 script->setError(ACC_INVALID_VALUE);
5083 }
5084}
5085
Jack Palevicheedf9d22009-06-04 16:23:40 -07005086extern "C"
5087void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5088 ACCsizei maxStringCount, ACCchar** strings){
5089 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5090}
5091
-b master422972c2009-06-17 19:13:52 -07005092extern "C"
5093void accDisassemble(ACCscript* script) {
5094 script->compiler.disassemble(stderr);
5095}
5096
Jack Palevicheedf9d22009-06-04 16:23:40 -07005097
Jack Palevich1cdef202009-05-22 12:06:27 -07005098} // namespace acc
5099