blob: a21fd747b5a8a0e1c3a24ec3194019c776c46cd1 [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
Jack Palevich2ff5c222009-07-23 15:11:22 -07003219 Arena* mpCurrentArena;
3220
Jack Palevich569f1352009-06-29 14:29:08 -07003221 TokenTable mTokenTable;
3222 SymbolStack mGlobals;
3223 SymbolStack mLocals;
3224
Jack Palevich40600de2009-07-01 15:32:35 -07003225 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003226 Type* mkpInt; // int
3227 Type* mkpChar; // char
3228 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003229 Type* mkpFloat;
3230 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003231 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003232 Type* mkpIntPtr;
3233 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003234 Type* mkpFloatPtr;
3235 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003236 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003237
Jack Palevich36d94142009-06-08 15:55:32 -07003238 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003239 int mLineNumber;
3240 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003241
3242 CodeBuf codeBuf;
3243 CodeGenerator* pGen;
3244
Jack Palevicheedf9d22009-06-04 16:23:40 -07003245 String mErrorBuf;
3246
Jack Palevicheedf9d22009-06-04 16:23:40 -07003247 String mPragmas;
3248 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003249 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003250
Jack Palevich21a15a22009-05-11 14:49:29 -07003251 static const int ALLOC_SIZE = 99999;
3252
Jack Palevich303d8ff2009-06-11 19:06:24 -07003253 static const int TOK_DUMMY = 1;
3254 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003255 static const int TOK_NUM_FLOAT = 3;
3256 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003257
3258 // 3..255 are character and/or operators
3259
Jack Palevich2db168f2009-06-11 14:29:47 -07003260 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003261 // Order has to match string list in "internKeywords".
3262 enum {
3263 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3264 TOK_INT = TOK_KEYWORD,
3265 TOK_CHAR,
3266 TOK_VOID,
3267 TOK_IF,
3268 TOK_ELSE,
3269 TOK_WHILE,
3270 TOK_BREAK,
3271 TOK_RETURN,
3272 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003273 TOK_AUTO,
3274 TOK_CASE,
3275 TOK_CONST,
3276 TOK_CONTINUE,
3277 TOK_DEFAULT,
3278 TOK_DO,
3279 TOK_DOUBLE,
3280 TOK_ENUM,
3281 TOK_EXTERN,
3282 TOK_FLOAT,
3283 TOK_GOTO,
3284 TOK_LONG,
3285 TOK_REGISTER,
3286 TOK_SHORT,
3287 TOK_SIGNED,
3288 TOK_SIZEOF,
3289 TOK_STATIC,
3290 TOK_STRUCT,
3291 TOK_SWITCH,
3292 TOK_TYPEDEF,
3293 TOK_UNION,
3294 TOK_UNSIGNED,
3295 TOK_VOLATILE,
3296 TOK__BOOL,
3297 TOK__COMPLEX,
3298 TOK__IMAGINARY,
3299 TOK_INLINE,
3300 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003301
3302 // Symbols start after keywords
3303
3304 TOK_SYMBOL,
3305 TOK_PRAGMA = TOK_SYMBOL,
3306 TOK_DEFINE,
3307 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003308 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003309
3310 static const int LOCAL = 0x200;
3311
3312 static const int SYM_FORWARD = 0;
3313 static const int SYM_DEFINE = 1;
3314
3315 /* tokens in string heap */
3316 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003317
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003318 static const int OP_INCREMENT = 0;
3319 static const int OP_DECREMENT = 1;
3320 static const int OP_MUL = 2;
3321 static const int OP_DIV = 3;
3322 static const int OP_MOD = 4;
3323 static const int OP_PLUS = 5;
3324 static const int OP_MINUS = 6;
3325 static const int OP_SHIFT_LEFT = 7;
3326 static const int OP_SHIFT_RIGHT = 8;
3327 static const int OP_LESS_EQUAL = 9;
3328 static const int OP_GREATER_EQUAL = 10;
3329 static const int OP_LESS = 11;
3330 static const int OP_GREATER = 12;
3331 static const int OP_EQUALS = 13;
3332 static const int OP_NOT_EQUALS = 14;
3333 static const int OP_LOGICAL_AND = 15;
3334 static const int OP_LOGICAL_OR = 16;
3335 static const int OP_BIT_AND = 17;
3336 static const int OP_BIT_XOR = 18;
3337 static const int OP_BIT_OR = 19;
3338 static const int OP_BIT_NOT = 20;
3339 static const int OP_LOGICAL_NOT = 21;
3340 static const int OP_COUNT = 22;
3341
3342 /* Operators are searched from front, the two-character operators appear
3343 * before the single-character operators with the same first character.
3344 * @ is used to pad out single-character operators.
3345 */
3346 static const char* operatorChars;
3347 static const char operatorLevel[];
3348
Jack Palevich569f1352009-06-29 14:29:08 -07003349 /* Called when we detect an internal problem. Does nothing in production.
3350 *
3351 */
3352 void internalError() {
3353 * (char*) 0 = 0;
3354 }
3355
Jack Palevich86351982009-06-30 18:09:56 -07003356 void assert(bool isTrue) {
3357 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003358 internalError();
3359 }
Jack Palevich86351982009-06-30 18:09:56 -07003360 }
3361
Jack Palevich40600de2009-07-01 15:32:35 -07003362 bool isSymbol(tokenid_t t) {
3363 return t >= TOK_SYMBOL &&
3364 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3365 }
3366
3367 bool isSymbolOrKeyword(tokenid_t t) {
3368 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003369 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003370 }
3371
Jack Palevich86351982009-06-30 18:09:56 -07003372 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003373 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003374 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3375 if (pV && pV->tok != t) {
3376 internalError();
3377 }
3378 return pV;
3379 }
3380
3381 inline bool isDefined(tokenid_t t) {
3382 return t >= TOK_SYMBOL && VI(t) != 0;
3383 }
3384
Jack Palevich40600de2009-07-01 15:32:35 -07003385 const char* nameof(tokenid_t t) {
3386 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003387 return mTokenTable[t].pText;
3388 }
3389
Jack Palevich21a15a22009-05-11 14:49:29 -07003390 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003391 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003392 }
3393
3394 void inp() {
3395 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003396 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003397 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003398 dptr = 0;
3399 ch = dch;
3400 }
Jack Palevichdc456462009-07-16 16:50:56 -07003401 } else {
3402 if (mbBumpLine) {
3403 mLineNumber++;
3404 mbBumpLine = false;
3405 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003406 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003407 if (ch == '\n') {
3408 mbBumpLine = true;
3409 }
3410 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003411#if 0
3412 printf("ch='%c' 0x%x\n", ch, ch);
3413#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003414 }
3415
3416 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003417 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003418 }
3419
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003420 int decodeHex(int c) {
3421 if (isdigit(c)) {
3422 c -= '0';
3423 } else if (c <= 'F') {
3424 c = c - 'A' + 10;
3425 } else {
3426 c =c - 'a' + 10;
3427 }
3428 return c;
3429 }
3430
Jack Palevichb4758ff2009-06-12 12:49:14 -07003431 /* read a character constant, advances ch to after end of constant */
3432 int getq() {
3433 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003434 if (ch == '\\') {
3435 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003436 if (isoctal(ch)) {
3437 // 1 to 3 octal characters.
3438 val = 0;
3439 for(int i = 0; i < 3; i++) {
3440 if (isoctal(ch)) {
3441 val = (val << 3) + ch - '0';
3442 inp();
3443 }
3444 }
3445 return val;
3446 } else if (ch == 'x' || ch == 'X') {
3447 // N hex chars
3448 inp();
3449 if (! isxdigit(ch)) {
3450 error("'x' character escape requires at least one digit.");
3451 } else {
3452 val = 0;
3453 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003454 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003455 inp();
3456 }
3457 }
3458 } else {
3459 int val = ch;
3460 switch (ch) {
3461 case 'a':
3462 val = '\a';
3463 break;
3464 case 'b':
3465 val = '\b';
3466 break;
3467 case 'f':
3468 val = '\f';
3469 break;
3470 case 'n':
3471 val = '\n';
3472 break;
3473 case 'r':
3474 val = '\r';
3475 break;
3476 case 't':
3477 val = '\t';
3478 break;
3479 case 'v':
3480 val = '\v';
3481 break;
3482 case '\\':
3483 val = '\\';
3484 break;
3485 case '\'':
3486 val = '\'';
3487 break;
3488 case '"':
3489 val = '"';
3490 break;
3491 case '?':
3492 val = '?';
3493 break;
3494 default:
3495 error("Undefined character escape %c", ch);
3496 break;
3497 }
3498 inp();
3499 return val;
3500 }
3501 } else {
3502 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003503 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003504 return val;
3505 }
3506
3507 static bool isoctal(int ch) {
3508 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003509 }
3510
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003511 bool acceptCh(int c) {
3512 bool result = c == ch;
3513 if (result) {
3514 pdef(ch);
3515 inp();
3516 }
3517 return result;
3518 }
3519
3520 bool acceptDigitsCh() {
3521 bool result = false;
3522 while (isdigit(ch)) {
3523 result = true;
3524 pdef(ch);
3525 inp();
3526 }
3527 return result;
3528 }
3529
3530 void parseFloat() {
3531 tok = TOK_NUM_DOUBLE;
3532 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003533 if(mTokenString.len() == 0) {
3534 mTokenString.append('0');
3535 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003536 acceptCh('.');
3537 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003538 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003539 acceptCh('-') || acceptCh('+');
3540 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003541 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003542 if (ch == 'f' || ch == 'F') {
3543 tok = TOK_NUM_FLOAT;
3544 inp();
3545 } else if (ch == 'l' || ch == 'L') {
3546 inp();
3547 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003548 }
3549 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003550 char* pEnd = pText + strlen(pText);
3551 char* pEndPtr = 0;
3552 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003553 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003554 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003555 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003556 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003557 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003558 if (errno || pEndPtr != pEnd) {
3559 error("Can't parse constant: %s", pText);
3560 }
3561 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003562 }
3563
Jack Palevich21a15a22009-05-11 14:49:29 -07003564 void next() {
3565 int l, a;
3566
Jack Palevich546b2242009-05-13 15:10:04 -07003567 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003568 if (ch == '#') {
3569 inp();
3570 next();
3571 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003572 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003573 } else if (tok == TOK_PRAGMA) {
3574 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003575 } else if (tok == TOK_LINE) {
3576 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003577 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003578 error("Unsupported preprocessor directive \"%s\"",
3579 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003580 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003581 }
3582 inp();
3583 }
3584 tokl = 0;
3585 tok = ch;
3586 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003587 if (isdigit(ch) || ch == '.') {
3588 // Start of a numeric constant. Could be integer, float, or
3589 // double, won't know until we look further.
3590 mTokenString.clear();
3591 pdef(ch);
3592 inp();
3593 int base = 10;
3594 if (tok == '0') {
3595 if (ch == 'x' || ch == 'X') {
3596 base = 16;
3597 tok = TOK_NUM;
3598 tokc = 0;
3599 inp();
3600 while ( isxdigit(ch) ) {
3601 tokc = (tokc << 4) + decodeHex(ch);
3602 inp();
3603 }
3604 } else if (isoctal(ch)){
3605 base = 8;
3606 tok = TOK_NUM;
3607 tokc = 0;
3608 while ( isoctal(ch) ) {
3609 tokc = (tokc << 3) + (ch - '0');
3610 inp();
3611 }
3612 }
3613 } else if (isdigit(tok)){
3614 acceptDigitsCh();
3615 }
3616 if (base == 10) {
3617 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3618 parseFloat();
3619 } else {
3620 // It's an integer constant
3621 char* pText = mTokenString.getUnwrapped();
3622 char* pEnd = pText + strlen(pText);
3623 char* pEndPtr = 0;
3624 errno = 0;
3625 tokc = strtol(pText, &pEndPtr, base);
3626 if (errno || pEndPtr != pEnd) {
3627 error("Can't parse constant: %s %d %d", pText, base, errno);
3628 }
3629 tok = TOK_NUM;
3630 }
3631 }
3632 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003633 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003634 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003635 pdef(ch);
3636 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003637 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003638 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3639 // Is this a macro?
3640 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3641 if (pMacroDefinition) {
3642 // Yes, it is a macro
3643 dptr = pMacroDefinition;
3644 dch = ch;
3645 inp();
3646 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003647 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003648 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003649 inp();
3650 if (tok == '\'') {
3651 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003652 tokc = getq();
3653 if (ch != '\'') {
3654 error("Expected a ' character, got %c", ch);
3655 } else {
3656 inp();
3657 }
Jack Palevich546b2242009-05-13 15:10:04 -07003658 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003659 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003660 while (ch && ch != EOF) {
3661 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003662 inp();
3663 inp();
3664 if (ch == '/')
3665 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003666 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003667 if (ch == EOF) {
3668 error("End of file inside comment.");
3669 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003670 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003671 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003672 } else if ((tok == '/') & (ch == '/')) {
3673 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003674 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003675 inp();
3676 }
3677 inp();
3678 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003679 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003680 const char* t = operatorChars;
3681 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003682 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003683 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003684 tokl = operatorLevel[opIndex];
3685 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003686 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003687#if 0
3688 printf("%c%c -> tokl=%d tokc=0x%x\n",
3689 l, a, tokl, tokc);
3690#endif
3691 if (a == ch) {
3692 inp();
3693 tok = TOK_DUMMY; /* dummy token for double tokens */
3694 }
3695 break;
3696 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003697 opIndex++;
3698 }
3699 if (l == 0) {
3700 tokl = 0;
3701 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003702 }
3703 }
3704 }
3705#if 0
3706 {
Jack Palevich569f1352009-06-29 14:29:08 -07003707 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003708 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003709 fprintf(stderr, "%s\n", buf.getUnwrapped());
3710 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003711#endif
3712 }
3713
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003714 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003715 next();
3716 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003717 String* pName = new String();
3718 while (isspace(ch)) {
3719 inp();
3720 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003721 if (ch == '(') {
3722 delete pName;
3723 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003724 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003725 }
3726 while (isspace(ch)) {
3727 inp();
3728 }
Jack Palevich569f1352009-06-29 14:29:08 -07003729 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003730 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003731 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003732 inp();
3733 }
Jack Palevich569f1352009-06-29 14:29:08 -07003734 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3735 memcpy(pDefn, value.getUnwrapped(), value.len());
3736 pDefn[value.len()] = 0;
3737 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003738 }
3739
Jack Palevicheedf9d22009-06-04 16:23:40 -07003740 void doPragma() {
3741 // # pragma name(val)
3742 int state = 0;
3743 while(ch != EOF && ch != '\n' && state < 10) {
3744 switch(state) {
3745 case 0:
3746 if (isspace(ch)) {
3747 inp();
3748 } else {
3749 state++;
3750 }
3751 break;
3752 case 1:
3753 if (isalnum(ch)) {
3754 mPragmas.append(ch);
3755 inp();
3756 } else if (ch == '(') {
3757 mPragmas.append(0);
3758 inp();
3759 state++;
3760 } else {
3761 state = 11;
3762 }
3763 break;
3764 case 2:
3765 if (isalnum(ch)) {
3766 mPragmas.append(ch);
3767 inp();
3768 } else if (ch == ')') {
3769 mPragmas.append(0);
3770 inp();
3771 state = 10;
3772 } else {
3773 state = 11;
3774 }
3775 break;
3776 }
3777 }
3778 if(state != 10) {
3779 error("Unexpected pragma syntax");
3780 }
3781 mPragmaStringCount += 2;
3782 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003783
Jack Palevichdc456462009-07-16 16:50:56 -07003784 void doLine() {
3785 // # line number { "filename "}
3786 next();
3787 if (tok != TOK_NUM) {
3788 error("Expected a line-number");
3789 } else {
3790 mLineNumber = tokc-1; // The end-of-line will increment it.
3791 }
3792 while(ch != EOF && ch != '\n') {
3793 inp();
3794 }
3795 }
3796
Jack Palevichac0e95e2009-05-29 13:53:44 -07003797 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003798 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003799 mErrorBuf.vprintf(fmt, ap);
3800 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003801 }
3802
Jack Palevich8b0624c2009-05-20 12:12:06 -07003803 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003804 if (tok != c) {
3805 error("'%c' expected", c);
3806 }
3807 next();
3808 }
3809
Jack Palevich86351982009-06-30 18:09:56 -07003810 bool accept(intptr_t c) {
3811 if (tok == c) {
3812 next();
3813 return true;
3814 }
3815 return false;
3816 }
3817
Jack Palevich40600de2009-07-01 15:32:35 -07003818 bool acceptStringLiteral() {
3819 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003820 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003821 // This while loop merges multiple adjacent string constants.
3822 while (tok == '"') {
3823 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003824 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003825 }
3826 if (ch != '"') {
3827 error("Unterminated string constant.");
3828 }
3829 inp();
3830 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003831 }
Jack Palevich40600de2009-07-01 15:32:35 -07003832 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003833 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003834 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003835 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003836
3837 return true;
3838 }
3839 return false;
3840 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003841
Jack Palevichb1544ca2009-07-16 15:09:20 -07003842 void linkGlobal(tokenid_t t, bool isFunction) {
3843 VariableInfo* pVI = VI(t);
3844 void* n = NULL;
3845 if (mpSymbolLookupFn) {
3846 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3847 }
3848 if (pVI->pType == NULL) {
3849 if (isFunction) {
3850 pVI->pType = mkpIntFn;
3851 } else {
3852 pVI->pType = mkpInt;
3853 }
3854 }
3855 pVI->pAddress = n;
3856 }
3857
Jack Palevich40600de2009-07-01 15:32:35 -07003858 /* Parse and evaluate a unary expression.
3859 * allowAssignment is true if '=' parsing wanted (quick hack)
3860 */
3861 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003862 tokenid_t t;
3863 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003864 t = 0;
3865 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3866 if (acceptStringLiteral()) {
3867 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003868 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003869 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003870 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003871 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003872 t = tok;
3873 next();
3874 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003875 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003876 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003877 // Align to 4-byte boundary
3878 glo = (char*) (((intptr_t) glo + 3) & -4);
3879 * (float*) glo = (float) ad;
3880 pGen->loadFloat((int) glo, mkpFloat);
3881 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003882 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003883 // Align to 8-byte boundary
3884 glo = (char*) (((intptr_t) glo + 7) & -8);
3885 * (double*) glo = ad;
3886 pGen->loadFloat((int) glo, mkpDouble);
3887 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003888 } else if (c == 2) {
3889 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003890 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003892 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003893 else if (t == '+') {
3894 // ignore unary plus.
3895 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003896 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003897 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003898 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003899 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003900 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003901 if (pCast) {
3902 skip(')');
3903 unary(false);
3904 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003905 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003906 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003907 skip(')');
3908 }
3909 } else if (t == '*') {
3910 /* This is a pointer dereference.
3911 */
3912 unary(false);
3913 Type* pR0Type = pGen->getR0Type();
3914 if (pR0Type->tag != TY_POINTER) {
3915 error("Expected a pointer type.");
3916 } else {
3917 if (pR0Type->pHead->tag == TY_FUNC) {
3918 t = 0;
3919 }
3920 if (accept('=')) {
3921 pGen->pushR0();
3922 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003923 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07003924 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003925 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07003926 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003927 }
Jack Palevich3f226492009-07-02 14:46:19 -07003928 // Else we fall through to the function call below, with
3929 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003930 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003931 VariableInfo* pVI = VI(tok);
Jack Palevich2ff5c222009-07-23 15:11:22 -07003932 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType));
Jack Palevich21a15a22009-05-11 14:49:29 -07003933 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003934 } else if (t == EOF ) {
3935 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003936 } else if (t == ';') {
3937 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003938 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003939 // Don't have to do anything special here, the error
3940 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003941 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003942 if (!isDefined(t)) {
3943 mGlobals.add(t);
3944 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003945 }
Jack Palevich8df46192009-07-07 14:48:51 -07003946 VariableInfo* pVI = VI(t);
3947 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003948 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003949 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003950 linkGlobal(t, tok == '(');
3951 n = (intptr_t) pVI->pAddress;
3952 if (!n && tok != '(') {
3953 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003954 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003955 }
Jack Palevich40600de2009-07-01 15:32:35 -07003956 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003957 /* assignment */
3958 next();
3959 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003960 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003961 } else if (tok != '(') {
3962 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003963 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003964 linkGlobal(t, false);
3965 n = (intptr_t) pVI->pAddress;
3966 if (!n) {
3967 error("Undeclared variable %s\n", nameof(t));
3968 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003969 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07003970 // load a variable
3971 pGen->loadR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003972 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003973 // post inc / post dec
3974 pGen->pushR0();
3975 impInc(tokc);
3976 pGen->storeR0(n, pVI->pType);
3977 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07003978 next();
3979 }
3980 }
3981 }
3982 }
3983
3984 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003985 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003986 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003987 VariableInfo* pVI = NULL;
3988 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003989 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003990 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003991 } else {
3992 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003993 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003994 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003995 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003996 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003997 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003998 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003999 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004000 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004001 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004002 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004003 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004004 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004005 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004006 Type* pTargetType;
4007 if (pArgList) {
4008 pTargetType = pArgList->pHead;
4009 pArgList = pArgList->pTail;
4010 } else {
4011 pTargetType = pGen->getR0Type();
4012 if (pTargetType->tag == TY_FLOAT) {
4013 pTargetType = mkpDouble;
4014 }
4015 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004016 if (pTargetType->tag == TY_VOID) {
4017 error("Can't pass void value for argument %d",
4018 argCount + 1);
4019 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004020 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004021 }
Jack Palevich95727a02009-07-06 12:07:15 -07004022 if (accept(',')) {
4023 // fine
4024 } else if ( tok != ')') {
4025 error("Expected ',' or ')'");
4026 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004027 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004028 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004029 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004030 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004031 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004032 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004033 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004034 if (!n) {
4035 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004036 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4037 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004039 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004040 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004041 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4042 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004043 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004044 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004045 }
4046 }
4047
Jack Palevich58c30ee2009-07-17 16:35:23 -07004048 /* Increment / decrement R0 */
4049
4050 void impInc(int op) {
4051 Type* pType = pGen->getR0Type();
4052 int lit = 1;
4053 if (op == OP_DECREMENT) {
4054 lit = -1;
4055 }
4056 switch (pType->tag) {
4057 case TY_INT:
4058 case TY_CHAR:
4059 case TY_POINTER:
4060 pGen->pushR0();
4061 pGen->li(lit);
4062 pGen->genOp(OP_PLUS);
4063 break;
4064 default:
4065 error("++/-- illegal for this type.");
4066 break;
4067 }
4068 }
4069
Jack Palevich40600de2009-07-01 15:32:35 -07004070 /* Recursive descent parser for binary operations.
4071 */
4072 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004073 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004074 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004075 if (level-- == 1)
4076 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004077 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004078 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004079 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004080 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004081 t = tokc;
4082 next();
4083
Jack Palevich40600de2009-07-01 15:32:35 -07004084 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004085 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004086 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004087 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004088 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004089 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004090 // Check for syntax error.
4091 if (pGen->getR0Type() == NULL) {
4092 // We failed to parse a right-hand argument.
4093 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004094 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004095 }
Jack Palevich40600de2009-07-01 15:32:35 -07004096 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004097 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004098 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004099 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004100 }
4101 }
4102 }
4103 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004104 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004105 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004106 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07004107 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004108 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004109 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07004110 }
4111 }
4112 }
4113
4114 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004115 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004116 }
4117
4118 int test_expr() {
4119 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004120 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004121 }
4122
Jack Palevicha6baa232009-06-12 11:25:59 -07004123 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004124 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004125
Jack Palevich95727a02009-07-06 12:07:15 -07004126 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004127 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004128 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004129 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004130 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004131 next();
4132 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 a = test_expr();
4134 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004135 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004136 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004137 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004138 n = pGen->gjmp(0); /* jmp */
4139 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004140 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004141 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004142 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004143 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004144 }
Jack Palevich546b2242009-05-13 15:10:04 -07004145 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004146 t = tok;
4147 next();
4148 skip('(');
4149 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004150 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004151 a = test_expr();
4152 } else {
4153 if (tok != ';')
4154 expr();
4155 skip(';');
4156 n = codeBuf.getPC();
4157 a = 0;
4158 if (tok != ';')
4159 a = test_expr();
4160 skip(';');
4161 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004162 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004163 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004164 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004165 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004166 n = t + 4;
4167 }
4168 }
4169 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004170 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004171 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004172 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004173 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004174 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004175 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004176 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004177 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004178 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004179 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004180 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004181 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004182 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004183 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004184 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004185 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004186 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004187 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004188 if (pReturnType->tag == TY_VOID) {
4189 error("Must not return a value from a void function");
4190 } else {
4191 pGen->convertR0(pReturnType);
4192 }
4193 } else {
4194 if (pReturnType->tag != TY_VOID) {
4195 error("Must specify a value here");
4196 }
Jack Palevich8df46192009-07-07 14:48:51 -07004197 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004198 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004199 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004200 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004201 } else if (tok != ';')
4202 expr();
4203 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004204 }
4205 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004206
Jack Palevicha8f427f2009-07-13 18:40:08 -07004207 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004208 if (a == b) {
4209 return true;
4210 }
4211 if (a == NULL || b == NULL) {
4212 return false;
4213 }
4214 TypeTag at = a->tag;
4215 if (at != b->tag) {
4216 return false;
4217 }
4218 if (at == TY_POINTER) {
4219 return typeEqual(a->pHead, b->pHead);
4220 } else if (at == TY_FUNC || at == TY_PARAM) {
4221 return typeEqual(a->pHead, b->pHead)
4222 && typeEqual(a->pTail, b->pTail);
4223 }
4224 return true;
4225 }
4226
Jack Palevich2ff5c222009-07-23 15:11:22 -07004227 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004228 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004229 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004230 memset(pType, 0, sizeof(*pType));
4231 pType->tag = tag;
4232 pType->pHead = pHead;
4233 pType->pTail = pTail;
4234 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004235 }
4236
Jack Palevich2ff5c222009-07-23 15:11:22 -07004237 Type* createPtrType(Type* pType) {
4238 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004239 }
4240
4241 /**
4242 * Try to print a type in declaration order
4243 */
Jack Palevich86351982009-06-30 18:09:56 -07004244 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004245 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004246 if (pType == NULL) {
4247 buffer.appendCStr("null");
4248 return;
4249 }
Jack Palevich3f226492009-07-02 14:46:19 -07004250 decodeTypeImp(buffer, pType);
4251 }
4252
4253 void decodeTypeImp(String& buffer, Type* pType) {
4254 decodeTypeImpPrefix(buffer, pType);
4255
Jack Palevich86351982009-06-30 18:09:56 -07004256 String temp;
4257 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004258 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004259 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004260 }
4261
4262 decodeTypeImpPostfix(buffer, pType);
4263 }
4264
4265 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4266 TypeTag tag = pType->tag;
4267
Jack Palevich37c54bd2009-07-14 18:35:36 -07004268 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004269 switch (tag) {
4270 case TY_INT:
4271 buffer.appendCStr("int");
4272 break;
4273 case TY_CHAR:
4274 buffer.appendCStr("char");
4275 break;
4276 case TY_VOID:
4277 buffer.appendCStr("void");
4278 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004279 case TY_FLOAT:
4280 buffer.appendCStr("float");
4281 break;
4282 case TY_DOUBLE:
4283 buffer.appendCStr("double");
4284 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004285 default:
4286 break;
4287 }
Jack Palevich86351982009-06-30 18:09:56 -07004288 buffer.append(' ');
4289 }
Jack Palevich3f226492009-07-02 14:46:19 -07004290
4291 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004292 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004293 break;
4294 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004295 break;
4296 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004297 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004298 case TY_FLOAT:
4299 break;
4300 case TY_DOUBLE:
4301 break;
Jack Palevich86351982009-06-30 18:09:56 -07004302 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004303 decodeTypeImpPrefix(buffer, pType->pHead);
4304 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4305 buffer.append('(');
4306 }
4307 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004308 break;
4309 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004310 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004311 break;
4312 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004313 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004314 break;
4315 default:
4316 String temp;
4317 temp.printf("Unknown tag %d", pType->tag);
4318 buffer.append(temp);
4319 break;
4320 }
Jack Palevich3f226492009-07-02 14:46:19 -07004321 }
4322
4323 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4324 TypeTag tag = pType->tag;
4325
4326 switch(tag) {
4327 case TY_POINTER:
4328 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4329 buffer.append(')');
4330 }
4331 decodeTypeImpPostfix(buffer, pType->pHead);
4332 break;
4333 case TY_FUNC:
4334 buffer.append('(');
4335 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4336 decodeTypeImp(buffer, pArg);
4337 if (pArg->pTail) {
4338 buffer.appendCStr(", ");
4339 }
4340 }
4341 buffer.append(')');
4342 break;
4343 default:
4344 break;
Jack Palevich86351982009-06-30 18:09:56 -07004345 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004346 }
4347
Jack Palevich86351982009-06-30 18:09:56 -07004348 void printType(Type* pType) {
4349 String buffer;
4350 decodeType(buffer, pType);
4351 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004352 }
4353
Jack Palevich2ff5c222009-07-23 15:11:22 -07004354 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004355 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004356 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004357 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004358 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004359 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004360 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004361 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004362 } else if (tok == TOK_FLOAT) {
4363 pType = mkpFloat;
4364 } else if (tok == TOK_DOUBLE) {
4365 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004366 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004367 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004368 }
4369 next();
Jack Palevich86351982009-06-30 18:09:56 -07004370 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004371 }
4372
Jack Palevich2ff5c222009-07-23 15:11:22 -07004373 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004374 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 Palevich2ff5c222009-07-23 15:11:22 -07004377 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004378 if (declName) {
4379 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004380 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004381
Jack Palevich86351982009-06-30 18:09:56 -07004382 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004383 }
Jack Palevich3f226492009-07-02 14:46:19 -07004384 // fprintf(stderr, "Parsed a declaration: ");
4385 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004386 if (reportFailure) {
4387 return NULL;
4388 }
Jack Palevich86351982009-06-30 18:09:56 -07004389 return pType;
4390 }
4391
Jack Palevich2ff5c222009-07-23 15:11:22 -07004392 Type* expectDeclaration(Type* pBaseType) {
4393 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004394 if (! pType) {
4395 error("Expected a declaration");
4396 }
4397 return pType;
4398 }
4399
Jack Palevich3f226492009-07-02 14:46:19 -07004400 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004401 Type* acceptCastTypeDeclaration() {
4402 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004403 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004404 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004405 }
Jack Palevich86351982009-06-30 18:09:56 -07004406 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004407 }
4408
Jack Palevich2ff5c222009-07-23 15:11:22 -07004409 Type* expectCastTypeDeclaration() {
4410 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004411 if (! pType) {
4412 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004413 }
Jack Palevich3f226492009-07-02 14:46:19 -07004414 return pType;
4415 }
4416
4417 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004418 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004419 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004420 int ptrCounter = 0;
4421 while (accept('*')) {
4422 ptrCounter++;
4423 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004424 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004425 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004426 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004427 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004428 }
4429 return pType;
4430 }
4431
4432 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004433 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004434 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004435 // direct-dcl :
4436 // name
4437 // (dcl)
4438 // direct-dcl()
4439 // direct-dcl[]
4440 Type* pNewHead = NULL;
4441 if (accept('(')) {
4442 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004443 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004444 skip(')');
4445 } else if ((declName = acceptSymbol()) != 0) {
4446 if (nameAllowed == false && declName) {
4447 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004448 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004449 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004450 } else if (nameRequired && ! declName) {
4451 String temp;
4452 decodeToken(temp, tok, true);
4453 error("Expected name. Got %s", temp.getUnwrapped());
4454 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004455 }
4456 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004457 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004458 Type* pTail = acceptArgs(nameAllowed);
4459 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004460 skip(')');
4461 }
Jack Palevich3f226492009-07-02 14:46:19 -07004462
4463 if (pNewHead) {
4464 Type* pA = pNewHead;
4465 while (pA->pHead) {
4466 pA = pA->pHead;
4467 }
4468 pA->pHead = pType;
4469 pType = pNewHead;
4470 }
Jack Palevich86351982009-06-30 18:09:56 -07004471 return pType;
4472 }
4473
Jack Palevich2ff5c222009-07-23 15:11:22 -07004474 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004475 Type* pHead = NULL;
4476 Type* pTail = NULL;
4477 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004478 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004479 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004480 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004481 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004482 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004483 if (!pHead) {
4484 pHead = pParam;
4485 pTail = pParam;
4486 } else {
4487 pTail->pTail = pParam;
4488 pTail = pParam;
4489 }
4490 }
4491 }
4492 if (! accept(',')) {
4493 break;
4494 }
4495 }
4496 return pHead;
4497 }
4498
Jack Palevich2ff5c222009-07-23 15:11:22 -07004499 Type* expectPrimitiveType() {
4500 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004501 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004502 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004503 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004504 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004505 }
Jack Palevich86351982009-06-30 18:09:56 -07004506 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004507 }
4508
Jack Palevich86351982009-06-30 18:09:56 -07004509 void addGlobalSymbol(Type* pDecl) {
4510 tokenid_t t = pDecl->id;
4511 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004512 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004513 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004514 }
Jack Palevich86351982009-06-30 18:09:56 -07004515 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004516 }
4517
Jack Palevich86351982009-06-30 18:09:56 -07004518 void reportDuplicate(tokenid_t t) {
4519 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004520 }
4521
Jack Palevich86351982009-06-30 18:09:56 -07004522 void addLocalSymbol(Type* pDecl) {
4523 tokenid_t t = pDecl->id;
4524 if (mLocals.isDefinedAtCurrentLevel(t)) {
4525 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004526 }
Jack Palevich86351982009-06-30 18:09:56 -07004527 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004528 }
4529
Jack Palevich95727a02009-07-06 12:07:15 -07004530 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004531 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004532
Jack Palevich95727a02009-07-06 12:07:15 -07004533 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004534 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004535 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004536 if (!pDecl) {
4537 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004538 }
Jack Palevich86351982009-06-30 18:09:56 -07004539 int variableAddress = 0;
4540 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004541 size_t alignment = pGen->alignmentOf(pDecl);
4542 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004543 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004544 variableAddress = -loc;
4545 VI(pDecl->id)->pAddress = (void*) variableAddress;
4546 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004547 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004548 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004549 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004550 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004551 if (tok == ',')
4552 next();
4553 }
4554 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004555 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004556 }
4557 }
4558
Jack Palevichf1728be2009-06-12 13:53:51 -07004559 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004560 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004561 }
4562
Jack Palevich37c54bd2009-07-14 18:35:36 -07004563 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004564 if (token == EOF ) {
4565 buffer.printf("EOF");
4566 } else if (token == TOK_NUM) {
4567 buffer.printf("numeric constant");
4568 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004569 if (token < 32) {
4570 buffer.printf("'\\x%02x'", token);
4571 } else {
4572 buffer.printf("'%c'", token);
4573 }
Jack Palevich569f1352009-06-29 14:29:08 -07004574 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004575 if (quote) {
4576 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4577 buffer.printf("keyword \"%s\"", nameof(token));
4578 } else {
4579 buffer.printf("symbol \"%s\"", nameof(token));
4580 }
4581 } else {
4582 buffer.printf("%s", nameof(token));
4583 }
Jack Palevich569f1352009-06-29 14:29:08 -07004584 }
4585 }
4586
Jack Palevich40600de2009-07-01 15:32:35 -07004587 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004588 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004589 if (!result) {
4590 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004591 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004592 error("Expected symbol. Got %s", temp.getUnwrapped());
4593 }
4594 return result;
4595 }
4596
Jack Palevich86351982009-06-30 18:09:56 -07004597 tokenid_t acceptSymbol() {
4598 tokenid_t result = 0;
4599 if (tok >= TOK_SYMBOL) {
4600 result = tok;
4601 next();
Jack Palevich86351982009-06-30 18:09:56 -07004602 }
4603 return result;
4604 }
4605
Jack Palevichb7c81e92009-06-04 19:56:13 -07004606 void globalDeclarations() {
4607 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004608 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004609 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004610 break;
4611 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004612 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004613 if (!pDecl) {
4614 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004615 }
Jack Palevich86351982009-06-30 18:09:56 -07004616 if (! isDefined(pDecl->id)) {
4617 addGlobalSymbol(pDecl);
4618 }
4619 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004620 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004621 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004622 }
Jack Palevich86351982009-06-30 18:09:56 -07004623 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004624 // it's a variable declaration
4625 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004626 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004627 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004628 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004629 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004630 }
Jack Palevich86351982009-06-30 18:09:56 -07004631 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004632 if (tok == TOK_NUM) {
4633 if (name) {
4634 * (int*) name->pAddress = tokc;
4635 }
4636 next();
4637 } else {
4638 error("Expected an integer constant");
4639 }
4640 }
Jack Palevich86351982009-06-30 18:09:56 -07004641 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004642 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004643 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004644 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004645 if (!pDecl) {
4646 break;
4647 }
4648 if (! isDefined(pDecl->id)) {
4649 addGlobalSymbol(pDecl);
4650 }
4651 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004652 }
4653 skip(';');
4654 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004655 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004656 if (accept(';')) {
4657 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004658 } else if (tok != '{') {
4659 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004660 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004661 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004662 if (name) {
4663 /* patch forward references (XXX: does not work for function
4664 pointers) */
4665 pGen->gsym((int) name->pForward);
4666 /* put function address */
4667 name->pAddress = (void*) codeBuf.getPC();
4668 }
4669 // Calculate stack offsets for parameters
4670 mLocals.pushLevel();
4671 intptr_t a = 8;
4672 int argCount = 0;
4673 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4674 Type* pArg = pP->pHead;
4675 addLocalSymbol(pArg);
4676 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004677 size_t alignment = pGen->alignmentOf(pArg);
4678 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004679 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004680 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004681 argCount++;
4682 }
4683 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004684 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004685 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004686 block(0, true);
4687 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004688 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004689 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004690 mpCurrentArena = &mGlobalArena;
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 Palevich2ff5c222009-07-23 15:11:22 -07004808 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004809 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004810 cleanup();
4811 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004812 mTokenTable.setArena(&mGlobalArena);
4813 mGlobals.setArena(&mGlobalArena);
4814 mGlobals.setTokenTable(&mTokenTable);
4815 mLocals.setArena(&mLocalArena);
4816 mLocals.setTokenTable(&mTokenTable);
4817
4818 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004819 codeBuf.init(ALLOC_SIZE);
4820 setArchitecture(NULL);
4821 if (!pGen) {
4822 return -1;
4823 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004824#ifdef PROVIDE_TRACE_CODEGEN
4825 pGen = new TraceCodeGenerator(pGen);
4826#endif
4827 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004828 pGen->init(&codeBuf);
4829 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004830 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4831 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004832 inp();
4833 next();
4834 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004835 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004836 result = pGen->finishCompile();
4837 if (result == 0) {
4838 if (mErrorBuf.len()) {
4839 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004840 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004841 }
Jack Palevichce105a92009-07-16 14:30:33 -07004842 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004843 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004844 }
4845
Jack Palevich86351982009-06-30 18:09:56 -07004846 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004847 mkpInt = createType(TY_INT, NULL, NULL);
4848 mkpChar = createType(TY_CHAR, NULL, NULL);
4849 mkpVoid = createType(TY_VOID, NULL, NULL);
4850 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4851 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4852 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4853 mkpIntPtr = createPtrType(mkpInt);
4854 mkpCharPtr = createPtrType(mkpChar);
4855 mkpFloatPtr = createPtrType(mkpFloat);
4856 mkpDoublePtr = createPtrType(mkpDouble);
4857 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004858 }
4859
Jack Palevicha6baa232009-06-12 11:25:59 -07004860 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004861 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004862 }
4863
Jack Palevich569f1352009-06-29 14:29:08 -07004864 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004865 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004866 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004867 }
4868
Jack Palevich569f1352009-06-29 14:29:08 -07004869 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004870 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004871 error("Undefined forward reference: %s",
4872 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004873 }
4874 return true;
4875 }
4876
Jack Palevich21a15a22009-05-11 14:49:29 -07004877 int dump(FILE* out) {
4878 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4879 return 0;
4880 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004881
Jack Palevicha6535612009-05-13 16:24:17 -07004882 int disassemble(FILE* out) {
4883 return pGen->disassemble(out);
4884 }
4885
Jack Palevich1cdef202009-05-22 12:06:27 -07004886 /* Look through the symbol table to find a symbol.
4887 * If found, return its value.
4888 */
4889 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004890 if (mCompileResult == 0) {
4891 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4892 VariableInfo* pVariableInfo = VI(tok);
4893 if (pVariableInfo) {
4894 return pVariableInfo->pAddress;
4895 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004896 }
4897 return NULL;
4898 }
4899
Jack Palevicheedf9d22009-06-04 16:23:40 -07004900 void getPragmas(ACCsizei* actualStringCount,
4901 ACCsizei maxStringCount, ACCchar** strings) {
4902 int stringCount = mPragmaStringCount;
4903 if (actualStringCount) {
4904 *actualStringCount = stringCount;
4905 }
4906 if (stringCount > maxStringCount) {
4907 stringCount = maxStringCount;
4908 }
4909 if (strings) {
4910 char* pPragmas = mPragmas.getUnwrapped();
4911 while (stringCount-- > 0) {
4912 *strings++ = pPragmas;
4913 pPragmas += strlen(pPragmas) + 1;
4914 }
4915 }
4916 }
4917
Jack Palevichac0e95e2009-05-29 13:53:44 -07004918 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004919 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004920 }
4921
Jack Palevich77ae76e2009-05-10 19:59:24 -07004922};
4923
Jack Paleviche7b59062009-05-19 17:12:17 -07004924const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004925 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4926
Jack Paleviche7b59062009-05-19 17:12:17 -07004927const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004928 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4929 5, 5, /* ==, != */
4930 9, 10, /* &&, || */
4931 6, 7, 8, /* & ^ | */
4932 2, 2 /* ~ ! */
4933 };
4934
Jack Palevich8b0624c2009-05-20 12:12:06 -07004935#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004936FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004937#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004938
Jack Palevich8b0624c2009-05-20 12:12:06 -07004939#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004940const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004941 0x1, // ++
4942 0xff, // --
4943 0xc1af0f, // *
4944 0xf9f79991, // /
4945 0xf9f79991, // % (With manual assist to swap results)
4946 0xc801, // +
4947 0xd8f7c829, // -
4948 0xe0d391, // <<
4949 0xf8d391, // >>
4950 0xe, // <=
4951 0xd, // >=
4952 0xc, // <
4953 0xf, // >
4954 0x4, // ==
4955 0x5, // !=
4956 0x0, // &&
4957 0x1, // ||
4958 0xc821, // &
4959 0xc831, // ^
4960 0xc809, // |
4961 0xd0f7, // ~
4962 0x4 // !
4963};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004964#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004965
Jack Palevich1cdef202009-05-22 12:06:27 -07004966struct ACCscript {
4967 ACCscript() {
4968 text = 0;
4969 textLength = 0;
4970 accError = ACC_NO_ERROR;
4971 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004972
Jack Palevich1cdef202009-05-22 12:06:27 -07004973 ~ACCscript() {
4974 delete text;
4975 }
Jack Palevich546b2242009-05-13 15:10:04 -07004976
Jack Palevich8c246a92009-07-14 21:14:10 -07004977 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4978 compiler.registerSymbolCallback(pFn, pContext);
4979 }
4980
Jack Palevich1cdef202009-05-22 12:06:27 -07004981 void setError(ACCenum error) {
4982 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4983 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004984 }
4985 }
4986
Jack Palevich1cdef202009-05-22 12:06:27 -07004987 ACCenum getError() {
4988 ACCenum result = accError;
4989 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004990 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004991 }
4992
Jack Palevich1cdef202009-05-22 12:06:27 -07004993 Compiler compiler;
4994 char* text;
4995 int textLength;
4996 ACCenum accError;
4997};
4998
4999
5000extern "C"
5001ACCscript* accCreateScript() {
5002 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005003}
Jack Palevich1cdef202009-05-22 12:06:27 -07005004
5005extern "C"
5006ACCenum accGetError( ACCscript* script ) {
5007 return script->getError();
5008}
5009
5010extern "C"
5011void accDeleteScript(ACCscript* script) {
5012 delete script;
5013}
5014
5015extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005016void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5017 ACCvoid* pContext) {
5018 script->registerSymbolCallback(pFn, pContext);
5019}
5020
5021extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005022void accScriptSource(ACCscript* script,
5023 ACCsizei count,
5024 const ACCchar ** string,
5025 const ACCint * length) {
5026 int totalLength = 0;
5027 for(int i = 0; i < count; i++) {
5028 int len = -1;
5029 const ACCchar* s = string[i];
5030 if (length) {
5031 len = length[i];
5032 }
5033 if (len < 0) {
5034 len = strlen(s);
5035 }
5036 totalLength += len;
5037 }
5038 delete script->text;
5039 char* text = new char[totalLength + 1];
5040 script->text = text;
5041 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005042 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005043 for(int i = 0; i < count; i++) {
5044 int len = -1;
5045 const ACCchar* s = string[i];
5046 if (length) {
5047 len = length[i];
5048 }
5049 if (len < 0) {
5050 len = strlen(s);
5051 }
Jack Palevich09555c72009-05-27 12:25:55 -07005052 memcpy(dest, s, len);
5053 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005054 }
5055 text[totalLength] = '\0';
5056}
5057
5058extern "C"
5059void accCompileScript(ACCscript* script) {
5060 int result = script->compiler.compile(script->text, script->textLength);
5061 if (result) {
5062 script->setError(ACC_INVALID_OPERATION);
5063 }
5064}
5065
5066extern "C"
5067void accGetScriptiv(ACCscript* script,
5068 ACCenum pname,
5069 ACCint * params) {
5070 switch (pname) {
5071 case ACC_INFO_LOG_LENGTH:
5072 *params = 0;
5073 break;
5074 }
5075}
5076
5077extern "C"
5078void accGetScriptInfoLog(ACCscript* script,
5079 ACCsizei maxLength,
5080 ACCsizei * length,
5081 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005082 char* message = script->compiler.getErrorMessage();
5083 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005084 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005085 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005086 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005087 if (infoLog && maxLength > 0) {
5088 int trimmedLength = maxLength < messageLength ?
5089 maxLength : messageLength;
5090 memcpy(infoLog, message, trimmedLength);
5091 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005092 }
5093}
5094
5095extern "C"
5096void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5097 ACCvoid ** address) {
5098 void* value = script->compiler.lookup(name);
5099 if (value) {
5100 *address = value;
5101 } else {
5102 script->setError(ACC_INVALID_VALUE);
5103 }
5104}
5105
Jack Palevicheedf9d22009-06-04 16:23:40 -07005106extern "C"
5107void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5108 ACCsizei maxStringCount, ACCchar** strings){
5109 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5110}
5111
-b master422972c2009-06-17 19:13:52 -07005112extern "C"
5113void accDisassemble(ACCscript* script) {
5114 script->compiler.disassemble(stderr);
5115}
5116
Jack Palevicheedf9d22009-06-04 16:23:40 -07005117
Jack Palevich1cdef202009-05-22 12:06:27 -07005118} // namespace acc
5119