blob: 2b0964d3097e438c868e462f800b8cbb46711b17 [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 Palevich1cdef202009-05-22 12:06:27 -0700359 /* Push R0 onto the stack.
360 */
361 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevich58c30ee2009-07-17 16:35:23 -0700363 /* Pop R0 from the stack.
364 */
365 virtual void popR0() = 0;
366
Jack Palevich9eed7a22009-07-06 17:24:34 -0700367 /* Store R0 to the address stored in TOS.
368 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700370 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700371
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700373 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700374 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Load the absolute address of a variable to R0.
377 * If ea <= LOCAL, then this is a local variable, or an
378 * argument, addressed relative to FP.
379 * else it is an absolute global address.
380 */
Jack Palevich8df46192009-07-07 14:48:51 -0700381 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700382
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 /* Store R0 to a variable.
384 * If ea <= LOCAL, then this is a local variable, or an
385 * argument, addressed relative to FP.
386 * else it is an absolute global address.
387 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700388 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 /* load R0 from a variable.
391 * If ea <= LOCAL, then this is a local variable, or an
392 * argument, addressed relative to FP.
393 * else it is an absolute global address.
Jack Palevich1cdef202009-05-22 12:06:27 -0700394 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700395 virtual void loadR0(int ea, Type* pType) = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700396
397 /**
398 * Convert R0 to the given type.
399 */
400 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700401
Jack Palevich1cdef202009-05-22 12:06:27 -0700402 /* Emit code to adjust the stack for a function call. Return the
403 * label for the address of the instruction that adjusts the
404 * stack size. This will be passed as argument "a" to
405 * endFunctionCallArguments.
406 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700407 virtual int beginFunctionCallArguments() = 0;
408
Jack Palevich1cdef202009-05-22 12:06:27 -0700409 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700410 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700411 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700412 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700413
Jack Palevich1cdef202009-05-22 12:06:27 -0700414 /* Patch the function call preamble.
415 * a is the address returned from beginFunctionCallArguments
416 * l is the number of bytes the arguments took on the stack.
417 * Typically you would also emit code to convert the argument
418 * list into whatever the native function calling convention is.
419 * On ARM for example you would pop the first 5 arguments into
420 * R0..R4
421 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700422 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700423
Jack Palevich1cdef202009-05-22 12:06:27 -0700424 /* Emit a call to an unknown function. The argument "symbol" needs to
425 * be stored in the location where the address should go. It forms
426 * a chain. The address will be patched later.
427 * Return the address of the word that has to be patched.
428 */
Jack Palevich8df46192009-07-07 14:48:51 -0700429 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700430
Jack Palevich1cdef202009-05-22 12:06:27 -0700431 /* Call a function using PC-relative addressing. t is the PC-relative
432 * address of the function. It has already been adjusted for the
433 * architectural jump offset, so just store it as-is.
434 */
Jack Palevich8df46192009-07-07 14:48:51 -0700435 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700436
Jack Palevich1cdef202009-05-22 12:06:27 -0700437 /* Call a function pointer. L is the number of bytes the arguments
438 * take on the stack. The address of the function is stored at
439 * location SP + l.
440 */
Jack Palevich8df46192009-07-07 14:48:51 -0700441 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700442
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 /* Adjust SP after returning from a function call. l is the
444 * number of bytes of arguments stored on the stack. isIndirect
445 * is true if this was an indirect call. (In which case the
446 * address of the function is stored at location SP + l.)
447 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700448 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700449
Jack Palevich1cdef202009-05-22 12:06:27 -0700450 /* Print a disassembly of the assembled code to out. Return
451 * non-zero if there is an error.
452 */
Jack Palevicha6535612009-05-13 16:24:17 -0700453 virtual int disassemble(FILE* out) = 0;
454
Jack Palevich1cdef202009-05-22 12:06:27 -0700455 /* Generate a symbol at the current PC. t is the head of a
456 * linked list of addresses to patch.
457 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700458 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700459
Jack Palevich1cdef202009-05-22 12:06:27 -0700460 /*
461 * Do any cleanup work required at the end of a compile.
462 * For example, an instruction cache might need to be
463 * invalidated.
464 * Return non-zero if there is an error.
465 */
466 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700467
Jack Palevicha6535612009-05-13 16:24:17 -0700468 /**
469 * Adjust relative branches by this amount.
470 */
471 virtual int jumpOffset() = 0;
472
Jack Palevich9eed7a22009-07-06 17:24:34 -0700473 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700474 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700475 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700476 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700477
478 /**
479 * Array element alignment (in bytes) for this type of data.
480 */
481 virtual size_t sizeOf(Type* type) = 0;
482
Jack Palevich9cbd2262009-07-08 16:48:41 -0700483 /**
484 * Stack argument size of this data type.
485 */
486 virtual size_t stackSizeOf(Type* pType) = 0;
487
Jack Palevich1a539db2009-07-08 13:04:41 -0700488 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700489 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700490 }
491
Jack Palevich21a15a22009-05-11 14:49:29 -0700492 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700493 /*
494 * Output a byte. Handles all values, 0..ff.
495 */
496 void ob(int n) {
497 pCodeBuf->ob(n);
498 }
499
Jack Palevich8b0624c2009-05-20 12:12:06 -0700500 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700501 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700502 }
503
Jack Palevich8b0624c2009-05-20 12:12:06 -0700504 intptr_t getBase() {
505 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700506 }
507
Jack Palevich8b0624c2009-05-20 12:12:06 -0700508 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700509 return pCodeBuf->getPC();
510 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700511
512 intptr_t getSize() {
513 return pCodeBuf->getSize();
514 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700515
516 void error(const char* fmt,...) {
517 va_list ap;
518 va_start(ap, fmt);
519 mErrorSink->verror(fmt, ap);
520 va_end(ap);
521 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700522
523 void assert(bool test) {
524 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700525 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700526 error("code generator assertion failed.");
527 }
528 }
Jack Palevich8df46192009-07-07 14:48:51 -0700529
530 void setR0Type(Type* pType) {
Jack Palevichba929a42009-07-17 10:20:32 -0700531 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700532 }
533
Jack Palevich8df46192009-07-07 14:48:51 -0700534 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700535 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700536 }
537
538 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700539 if (mExpressionStack.size()) {
540 mExpressionStack.push_back(mExpressionStack.back());
541 } else {
542 mExpressionStack.push_back(ExpressionValue());
543 }
544
Jack Palevich8df46192009-07-07 14:48:51 -0700545 }
546
547 void popType() {
548 mExpressionStack.pop_back();
549 }
550
551 bool bitsSame(Type* pA, Type* pB) {
552 return collapseType(pA->tag) == collapseType(pB->tag);
553 }
554
555 TypeTag collapseType(TypeTag tag) {
556 static const TypeTag collapsedTag[] = {
557 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
558 TY_VOID, TY_VOID};
559 return collapsedTag[tag];
560 }
561
Jack Palevich1a539db2009-07-08 13:04:41 -0700562 TypeTag collapseTypeR0() {
563 return collapseType(getR0Type()->tag);
564 }
565
566 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700567 return isFloatTag(pType->tag);
568 }
569
570 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700571 return tag == TY_FLOAT || tag == TY_DOUBLE;
572 }
573
Jack Palevicha8f427f2009-07-13 18:40:08 -0700574 Type* mkpInt;
575
Jack Palevich21a15a22009-05-11 14:49:29 -0700576 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700577 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700578 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700579 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700580 };
581
Jack Paleviche7b59062009-05-19 17:12:17 -0700582#ifdef PROVIDE_ARM_CODEGEN
583
Jack Palevich22305132009-05-13 10:58:45 -0700584 class ARMCodeGenerator : public CodeGenerator {
585 public:
586 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700587
Jack Palevich22305132009-05-13 10:58:45 -0700588 virtual ~ARMCodeGenerator() {}
589
590 /* returns address to patch with local variable size
591 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700592 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700593 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700594 // sp -> arg4 arg5 ...
595 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700596 int regArgCount = calcRegArgCount(pDecl);
597 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700598 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700599 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700600 }
601 // sp -> arg0 arg1 ...
602 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700603 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700604 // sp, fp -> oldfp, retadr, arg0 arg1 ....
605 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700606 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700607 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700608 // We don't know how many local variables we are going to use,
609 // but we will round the allocation up to a multiple of
610 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700611 }
612
Jack Palevichb7718b92009-07-09 22:00:24 -0700613 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700614 // Round local variable size up to a multiple of stack alignment
615 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
616 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700617 // Patch local variable allocation code:
618 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700619 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700620 }
Jack Palevich69796b62009-05-14 15:42:26 -0700621 *(char*) (localVariableAddress) = localVariableSize;
622
623 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
624 o4(0xE1A0E00B); // mov lr, fp
625 o4(0xE59BB000); // ldr fp, [fp]
626 o4(0xE28ED004); // add sp, lr, #4
627 // sp -> retadr, arg0, ...
628 o4(0xE8BD4000); // ldmfd sp!, {lr}
629 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700630
631 // We store the PC into the lr so we can adjust the sp before
632 // returning. We need to pull off the registers we pushed
633 // earlier. We don't need to actually store them anywhere,
634 // just adjust the stack.
635 int regArgCount = calcRegArgCount(pDecl);
636 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700637 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
638 }
639 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700640 }
641
642 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700643 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700644 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700645 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700646 }
647
Jack Palevich1a539db2009-07-08 13:04:41 -0700648 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700649 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700650 // Global, absolute address
651 o4(0xE59F0000); // ldr r0, .L1
652 o4(0xEA000000); // b .L99
653 o4(address); // .L1: .word ea
654 // .L99:
655
656 switch (pType->tag) {
657 case TY_FLOAT:
658 o4(0xE5900000); // ldr r0, [r0]
659 break;
660 case TY_DOUBLE:
661 o4(0xE1C000D0); // ldrd r0, [r0]
662 break;
663 default:
664 assert(false);
665 break;
666 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700667 }
668
Jack Palevich22305132009-05-13 10:58:45 -0700669 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700670 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700671 }
672
673 /* l = 0: je, l == 1: jne */
674 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700675 Type* pR0Type = getR0Type();
676 TypeTag tagR0 = pR0Type->tag;
677 switch(tagR0) {
678 case TY_FLOAT:
679 callRuntime((void*) runtime_is_non_zero_f);
680 break;
681 case TY_DOUBLE:
682 callRuntime((void*) runtime_is_non_zero_d);
683 break;
684 default:
685 break;
686 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700687 o4(0xE3500000); // cmp r0,#0
688 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
689 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700690 }
691
Jack Palevich58c30ee2009-07-17 16:35:23 -0700692 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700693 Type* pR0Type = getR0Type();
694 Type* pTOSType = getTOSType();
695 TypeTag tagR0 = collapseType(pR0Type->tag);
696 TypeTag tagTOS = collapseType(pTOSType->tag);
697 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700698 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700699 o4(0xE1510000); // cmp r1, r1
700 switch(op) {
701 case OP_EQUALS:
702 o4(0x03A00001); // moveq r0,#1
703 o4(0x13A00000); // movne r0,#0
704 break;
705 case OP_NOT_EQUALS:
706 o4(0x03A00000); // moveq r0,#0
707 o4(0x13A00001); // movne r0,#1
708 break;
709 case OP_LESS_EQUAL:
710 o4(0xD3A00001); // movle r0,#1
711 o4(0xC3A00000); // movgt r0,#0
712 break;
713 case OP_GREATER:
714 o4(0xD3A00000); // movle r0,#0
715 o4(0xC3A00001); // movgt r0,#1
716 break;
717 case OP_GREATER_EQUAL:
718 o4(0xA3A00001); // movge r0,#1
719 o4(0xB3A00000); // movlt r0,#0
720 break;
721 case OP_LESS:
722 o4(0xA3A00000); // movge r0,#0
723 o4(0xB3A00001); // movlt r0,#1
724 break;
725 default:
726 error("Unknown comparison op %d", op);
727 break;
728 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700729 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
730 setupDoubleArgs();
731 switch(op) {
732 case OP_EQUALS:
733 callRuntime((void*) runtime_cmp_eq_dd);
734 break;
735 case OP_NOT_EQUALS:
736 callRuntime((void*) runtime_cmp_ne_dd);
737 break;
738 case OP_LESS_EQUAL:
739 callRuntime((void*) runtime_cmp_le_dd);
740 break;
741 case OP_GREATER:
742 callRuntime((void*) runtime_cmp_gt_dd);
743 break;
744 case OP_GREATER_EQUAL:
745 callRuntime((void*) runtime_cmp_ge_dd);
746 break;
747 case OP_LESS:
748 callRuntime((void*) runtime_cmp_lt_dd);
749 break;
750 default:
751 error("Unknown comparison op %d", op);
752 break;
753 }
754 } else {
755 setupFloatArgs();
756 switch(op) {
757 case OP_EQUALS:
758 callRuntime((void*) runtime_cmp_eq_ff);
759 break;
760 case OP_NOT_EQUALS:
761 callRuntime((void*) runtime_cmp_ne_ff);
762 break;
763 case OP_LESS_EQUAL:
764 callRuntime((void*) runtime_cmp_le_ff);
765 break;
766 case OP_GREATER:
767 callRuntime((void*) runtime_cmp_gt_ff);
768 break;
769 case OP_GREATER_EQUAL:
770 callRuntime((void*) runtime_cmp_ge_ff);
771 break;
772 case OP_LESS:
773 callRuntime((void*) runtime_cmp_lt_ff);
774 break;
775 default:
776 error("Unknown comparison op %d", op);
777 break;
778 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700779 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700780 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700781 }
782
Jack Palevich546b2242009-05-13 15:10:04 -0700783 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700784 Type* pR0Type = getR0Type();
785 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700786 TypeTag tagR0 = pR0Type->tag;
787 TypeTag tagTOS = pTOSType->tag;
788 bool isFloatR0 = isFloatTag(tagR0);
789 bool isFloatTOS = isFloatTag(tagTOS);
790 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700791 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700792 bool isPtrR0 = tagR0 == TY_POINTER;
793 bool isPtrTOS = tagTOS == TY_POINTER;
794 if (isPtrR0 || isPtrTOS) {
795 if (isPtrR0 && isPtrTOS) {
796 if (op != OP_MINUS) {
797 error("Unsupported pointer-pointer operation %d.", op);
798 }
799 if (! typeEqual(pR0Type, pTOSType)) {
800 error("Incompatible pointer types for subtraction.");
801 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700802 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700803 setR0Type(mkpInt);
804 int size = sizeOf(pR0Type->pHead);
805 if (size != 1) {
806 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700807 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700808 // TODO: Optimize for power-of-two.
809 genOp(OP_DIV);
810 }
811 } else {
812 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
813 error("Unsupported pointer-scalar operation %d", op);
814 }
815 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700816 int size = sizeOf(pPtrType->pHead);
817 if (size != 1) {
818 // TODO: Optimize for power-of-two.
819 liReg(size, 2);
820 if (isPtrR0) {
821 o4(0x0E0010192); // mul r1,r2,r1
822 } else {
823 o4(0x0E0000092); // mul r0,r2,r0
824 }
825 }
826 switch(op) {
827 case OP_PLUS:
828 o4(0xE0810000); // add r0,r1,r0
829 break;
830 case OP_MINUS:
831 o4(0xE0410000); // sub r0,r1,r0
832 break;
833 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700834 setR0Type(pPtrType);
835 }
836 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700837 switch(op) {
838 case OP_MUL:
839 o4(0x0E0000091); // mul r0,r1,r0
840 break;
841 case OP_DIV:
842 callRuntime((void*) runtime_DIV);
843 break;
844 case OP_MOD:
845 callRuntime((void*) runtime_MOD);
846 break;
847 case OP_PLUS:
848 o4(0xE0810000); // add r0,r1,r0
849 break;
850 case OP_MINUS:
851 o4(0xE0410000); // sub r0,r1,r0
852 break;
853 case OP_SHIFT_LEFT:
854 o4(0xE1A00011); // lsl r0,r1,r0
855 break;
856 case OP_SHIFT_RIGHT:
857 o4(0xE1A00051); // asr r0,r1,r0
858 break;
859 case OP_BIT_AND:
860 o4(0xE0010000); // and r0,r1,r0
861 break;
862 case OP_BIT_XOR:
863 o4(0xE0210000); // eor r0,r1,r0
864 break;
865 case OP_BIT_OR:
866 o4(0xE1810000); // orr r0,r1,r0
867 break;
868 case OP_BIT_NOT:
869 o4(0xE1E00000); // mvn r0, r0
870 break;
871 default:
872 error("Unimplemented op %d\n", op);
873 break;
874 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700875 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700876 } else {
877 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
878 if (pResultType->tag == TY_DOUBLE) {
879 setupDoubleArgs();
880 switch(op) {
881 case OP_MUL:
882 callRuntime((void*) runtime_op_mul_dd);
883 break;
884 case OP_DIV:
885 callRuntime((void*) runtime_op_div_dd);
886 break;
887 case OP_PLUS:
888 callRuntime((void*) runtime_op_add_dd);
889 break;
890 case OP_MINUS:
891 callRuntime((void*) runtime_op_sub_dd);
892 break;
893 default:
894 error("Unsupported binary floating operation %d\n", op);
895 break;
896 }
897 } else {
898 setupFloatArgs();
899 switch(op) {
900 case OP_MUL:
901 callRuntime((void*) runtime_op_mul_ff);
902 break;
903 case OP_DIV:
904 callRuntime((void*) runtime_op_div_ff);
905 break;
906 case OP_PLUS:
907 callRuntime((void*) runtime_op_add_ff);
908 break;
909 case OP_MINUS:
910 callRuntime((void*) runtime_op_sub_ff);
911 break;
912 default:
913 error("Unsupported binary floating operation %d\n", op);
914 break;
915 }
916 }
917 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700918 }
Jack Palevich22305132009-05-13 10:58:45 -0700919 }
920
Jack Palevich58c30ee2009-07-17 16:35:23 -0700921 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700922 if (op != OP_LOGICAL_NOT) {
923 error("Unknown unary cmp %d", op);
924 } else {
925 Type* pR0Type = getR0Type();
926 TypeTag tag = collapseType(pR0Type->tag);
927 switch(tag) {
928 case TY_INT:
929 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700930 o4(0xE1510000); // cmp r1, r0
931 o4(0x03A00001); // moveq r0,#1
932 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700933 break;
934 case TY_FLOAT:
935 callRuntime((void*) runtime_is_zero_f);
936 break;
937 case TY_DOUBLE:
938 callRuntime((void*) runtime_is_zero_d);
939 break;
940 default:
941 error("gUnaryCmp unsupported type");
942 break;
943 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700944 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700945 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700946 }
947
948 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700949 Type* pR0Type = getR0Type();
950 TypeTag tag = collapseType(pR0Type->tag);
951 switch(tag) {
952 case TY_INT:
953 switch(op) {
954 case OP_MINUS:
955 o4(0xE3A01000); // mov r1, #0
956 o4(0xE0410000); // sub r0,r1,r0
957 break;
958 case OP_BIT_NOT:
959 o4(0xE1E00000); // mvn r0, r0
960 break;
961 default:
962 error("Unknown unary op %d\n", op);
963 break;
964 }
965 break;
966 case TY_FLOAT:
967 case TY_DOUBLE:
968 switch (op) {
969 case OP_MINUS:
970 if (tag == TY_FLOAT) {
971 callRuntime((void*) runtime_op_neg_f);
972 } else {
973 callRuntime((void*) runtime_op_neg_d);
974 }
975 break;
976 case OP_BIT_NOT:
977 error("Can't apply '~' operator to a float or double.");
978 break;
979 default:
980 error("Unknown unary op %d\n", op);
981 break;
982 }
983 break;
984 default:
985 error("genUnaryOp unsupported type");
986 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700987 }
Jack Palevich22305132009-05-13 10:58:45 -0700988 }
989
Jack Palevich1cdef202009-05-22 12:06:27 -0700990 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -0700991 Type* pR0Type = getR0Type();
992 TypeTag r0ct = collapseType(pR0Type->tag);
993 if (r0ct != TY_DOUBLE) {
994 o4(0xE92D0001); // stmfd sp!,{r0}
995 mStackUse += 4;
996 } else {
997 o4(0xE92D0003); // stmfd sp!,{r0,r1}
998 mStackUse += 8;
999 }
Jack Palevich8df46192009-07-07 14:48:51 -07001000 pushType();
-b master422972c2009-06-17 19:13:52 -07001001 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001002 }
1003
Jack Palevich58c30ee2009-07-17 16:35:23 -07001004 virtual void popR0() {
1005 Type* pTOSType = getTOSType();
1006 switch (collapseType(pTOSType->tag)){
1007 case TY_INT:
1008 case TY_FLOAT:
1009 o4(0xE8BD0001); // ldmfd sp!,{r0}
1010 mStackUse -= 4;
1011 break;
1012 case TY_DOUBLE:
1013 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1014 mStackUse -= 8;
1015 break;
1016 default:
1017 error("Can't pop this type.");
1018 break;
1019 }
1020 popType();
1021 LOG_STACK("popR0: %d\n", mStackUse);
1022 }
1023
1024 virtual void storeR0ToTOS() {
1025 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001026 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001027 o4(0xE8BD0004); // ldmfd sp!,{r2}
1028 popType();
-b master422972c2009-06-17 19:13:52 -07001029 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001030 switch (pPointerType->pHead->tag) {
1031 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001032 case TY_FLOAT:
1033 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001034 break;
1035 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001036 o4(0xE5C20000); // strb r0, [r2]
1037 break;
1038 case TY_DOUBLE:
1039 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001040 break;
1041 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001042 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001043 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001044 }
Jack Palevich22305132009-05-13 10:58:45 -07001045 }
1046
Jack Palevich58c30ee2009-07-17 16:35:23 -07001047 virtual void loadR0FromR0() {
1048 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001049 assert(pPointerType->tag == TY_POINTER);
1050 switch (pPointerType->pHead->tag) {
1051 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001052 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001053 o4(0xE5900000); // ldr r0, [r0]
1054 break;
1055 case TY_CHAR:
1056 o4(0xE5D00000); // ldrb r0, [r0]
1057 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001058 case TY_DOUBLE:
1059 o4(0xE1C000D0); // ldrd r0, [r0]
1060 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001061 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001062 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001063 break;
1064 }
Jack Palevich8df46192009-07-07 14:48:51 -07001065 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001066 }
1067
Jack Palevich8df46192009-07-07 14:48:51 -07001068 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001069 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001070 // Local, fp relative
1071 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1072 error("Offset out of range: %08x", ea);
1073 }
1074 if (ea < 0) {
1075 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1076 } else {
1077 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1078 }
Jack Palevichbd894902009-05-14 19:35:31 -07001079 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001080 // Global, absolute.
1081 o4(0xE59F0000); // ldr r0, .L1
1082 o4(0xEA000000); // b .L99
1083 o4(ea); // .L1: .word 0
1084 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001085 }
Jack Palevich8df46192009-07-07 14:48:51 -07001086 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001087 }
1088
Jack Palevich9cbd2262009-07-08 16:48:41 -07001089 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001090 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001091 TypeTag tag = pType->tag;
1092 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001093 case TY_CHAR:
1094 if (ea > -LOCAL && ea < LOCAL) {
1095 // Local, fp relative
1096 if (ea < -4095 || ea > 4095) {
1097 error("Offset out of range: %08x", ea);
1098 }
1099 if (ea < 0) {
1100 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1101 } else {
1102 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1103 }
1104 } else{
1105 // Global, absolute
1106 o4(0xE59F1000); // ldr r1, .L1
1107 o4(0xEA000000); // b .L99
1108 o4(ea); // .L1: .word 0
1109 o4(0xE5C10000); // .L99: strb r0, [r1]
1110 }
1111 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001112 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001113 case TY_INT:
1114 case TY_FLOAT:
1115 if (ea > -LOCAL && ea < LOCAL) {
1116 // Local, fp relative
1117 if (ea < -4095 || ea > 4095) {
1118 error("Offset out of range: %08x", ea);
1119 }
1120 if (ea < 0) {
1121 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1122 } else {
1123 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1124 }
1125 } else{
1126 // Global, absolute
1127 o4(0xE59F1000); // ldr r1, .L1
1128 o4(0xEA000000); // b .L99
1129 o4(ea); // .L1: .word 0
1130 o4(0xE5810000); // .L99: str r0, [r1]
1131 }
1132 break;
1133 case TY_DOUBLE:
1134 if ((ea & 0x7) != 0) {
1135 error("double address is not aligned: %d", ea);
1136 }
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) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001143 o4(0xE50B0000 | (0xfff & (4-ea))); // str r0, [fp,#-ea]
1144 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001145#if 0
1146 // strd doesn't seem to work. Is encoding wrong?
1147 } else if (ea < 0) {
1148 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1149 } else if (ea < 256) {
1150 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1151#endif
1152 } else {
1153 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1154 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1155 }
1156 } else{
1157 // Global, absolute
1158 o4(0xE59F2000); // ldr r2, .L1
1159 o4(0xEA000000); // b .L99
1160 o4(ea); // .L1: .word 0
1161 o4(0xE1C200F0); // .L99: strd r0, [r2]
1162 }
1163 break;
1164 default:
1165 error("Unable to store to type %d", tag);
1166 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001167 }
Jack Palevich22305132009-05-13 10:58:45 -07001168 }
1169
Jack Palevich58c30ee2009-07-17 16:35:23 -07001170 virtual void loadR0(int ea, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001171 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001172 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001173 case TY_CHAR:
1174 if (ea < LOCAL) {
1175 // Local, fp relative
1176 if (ea < -4095 || ea > 4095) {
1177 error("Offset out of range: %08x", ea);
1178 }
1179 if (ea < 0) {
1180 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1181 } else {
1182 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1183 }
1184 } else {
1185 // Global, absolute
1186 o4(0xE59F2000); // ldr r2, .L1
1187 o4(0xEA000000); // b .L99
1188 o4(ea); // .L1: .word ea
1189 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1190 }
Jack Palevich25c0cca2009-07-13 16:56:28 -07001191 break;
1192 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001193 case TY_INT:
1194 case TY_FLOAT:
1195 if (ea < LOCAL) {
1196 // Local, fp relative
1197 if (ea < -4095 || ea > 4095) {
1198 error("Offset out of range: %08x", ea);
1199 }
1200 if (ea < 0) {
1201 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1202 } else {
1203 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1204 }
1205 } else {
1206 // Global, absolute
1207 o4(0xE59F2000); // ldr r2, .L1
1208 o4(0xEA000000); // b .L99
1209 o4(ea); // .L1: .word ea
1210 o4(0xE5920000); // .L99: ldr r0, [r2]
1211 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001212 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001213 case TY_DOUBLE:
1214 if ((ea & 0x7) != 0) {
1215 error("double address is not aligned: %d", ea);
1216 }
1217 if (ea < LOCAL) {
1218 // Local, fp relative
1219 if (ea < -4095 || ea > 4095) {
1220 error("Offset out of range: %08x", ea);
1221 }
1222 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001223 o4(0xE51B0000 | (0xfff & (4-ea))); // ldr r0, [fp,#-ea]
1224 o4(0xE51B1000 | (0xfff & (-ea))); // ldr r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001225 } else {
1226 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1227 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1228 }
1229 } else {
1230 // Global, absolute
1231 o4(0xE59F2000); // ldr r2, .L1
1232 o4(0xEA000000); // b .L99
1233 o4(ea); // .L1: .word ea
1234 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1235 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001236 break;
1237 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001238 error("Unable to load type %d", tag);
1239 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001240 }
Jack Palevich8df46192009-07-07 14:48:51 -07001241 setR0Type(pType);
1242 }
1243
1244 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001245 Type* pR0Type = getR0Type();
1246 if (bitsSame(pType, pR0Type)) {
1247 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001248 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001249 TypeTag r0Tag = collapseType(pR0Type->tag);
1250 TypeTag destTag = collapseType(pType->tag);
1251 if (r0Tag == TY_INT) {
1252 if (destTag == TY_FLOAT) {
1253 callRuntime((void*) runtime_int_to_float);
1254 } else {
1255 assert(destTag == TY_DOUBLE);
1256 callRuntime((void*) runtime_int_to_double);
1257 }
1258 } else if (r0Tag == TY_FLOAT) {
1259 if (destTag == TY_INT) {
1260 callRuntime((void*) runtime_float_to_int);
1261 } else {
1262 assert(destTag == TY_DOUBLE);
1263 callRuntime((void*) runtime_float_to_double);
1264 }
1265 } else {
1266 assert (r0Tag == TY_DOUBLE);
1267 if (destTag == TY_INT) {
1268 callRuntime((void*) runtime_double_to_int);
1269 } else {
1270 assert(destTag == TY_FLOAT);
1271 callRuntime((void*) runtime_double_to_float);
1272 }
1273 }
Jack Palevich8df46192009-07-07 14:48:51 -07001274 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001275 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001276 }
1277
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001278 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001279 return o4(0xE24DDF00); // Placeholder
1280 }
1281
Jack Palevich8148c5b2009-07-16 18:24:47 -07001282 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001283 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001284 Type* pR0Type = getR0Type();
1285 TypeTag r0ct = collapseType(pR0Type->tag);
1286 switch(r0ct) {
1287 case TY_INT:
1288 case TY_FLOAT:
1289 if (l < 0 || l > 4096-4) {
1290 error("l out of range for stack offset: 0x%08x", l);
1291 }
1292 o4(0xE58D0000 + l); // str r0, [sp, #l]
1293 return 4;
1294 case TY_DOUBLE: {
1295 // Align to 8 byte boundary
1296 int l2 = (l + 7) & ~7;
1297 if (l2 < 0 || l2 > 4096-8) {
1298 error("l out of range for stack offset: 0x%08x", l);
1299 }
1300 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1301 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1302 return (l2 - l) + 8;
1303 }
1304 default:
1305 assert(false);
1306 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001307 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001308 }
1309
Jack Palevichb7718b92009-07-09 22:00:24 -07001310 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001311 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001312 // Have to calculate register arg count from actual stack size,
1313 // in order to properly handle ... functions.
1314 int regArgCount = l >> 2;
1315 if (regArgCount > 4) {
1316 regArgCount = 4;
1317 }
1318 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001319 argumentStackUse -= regArgCount * 4;
1320 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1321 }
1322 mStackUse += argumentStackUse;
1323
1324 // Align stack.
1325 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1326 * STACK_ALIGNMENT);
1327 mStackAlignmentAdjustment = 0;
1328 if (missalignment > 0) {
1329 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1330 }
1331 l += mStackAlignmentAdjustment;
1332
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001333 if (l < 0 || l > 0x3FC) {
1334 error("L out of range for stack adjustment: 0x%08x", l);
1335 }
1336 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001337 mStackUse += mStackAlignmentAdjustment;
1338 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1339 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001340 }
1341
Jack Palevich8df46192009-07-07 14:48:51 -07001342 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001343 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001344 // Forward calls are always short (local)
1345 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001346 }
1347
Jack Palevich8df46192009-07-07 14:48:51 -07001348 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001349 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001350 int abs = t + getPC() + jumpOffset();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001351 if (t >= - (1 << 25) && t < (1 << 25)) {
1352 o4(0xEB000000 | encodeAddress(t));
1353 } else {
1354 // Long call.
1355 o4(0xE59FC000); // ldr r12, .L1
1356 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001357 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001358 o4(0xE08CC00F); // .L99: add r12,pc
1359 o4(0xE12FFF3C); // blx r12
1360 }
Jack Palevich22305132009-05-13 10:58:45 -07001361 }
1362
Jack Palevich8df46192009-07-07 14:48:51 -07001363 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001364 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001365 int argCount = l >> 2;
1366 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001367 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001368 if (adjustedL < 0 || adjustedL > 4096-4) {
1369 error("l out of range for stack offset: 0x%08x", l);
1370 }
1371 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1372 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001373 }
1374
Jack Palevichb7718b92009-07-09 22:00:24 -07001375 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001376 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001377 // Have to calculate register arg count from actual stack size,
1378 // in order to properly handle ... functions.
1379 int regArgCount = l >> 2;
1380 if (regArgCount > 4) {
1381 regArgCount = 4;
1382 }
1383 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001384 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1385 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001386 if (stackUse) {
1387 if (stackUse < 0 || stackUse > 255) {
1388 error("L out of range for stack adjustment: 0x%08x", l);
1389 }
1390 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001391 mStackUse -= stackUse * 4;
1392 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001393 }
Jack Palevich22305132009-05-13 10:58:45 -07001394 }
1395
Jack Palevicha6535612009-05-13 16:24:17 -07001396 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001397 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001398 }
1399
1400 /* output a symbol and patch all calls to it */
1401 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001402 int n;
1403 int base = getBase();
1404 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001405 while (t) {
1406 int data = * (int*) t;
1407 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1408 if (decodedOffset == 0) {
1409 n = 0;
1410 } else {
1411 n = base + decodedOffset; /* next value */
1412 }
1413 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1414 | encodeRelAddress(pc - t - 8);
1415 t = n;
1416 }
1417 }
1418
Jack Palevich1cdef202009-05-22 12:06:27 -07001419 virtual int finishCompile() {
1420#if defined(__arm__)
1421 const long base = long(getBase());
1422 const long curr = long(getPC());
1423 int err = cacheflush(base, curr, 0);
1424 return err;
1425#else
1426 return 0;
1427#endif
1428 }
1429
Jack Palevicha6535612009-05-13 16:24:17 -07001430 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001431#ifdef ENABLE_ARM_DISASSEMBLY
1432 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001433 disasm_interface_t di;
1434 di.di_readword = disassemble_readword;
1435 di.di_printaddr = disassemble_printaddr;
1436 di.di_printf = disassemble_printf;
1437
1438 int base = getBase();
1439 int pc = getPC();
1440 for(int i = base; i < pc; i += 4) {
1441 fprintf(out, "%08x: %08x ", i, *(int*) i);
1442 ::disasm(&di, i, 0);
1443 }
Jack Palevich09555c72009-05-27 12:25:55 -07001444#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001445 return 0;
1446 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001447
Jack Palevich9eed7a22009-07-06 17:24:34 -07001448 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001449 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001450 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001451 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001452 switch(pType->tag) {
1453 case TY_DOUBLE:
1454 return 8;
1455 default:
1456 return 4;
1457 }
1458 }
1459
1460 /**
1461 * Array element alignment (in bytes) for this type of data.
1462 */
1463 virtual size_t sizeOf(Type* pType){
1464 switch(pType->tag) {
1465 case TY_INT:
1466 return 4;
1467 case TY_CHAR:
1468 return 1;
1469 default:
1470 return 0;
1471 case TY_FLOAT:
1472 return 4;
1473 case TY_DOUBLE:
1474 return 8;
1475 case TY_POINTER:
1476 return 4;
1477 }
1478 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001479
1480 virtual size_t stackSizeOf(Type* pType) {
1481 switch(pType->tag) {
1482 case TY_DOUBLE:
1483 return 8;
1484 default:
1485 return 4;
1486 }
1487 }
1488
Jack Palevich22305132009-05-13 10:58:45 -07001489 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001490 static FILE* disasmOut;
1491
1492 static u_int
1493 disassemble_readword(u_int address)
1494 {
1495 return(*((u_int *)address));
1496 }
1497
1498 static void
1499 disassemble_printaddr(u_int address)
1500 {
1501 fprintf(disasmOut, "0x%08x", address);
1502 }
1503
1504 static void
1505 disassemble_printf(const char *fmt, ...) {
1506 va_list ap;
1507 va_start(ap, fmt);
1508 vfprintf(disasmOut, fmt, ap);
1509 va_end(ap);
1510 }
1511
1512 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1513
1514 /** Encode a relative address that might also be
1515 * a label.
1516 */
1517 int encodeAddress(int value) {
1518 int base = getBase();
1519 if (value >= base && value <= getPC() ) {
1520 // This is a label, encode it relative to the base.
1521 value = value - base;
1522 }
1523 return encodeRelAddress(value);
1524 }
1525
1526 int encodeRelAddress(int value) {
1527 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1528 }
Jack Palevich22305132009-05-13 10:58:45 -07001529
Jack Palevichb7718b92009-07-09 22:00:24 -07001530 int calcRegArgCount(Type* pDecl) {
1531 int reg = 0;
1532 Type* pArgs = pDecl->pTail;
1533 while (pArgs && reg < 4) {
1534 Type* pArg = pArgs->pHead;
1535 if ( pArg->tag == TY_DOUBLE) {
1536 int evenReg = (reg + 1) & ~1;
1537 if (evenReg >= 4) {
1538 break;
1539 }
1540 reg = evenReg + 2;
1541 } else {
1542 reg++;
1543 }
1544 pArgs = pArgs->pTail;
1545 }
1546 return reg;
1547 }
1548
Jack Palevich58c30ee2009-07-17 16:35:23 -07001549 void setupIntPtrArgs() {
1550 o4(0xE8BD0002); // ldmfd sp!,{r1}
1551 mStackUse -= 4;
1552 popType();
1553 }
1554
Jack Palevichb7718b92009-07-09 22:00:24 -07001555 /* Pop TOS to R1
1556 * Make sure both R0 and TOS are floats. (Could be ints)
1557 * We know that at least one of R0 and TOS is already a float
1558 */
1559 void setupFloatArgs() {
1560 Type* pR0Type = getR0Type();
1561 Type* pTOSType = getTOSType();
1562 TypeTag tagR0 = collapseType(pR0Type->tag);
1563 TypeTag tagTOS = collapseType(pTOSType->tag);
1564 if (tagR0 != TY_FLOAT) {
1565 assert(tagR0 == TY_INT);
1566 callRuntime((void*) runtime_int_to_float);
1567 }
1568 if (tagTOS != TY_FLOAT) {
1569 assert(tagTOS == TY_INT);
1570 assert(tagR0 == TY_FLOAT);
1571 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1572 o4(0xE59D0004); // ldr r0, [sp, #4]
1573 callRuntime((void*) runtime_int_to_float);
1574 o4(0xE1A01000); // mov r1, r0
1575 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1576 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1577 } else {
1578 // Pop TOS
1579 o4(0xE8BD0002); // ldmfd sp!,{r1}
1580 }
1581 mStackUse -= 4;
1582 popType();
1583 }
1584
1585 /* Pop TOS into R2..R3
1586 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1587 * We know that at least one of R0 and TOS are already a double.
1588 */
1589
1590 void setupDoubleArgs() {
1591 Type* pR0Type = getR0Type();
1592 Type* pTOSType = getTOSType();
1593 TypeTag tagR0 = collapseType(pR0Type->tag);
1594 TypeTag tagTOS = collapseType(pTOSType->tag);
1595 if (tagR0 != TY_DOUBLE) {
1596 if (tagR0 == TY_INT) {
1597 callRuntime((void*) runtime_int_to_double);
1598 } else {
1599 assert(tagR0 == TY_FLOAT);
1600 callRuntime((void*) runtime_float_to_double);
1601 }
1602 }
1603 if (tagTOS != TY_DOUBLE) {
1604 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1605 o4(0xE59D0008); // ldr r0, [sp, #8]
1606 if (tagTOS == TY_INT) {
1607 callRuntime((void*) runtime_int_to_double);
1608 } else {
1609 assert(tagTOS == TY_FLOAT);
1610 callRuntime((void*) runtime_float_to_double);
1611 }
1612 o4(0xE1A02000); // mov r2, r0
1613 o4(0xE1A03001); // mov r3, r1
1614 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1615 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1616 mStackUse -= 4;
1617 } else {
1618 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1619 mStackUse -= 8;
1620 }
1621 popType();
1622 }
1623
Jack Palevicha8f427f2009-07-13 18:40:08 -07001624 void liReg(int t, int reg) {
1625 assert(reg >= 0 && reg < 16);
1626 int rN = (reg & 0xf) << 12;
1627 if (t >= 0 && t < 255) {
1628 o4((0xE3A00000 + t) | rN); // mov rN, #0
1629 } else if (t >= -256 && t < 0) {
1630 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001631 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001632 } else {
1633 o4(0xE51F0000 | rN); // ldr rN, .L3
1634 o4(0xEA000000); // b .L99
1635 o4(t); // .L3: .word 0
1636 // .L99:
1637 }
1638 }
1639
Jack Palevichb7718b92009-07-09 22:00:24 -07001640 void callRuntime(void* fn) {
1641 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001642 o4(0xEA000000); // b .L99
1643 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001644 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001645 }
1646
Jack Palevichb7718b92009-07-09 22:00:24 -07001647 // Integer math:
1648
1649 static int runtime_DIV(int b, int a) {
1650 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001651 }
1652
Jack Palevichb7718b92009-07-09 22:00:24 -07001653 static int runtime_MOD(int b, int a) {
1654 return a % b;
1655 }
1656
1657 // Comparison to zero
1658
1659 static int runtime_is_non_zero_f(float a) {
1660 return a != 0;
1661 }
1662
1663 static int runtime_is_non_zero_d(double a) {
1664 return a != 0;
1665 }
1666
1667 // Comparison to zero
1668
1669 static int runtime_is_zero_f(float a) {
1670 return a == 0;
1671 }
1672
1673 static int runtime_is_zero_d(double a) {
1674 return a == 0;
1675 }
1676
1677 // Type conversion
1678
1679 static int runtime_float_to_int(float a) {
1680 return (int) a;
1681 }
1682
1683 static double runtime_float_to_double(float a) {
1684 return (double) a;
1685 }
1686
1687 static int runtime_double_to_int(double a) {
1688 return (int) a;
1689 }
1690
1691 static float runtime_double_to_float(double a) {
1692 return (float) a;
1693 }
1694
1695 static float runtime_int_to_float(int a) {
1696 return (float) a;
1697 }
1698
1699 static double runtime_int_to_double(int a) {
1700 return (double) a;
1701 }
1702
1703 // Comparisons float
1704
1705 static int runtime_cmp_eq_ff(float b, float a) {
1706 return a == b;
1707 }
1708
1709 static int runtime_cmp_ne_ff(float b, float a) {
1710 return a != b;
1711 }
1712
1713 static int runtime_cmp_lt_ff(float b, float a) {
1714 return a < b;
1715 }
1716
1717 static int runtime_cmp_le_ff(float b, float a) {
1718 return a <= b;
1719 }
1720
1721 static int runtime_cmp_ge_ff(float b, float a) {
1722 return a >= b;
1723 }
1724
1725 static int runtime_cmp_gt_ff(float b, float a) {
1726 return a > b;
1727 }
1728
1729 // Comparisons double
1730
1731 static int runtime_cmp_eq_dd(double b, double a) {
1732 return a == b;
1733 }
1734
1735 static int runtime_cmp_ne_dd(double b, double a) {
1736 return a != b;
1737 }
1738
1739 static int runtime_cmp_lt_dd(double b, double a) {
1740 return a < b;
1741 }
1742
1743 static int runtime_cmp_le_dd(double b, double a) {
1744 return a <= b;
1745 }
1746
1747 static int runtime_cmp_ge_dd(double b, double a) {
1748 return a >= b;
1749 }
1750
1751 static int runtime_cmp_gt_dd(double b, double a) {
1752 return a > b;
1753 }
1754
1755 // Math float
1756
1757 static float runtime_op_add_ff(float b, float a) {
1758 return a + b;
1759 }
1760
1761 static float runtime_op_sub_ff(float b, float a) {
1762 return a - b;
1763 }
1764
1765 static float runtime_op_mul_ff(float b, float a) {
1766 return a * b;
1767 }
1768
1769 static float runtime_op_div_ff(float b, float a) {
1770 return a / b;
1771 }
1772
1773 static float runtime_op_neg_f(float a) {
1774 return -a;
1775 }
1776
1777 // Math double
1778
1779 static double runtime_op_add_dd(double b, double a) {
1780 return a + b;
1781 }
1782
1783 static double runtime_op_sub_dd(double b, double a) {
1784 return a - b;
1785 }
1786
1787 static double runtime_op_mul_dd(double b, double a) {
1788 return a * b;
1789 }
1790
1791 static double runtime_op_div_dd(double b, double a) {
1792 return a / b;
1793 }
1794
1795 static double runtime_op_neg_d(double a) {
1796 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001797 }
-b master422972c2009-06-17 19:13:52 -07001798
1799 static const int STACK_ALIGNMENT = 8;
1800 int mStackUse;
1801 // This variable holds the amount we adjusted the stack in the most
1802 // recent endFunctionCallArguments call. It's examined by the
1803 // following adjustStackAfterCall call.
1804 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001805 };
1806
Jack Palevich09555c72009-05-27 12:25:55 -07001807#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001808
1809#ifdef PROVIDE_X86_CODEGEN
1810
Jack Palevich21a15a22009-05-11 14:49:29 -07001811 class X86CodeGenerator : public CodeGenerator {
1812 public:
1813 X86CodeGenerator() {}
1814 virtual ~X86CodeGenerator() {}
1815
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001816 /* returns address to patch with local variable size
1817 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001818 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001819 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1820 return oad(0xec81, 0); /* sub $xxx, %esp */
1821 }
1822
Jack Palevichb7718b92009-07-09 22:00:24 -07001823 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001824 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001825 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001826 }
1827
Jack Palevich21a15a22009-05-11 14:49:29 -07001828 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001829 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001830 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001831 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001832 }
1833
Jack Palevich1a539db2009-07-08 13:04:41 -07001834 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001835 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001836 switch (pType->tag) {
1837 case TY_FLOAT:
1838 oad(0x05D9, address); // flds
1839 break;
1840 case TY_DOUBLE:
1841 oad(0x05DD, address); // fldl
1842 break;
1843 default:
1844 assert(false);
1845 break;
1846 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001847 }
1848
Jack Palevich22305132009-05-13 10:58:45 -07001849 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001850 return psym(0xe9, t);
1851 }
1852
1853 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001854 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001855 Type* pR0Type = getR0Type();
1856 TypeTag tagR0 = pR0Type->tag;
1857 bool isFloatR0 = isFloatTag(tagR0);
1858 if (isFloatR0) {
1859 o(0xeed9); // fldz
1860 o(0xe9da); // fucompp
1861 o(0xe0df); // fnstsw %ax
1862 o(0x9e); // sahf
1863 } else {
1864 o(0xc085); // test %eax, %eax
1865 }
1866 // Use two output statements to generate one instruction.
1867 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001868 return psym(0x84 + l, t);
1869 }
1870
Jack Palevich58c30ee2009-07-17 16:35:23 -07001871 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001872 Type* pR0Type = getR0Type();
1873 Type* pTOSType = getTOSType();
1874 TypeTag tagR0 = pR0Type->tag;
1875 TypeTag tagTOS = pTOSType->tag;
1876 bool isFloatR0 = isFloatTag(tagR0);
1877 bool isFloatTOS = isFloatTag(tagTOS);
1878 if (!isFloatR0 && !isFloatTOS) {
1879 int t = decodeOp(op);
1880 o(0x59); /* pop %ecx */
1881 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001882 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001883 o(0x0f); /* setxx %al */
1884 o(t + 0x90);
1885 o(0xc0);
1886 popType();
1887 } else {
1888 setupFloatOperands();
1889 switch (op) {
1890 case OP_EQUALS:
1891 o(0xe9da); // fucompp
1892 o(0xe0df); // fnstsw %ax
1893 o(0x9e); // sahf
1894 o(0xc0940f); // sete %al
1895 o(0xc29b0f); // setnp %dl
1896 o(0xd021); // andl %edx, %eax
1897 break;
1898 case OP_NOT_EQUALS:
1899 o(0xe9da); // fucompp
1900 o(0xe0df); // fnstsw %ax
1901 o(0x9e); // sahf
1902 o(0xc0950f); // setne %al
1903 o(0xc29a0f); // setp %dl
1904 o(0xd009); // orl %edx, %eax
1905 break;
1906 case OP_GREATER_EQUAL:
1907 o(0xe9da); // fucompp
1908 o(0xe0df); // fnstsw %ax
1909 o(0x05c4f6); // testb $5, %ah
1910 o(0xc0940f); // sete %al
1911 break;
1912 case OP_LESS:
1913 o(0xc9d9); // fxch %st(1)
1914 o(0xe9da); // fucompp
1915 o(0xe0df); // fnstsw %ax
1916 o(0x9e); // sahf
1917 o(0xc0970f); // seta %al
1918 break;
1919 case OP_LESS_EQUAL:
1920 o(0xc9d9); // fxch %st(1)
1921 o(0xe9da); // fucompp
1922 o(0xe0df); // fnstsw %ax
1923 o(0x9e); // sahf
1924 o(0xc0930f); // setea %al
1925 break;
1926 case OP_GREATER:
1927 o(0xe9da); // fucompp
1928 o(0xe0df); // fnstsw %ax
1929 o(0x45c4f6); // testb $69, %ah
1930 o(0xc0940f); // sete %al
1931 break;
1932 default:
1933 error("Unknown comparison op");
1934 }
1935 o(0xc0b60f); // movzbl %al, %eax
1936 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001937 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001938 }
1939
Jack Palevich546b2242009-05-13 15:10:04 -07001940 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001941 Type* pR0Type = getR0Type();
1942 Type* pTOSType = getTOSType();
1943 TypeTag tagR0 = pR0Type->tag;
1944 TypeTag tagTOS = pTOSType->tag;
1945 bool isFloatR0 = isFloatTag(tagR0);
1946 bool isFloatTOS = isFloatTag(tagTOS);
1947 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001948 bool isPtrR0 = tagR0 == TY_POINTER;
1949 bool isPtrTOS = tagTOS == TY_POINTER;
1950 if (isPtrR0 || isPtrTOS) {
1951 if (isPtrR0 && isPtrTOS) {
1952 if (op != OP_MINUS) {
1953 error("Unsupported pointer-pointer operation %d.", op);
1954 }
1955 if (! typeEqual(pR0Type, pTOSType)) {
1956 error("Incompatible pointer types for subtraction.");
1957 }
1958 o(0x59); /* pop %ecx */
1959 o(decodeOp(op));
1960 popType();
1961 setR0Type(mkpInt);
1962 int size = sizeOf(pR0Type->pHead);
1963 if (size != 1) {
1964 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001965 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001966 // TODO: Optimize for power-of-two.
1967 genOp(OP_DIV);
1968 }
1969 } else {
1970 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1971 error("Unsupported pointer-scalar operation %d", op);
1972 }
1973 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1974 o(0x59); /* pop %ecx */
1975 int size = sizeOf(pPtrType->pHead);
1976 if (size != 1) {
1977 // TODO: Optimize for power-of-two.
1978 if (isPtrR0) {
1979 oad(0xC969, size); // imull $size, %ecx
1980 } else {
1981 oad(0xC069, size); // mul $size, %eax
1982 }
1983 }
1984 o(decodeOp(op));
1985 popType();
1986 setR0Type(pPtrType);
1987 }
1988 } else {
1989 o(0x59); /* pop %ecx */
1990 o(decodeOp(op));
1991 if (op == OP_MOD)
1992 o(0x92); /* xchg %edx, %eax */
1993 popType();
1994 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001995 } else {
1996 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1997 setupFloatOperands();
1998 // Both float. x87 R0 == left hand, x87 R1 == right hand
1999 switch (op) {
2000 case OP_MUL:
2001 o(0xc9de); // fmulp
2002 break;
2003 case OP_DIV:
2004 o(0xf1de); // fdivp
2005 break;
2006 case OP_PLUS:
2007 o(0xc1de); // faddp
2008 break;
2009 case OP_MINUS:
2010 o(0xe1de); // fsubp
2011 break;
2012 default:
2013 error("Unsupported binary floating operation.");
2014 break;
2015 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002016 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002017 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002018 }
2019
Jack Palevich58c30ee2009-07-17 16:35:23 -07002020 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002021 if (op != OP_LOGICAL_NOT) {
2022 error("Unknown unary cmp %d", op);
2023 } else {
2024 Type* pR0Type = getR0Type();
2025 TypeTag tag = collapseType(pR0Type->tag);
2026 switch(tag) {
2027 case TY_INT: {
2028 oad(0xb9, 0); /* movl $0, %ecx */
2029 int t = decodeOp(op);
2030 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002031 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002032 o(0x0f); /* setxx %al */
2033 o(t + 0x90);
2034 o(0xc0);
2035 }
2036 break;
2037 case TY_FLOAT:
2038 case TY_DOUBLE:
2039 o(0xeed9); // fldz
2040 o(0xe9da); // fucompp
2041 o(0xe0df); // fnstsw %ax
2042 o(0x9e); // sahf
2043 o(0xc0950f); // setne %al
2044 o(0xc29a0f); // setp %dl
2045 o(0xd009); // orl %edx, %eax
2046 o(0xc0b60f); // movzbl %al, %eax
2047 o(0x01f083); // xorl $1, %eax
2048 break;
2049 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002050 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002051 break;
2052 }
2053 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002054 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002055 }
2056
2057 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002058 Type* pR0Type = getR0Type();
2059 TypeTag tag = collapseType(pR0Type->tag);
2060 switch(tag) {
2061 case TY_INT:
2062 oad(0xb9, 0); /* movl $0, %ecx */
2063 o(decodeOp(op));
2064 break;
2065 case TY_FLOAT:
2066 case TY_DOUBLE:
2067 switch (op) {
2068 case OP_MINUS:
2069 o(0xe0d9); // fchs
2070 break;
2071 case OP_BIT_NOT:
2072 error("Can't apply '~' operator to a float or double.");
2073 break;
2074 default:
2075 error("Unknown unary op %d\n", op);
2076 break;
2077 }
2078 break;
2079 default:
2080 error("genUnaryOp unsupported type");
2081 break;
2082 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002083 }
2084
Jack Palevich1cdef202009-05-22 12:06:27 -07002085 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002086 Type* pR0Type = getR0Type();
2087 TypeTag r0ct = collapseType(pR0Type->tag);
2088 switch(r0ct) {
2089 case TY_INT:
2090 o(0x50); /* push %eax */
2091 break;
2092 case TY_FLOAT:
2093 o(0x50); /* push %eax */
2094 o(0x241cd9); // fstps 0(%esp)
2095 break;
2096 case TY_DOUBLE:
2097 o(0x50); /* push %eax */
2098 o(0x50); /* push %eax */
2099 o(0x241cdd); // fstpl 0(%esp)
2100 break;
2101 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002102 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002103 break;
2104 }
Jack Palevich8df46192009-07-07 14:48:51 -07002105 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002106 }
2107
Jack Palevich58c30ee2009-07-17 16:35:23 -07002108 virtual void popR0() {
2109 Type* pR0Type = getR0Type();
2110 TypeTag r0ct = collapseType(pR0Type->tag);
2111 switch(r0ct) {
2112 case TY_INT:
2113 o(0x58); /* popl %eax */
2114 break;
2115 case TY_FLOAT:
2116 o(0x2404d9); // flds (%esp)
2117 o(0x58); /* popl %eax */
2118 break;
2119 case TY_DOUBLE:
2120 o(0x2404dd); // fldl (%esp)
2121 o(0x58); /* popl %eax */
2122 o(0x58); /* popl %eax */
2123 break;
2124 default:
2125 error("pushR0 unsupported type %d", r0ct);
2126 break;
2127 }
2128 popType();
2129 }
2130
2131 virtual void storeR0ToTOS() {
2132 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002133 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002134 Type* pTargetType = pPointerType->pHead;
2135 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002136 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002137 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002138 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002139 case TY_INT:
2140 o(0x0189); /* movl %eax/%al, (%ecx) */
2141 break;
2142 case TY_CHAR:
2143 o(0x0188); /* movl %eax/%al, (%ecx) */
2144 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002145 case TY_FLOAT:
2146 o(0x19d9); /* fstps (%ecx) */
2147 break;
2148 case TY_DOUBLE:
2149 o(0x19dd); /* fstpl (%ecx) */
2150 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002151 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002152 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002153 break;
2154 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002155 }
2156
Jack Palevich58c30ee2009-07-17 16:35:23 -07002157 virtual void loadR0FromR0() {
2158 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002159 assert(pPointerType->tag == TY_POINTER);
2160 switch (pPointerType->pHead->tag) {
2161 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002162 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002163 break;
2164 case TY_CHAR:
2165 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002166 ob(0); /* add zero in code */
2167 break;
2168 case TY_FLOAT:
2169 o2(0x00d9); // flds (%eax)
2170 break;
2171 case TY_DOUBLE:
2172 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002173 break;
2174 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002175 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002176 break;
2177 }
Jack Palevich8df46192009-07-07 14:48:51 -07002178 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002179 }
2180
Jack Palevich8df46192009-07-07 14:48:51 -07002181 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002182 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002183 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002184 }
2185
Jack Palevich9cbd2262009-07-08 16:48:41 -07002186 virtual void storeR0(int ea, Type* pType) {
2187 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002188 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002189 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002190 case TY_CHAR:
2191 if (ea < -LOCAL || ea > LOCAL) {
2192 oad(0xa2, ea); // movb %al,ea
2193 } else {
2194 oad(0x8588, ea); // movb %al,ea(%ebp)
2195 }
2196 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002197 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002198 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002199 gmov(6, ea); /* mov %eax, EA */
2200 break;
2201 case TY_FLOAT:
2202 if (ea < -LOCAL || ea > LOCAL) {
2203 oad(0x1dd9, ea); // fstps ea
2204 } else {
2205 oad(0x9dd9, ea); // fstps ea(%ebp)
2206 }
2207 break;
2208 case TY_DOUBLE:
2209 if (ea < -LOCAL || ea > LOCAL) {
2210 oad(0x1ddd, ea); // fstpl ea
2211 } else {
2212 oad(0x9ddd, ea); // fstpl ea(%ebp)
2213 }
2214 break;
2215 default:
2216 error("Unable to store to type %d", tag);
2217 break;
2218 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002219 }
2220
Jack Palevich58c30ee2009-07-17 16:35:23 -07002221 virtual void loadR0(int ea, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002222 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002223 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002224 case TY_CHAR:
2225 if (ea < -LOCAL || ea > LOCAL) {
2226 oad(0x05BE0F, ea); // movsbl ea,%eax
2227 } else {
2228 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2229 }
Jack Palevich25c0cca2009-07-13 16:56:28 -07002230 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002231 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002232 case TY_POINTER:
Jack Palevich58c30ee2009-07-17 16:35:23 -07002233 gmov(8, ea); /* mov EA, %eax */
Jack Palevich128ad2d2009-07-08 14:51:31 -07002234 break;
2235 case TY_FLOAT:
2236 if (ea < -LOCAL || ea > LOCAL) {
2237 oad(0x05d9, ea); // flds ea
2238 } else {
2239 oad(0x85d9, ea); // flds ea(%ebp)
2240 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002241 break;
2242 case TY_DOUBLE:
2243 if (ea < -LOCAL || ea > LOCAL) {
2244 oad(0x05dd, ea); // fldl ea
2245 } else {
2246 oad(0x85dd, ea); // fldl ea(%ebp)
2247 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002248 break;
2249 default:
2250 error("Unable to load type %d", tag);
2251 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002252 }
Jack Palevich8df46192009-07-07 14:48:51 -07002253 setR0Type(pType);
2254 }
2255
2256 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002257 Type* pR0Type = getR0Type();
2258 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002259 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002260 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002261 return;
2262 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002263 if (bitsSame(pType, pR0Type)) {
2264 // do nothing special
2265 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2266 // do nothing special, both held in same register on x87.
2267 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002268 TypeTag r0Tag = collapseType(pR0Type->tag);
2269 TypeTag destTag = collapseType(pType->tag);
2270 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2271 // Convert R0 from int to float
2272 o(0x50); // push %eax
2273 o(0x2404DB); // fildl 0(%esp)
2274 o(0x58); // pop %eax
2275 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2276 // Convert R0 from float to int. Complicated because
2277 // need to save and restore the rounding mode.
2278 o(0x50); // push %eax
2279 o(0x50); // push %eax
2280 o(0x02247cD9); // fnstcw 2(%esp)
2281 o(0x2444b70f); // movzwl 2(%esp), %eax
2282 o(0x02);
2283 o(0x0cb4); // movb $12, %ah
2284 o(0x24048966); // movw %ax, 0(%esp)
2285 o(0x242cd9); // fldcw 0(%esp)
2286 o(0x04245cdb); // fistpl 4(%esp)
2287 o(0x02246cd9); // fldcw 2(%esp)
2288 o(0x58); // pop %eax
2289 o(0x58); // pop %eax
2290 } else {
2291 error("Incompatible types old: %d new: %d",
2292 pR0Type->tag, pType->tag);
2293 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002294 }
2295 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002296 }
2297
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002298 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002299 return oad(0xec81, 0); /* sub $xxx, %esp */
2300 }
2301
Jack Palevich8148c5b2009-07-16 18:24:47 -07002302 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2303 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002304 Type* pR0Type = getR0Type();
2305 TypeTag r0ct = collapseType(pR0Type->tag);
2306 switch(r0ct) {
2307 case TY_INT:
2308 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2309 return 4;
2310 case TY_FLOAT:
2311 oad(0x249CD9, l); /* fstps xxx(%esp) */
2312 return 4;
2313 case TY_DOUBLE:
2314 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2315 return 8;
2316 default:
2317 assert(false);
2318 return 0;
2319 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002320 }
2321
Jack Palevichb7718b92009-07-09 22:00:24 -07002322 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002323 * (int*) a = l;
2324 }
2325
Jack Palevich8df46192009-07-07 14:48:51 -07002326 virtual int callForward(int symbol, Type* pFunc) {
2327 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002328 return psym(0xe8, symbol); /* call xxx */
2329 }
2330
Jack Palevich8df46192009-07-07 14:48:51 -07002331 virtual void callRelative(int t, Type* pFunc) {
2332 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002333 psym(0xe8, t); /* call xxx */
2334 }
2335
Jack Palevich8df46192009-07-07 14:48:51 -07002336 virtual void callIndirect(int l, Type* pFunc) {
2337 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002338 oad(0x2494ff, l); /* call *xxx(%esp) */
2339 }
2340
Jack Palevichb7718b92009-07-09 22:00:24 -07002341 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002342 if (isIndirect) {
2343 l += 4;
2344 }
-b master422972c2009-06-17 19:13:52 -07002345 if (l > 0) {
2346 oad(0xc481, l); /* add $xxx, %esp */
2347 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002348 }
2349
Jack Palevicha6535612009-05-13 16:24:17 -07002350 virtual int jumpOffset() {
2351 return 5;
2352 }
2353
2354 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002355 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002356 }
2357
Jack Paleviche7b59062009-05-19 17:12:17 -07002358 /* output a symbol and patch all calls to it */
2359 virtual void gsym(int t) {
2360 int n;
2361 int pc = getPC();
2362 while (t) {
2363 n = *(int *) t; /* next value */
2364 *(int *) t = pc - t - 4;
2365 t = n;
2366 }
2367 }
2368
Jack Palevich1cdef202009-05-22 12:06:27 -07002369 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002370 size_t pagesize = 4096;
2371 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2372 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2373 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2374 if (err) {
2375 error("mprotect() failed: %d", errno);
2376 }
2377 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002378 }
2379
Jack Palevich9eed7a22009-07-06 17:24:34 -07002380 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002381 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002382 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002383 virtual size_t alignmentOf(Type* pType){
2384 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002385 }
2386
2387 /**
2388 * Array element alignment (in bytes) for this type of data.
2389 */
2390 virtual size_t sizeOf(Type* pType){
2391 switch(pType->tag) {
2392 case TY_INT:
2393 return 4;
2394 case TY_CHAR:
2395 return 1;
2396 default:
2397 return 0;
2398 case TY_FLOAT:
2399 return 4;
2400 case TY_DOUBLE:
2401 return 8;
2402 case TY_POINTER:
2403 return 4;
2404 }
2405 }
2406
Jack Palevich9cbd2262009-07-08 16:48:41 -07002407 virtual size_t stackSizeOf(Type* pType) {
2408 switch(pType->tag) {
2409 case TY_DOUBLE:
2410 return 8;
2411 default:
2412 return 4;
2413 }
2414 }
2415
Jack Palevich21a15a22009-05-11 14:49:29 -07002416 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002417
2418 /** Output 1 to 4 bytes.
2419 *
2420 */
2421 void o(int n) {
2422 /* cannot use unsigned, so we must do a hack */
2423 while (n && n != -1) {
2424 ob(n & 0xff);
2425 n = n >> 8;
2426 }
2427 }
2428
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002429 /* Output exactly 2 bytes
2430 */
2431 void o2(int n) {
2432 ob(n & 0xff);
2433 ob(0xff & (n >> 8));
2434 }
2435
Jack Paleviche7b59062009-05-19 17:12:17 -07002436 /* psym is used to put an instruction with a data field which is a
2437 reference to a symbol. It is in fact the same as oad ! */
2438 int psym(int n, int t) {
2439 return oad(n, t);
2440 }
2441
2442 /* instruction + address */
2443 int oad(int n, int t) {
2444 o(n);
2445 int result = getPC();
2446 o4(t);
2447 return result;
2448 }
2449
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002450 static const int operatorHelper[];
2451
2452 int decodeOp(int op) {
2453 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002454 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002455 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002456 }
2457 return operatorHelper[op];
2458 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002459
Jack Palevich546b2242009-05-13 15:10:04 -07002460 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002461 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002462 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002463 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002464
2465 void setupFloatOperands() {
2466 Type* pR0Type = getR0Type();
2467 Type* pTOSType = getTOSType();
2468 TypeTag tagR0 = pR0Type->tag;
2469 TypeTag tagTOS = pTOSType->tag;
2470 bool isFloatR0 = isFloatTag(tagR0);
2471 bool isFloatTOS = isFloatTag(tagTOS);
2472 if (! isFloatR0) {
2473 // Convert R0 from int to float
2474 o(0x50); // push %eax
2475 o(0x2404DB); // fildl 0(%esp)
2476 o(0x58); // pop %eax
2477 }
2478 if (! isFloatTOS){
2479 o(0x2404DB); // fildl 0(%esp);
2480 o(0x58); // pop %eax
2481 } else {
2482 if (tagTOS == TY_FLOAT) {
2483 o(0x2404d9); // flds (%esp)
2484 o(0x58); // pop %eax
2485 } else {
2486 o(0x2404dd); // fldl (%esp)
2487 o(0x58); // pop %eax
2488 o(0x58); // pop %eax
2489 }
2490 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002491 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002492 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002493 };
2494
Jack Paleviche7b59062009-05-19 17:12:17 -07002495#endif // PROVIDE_X86_CODEGEN
2496
Jack Palevichb67b18f2009-06-11 21:12:23 -07002497#ifdef PROVIDE_TRACE_CODEGEN
2498 class TraceCodeGenerator : public CodeGenerator {
2499 private:
2500 CodeGenerator* mpBase;
2501
2502 public:
2503 TraceCodeGenerator(CodeGenerator* pBase) {
2504 mpBase = pBase;
2505 }
2506
2507 virtual ~TraceCodeGenerator() {
2508 delete mpBase;
2509 }
2510
2511 virtual void init(CodeBuf* pCodeBuf) {
2512 mpBase->init(pCodeBuf);
2513 }
2514
2515 void setErrorSink(ErrorSink* pErrorSink) {
2516 mpBase->setErrorSink(pErrorSink);
2517 }
2518
2519 /* returns address to patch with local variable size
2520 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002521 virtual int functionEntry(Type* pDecl) {
2522 int result = mpBase->functionEntry(pDecl);
2523 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002524 return result;
2525 }
2526
Jack Palevichb7718b92009-07-09 22:00:24 -07002527 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2528 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2529 localVariableAddress, localVariableSize);
2530 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002531 }
2532
2533 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002534 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002535 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002536 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002537 }
2538
Jack Palevich1a539db2009-07-08 13:04:41 -07002539 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002540 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002541 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002542 }
2543
Jack Palevichb67b18f2009-06-11 21:12:23 -07002544 virtual int gjmp(int t) {
2545 int result = mpBase->gjmp(t);
2546 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2547 return result;
2548 }
2549
2550 /* l = 0: je, l == 1: jne */
2551 virtual int gtst(bool l, int t) {
2552 int result = mpBase->gtst(l, t);
2553 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2554 return result;
2555 }
2556
Jack Palevich58c30ee2009-07-17 16:35:23 -07002557 virtual void gcmp(int op) {
2558 fprintf(stderr, "gcmp(%d)\n", op);
2559 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002560 }
2561
2562 virtual void genOp(int op) {
2563 fprintf(stderr, "genOp(%d)\n", op);
2564 mpBase->genOp(op);
2565 }
2566
Jack Palevich9eed7a22009-07-06 17:24:34 -07002567
Jack Palevich58c30ee2009-07-17 16:35:23 -07002568 virtual void gUnaryCmp(int op) {
2569 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2570 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002571 }
2572
2573 virtual void genUnaryOp(int op) {
2574 fprintf(stderr, "genUnaryOp(%d)\n", op);
2575 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002576 }
2577
2578 virtual void pushR0() {
2579 fprintf(stderr, "pushR0()\n");
2580 mpBase->pushR0();
2581 }
2582
Jack Palevich58c30ee2009-07-17 16:35:23 -07002583 virtual void popR0() {
2584 fprintf(stderr, "popR0()\n");
2585 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002586 }
2587
Jack Palevich58c30ee2009-07-17 16:35:23 -07002588 virtual void storeR0ToTOS() {
2589 fprintf(stderr, "storeR0ToTOS()\n");
2590 mpBase->storeR0ToTOS();
2591 }
2592
2593 virtual void loadR0FromR0() {
2594 fprintf(stderr, "loadR0FromR0()\n");
2595 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002596 }
2597
Jack Palevich8df46192009-07-07 14:48:51 -07002598 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002599 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002600 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002601 }
2602
Jack Palevich9cbd2262009-07-08 16:48:41 -07002603 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002604 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002605 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002606 }
2607
Jack Palevich58c30ee2009-07-17 16:35:23 -07002608 virtual void loadR0(int ea, Type* pType) {
2609 fprintf(stderr, "loadR0(%d, pType)\n", ea);
2610 mpBase->loadR0(ea, pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002611 }
2612
2613 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002614 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002615 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002616 }
2617
2618 virtual int beginFunctionCallArguments() {
2619 int result = mpBase->beginFunctionCallArguments();
2620 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2621 return result;
2622 }
2623
Jack Palevich8148c5b2009-07-16 18:24:47 -07002624 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2625 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2626 pArgType->tag);
2627 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002628 }
2629
Jack Palevichb7718b92009-07-09 22:00:24 -07002630 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002631 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002632 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002633 }
2634
Jack Palevich8df46192009-07-07 14:48:51 -07002635 virtual int callForward(int symbol, Type* pFunc) {
2636 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002637 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2638 return result;
2639 }
2640
Jack Palevich8df46192009-07-07 14:48:51 -07002641 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002642 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002643 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002644 }
2645
Jack Palevich8df46192009-07-07 14:48:51 -07002646 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002647 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002648 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002649 }
2650
Jack Palevichb7718b92009-07-09 22:00:24 -07002651 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2652 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2653 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002654 }
2655
2656 virtual int jumpOffset() {
2657 return mpBase->jumpOffset();
2658 }
2659
2660 virtual int disassemble(FILE* out) {
2661 return mpBase->disassemble(out);
2662 }
2663
2664 /* output a symbol and patch all calls to it */
2665 virtual void gsym(int t) {
2666 fprintf(stderr, "gsym(%d)\n", t);
2667 mpBase->gsym(t);
2668 }
2669
2670 virtual int finishCompile() {
2671 int result = mpBase->finishCompile();
2672 fprintf(stderr, "finishCompile() = %d\n", result);
2673 return result;
2674 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002675
2676 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002677 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002678 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002679 virtual size_t alignmentOf(Type* pType){
2680 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002681 }
2682
2683 /**
2684 * Array element alignment (in bytes) for this type of data.
2685 */
2686 virtual size_t sizeOf(Type* pType){
2687 return mpBase->sizeOf(pType);
2688 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002689
Jack Palevich9cbd2262009-07-08 16:48:41 -07002690
2691 virtual size_t stackSizeOf(Type* pType) {
2692 return mpBase->stackSizeOf(pType);
2693 }
2694
2695
Jack Palevich1a539db2009-07-08 13:04:41 -07002696 virtual Type* getR0Type() {
2697 return mpBase->getR0Type();
2698 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002699 };
2700
2701#endif // PROVIDE_TRACE_CODEGEN
2702
Jack Palevich569f1352009-06-29 14:29:08 -07002703 class Arena {
2704 public:
2705 // Used to record a given allocation amount.
2706 // Used:
2707 // Mark mark = arena.mark();
2708 // ... lots of arena.allocate()
2709 // arena.free(mark);
2710
2711 struct Mark {
2712 size_t chunk;
2713 size_t offset;
2714 };
2715
2716 Arena() {
2717 mCurrentChunk = 0;
2718 Chunk start(CHUNK_SIZE);
2719 mData.push_back(start);
2720 }
2721
2722 ~Arena() {
2723 for(size_t i = 0; i < mData.size(); i++) {
2724 mData[i].free();
2725 }
2726 }
2727
2728 // Alloc using the standard alignment size safe for any variable
2729 void* alloc(size_t size) {
2730 return alloc(size, 8);
2731 }
2732
2733 Mark mark(){
2734 Mark result;
2735 result.chunk = mCurrentChunk;
2736 result.offset = mData[mCurrentChunk].mOffset;
2737 return result;
2738 }
2739
2740 void freeToMark(const Mark& mark) {
2741 mCurrentChunk = mark.chunk;
2742 mData[mCurrentChunk].mOffset = mark.offset;
2743 }
2744
2745 private:
2746 // Allocate memory aligned to a given size
2747 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2748 // Memory is not zero filled.
2749
2750 void* alloc(size_t size, size_t alignment) {
2751 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2752 if (mCurrentChunk + 1 < mData.size()) {
2753 mCurrentChunk++;
2754 } else {
2755 size_t allocSize = CHUNK_SIZE;
2756 if (allocSize < size + alignment - 1) {
2757 allocSize = size + alignment - 1;
2758 }
2759 Chunk chunk(allocSize);
2760 mData.push_back(chunk);
2761 mCurrentChunk++;
2762 }
2763 }
2764 return mData[mCurrentChunk].allocate(size, alignment);
2765 }
2766
2767 static const size_t CHUNK_SIZE = 128*1024;
2768 // Note: this class does not deallocate its
2769 // memory when it's destroyed. It depends upon
2770 // its parent to deallocate the memory.
2771 struct Chunk {
2772 Chunk() {
2773 mpData = 0;
2774 mSize = 0;
2775 mOffset = 0;
2776 }
2777
2778 Chunk(size_t size) {
2779 mSize = size;
2780 mpData = (char*) malloc(size);
2781 mOffset = 0;
2782 }
2783
2784 ~Chunk() {
2785 // Doesn't deallocate memory.
2786 }
2787
2788 void* allocate(size_t size, size_t alignment) {
2789 size_t alignedOffset = aligned(mOffset, alignment);
2790 void* result = mpData + alignedOffset;
2791 mOffset = alignedOffset + size;
2792 return result;
2793 }
2794
2795 void free() {
2796 if (mpData) {
2797 ::free(mpData);
2798 mpData = 0;
2799 }
2800 }
2801
2802 size_t remainingCapacity(size_t alignment) {
2803 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2804 }
2805
2806 // Assume alignment is a power of two
2807 inline size_t aligned(size_t v, size_t alignment) {
2808 size_t mask = alignment-1;
2809 return (v + mask) & ~mask;
2810 }
2811
2812 char* mpData;
2813 size_t mSize;
2814 size_t mOffset;
2815 };
2816
2817 size_t mCurrentChunk;
2818
2819 Vector<Chunk> mData;
2820 };
2821
Jack Palevich569f1352009-06-29 14:29:08 -07002822 struct VariableInfo;
2823
2824 struct Token {
2825 int hash;
2826 size_t length;
2827 char* pText;
2828 tokenid_t id;
2829
2830 // Current values for the token
2831 char* mpMacroDefinition;
2832 VariableInfo* mpVariableInfo;
2833 };
2834
2835 class TokenTable {
2836 public:
2837 // Don't use 0..0xff, allows characters and operators to be tokens too.
2838
2839 static const int TOKEN_BASE = 0x100;
2840 TokenTable() {
2841 mpMap = hashmapCreate(128, hashFn, equalsFn);
2842 }
2843
2844 ~TokenTable() {
2845 hashmapFree(mpMap);
2846 }
2847
2848 void setArena(Arena* pArena) {
2849 mpArena = pArena;
2850 }
2851
2852 // Returns a token for a given string of characters.
2853 tokenid_t intern(const char* pText, size_t length) {
2854 Token probe;
2855 int hash = hashmapHash((void*) pText, length);
2856 {
2857 Token probe;
2858 probe.hash = hash;
2859 probe.length = length;
2860 probe.pText = (char*) pText;
2861 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2862 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002863 return pValue->id;
2864 }
2865 }
2866
2867 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2868 memset(pToken, 0, sizeof(*pToken));
2869 pToken->hash = hash;
2870 pToken->length = length;
2871 pToken->pText = (char*) mpArena->alloc(length + 1);
2872 memcpy(pToken->pText, pText, length);
2873 pToken->pText[length] = 0;
2874 pToken->id = mTokens.size() + TOKEN_BASE;
2875 mTokens.push_back(pToken);
2876 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002877 return pToken->id;
2878 }
2879
2880 // Return the Token for a given tokenid.
2881 Token& operator[](tokenid_t id) {
2882 return *mTokens[id - TOKEN_BASE];
2883 }
2884
2885 inline size_t size() {
2886 return mTokens.size();
2887 }
2888
2889 private:
2890
2891 static int hashFn(void* pKey) {
2892 Token* pToken = (Token*) pKey;
2893 return pToken->hash;
2894 }
2895
2896 static bool equalsFn(void* keyA, void* keyB) {
2897 Token* pTokenA = (Token*) keyA;
2898 Token* pTokenB = (Token*) keyB;
2899 // Don't need to compare hash values, they should always be equal
2900 return pTokenA->length == pTokenB->length
2901 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2902 }
2903
2904 Hashmap* mpMap;
2905 Vector<Token*> mTokens;
2906 Arena* mpArena;
2907 };
2908
Jack Palevich1cdef202009-05-22 12:06:27 -07002909 class InputStream {
2910 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002911 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002912 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002913 };
2914
2915 class TextInputStream : public InputStream {
2916 public:
2917 TextInputStream(const char* text, size_t textLength)
2918 : pText(text), mTextLength(textLength), mPosition(0) {
2919 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002920
Jack Palevichdc456462009-07-16 16:50:56 -07002921 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002922 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2923 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002924
Jack Palevichdc456462009-07-16 16:50:56 -07002925 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002926 const char* pText;
2927 size_t mTextLength;
2928 size_t mPosition;
2929 };
2930
Jack Palevicheedf9d22009-06-04 16:23:40 -07002931 class String {
2932 public:
2933 String() {
2934 mpBase = 0;
2935 mUsed = 0;
2936 mSize = 0;
2937 }
2938
Jack Palevich303d8ff2009-06-11 19:06:24 -07002939 String(const char* item, int len, bool adopt) {
2940 if (len < 0) {
2941 len = strlen(item);
2942 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002943 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002944 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002945 mUsed = len;
2946 mSize = len + 1;
2947 } else {
2948 mpBase = 0;
2949 mUsed = 0;
2950 mSize = 0;
2951 appendBytes(item, len);
2952 }
2953 }
2954
Jack Palevich303d8ff2009-06-11 19:06:24 -07002955 String(const String& other) {
2956 mpBase = 0;
2957 mUsed = 0;
2958 mSize = 0;
2959 appendBytes(other.getUnwrapped(), other.len());
2960 }
2961
Jack Palevicheedf9d22009-06-04 16:23:40 -07002962 ~String() {
2963 if (mpBase) {
2964 free(mpBase);
2965 }
2966 }
2967
Jack Palevicha6baa232009-06-12 11:25:59 -07002968 String& operator=(const String& other) {
2969 clear();
2970 appendBytes(other.getUnwrapped(), other.len());
2971 return *this;
2972 }
2973
Jack Palevich303d8ff2009-06-11 19:06:24 -07002974 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002975 return mpBase;
2976 }
2977
Jack Palevich303d8ff2009-06-11 19:06:24 -07002978 void clear() {
2979 mUsed = 0;
2980 if (mSize > 0) {
2981 mpBase[0] = 0;
2982 }
2983 }
2984
Jack Palevicheedf9d22009-06-04 16:23:40 -07002985 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002986 appendBytes(s, strlen(s));
2987 }
2988
2989 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002990 memcpy(ensure(n), s, n + 1);
2991 }
2992
2993 void append(char c) {
2994 * ensure(1) = c;
2995 }
2996
Jack Palevich86351982009-06-30 18:09:56 -07002997 void append(String& other) {
2998 appendBytes(other.getUnwrapped(), other.len());
2999 }
3000
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003001 char* orphan() {
3002 char* result = mpBase;
3003 mpBase = 0;
3004 mUsed = 0;
3005 mSize = 0;
3006 return result;
3007 }
3008
Jack Palevicheedf9d22009-06-04 16:23:40 -07003009 void printf(const char* fmt,...) {
3010 va_list ap;
3011 va_start(ap, fmt);
3012 vprintf(fmt, ap);
3013 va_end(ap);
3014 }
3015
3016 void vprintf(const char* fmt, va_list ap) {
3017 char* temp;
3018 int numChars = vasprintf(&temp, fmt, ap);
3019 memcpy(ensure(numChars), temp, numChars+1);
3020 free(temp);
3021 }
3022
Jack Palevich303d8ff2009-06-11 19:06:24 -07003023 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003024 return mUsed;
3025 }
3026
3027 private:
3028 char* ensure(int n) {
3029 size_t newUsed = mUsed + n;
3030 if (newUsed > mSize) {
3031 size_t newSize = mSize * 2 + 10;
3032 if (newSize < newUsed) {
3033 newSize = newUsed;
3034 }
3035 mpBase = (char*) realloc(mpBase, newSize + 1);
3036 mSize = newSize;
3037 }
3038 mpBase[newUsed] = '\0';
3039 char* result = mpBase + mUsed;
3040 mUsed = newUsed;
3041 return result;
3042 }
3043
3044 char* mpBase;
3045 size_t mUsed;
3046 size_t mSize;
3047 };
3048
Jack Palevich569f1352009-06-29 14:29:08 -07003049 void internKeywords() {
3050 // Note: order has to match TOK_ constants
3051 static const char* keywords[] = {
3052 "int",
3053 "char",
3054 "void",
3055 "if",
3056 "else",
3057 "while",
3058 "break",
3059 "return",
3060 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003061 "auto",
3062 "case",
3063 "const",
3064 "continue",
3065 "default",
3066 "do",
3067 "double",
3068 "enum",
3069 "extern",
3070 "float",
3071 "goto",
3072 "long",
3073 "register",
3074 "short",
3075 "signed",
3076 "sizeof",
3077 "static",
3078 "struct",
3079 "switch",
3080 "typedef",
3081 "union",
3082 "unsigned",
3083 "volatile",
3084 "_Bool",
3085 "_Complex",
3086 "_Imaginary",
3087 "inline",
3088 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003089
3090 // predefined tokens that can also be symbols start here:
3091 "pragma",
3092 "define",
3093 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003094 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003095
Jack Palevich569f1352009-06-29 14:29:08 -07003096 for(int i = 0; keywords[i]; i++) {
3097 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003098 }
Jack Palevich569f1352009-06-29 14:29:08 -07003099 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003100
Jack Palevich36d94142009-06-08 15:55:32 -07003101 struct InputState {
3102 InputStream* pStream;
3103 int oldCh;
3104 };
3105
Jack Palevich2db168f2009-06-11 14:29:47 -07003106 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003107 void* pAddress;
3108 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003109 tokenid_t tok;
3110 size_t level;
3111 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003112 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003113 };
3114
Jack Palevich303d8ff2009-06-11 19:06:24 -07003115 class SymbolStack {
3116 public:
3117 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003118 mpArena = 0;
3119 mpTokenTable = 0;
3120 }
3121
3122 void setArena(Arena* pArena) {
3123 mpArena = pArena;
3124 }
3125
3126 void setTokenTable(TokenTable* pTokenTable) {
3127 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003128 }
3129
3130 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003131 Mark mark;
3132 mark.mArenaMark = mpArena->mark();
3133 mark.mSymbolHead = mStack.size();
3134 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003135 }
3136
3137 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003138 // Undo any shadowing that was done:
3139 Mark mark = mLevelStack.back();
3140 mLevelStack.pop_back();
3141 while (mStack.size() > mark.mSymbolHead) {
3142 VariableInfo* pV = mStack.back();
3143 mStack.pop_back();
3144 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003145 }
Jack Palevich569f1352009-06-29 14:29:08 -07003146 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003147 }
3148
Jack Palevich569f1352009-06-29 14:29:08 -07003149 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3150 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3151 return pV && pV->level == level();
3152 }
3153
3154 VariableInfo* add(tokenid_t tok) {
3155 Token& token = (*mpTokenTable)[tok];
3156 VariableInfo* pOldV = token.mpVariableInfo;
3157 VariableInfo* pNewV =
3158 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3159 memset(pNewV, 0, sizeof(VariableInfo));
3160 pNewV->tok = tok;
3161 pNewV->level = level();
3162 pNewV->pOldDefinition = pOldV;
3163 token.mpVariableInfo = pNewV;
3164 mStack.push_back(pNewV);
3165 return pNewV;
3166 }
3167
Jack Palevich86351982009-06-30 18:09:56 -07003168 VariableInfo* add(Type* pType) {
3169 VariableInfo* pVI = add(pType->id);
3170 pVI->pType = pType;
3171 return pVI;
3172 }
3173
Jack Palevich569f1352009-06-29 14:29:08 -07003174 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3175 for (size_t i = 0; i < mStack.size(); i++) {
3176 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003177 break;
3178 }
3179 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003180 }
3181
Jack Palevich303d8ff2009-06-11 19:06:24 -07003182 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003183 inline size_t level() {
3184 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003185 }
3186
Jack Palevich569f1352009-06-29 14:29:08 -07003187 struct Mark {
3188 Arena::Mark mArenaMark;
3189 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003190 };
3191
Jack Palevich569f1352009-06-29 14:29:08 -07003192 Arena* mpArena;
3193 TokenTable* mpTokenTable;
3194 Vector<VariableInfo*> mStack;
3195 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003196 };
Jack Palevich36d94142009-06-08 15:55:32 -07003197
3198 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003199 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003200 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003201 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003202 int tokl; // token operator level
3203 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003204 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003205 intptr_t loc; // local variable index
3206 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003207 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003208 char* dptr; // Macro state: Points to macro text during macro playback.
3209 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003210 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003211 ACCSymbolLookupFn mpSymbolLookupFn;
3212 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003213
3214 // Arena for the duration of the compile
3215 Arena mGlobalArena;
3216 // Arena for data that's only needed when compiling a single function
3217 Arena mLocalArena;
3218
3219 TokenTable mTokenTable;
3220 SymbolStack mGlobals;
3221 SymbolStack mLocals;
3222
Jack Palevich40600de2009-07-01 15:32:35 -07003223 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003224 Type* mkpInt; // int
3225 Type* mkpChar; // char
3226 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003227 Type* mkpFloat;
3228 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003229 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003230 Type* mkpIntPtr;
3231 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003232 Type* mkpFloatPtr;
3233 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003234 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003235
Jack Palevich36d94142009-06-08 15:55:32 -07003236 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003237 int mLineNumber;
3238 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003239
3240 CodeBuf codeBuf;
3241 CodeGenerator* pGen;
3242
Jack Palevicheedf9d22009-06-04 16:23:40 -07003243 String mErrorBuf;
3244
Jack Palevicheedf9d22009-06-04 16:23:40 -07003245 String mPragmas;
3246 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003247 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003248
Jack Palevich21a15a22009-05-11 14:49:29 -07003249 static const int ALLOC_SIZE = 99999;
3250
Jack Palevich303d8ff2009-06-11 19:06:24 -07003251 static const int TOK_DUMMY = 1;
3252 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003253 static const int TOK_NUM_FLOAT = 3;
3254 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003255
3256 // 3..255 are character and/or operators
3257
Jack Palevich2db168f2009-06-11 14:29:47 -07003258 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003259 // Order has to match string list in "internKeywords".
3260 enum {
3261 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3262 TOK_INT = TOK_KEYWORD,
3263 TOK_CHAR,
3264 TOK_VOID,
3265 TOK_IF,
3266 TOK_ELSE,
3267 TOK_WHILE,
3268 TOK_BREAK,
3269 TOK_RETURN,
3270 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003271 TOK_AUTO,
3272 TOK_CASE,
3273 TOK_CONST,
3274 TOK_CONTINUE,
3275 TOK_DEFAULT,
3276 TOK_DO,
3277 TOK_DOUBLE,
3278 TOK_ENUM,
3279 TOK_EXTERN,
3280 TOK_FLOAT,
3281 TOK_GOTO,
3282 TOK_LONG,
3283 TOK_REGISTER,
3284 TOK_SHORT,
3285 TOK_SIGNED,
3286 TOK_SIZEOF,
3287 TOK_STATIC,
3288 TOK_STRUCT,
3289 TOK_SWITCH,
3290 TOK_TYPEDEF,
3291 TOK_UNION,
3292 TOK_UNSIGNED,
3293 TOK_VOLATILE,
3294 TOK__BOOL,
3295 TOK__COMPLEX,
3296 TOK__IMAGINARY,
3297 TOK_INLINE,
3298 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003299
3300 // Symbols start after keywords
3301
3302 TOK_SYMBOL,
3303 TOK_PRAGMA = TOK_SYMBOL,
3304 TOK_DEFINE,
3305 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003306 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003307
3308 static const int LOCAL = 0x200;
3309
3310 static const int SYM_FORWARD = 0;
3311 static const int SYM_DEFINE = 1;
3312
3313 /* tokens in string heap */
3314 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003315
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003316 static const int OP_INCREMENT = 0;
3317 static const int OP_DECREMENT = 1;
3318 static const int OP_MUL = 2;
3319 static const int OP_DIV = 3;
3320 static const int OP_MOD = 4;
3321 static const int OP_PLUS = 5;
3322 static const int OP_MINUS = 6;
3323 static const int OP_SHIFT_LEFT = 7;
3324 static const int OP_SHIFT_RIGHT = 8;
3325 static const int OP_LESS_EQUAL = 9;
3326 static const int OP_GREATER_EQUAL = 10;
3327 static const int OP_LESS = 11;
3328 static const int OP_GREATER = 12;
3329 static const int OP_EQUALS = 13;
3330 static const int OP_NOT_EQUALS = 14;
3331 static const int OP_LOGICAL_AND = 15;
3332 static const int OP_LOGICAL_OR = 16;
3333 static const int OP_BIT_AND = 17;
3334 static const int OP_BIT_XOR = 18;
3335 static const int OP_BIT_OR = 19;
3336 static const int OP_BIT_NOT = 20;
3337 static const int OP_LOGICAL_NOT = 21;
3338 static const int OP_COUNT = 22;
3339
3340 /* Operators are searched from front, the two-character operators appear
3341 * before the single-character operators with the same first character.
3342 * @ is used to pad out single-character operators.
3343 */
3344 static const char* operatorChars;
3345 static const char operatorLevel[];
3346
Jack Palevich569f1352009-06-29 14:29:08 -07003347 /* Called when we detect an internal problem. Does nothing in production.
3348 *
3349 */
3350 void internalError() {
3351 * (char*) 0 = 0;
3352 }
3353
Jack Palevich86351982009-06-30 18:09:56 -07003354 void assert(bool isTrue) {
3355 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003356 internalError();
3357 }
Jack Palevich86351982009-06-30 18:09:56 -07003358 }
3359
Jack Palevich40600de2009-07-01 15:32:35 -07003360 bool isSymbol(tokenid_t t) {
3361 return t >= TOK_SYMBOL &&
3362 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3363 }
3364
3365 bool isSymbolOrKeyword(tokenid_t t) {
3366 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003367 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003368 }
3369
Jack Palevich86351982009-06-30 18:09:56 -07003370 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003371 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003372 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3373 if (pV && pV->tok != t) {
3374 internalError();
3375 }
3376 return pV;
3377 }
3378
3379 inline bool isDefined(tokenid_t t) {
3380 return t >= TOK_SYMBOL && VI(t) != 0;
3381 }
3382
Jack Palevich40600de2009-07-01 15:32:35 -07003383 const char* nameof(tokenid_t t) {
3384 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003385 return mTokenTable[t].pText;
3386 }
3387
Jack Palevich21a15a22009-05-11 14:49:29 -07003388 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003389 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003390 }
3391
3392 void inp() {
3393 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003394 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003395 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003396 dptr = 0;
3397 ch = dch;
3398 }
Jack Palevichdc456462009-07-16 16:50:56 -07003399 } else {
3400 if (mbBumpLine) {
3401 mLineNumber++;
3402 mbBumpLine = false;
3403 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003404 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003405 if (ch == '\n') {
3406 mbBumpLine = true;
3407 }
3408 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003409#if 0
3410 printf("ch='%c' 0x%x\n", ch, ch);
3411#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003412 }
3413
3414 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003415 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003416 }
3417
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003418 int decodeHex(int c) {
3419 if (isdigit(c)) {
3420 c -= '0';
3421 } else if (c <= 'F') {
3422 c = c - 'A' + 10;
3423 } else {
3424 c =c - 'a' + 10;
3425 }
3426 return c;
3427 }
3428
Jack Palevichb4758ff2009-06-12 12:49:14 -07003429 /* read a character constant, advances ch to after end of constant */
3430 int getq() {
3431 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003432 if (ch == '\\') {
3433 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003434 if (isoctal(ch)) {
3435 // 1 to 3 octal characters.
3436 val = 0;
3437 for(int i = 0; i < 3; i++) {
3438 if (isoctal(ch)) {
3439 val = (val << 3) + ch - '0';
3440 inp();
3441 }
3442 }
3443 return val;
3444 } else if (ch == 'x' || ch == 'X') {
3445 // N hex chars
3446 inp();
3447 if (! isxdigit(ch)) {
3448 error("'x' character escape requires at least one digit.");
3449 } else {
3450 val = 0;
3451 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003452 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003453 inp();
3454 }
3455 }
3456 } else {
3457 int val = ch;
3458 switch (ch) {
3459 case 'a':
3460 val = '\a';
3461 break;
3462 case 'b':
3463 val = '\b';
3464 break;
3465 case 'f':
3466 val = '\f';
3467 break;
3468 case 'n':
3469 val = '\n';
3470 break;
3471 case 'r':
3472 val = '\r';
3473 break;
3474 case 't':
3475 val = '\t';
3476 break;
3477 case 'v':
3478 val = '\v';
3479 break;
3480 case '\\':
3481 val = '\\';
3482 break;
3483 case '\'':
3484 val = '\'';
3485 break;
3486 case '"':
3487 val = '"';
3488 break;
3489 case '?':
3490 val = '?';
3491 break;
3492 default:
3493 error("Undefined character escape %c", ch);
3494 break;
3495 }
3496 inp();
3497 return val;
3498 }
3499 } else {
3500 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003501 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003502 return val;
3503 }
3504
3505 static bool isoctal(int ch) {
3506 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003507 }
3508
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003509 bool acceptCh(int c) {
3510 bool result = c == ch;
3511 if (result) {
3512 pdef(ch);
3513 inp();
3514 }
3515 return result;
3516 }
3517
3518 bool acceptDigitsCh() {
3519 bool result = false;
3520 while (isdigit(ch)) {
3521 result = true;
3522 pdef(ch);
3523 inp();
3524 }
3525 return result;
3526 }
3527
3528 void parseFloat() {
3529 tok = TOK_NUM_DOUBLE;
3530 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003531 if(mTokenString.len() == 0) {
3532 mTokenString.append('0');
3533 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003534 acceptCh('.');
3535 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003536 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003537 acceptCh('-') || acceptCh('+');
3538 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003539 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003540 if (ch == 'f' || ch == 'F') {
3541 tok = TOK_NUM_FLOAT;
3542 inp();
3543 } else if (ch == 'l' || ch == 'L') {
3544 inp();
3545 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003546 }
3547 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003548 char* pEnd = pText + strlen(pText);
3549 char* pEndPtr = 0;
3550 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003551 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003552 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003553 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003554 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003555 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003556 if (errno || pEndPtr != pEnd) {
3557 error("Can't parse constant: %s", pText);
3558 }
3559 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003560 }
3561
Jack Palevich21a15a22009-05-11 14:49:29 -07003562 void next() {
3563 int l, a;
3564
Jack Palevich546b2242009-05-13 15:10:04 -07003565 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003566 if (ch == '#') {
3567 inp();
3568 next();
3569 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003570 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003571 } else if (tok == TOK_PRAGMA) {
3572 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003573 } else if (tok == TOK_LINE) {
3574 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003575 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003576 error("Unsupported preprocessor directive \"%s\"",
3577 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003578 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003579 }
3580 inp();
3581 }
3582 tokl = 0;
3583 tok = ch;
3584 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003585 if (isdigit(ch) || ch == '.') {
3586 // Start of a numeric constant. Could be integer, float, or
3587 // double, won't know until we look further.
3588 mTokenString.clear();
3589 pdef(ch);
3590 inp();
3591 int base = 10;
3592 if (tok == '0') {
3593 if (ch == 'x' || ch == 'X') {
3594 base = 16;
3595 tok = TOK_NUM;
3596 tokc = 0;
3597 inp();
3598 while ( isxdigit(ch) ) {
3599 tokc = (tokc << 4) + decodeHex(ch);
3600 inp();
3601 }
3602 } else if (isoctal(ch)){
3603 base = 8;
3604 tok = TOK_NUM;
3605 tokc = 0;
3606 while ( isoctal(ch) ) {
3607 tokc = (tokc << 3) + (ch - '0');
3608 inp();
3609 }
3610 }
3611 } else if (isdigit(tok)){
3612 acceptDigitsCh();
3613 }
3614 if (base == 10) {
3615 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3616 parseFloat();
3617 } else {
3618 // It's an integer constant
3619 char* pText = mTokenString.getUnwrapped();
3620 char* pEnd = pText + strlen(pText);
3621 char* pEndPtr = 0;
3622 errno = 0;
3623 tokc = strtol(pText, &pEndPtr, base);
3624 if (errno || pEndPtr != pEnd) {
3625 error("Can't parse constant: %s %d %d", pText, base, errno);
3626 }
3627 tok = TOK_NUM;
3628 }
3629 }
3630 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003631 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003632 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003633 pdef(ch);
3634 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003635 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003636 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3637 // Is this a macro?
3638 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3639 if (pMacroDefinition) {
3640 // Yes, it is a macro
3641 dptr = pMacroDefinition;
3642 dch = ch;
3643 inp();
3644 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003645 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003646 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003647 inp();
3648 if (tok == '\'') {
3649 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003650 tokc = getq();
3651 if (ch != '\'') {
3652 error("Expected a ' character, got %c", ch);
3653 } else {
3654 inp();
3655 }
Jack Palevich546b2242009-05-13 15:10:04 -07003656 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003657 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003658 while (ch && ch != EOF) {
3659 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003660 inp();
3661 inp();
3662 if (ch == '/')
3663 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003664 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003665 if (ch == EOF) {
3666 error("End of file inside comment.");
3667 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003668 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003669 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003670 } else if ((tok == '/') & (ch == '/')) {
3671 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003672 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003673 inp();
3674 }
3675 inp();
3676 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003677 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003678 const char* t = operatorChars;
3679 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003680 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003681 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003682 tokl = operatorLevel[opIndex];
3683 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003684 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003685#if 0
3686 printf("%c%c -> tokl=%d tokc=0x%x\n",
3687 l, a, tokl, tokc);
3688#endif
3689 if (a == ch) {
3690 inp();
3691 tok = TOK_DUMMY; /* dummy token for double tokens */
3692 }
3693 break;
3694 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003695 opIndex++;
3696 }
3697 if (l == 0) {
3698 tokl = 0;
3699 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003700 }
3701 }
3702 }
3703#if 0
3704 {
Jack Palevich569f1352009-06-29 14:29:08 -07003705 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003706 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003707 fprintf(stderr, "%s\n", buf.getUnwrapped());
3708 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003709#endif
3710 }
3711
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003712 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003713 next();
3714 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003715 String* pName = new String();
3716 while (isspace(ch)) {
3717 inp();
3718 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003719 if (ch == '(') {
3720 delete pName;
3721 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003722 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003723 }
3724 while (isspace(ch)) {
3725 inp();
3726 }
Jack Palevich569f1352009-06-29 14:29:08 -07003727 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003728 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003729 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003730 inp();
3731 }
Jack Palevich569f1352009-06-29 14:29:08 -07003732 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3733 memcpy(pDefn, value.getUnwrapped(), value.len());
3734 pDefn[value.len()] = 0;
3735 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003736 }
3737
Jack Palevicheedf9d22009-06-04 16:23:40 -07003738 void doPragma() {
3739 // # pragma name(val)
3740 int state = 0;
3741 while(ch != EOF && ch != '\n' && state < 10) {
3742 switch(state) {
3743 case 0:
3744 if (isspace(ch)) {
3745 inp();
3746 } else {
3747 state++;
3748 }
3749 break;
3750 case 1:
3751 if (isalnum(ch)) {
3752 mPragmas.append(ch);
3753 inp();
3754 } else if (ch == '(') {
3755 mPragmas.append(0);
3756 inp();
3757 state++;
3758 } else {
3759 state = 11;
3760 }
3761 break;
3762 case 2:
3763 if (isalnum(ch)) {
3764 mPragmas.append(ch);
3765 inp();
3766 } else if (ch == ')') {
3767 mPragmas.append(0);
3768 inp();
3769 state = 10;
3770 } else {
3771 state = 11;
3772 }
3773 break;
3774 }
3775 }
3776 if(state != 10) {
3777 error("Unexpected pragma syntax");
3778 }
3779 mPragmaStringCount += 2;
3780 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003781
Jack Palevichdc456462009-07-16 16:50:56 -07003782 void doLine() {
3783 // # line number { "filename "}
3784 next();
3785 if (tok != TOK_NUM) {
3786 error("Expected a line-number");
3787 } else {
3788 mLineNumber = tokc-1; // The end-of-line will increment it.
3789 }
3790 while(ch != EOF && ch != '\n') {
3791 inp();
3792 }
3793 }
3794
Jack Palevichac0e95e2009-05-29 13:53:44 -07003795 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003796 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003797 mErrorBuf.vprintf(fmt, ap);
3798 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003799 }
3800
Jack Palevich8b0624c2009-05-20 12:12:06 -07003801 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003802 if (tok != c) {
3803 error("'%c' expected", c);
3804 }
3805 next();
3806 }
3807
Jack Palevich86351982009-06-30 18:09:56 -07003808 bool accept(intptr_t c) {
3809 if (tok == c) {
3810 next();
3811 return true;
3812 }
3813 return false;
3814 }
3815
Jack Palevich40600de2009-07-01 15:32:35 -07003816 bool acceptStringLiteral() {
3817 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003818 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003819 // This while loop merges multiple adjacent string constants.
3820 while (tok == '"') {
3821 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003822 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003823 }
3824 if (ch != '"') {
3825 error("Unterminated string constant.");
3826 }
3827 inp();
3828 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003829 }
Jack Palevich40600de2009-07-01 15:32:35 -07003830 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003831 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003832 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003833 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003834
3835 return true;
3836 }
3837 return false;
3838 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003839
Jack Palevichb1544ca2009-07-16 15:09:20 -07003840 void linkGlobal(tokenid_t t, bool isFunction) {
3841 VariableInfo* pVI = VI(t);
3842 void* n = NULL;
3843 if (mpSymbolLookupFn) {
3844 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3845 }
3846 if (pVI->pType == NULL) {
3847 if (isFunction) {
3848 pVI->pType = mkpIntFn;
3849 } else {
3850 pVI->pType = mkpInt;
3851 }
3852 }
3853 pVI->pAddress = n;
3854 }
3855
Jack Palevich40600de2009-07-01 15:32:35 -07003856 /* Parse and evaluate a unary expression.
3857 * allowAssignment is true if '=' parsing wanted (quick hack)
3858 */
3859 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003860 tokenid_t t;
3861 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003862 t = 0;
3863 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3864 if (acceptStringLiteral()) {
3865 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003866 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003867 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003868 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003869 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003870 t = tok;
3871 next();
3872 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003873 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003874 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003875 // Align to 4-byte boundary
3876 glo = (char*) (((intptr_t) glo + 3) & -4);
3877 * (float*) glo = (float) ad;
3878 pGen->loadFloat((int) glo, mkpFloat);
3879 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003880 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003881 // Align to 8-byte boundary
3882 glo = (char*) (((intptr_t) glo + 7) & -8);
3883 * (double*) glo = ad;
3884 pGen->loadFloat((int) glo, mkpDouble);
3885 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 } else if (c == 2) {
3887 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003888 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003889 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003890 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003891 else if (t == '+') {
3892 // ignore unary plus.
3893 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003894 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003895 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003896 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003897 // It's either a cast or an expression
3898 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3899 if (pCast) {
3900 skip(')');
3901 unary(false);
3902 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003903 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003904 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003905 skip(')');
3906 }
3907 } else if (t == '*') {
3908 /* This is a pointer dereference.
3909 */
3910 unary(false);
3911 Type* pR0Type = pGen->getR0Type();
3912 if (pR0Type->tag != TY_POINTER) {
3913 error("Expected a pointer type.");
3914 } else {
3915 if (pR0Type->pHead->tag == TY_FUNC) {
3916 t = 0;
3917 }
3918 if (accept('=')) {
3919 pGen->pushR0();
3920 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003921 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07003922 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003923 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07003924 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003925 }
Jack Palevich3f226492009-07-02 14:46:19 -07003926 // Else we fall through to the function call below, with
3927 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003928 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003929 VariableInfo* pVI = VI(tok);
3930 pGen->leaR0((int) pVI->pAddress,
3931 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003932 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003933 } else if (t == EOF ) {
3934 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003935 } else if (t == ';') {
3936 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003937 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003938 // Don't have to do anything special here, the error
3939 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003940 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003941 if (!isDefined(t)) {
3942 mGlobals.add(t);
3943 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003944 }
Jack Palevich8df46192009-07-07 14:48:51 -07003945 VariableInfo* pVI = VI(t);
3946 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003947 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003948 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003949 linkGlobal(t, tok == '(');
3950 n = (intptr_t) pVI->pAddress;
3951 if (!n && tok != '(') {
3952 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003953 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003954 }
Jack Palevich40600de2009-07-01 15:32:35 -07003955 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003956 /* assignment */
3957 next();
3958 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003959 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003960 } else if (tok != '(') {
3961 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003962 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003963 linkGlobal(t, false);
3964 n = (intptr_t) pVI->pAddress;
3965 if (!n) {
3966 error("Undeclared variable %s\n", nameof(t));
3967 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003968 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07003969 // load a variable
3970 pGen->loadR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003971 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003972 // post inc / post dec
3973 pGen->pushR0();
3974 impInc(tokc);
3975 pGen->storeR0(n, pVI->pType);
3976 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003977 next();
3978 }
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 Palevich58c30ee2009-07-17 16:35:23 -07004047 /* Increment / decrement R0 */
4048
4049 void impInc(int op) {
4050 Type* pType = pGen->getR0Type();
4051 int lit = 1;
4052 if (op == OP_DECREMENT) {
4053 lit = -1;
4054 }
4055 switch (pType->tag) {
4056 case TY_INT:
4057 case TY_CHAR:
4058 case TY_POINTER:
4059 pGen->pushR0();
4060 pGen->li(lit);
4061 pGen->genOp(OP_PLUS);
4062 break;
4063 default:
4064 error("++/-- illegal for this type.");
4065 break;
4066 }
4067 }
4068
Jack Palevich40600de2009-07-01 15:32:35 -07004069 /* Recursive descent parser for binary operations.
4070 */
4071 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004072 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004073 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004074 if (level-- == 1)
4075 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004076 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004077 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004078 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004079 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004080 t = tokc;
4081 next();
4082
Jack Palevich40600de2009-07-01 15:32:35 -07004083 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004084 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004085 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004086 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004087 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004088 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004089 // Check for syntax error.
4090 if (pGen->getR0Type() == NULL) {
4091 // We failed to parse a right-hand argument.
4092 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004093 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004094 }
Jack Palevich40600de2009-07-01 15:32:35 -07004095 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004096 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004097 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004098 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004099 }
4100 }
4101 }
4102 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004103 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004104 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004105 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07004106 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004107 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004108 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07004109 }
4110 }
4111 }
4112
4113 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004114 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004115 }
4116
4117 int test_expr() {
4118 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004119 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004120 }
4121
Jack Palevicha6baa232009-06-12 11:25:59 -07004122 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004123 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004124
Jack Palevich95727a02009-07-06 12:07:15 -07004125 Type* pBaseType;
4126 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004127 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004128 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004129 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004130 next();
4131 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004132 a = test_expr();
4133 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004134 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004135 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004136 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004137 n = pGen->gjmp(0); /* jmp */
4138 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004139 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004140 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004141 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004142 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004143 }
Jack Palevich546b2242009-05-13 15:10:04 -07004144 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004145 t = tok;
4146 next();
4147 skip('(');
4148 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004149 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004150 a = test_expr();
4151 } else {
4152 if (tok != ';')
4153 expr();
4154 skip(';');
4155 n = codeBuf.getPC();
4156 a = 0;
4157 if (tok != ';')
4158 a = test_expr();
4159 skip(';');
4160 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004161 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004162 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004163 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004164 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004165 n = t + 4;
4166 }
4167 }
4168 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004169 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004170 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004171 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004172 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004173 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004174 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004175 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004176 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004177 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004178 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004179 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004180 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004181 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004182 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004183 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004184 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004185 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004186 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004187 if (pReturnType->tag == TY_VOID) {
4188 error("Must not return a value from a void function");
4189 } else {
4190 pGen->convertR0(pReturnType);
4191 }
4192 } else {
4193 if (pReturnType->tag != TY_VOID) {
4194 error("Must specify a value here");
4195 }
Jack Palevich8df46192009-07-07 14:48:51 -07004196 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004197 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004198 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004199 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004200 } else if (tok != ';')
4201 expr();
4202 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004203 }
4204 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004205
Jack Palevicha8f427f2009-07-13 18:40:08 -07004206 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004207 if (a == b) {
4208 return true;
4209 }
4210 if (a == NULL || b == NULL) {
4211 return false;
4212 }
4213 TypeTag at = a->tag;
4214 if (at != b->tag) {
4215 return false;
4216 }
4217 if (at == TY_POINTER) {
4218 return typeEqual(a->pHead, b->pHead);
4219 } else if (at == TY_FUNC || at == TY_PARAM) {
4220 return typeEqual(a->pHead, b->pHead)
4221 && typeEqual(a->pTail, b->pTail);
4222 }
4223 return true;
4224 }
4225
Jack Palevich86351982009-06-30 18:09:56 -07004226 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4227 assert(tag >= TY_INT && tag <= TY_PARAM);
4228 Type* pType = (Type*) arena.alloc(sizeof(Type));
4229 memset(pType, 0, sizeof(*pType));
4230 pType->tag = tag;
4231 pType->pHead = pHead;
4232 pType->pTail = pTail;
4233 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004234 }
4235
Jack Palevich3f226492009-07-02 14:46:19 -07004236 Type* createPtrType(Type* pType, Arena& arena) {
4237 return createType(TY_POINTER, pType, NULL, arena);
4238 }
4239
4240 /**
4241 * Try to print a type in declaration order
4242 */
Jack Palevich86351982009-06-30 18:09:56 -07004243 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004244 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004245 if (pType == NULL) {
4246 buffer.appendCStr("null");
4247 return;
4248 }
Jack Palevich3f226492009-07-02 14:46:19 -07004249 decodeTypeImp(buffer, pType);
4250 }
4251
4252 void decodeTypeImp(String& buffer, Type* pType) {
4253 decodeTypeImpPrefix(buffer, pType);
4254
Jack Palevich86351982009-06-30 18:09:56 -07004255 String temp;
4256 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004257 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004258 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004259 }
4260
4261 decodeTypeImpPostfix(buffer, pType);
4262 }
4263
4264 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4265 TypeTag tag = pType->tag;
4266
Jack Palevich37c54bd2009-07-14 18:35:36 -07004267 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004268 switch (tag) {
4269 case TY_INT:
4270 buffer.appendCStr("int");
4271 break;
4272 case TY_CHAR:
4273 buffer.appendCStr("char");
4274 break;
4275 case TY_VOID:
4276 buffer.appendCStr("void");
4277 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004278 case TY_FLOAT:
4279 buffer.appendCStr("float");
4280 break;
4281 case TY_DOUBLE:
4282 buffer.appendCStr("double");
4283 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004284 default:
4285 break;
4286 }
Jack Palevich86351982009-06-30 18:09:56 -07004287 buffer.append(' ');
4288 }
Jack Palevich3f226492009-07-02 14:46:19 -07004289
4290 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004291 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004292 break;
4293 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004294 break;
4295 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004296 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004297 case TY_FLOAT:
4298 break;
4299 case TY_DOUBLE:
4300 break;
Jack Palevich86351982009-06-30 18:09:56 -07004301 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004302 decodeTypeImpPrefix(buffer, pType->pHead);
4303 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4304 buffer.append('(');
4305 }
4306 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004307 break;
4308 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004309 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004310 break;
4311 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004312 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004313 break;
4314 default:
4315 String temp;
4316 temp.printf("Unknown tag %d", pType->tag);
4317 buffer.append(temp);
4318 break;
4319 }
Jack Palevich3f226492009-07-02 14:46:19 -07004320 }
4321
4322 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4323 TypeTag tag = pType->tag;
4324
4325 switch(tag) {
4326 case TY_POINTER:
4327 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4328 buffer.append(')');
4329 }
4330 decodeTypeImpPostfix(buffer, pType->pHead);
4331 break;
4332 case TY_FUNC:
4333 buffer.append('(');
4334 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4335 decodeTypeImp(buffer, pArg);
4336 if (pArg->pTail) {
4337 buffer.appendCStr(", ");
4338 }
4339 }
4340 buffer.append(')');
4341 break;
4342 default:
4343 break;
Jack Palevich86351982009-06-30 18:09:56 -07004344 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004345 }
4346
Jack Palevich86351982009-06-30 18:09:56 -07004347 void printType(Type* pType) {
4348 String buffer;
4349 decodeType(buffer, pType);
4350 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004351 }
4352
Jack Palevich86351982009-06-30 18:09:56 -07004353 Type* acceptPrimitiveType(Arena& arena) {
4354 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004355 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004356 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004357 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004358 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004359 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004360 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004361 } else if (tok == TOK_FLOAT) {
4362 pType = mkpFloat;
4363 } else if (tok == TOK_DOUBLE) {
4364 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004365 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004366 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004367 }
4368 next();
Jack Palevich86351982009-06-30 18:09:56 -07004369 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004370 }
4371
Jack Palevich3f226492009-07-02 14:46:19 -07004372 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4373 Arena& arena) {
4374 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004375 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004376 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004377 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004378 if (declName) {
4379 // Clone the parent type so we can set a unique ID
4380 pType = createType(pType->tag, pType->pHead,
4381 pType->pTail, arena);
4382
Jack Palevich86351982009-06-30 18:09:56 -07004383 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004384 }
Jack Palevich3f226492009-07-02 14:46:19 -07004385 // fprintf(stderr, "Parsed a declaration: ");
4386 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004387 if (reportFailure) {
4388 return NULL;
4389 }
Jack Palevich86351982009-06-30 18:09:56 -07004390 return pType;
4391 }
4392
Jack Palevich3f226492009-07-02 14:46:19 -07004393 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4394 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004395 if (! pType) {
4396 error("Expected a declaration");
4397 }
4398 return pType;
4399 }
4400
Jack Palevich3f226492009-07-02 14:46:19 -07004401 /* Used for accepting types that appear in casts */
4402 Type* acceptCastTypeDeclaration(Arena& arena) {
4403 Type* pType = acceptPrimitiveType(arena);
4404 if (pType) {
4405 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004406 }
Jack Palevich86351982009-06-30 18:09:56 -07004407 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004408 }
4409
Jack Palevich3f226492009-07-02 14:46:19 -07004410 Type* expectCastTypeDeclaration(Arena& arena) {
4411 Type* pType = acceptCastTypeDeclaration(arena);
4412 if (! pType) {
4413 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004414 }
Jack Palevich3f226492009-07-02 14:46:19 -07004415 return pType;
4416 }
4417
4418 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004419 bool nameAllowed, bool nameRequired, Arena& arena,
4420 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004421 int ptrCounter = 0;
4422 while (accept('*')) {
4423 ptrCounter++;
4424 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004425 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena,
4426 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004427 while (ptrCounter-- > 0) {
4428 pType = createType(TY_POINTER, pType, NULL, arena);
4429 }
4430 return pType;
4431 }
4432
4433 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004434 bool nameAllowed, bool nameRequired, Arena& arena,
4435 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004436 // direct-dcl :
4437 // name
4438 // (dcl)
4439 // direct-dcl()
4440 // direct-dcl[]
4441 Type* pNewHead = NULL;
4442 if (accept('(')) {
4443 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004444 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004445 skip(')');
4446 } else if ((declName = acceptSymbol()) != 0) {
4447 if (nameAllowed == false && declName) {
4448 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004449 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004450 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004451 } else if (nameRequired && ! declName) {
4452 String temp;
4453 decodeToken(temp, tok, true);
4454 error("Expected name. Got %s", temp.getUnwrapped());
4455 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004456 }
4457 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004458 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004459 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004460 pType = createType(TY_FUNC, pType, pTail, arena);
4461 skip(')');
4462 }
Jack Palevich3f226492009-07-02 14:46:19 -07004463
4464 if (pNewHead) {
4465 Type* pA = pNewHead;
4466 while (pA->pHead) {
4467 pA = pA->pHead;
4468 }
4469 pA->pHead = pType;
4470 pType = pNewHead;
4471 }
Jack Palevich86351982009-06-30 18:09:56 -07004472 return pType;
4473 }
4474
Jack Palevich3f226492009-07-02 14:46:19 -07004475 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004476 Type* pHead = NULL;
4477 Type* pTail = NULL;
4478 for(;;) {
4479 Type* pBaseArg = acceptPrimitiveType(arena);
4480 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004481 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4482 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004483 if (pArg) {
4484 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4485 if (!pHead) {
4486 pHead = pParam;
4487 pTail = pParam;
4488 } else {
4489 pTail->pTail = pParam;
4490 pTail = pParam;
4491 }
4492 }
4493 }
4494 if (! accept(',')) {
4495 break;
4496 }
4497 }
4498 return pHead;
4499 }
4500
4501 Type* expectPrimitiveType(Arena& arena) {
4502 Type* pType = acceptPrimitiveType(arena);
4503 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004504 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004505 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004506 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004507 }
Jack Palevich86351982009-06-30 18:09:56 -07004508 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004509 }
4510
Jack Palevich86351982009-06-30 18:09:56 -07004511 void addGlobalSymbol(Type* pDecl) {
4512 tokenid_t t = pDecl->id;
4513 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004514 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004515 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004516 }
Jack Palevich86351982009-06-30 18:09:56 -07004517 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004518 }
4519
Jack Palevich86351982009-06-30 18:09:56 -07004520 void reportDuplicate(tokenid_t t) {
4521 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004522 }
4523
Jack Palevich86351982009-06-30 18:09:56 -07004524 void addLocalSymbol(Type* pDecl) {
4525 tokenid_t t = pDecl->id;
4526 if (mLocals.isDefinedAtCurrentLevel(t)) {
4527 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004528 }
Jack Palevich86351982009-06-30 18:09:56 -07004529 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004530 }
4531
Jack Palevich95727a02009-07-06 12:07:15 -07004532 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004533 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004534
Jack Palevich95727a02009-07-06 12:07:15 -07004535 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004536 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004537 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4538 if (!pDecl) {
4539 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004540 }
Jack Palevich86351982009-06-30 18:09:56 -07004541 int variableAddress = 0;
4542 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004543 size_t alignment = pGen->alignmentOf(pDecl);
4544 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004545 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004546 variableAddress = -loc;
4547 VI(pDecl->id)->pAddress = (void*) variableAddress;
4548 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004549 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004550 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004551 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004552 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004553 if (tok == ',')
4554 next();
4555 }
4556 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004557 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004558 }
4559 }
4560
Jack Palevichf1728be2009-06-12 13:53:51 -07004561 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004562 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004563 }
4564
Jack Palevich37c54bd2009-07-14 18:35:36 -07004565 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004566 if (token == EOF ) {
4567 buffer.printf("EOF");
4568 } else if (token == TOK_NUM) {
4569 buffer.printf("numeric constant");
4570 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004571 if (token < 32) {
4572 buffer.printf("'\\x%02x'", token);
4573 } else {
4574 buffer.printf("'%c'", token);
4575 }
Jack Palevich569f1352009-06-29 14:29:08 -07004576 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004577 if (quote) {
4578 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4579 buffer.printf("keyword \"%s\"", nameof(token));
4580 } else {
4581 buffer.printf("symbol \"%s\"", nameof(token));
4582 }
4583 } else {
4584 buffer.printf("%s", nameof(token));
4585 }
Jack Palevich569f1352009-06-29 14:29:08 -07004586 }
4587 }
4588
Jack Palevich40600de2009-07-01 15:32:35 -07004589 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004590 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004591 if (!result) {
4592 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004593 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004594 error("Expected symbol. Got %s", temp.getUnwrapped());
4595 }
4596 return result;
4597 }
4598
Jack Palevich86351982009-06-30 18:09:56 -07004599 tokenid_t acceptSymbol() {
4600 tokenid_t result = 0;
4601 if (tok >= TOK_SYMBOL) {
4602 result = tok;
4603 next();
Jack Palevich86351982009-06-30 18:09:56 -07004604 }
4605 return result;
4606 }
4607
Jack Palevichb7c81e92009-06-04 19:56:13 -07004608 void globalDeclarations() {
4609 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004610 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4611 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004612 break;
4613 }
Jack Palevich86351982009-06-30 18:09:56 -07004614 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4615 if (!pDecl) {
4616 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004617 }
Jack Palevich86351982009-06-30 18:09:56 -07004618 if (! isDefined(pDecl->id)) {
4619 addGlobalSymbol(pDecl);
4620 }
4621 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004622 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004623 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004624 }
Jack Palevich86351982009-06-30 18:09:56 -07004625 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004626 // it's a variable declaration
4627 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004628 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004629 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004630 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004631 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004632 }
Jack Palevich86351982009-06-30 18:09:56 -07004633 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004634 if (tok == TOK_NUM) {
4635 if (name) {
4636 * (int*) name->pAddress = tokc;
4637 }
4638 next();
4639 } else {
4640 error("Expected an integer constant");
4641 }
4642 }
Jack Palevich86351982009-06-30 18:09:56 -07004643 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004644 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004645 }
Jack Palevich86351982009-06-30 18:09:56 -07004646 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4647 if (!pDecl) {
4648 break;
4649 }
4650 if (! isDefined(pDecl->id)) {
4651 addGlobalSymbol(pDecl);
4652 }
4653 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004654 }
4655 skip(';');
4656 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004657 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004658 if (accept(';')) {
4659 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004660 } else if (tok != '{') {
4661 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004662 } else {
4663 if (name) {
4664 /* patch forward references (XXX: does not work for function
4665 pointers) */
4666 pGen->gsym((int) name->pForward);
4667 /* put function address */
4668 name->pAddress = (void*) codeBuf.getPC();
4669 }
4670 // Calculate stack offsets for parameters
4671 mLocals.pushLevel();
4672 intptr_t a = 8;
4673 int argCount = 0;
4674 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4675 Type* pArg = pP->pHead;
4676 addLocalSymbol(pArg);
4677 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004678 size_t alignment = pGen->alignmentOf(pArg);
4679 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004680 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004681 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004682 argCount++;
4683 }
4684 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004685 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004686 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004687 block(0, true);
4688 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004689 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004690 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004691 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004692 }
4693 }
4694 }
4695
Jack Palevich9cbd2262009-07-08 16:48:41 -07004696 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4697 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4698 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004699 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004700 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004701 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004702 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004703 char* result = (char*) base;
4704 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004705 return result;
4706 }
4707
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004709 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004710 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004711 pGlobalBase = 0;
4712 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004713 if (pGen) {
4714 delete pGen;
4715 pGen = 0;
4716 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004717 if (file) {
4718 delete file;
4719 file = 0;
4720 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004721 }
4722
Jack Palevich8c246a92009-07-14 21:14:10 -07004723 // One-time initialization, when class is constructed.
4724 void init() {
4725 mpSymbolLookupFn = 0;
4726 mpSymbolLookupContext = 0;
4727 }
4728
Jack Palevich21a15a22009-05-11 14:49:29 -07004729 void clear() {
4730 tok = 0;
4731 tokc = 0;
4732 tokl = 0;
4733 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004734 rsym = 0;
4735 loc = 0;
4736 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004737 dptr = 0;
4738 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004739 file = 0;
4740 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004741 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004742 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004743 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004744 mLineNumber = 1;
4745 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004746 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004747
Jack Palevich22305132009-05-13 10:58:45 -07004748 void setArchitecture(const char* architecture) {
4749 delete pGen;
4750 pGen = 0;
4751
4752 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004753#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004754 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004755 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004756 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004757#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004758#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004759 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004760 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004761 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004762#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004763 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004764 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004765 }
4766 }
4767
4768 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004769#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004770 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004771#elif defined(DEFAULT_X86_CODEGEN)
4772 pGen = new X86CodeGenerator();
4773#endif
4774 }
4775 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004776 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004777 } else {
4778 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004779 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004780 }
4781 }
4782
Jack Palevich77ae76e2009-05-10 19:59:24 -07004783public:
Jack Palevich22305132009-05-13 10:58:45 -07004784 struct args {
4785 args() {
4786 architecture = 0;
4787 }
4788 const char* architecture;
4789 };
4790
Jack Paleviche7b59062009-05-19 17:12:17 -07004791 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004792 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004793 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004794 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004795
Jack Paleviche7b59062009-05-19 17:12:17 -07004796 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004797 cleanup();
4798 }
4799
Jack Palevich8c246a92009-07-14 21:14:10 -07004800 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4801 mpSymbolLookupFn = pFn;
4802 mpSymbolLookupContext = pContext;
4803 }
4804
Jack Palevich1cdef202009-05-22 12:06:27 -07004805 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004806 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004807
Jack Palevicha8f427f2009-07-13 18:40:08 -07004808 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004809 cleanup();
4810 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004811 mTokenTable.setArena(&mGlobalArena);
4812 mGlobals.setArena(&mGlobalArena);
4813 mGlobals.setTokenTable(&mTokenTable);
4814 mLocals.setArena(&mLocalArena);
4815 mLocals.setTokenTable(&mTokenTable);
4816
4817 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004818 codeBuf.init(ALLOC_SIZE);
4819 setArchitecture(NULL);
4820 if (!pGen) {
4821 return -1;
4822 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004823#ifdef PROVIDE_TRACE_CODEGEN
4824 pGen = new TraceCodeGenerator(pGen);
4825#endif
4826 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004827 pGen->init(&codeBuf);
4828 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004829 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4830 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004831 inp();
4832 next();
4833 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004834 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004835 result = pGen->finishCompile();
4836 if (result == 0) {
4837 if (mErrorBuf.len()) {
4838 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004839 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004840 }
Jack Palevichce105a92009-07-16 14:30:33 -07004841 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004842 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004843 }
4844
Jack Palevich86351982009-06-30 18:09:56 -07004845 void createPrimitiveTypes() {
4846 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4847 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4848 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004849 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4850 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004851 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004852 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4853 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004854 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4855 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004856 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004857 }
4858
Jack Palevicha6baa232009-06-12 11:25:59 -07004859 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004860 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004861 }
4862
Jack Palevich569f1352009-06-29 14:29:08 -07004863 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004864 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004865 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004866 }
4867
Jack Palevich569f1352009-06-29 14:29:08 -07004868 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004869 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004870 error("Undefined forward reference: %s",
4871 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004872 }
4873 return true;
4874 }
4875
Jack Palevich21a15a22009-05-11 14:49:29 -07004876 int dump(FILE* out) {
4877 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4878 return 0;
4879 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004880
Jack Palevicha6535612009-05-13 16:24:17 -07004881 int disassemble(FILE* out) {
4882 return pGen->disassemble(out);
4883 }
4884
Jack Palevich1cdef202009-05-22 12:06:27 -07004885 /* Look through the symbol table to find a symbol.
4886 * If found, return its value.
4887 */
4888 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004889 if (mCompileResult == 0) {
4890 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4891 VariableInfo* pVariableInfo = VI(tok);
4892 if (pVariableInfo) {
4893 return pVariableInfo->pAddress;
4894 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004895 }
4896 return NULL;
4897 }
4898
Jack Palevicheedf9d22009-06-04 16:23:40 -07004899 void getPragmas(ACCsizei* actualStringCount,
4900 ACCsizei maxStringCount, ACCchar** strings) {
4901 int stringCount = mPragmaStringCount;
4902 if (actualStringCount) {
4903 *actualStringCount = stringCount;
4904 }
4905 if (stringCount > maxStringCount) {
4906 stringCount = maxStringCount;
4907 }
4908 if (strings) {
4909 char* pPragmas = mPragmas.getUnwrapped();
4910 while (stringCount-- > 0) {
4911 *strings++ = pPragmas;
4912 pPragmas += strlen(pPragmas) + 1;
4913 }
4914 }
4915 }
4916
Jack Palevichac0e95e2009-05-29 13:53:44 -07004917 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004918 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004919 }
4920
Jack Palevich77ae76e2009-05-10 19:59:24 -07004921};
4922
Jack Paleviche7b59062009-05-19 17:12:17 -07004923const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004924 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4925
Jack Paleviche7b59062009-05-19 17:12:17 -07004926const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004927 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4928 5, 5, /* ==, != */
4929 9, 10, /* &&, || */
4930 6, 7, 8, /* & ^ | */
4931 2, 2 /* ~ ! */
4932 };
4933
Jack Palevich8b0624c2009-05-20 12:12:06 -07004934#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004935FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004936#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004937
Jack Palevich8b0624c2009-05-20 12:12:06 -07004938#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004939const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004940 0x1, // ++
4941 0xff, // --
4942 0xc1af0f, // *
4943 0xf9f79991, // /
4944 0xf9f79991, // % (With manual assist to swap results)
4945 0xc801, // +
4946 0xd8f7c829, // -
4947 0xe0d391, // <<
4948 0xf8d391, // >>
4949 0xe, // <=
4950 0xd, // >=
4951 0xc, // <
4952 0xf, // >
4953 0x4, // ==
4954 0x5, // !=
4955 0x0, // &&
4956 0x1, // ||
4957 0xc821, // &
4958 0xc831, // ^
4959 0xc809, // |
4960 0xd0f7, // ~
4961 0x4 // !
4962};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004963#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004964
Jack Palevich1cdef202009-05-22 12:06:27 -07004965struct ACCscript {
4966 ACCscript() {
4967 text = 0;
4968 textLength = 0;
4969 accError = ACC_NO_ERROR;
4970 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004971
Jack Palevich1cdef202009-05-22 12:06:27 -07004972 ~ACCscript() {
4973 delete text;
4974 }
Jack Palevich546b2242009-05-13 15:10:04 -07004975
Jack Palevich8c246a92009-07-14 21:14:10 -07004976 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4977 compiler.registerSymbolCallback(pFn, pContext);
4978 }
4979
Jack Palevich1cdef202009-05-22 12:06:27 -07004980 void setError(ACCenum error) {
4981 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4982 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004983 }
4984 }
4985
Jack Palevich1cdef202009-05-22 12:06:27 -07004986 ACCenum getError() {
4987 ACCenum result = accError;
4988 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004989 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004990 }
4991
Jack Palevich1cdef202009-05-22 12:06:27 -07004992 Compiler compiler;
4993 char* text;
4994 int textLength;
4995 ACCenum accError;
4996};
4997
4998
4999extern "C"
5000ACCscript* accCreateScript() {
5001 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005002}
Jack Palevich1cdef202009-05-22 12:06:27 -07005003
5004extern "C"
5005ACCenum accGetError( ACCscript* script ) {
5006 return script->getError();
5007}
5008
5009extern "C"
5010void accDeleteScript(ACCscript* script) {
5011 delete script;
5012}
5013
5014extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005015void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5016 ACCvoid* pContext) {
5017 script->registerSymbolCallback(pFn, pContext);
5018}
5019
5020extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005021void accScriptSource(ACCscript* script,
5022 ACCsizei count,
5023 const ACCchar ** string,
5024 const ACCint * length) {
5025 int totalLength = 0;
5026 for(int i = 0; i < count; i++) {
5027 int len = -1;
5028 const ACCchar* s = string[i];
5029 if (length) {
5030 len = length[i];
5031 }
5032 if (len < 0) {
5033 len = strlen(s);
5034 }
5035 totalLength += len;
5036 }
5037 delete script->text;
5038 char* text = new char[totalLength + 1];
5039 script->text = text;
5040 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005041 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005042 for(int i = 0; i < count; i++) {
5043 int len = -1;
5044 const ACCchar* s = string[i];
5045 if (length) {
5046 len = length[i];
5047 }
5048 if (len < 0) {
5049 len = strlen(s);
5050 }
Jack Palevich09555c72009-05-27 12:25:55 -07005051 memcpy(dest, s, len);
5052 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005053 }
5054 text[totalLength] = '\0';
5055}
5056
5057extern "C"
5058void accCompileScript(ACCscript* script) {
5059 int result = script->compiler.compile(script->text, script->textLength);
5060 if (result) {
5061 script->setError(ACC_INVALID_OPERATION);
5062 }
5063}
5064
5065extern "C"
5066void accGetScriptiv(ACCscript* script,
5067 ACCenum pname,
5068 ACCint * params) {
5069 switch (pname) {
5070 case ACC_INFO_LOG_LENGTH:
5071 *params = 0;
5072 break;
5073 }
5074}
5075
5076extern "C"
5077void accGetScriptInfoLog(ACCscript* script,
5078 ACCsizei maxLength,
5079 ACCsizei * length,
5080 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005081 char* message = script->compiler.getErrorMessage();
5082 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005083 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005084 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005085 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005086 if (infoLog && maxLength > 0) {
5087 int trimmedLength = maxLength < messageLength ?
5088 maxLength : messageLength;
5089 memcpy(infoLog, message, trimmedLength);
5090 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005091 }
5092}
5093
5094extern "C"
5095void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5096 ACCvoid ** address) {
5097 void* value = script->compiler.lookup(name);
5098 if (value) {
5099 *address = value;
5100 } else {
5101 script->setError(ACC_INVALID_VALUE);
5102 }
5103}
5104
Jack Palevicheedf9d22009-06-04 16:23:40 -07005105extern "C"
5106void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5107 ACCsizei maxStringCount, ACCchar** strings){
5108 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5109}
5110
-b master422972c2009-06-17 19:13:52 -07005111extern "C"
5112void accDisassemble(ACCscript* script) {
5113 script->compiler.disassemble(stderr);
5114}
5115
Jack Palevicheedf9d22009-06-04 16:23:40 -07005116
Jack Palevich1cdef202009-05-22 12:06:27 -07005117} // namespace acc
5118