blob: 877cc4d547463f2e64e3d0b4ff6369a309689b1e [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 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700484 * Stack alignment of this type of data
485 */
486 virtual size_t stackAlignmentOf(Type* pType) = 0;
487
488 /**
489 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700490 */
491 virtual size_t stackSizeOf(Type* pType) = 0;
492
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700493 Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700494 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700495 }
496
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700497 ExpressionType getR0ExpressionType() {
498 return mExpressionStack.back().et;
499 }
500
501 void setR0ExpressionType(ExpressionType et) {
502 mExpressionStack.back().et = et;
503 }
504
Jack Palevich21a15a22009-05-11 14:49:29 -0700505 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700506 /*
507 * Output a byte. Handles all values, 0..ff.
508 */
509 void ob(int n) {
510 pCodeBuf->ob(n);
511 }
512
Jack Palevich8b0624c2009-05-20 12:12:06 -0700513 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700514 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700515 }
516
Jack Palevich8b0624c2009-05-20 12:12:06 -0700517 intptr_t getBase() {
518 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700519 }
520
Jack Palevich8b0624c2009-05-20 12:12:06 -0700521 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700522 return pCodeBuf->getPC();
523 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700524
525 intptr_t getSize() {
526 return pCodeBuf->getSize();
527 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700528
529 void error(const char* fmt,...) {
530 va_list ap;
531 va_start(ap, fmt);
532 mErrorSink->verror(fmt, ap);
533 va_end(ap);
534 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700535
536 void assert(bool test) {
537 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700538 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700539 error("code generator assertion failed.");
540 }
541 }
Jack Palevich8df46192009-07-07 14:48:51 -0700542
543 void setR0Type(Type* pType) {
Jack Palevichba929a42009-07-17 10:20:32 -0700544 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700545 }
546
Jack Palevich8df46192009-07-07 14:48:51 -0700547 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700548 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700549 }
550
551 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700552 if (mExpressionStack.size()) {
553 mExpressionStack.push_back(mExpressionStack.back());
554 } else {
555 mExpressionStack.push_back(ExpressionValue());
556 }
557
Jack Palevich8df46192009-07-07 14:48:51 -0700558 }
559
560 void popType() {
561 mExpressionStack.pop_back();
562 }
563
564 bool bitsSame(Type* pA, Type* pB) {
565 return collapseType(pA->tag) == collapseType(pB->tag);
566 }
567
568 TypeTag collapseType(TypeTag tag) {
569 static const TypeTag collapsedTag[] = {
570 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
571 TY_VOID, TY_VOID};
572 return collapsedTag[tag];
573 }
574
Jack Palevich1a539db2009-07-08 13:04:41 -0700575 TypeTag collapseTypeR0() {
576 return collapseType(getR0Type()->tag);
577 }
578
579 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700580 return isFloatTag(pType->tag);
581 }
582
583 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700584 return tag == TY_FLOAT || tag == TY_DOUBLE;
585 }
586
Jack Palevicha8f427f2009-07-13 18:40:08 -0700587 Type* mkpInt;
588
Jack Palevich21a15a22009-05-11 14:49:29 -0700589 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700590 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700591 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700592 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700593 };
594
Jack Paleviche7b59062009-05-19 17:12:17 -0700595#ifdef PROVIDE_ARM_CODEGEN
596
Jack Palevich22305132009-05-13 10:58:45 -0700597 class ARMCodeGenerator : public CodeGenerator {
598 public:
599 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700600
Jack Palevich22305132009-05-13 10:58:45 -0700601 virtual ~ARMCodeGenerator() {}
602
603 /* returns address to patch with local variable size
604 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700605 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700606 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700607 // sp -> arg4 arg5 ...
608 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700609 int regArgCount = calcRegArgCount(pDecl);
610 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700611 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700612 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700613 }
614 // sp -> arg0 arg1 ...
615 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700616 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700617 // sp, fp -> oldfp, retadr, arg0 arg1 ....
618 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700619 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700620 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700621 // We don't know how many local variables we are going to use,
622 // but we will round the allocation up to a multiple of
623 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700624 }
625
Jack Palevichb7718b92009-07-09 22:00:24 -0700626 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700627 // Round local variable size up to a multiple of stack alignment
628 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
629 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700630 // Patch local variable allocation code:
631 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700632 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700633 }
Jack Palevich69796b62009-05-14 15:42:26 -0700634 *(char*) (localVariableAddress) = localVariableSize;
635
636 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
637 o4(0xE1A0E00B); // mov lr, fp
638 o4(0xE59BB000); // ldr fp, [fp]
639 o4(0xE28ED004); // add sp, lr, #4
640 // sp -> retadr, arg0, ...
641 o4(0xE8BD4000); // ldmfd sp!, {lr}
642 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700643
644 // We store the PC into the lr so we can adjust the sp before
645 // returning. We need to pull off the registers we pushed
646 // earlier. We don't need to actually store them anywhere,
647 // just adjust the stack.
648 int regArgCount = calcRegArgCount(pDecl);
649 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700650 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
651 }
652 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700653 }
654
655 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700656 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700657 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700658 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700659 }
660
Jack Palevich1a539db2009-07-08 13:04:41 -0700661 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700662 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700663 // Global, absolute address
664 o4(0xE59F0000); // ldr r0, .L1
665 o4(0xEA000000); // b .L99
666 o4(address); // .L1: .word ea
667 // .L99:
668
669 switch (pType->tag) {
670 case TY_FLOAT:
671 o4(0xE5900000); // ldr r0, [r0]
672 break;
673 case TY_DOUBLE:
674 o4(0xE1C000D0); // ldrd r0, [r0]
675 break;
676 default:
677 assert(false);
678 break;
679 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700680 }
681
Jack Palevich22305132009-05-13 10:58:45 -0700682 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700683 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700684 }
685
686 /* l = 0: je, l == 1: jne */
687 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700688 Type* pR0Type = getR0Type();
689 TypeTag tagR0 = pR0Type->tag;
690 switch(tagR0) {
691 case TY_FLOAT:
692 callRuntime((void*) runtime_is_non_zero_f);
693 break;
694 case TY_DOUBLE:
695 callRuntime((void*) runtime_is_non_zero_d);
696 break;
697 default:
698 break;
699 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700700 o4(0xE3500000); // cmp r0,#0
701 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
702 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700703 }
704
Jack Palevich58c30ee2009-07-17 16:35:23 -0700705 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700706 Type* pR0Type = getR0Type();
707 Type* pTOSType = getTOSType();
708 TypeTag tagR0 = collapseType(pR0Type->tag);
709 TypeTag tagTOS = collapseType(pTOSType->tag);
710 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700711 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700712 o4(0xE1510000); // cmp r1, r1
713 switch(op) {
714 case OP_EQUALS:
715 o4(0x03A00001); // moveq r0,#1
716 o4(0x13A00000); // movne r0,#0
717 break;
718 case OP_NOT_EQUALS:
719 o4(0x03A00000); // moveq r0,#0
720 o4(0x13A00001); // movne r0,#1
721 break;
722 case OP_LESS_EQUAL:
723 o4(0xD3A00001); // movle r0,#1
724 o4(0xC3A00000); // movgt r0,#0
725 break;
726 case OP_GREATER:
727 o4(0xD3A00000); // movle r0,#0
728 o4(0xC3A00001); // movgt r0,#1
729 break;
730 case OP_GREATER_EQUAL:
731 o4(0xA3A00001); // movge r0,#1
732 o4(0xB3A00000); // movlt r0,#0
733 break;
734 case OP_LESS:
735 o4(0xA3A00000); // movge r0,#0
736 o4(0xB3A00001); // movlt r0,#1
737 break;
738 default:
739 error("Unknown comparison op %d", op);
740 break;
741 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700742 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
743 setupDoubleArgs();
744 switch(op) {
745 case OP_EQUALS:
746 callRuntime((void*) runtime_cmp_eq_dd);
747 break;
748 case OP_NOT_EQUALS:
749 callRuntime((void*) runtime_cmp_ne_dd);
750 break;
751 case OP_LESS_EQUAL:
752 callRuntime((void*) runtime_cmp_le_dd);
753 break;
754 case OP_GREATER:
755 callRuntime((void*) runtime_cmp_gt_dd);
756 break;
757 case OP_GREATER_EQUAL:
758 callRuntime((void*) runtime_cmp_ge_dd);
759 break;
760 case OP_LESS:
761 callRuntime((void*) runtime_cmp_lt_dd);
762 break;
763 default:
764 error("Unknown comparison op %d", op);
765 break;
766 }
767 } else {
768 setupFloatArgs();
769 switch(op) {
770 case OP_EQUALS:
771 callRuntime((void*) runtime_cmp_eq_ff);
772 break;
773 case OP_NOT_EQUALS:
774 callRuntime((void*) runtime_cmp_ne_ff);
775 break;
776 case OP_LESS_EQUAL:
777 callRuntime((void*) runtime_cmp_le_ff);
778 break;
779 case OP_GREATER:
780 callRuntime((void*) runtime_cmp_gt_ff);
781 break;
782 case OP_GREATER_EQUAL:
783 callRuntime((void*) runtime_cmp_ge_ff);
784 break;
785 case OP_LESS:
786 callRuntime((void*) runtime_cmp_lt_ff);
787 break;
788 default:
789 error("Unknown comparison op %d", op);
790 break;
791 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700792 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700793 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700794 }
795
Jack Palevich546b2242009-05-13 15:10:04 -0700796 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700797 Type* pR0Type = getR0Type();
798 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700799 TypeTag tagR0 = pR0Type->tag;
800 TypeTag tagTOS = pTOSType->tag;
801 bool isFloatR0 = isFloatTag(tagR0);
802 bool isFloatTOS = isFloatTag(tagTOS);
803 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700804 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700805 bool isPtrR0 = tagR0 == TY_POINTER;
806 bool isPtrTOS = tagTOS == TY_POINTER;
807 if (isPtrR0 || isPtrTOS) {
808 if (isPtrR0 && isPtrTOS) {
809 if (op != OP_MINUS) {
810 error("Unsupported pointer-pointer operation %d.", op);
811 }
812 if (! typeEqual(pR0Type, pTOSType)) {
813 error("Incompatible pointer types for subtraction.");
814 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700815 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700816 setR0Type(mkpInt);
817 int size = sizeOf(pR0Type->pHead);
818 if (size != 1) {
819 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700820 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700821 // TODO: Optimize for power-of-two.
822 genOp(OP_DIV);
823 }
824 } else {
825 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
826 error("Unsupported pointer-scalar operation %d", op);
827 }
828 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700829 int size = sizeOf(pPtrType->pHead);
830 if (size != 1) {
831 // TODO: Optimize for power-of-two.
832 liReg(size, 2);
833 if (isPtrR0) {
834 o4(0x0E0010192); // mul r1,r2,r1
835 } else {
836 o4(0x0E0000092); // mul r0,r2,r0
837 }
838 }
839 switch(op) {
840 case OP_PLUS:
841 o4(0xE0810000); // add r0,r1,r0
842 break;
843 case OP_MINUS:
844 o4(0xE0410000); // sub r0,r1,r0
845 break;
846 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700847 setR0Type(pPtrType);
848 }
849 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700850 switch(op) {
851 case OP_MUL:
852 o4(0x0E0000091); // mul r0,r1,r0
853 break;
854 case OP_DIV:
855 callRuntime((void*) runtime_DIV);
856 break;
857 case OP_MOD:
858 callRuntime((void*) runtime_MOD);
859 break;
860 case OP_PLUS:
861 o4(0xE0810000); // add r0,r1,r0
862 break;
863 case OP_MINUS:
864 o4(0xE0410000); // sub r0,r1,r0
865 break;
866 case OP_SHIFT_LEFT:
867 o4(0xE1A00011); // lsl r0,r1,r0
868 break;
869 case OP_SHIFT_RIGHT:
870 o4(0xE1A00051); // asr r0,r1,r0
871 break;
872 case OP_BIT_AND:
873 o4(0xE0010000); // and r0,r1,r0
874 break;
875 case OP_BIT_XOR:
876 o4(0xE0210000); // eor r0,r1,r0
877 break;
878 case OP_BIT_OR:
879 o4(0xE1810000); // orr r0,r1,r0
880 break;
881 case OP_BIT_NOT:
882 o4(0xE1E00000); // mvn r0, r0
883 break;
884 default:
885 error("Unimplemented op %d\n", op);
886 break;
887 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700888 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700889 } else {
890 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
891 if (pResultType->tag == TY_DOUBLE) {
892 setupDoubleArgs();
893 switch(op) {
894 case OP_MUL:
895 callRuntime((void*) runtime_op_mul_dd);
896 break;
897 case OP_DIV:
898 callRuntime((void*) runtime_op_div_dd);
899 break;
900 case OP_PLUS:
901 callRuntime((void*) runtime_op_add_dd);
902 break;
903 case OP_MINUS:
904 callRuntime((void*) runtime_op_sub_dd);
905 break;
906 default:
907 error("Unsupported binary floating operation %d\n", op);
908 break;
909 }
910 } else {
911 setupFloatArgs();
912 switch(op) {
913 case OP_MUL:
914 callRuntime((void*) runtime_op_mul_ff);
915 break;
916 case OP_DIV:
917 callRuntime((void*) runtime_op_div_ff);
918 break;
919 case OP_PLUS:
920 callRuntime((void*) runtime_op_add_ff);
921 break;
922 case OP_MINUS:
923 callRuntime((void*) runtime_op_sub_ff);
924 break;
925 default:
926 error("Unsupported binary floating operation %d\n", op);
927 break;
928 }
929 }
930 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700931 }
Jack Palevich22305132009-05-13 10:58:45 -0700932 }
933
Jack Palevich58c30ee2009-07-17 16:35:23 -0700934 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700935 if (op != OP_LOGICAL_NOT) {
936 error("Unknown unary cmp %d", op);
937 } else {
938 Type* pR0Type = getR0Type();
939 TypeTag tag = collapseType(pR0Type->tag);
940 switch(tag) {
941 case TY_INT:
942 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700943 o4(0xE1510000); // cmp r1, r0
944 o4(0x03A00001); // moveq r0,#1
945 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700946 break;
947 case TY_FLOAT:
948 callRuntime((void*) runtime_is_zero_f);
949 break;
950 case TY_DOUBLE:
951 callRuntime((void*) runtime_is_zero_d);
952 break;
953 default:
954 error("gUnaryCmp unsupported type");
955 break;
956 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700957 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700958 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700959 }
960
961 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700962 Type* pR0Type = getR0Type();
963 TypeTag tag = collapseType(pR0Type->tag);
964 switch(tag) {
965 case TY_INT:
966 switch(op) {
967 case OP_MINUS:
968 o4(0xE3A01000); // mov r1, #0
969 o4(0xE0410000); // sub r0,r1,r0
970 break;
971 case OP_BIT_NOT:
972 o4(0xE1E00000); // mvn r0, r0
973 break;
974 default:
975 error("Unknown unary op %d\n", op);
976 break;
977 }
978 break;
979 case TY_FLOAT:
980 case TY_DOUBLE:
981 switch (op) {
982 case OP_MINUS:
983 if (tag == TY_FLOAT) {
984 callRuntime((void*) runtime_op_neg_f);
985 } else {
986 callRuntime((void*) runtime_op_neg_d);
987 }
988 break;
989 case OP_BIT_NOT:
990 error("Can't apply '~' operator to a float or double.");
991 break;
992 default:
993 error("Unknown unary op %d\n", op);
994 break;
995 }
996 break;
997 default:
998 error("genUnaryOp unsupported type");
999 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001000 }
Jack Palevich22305132009-05-13 10:58:45 -07001001 }
1002
Jack Palevich1cdef202009-05-22 12:06:27 -07001003 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001004 Type* pR0Type = getR0Type();
1005 TypeTag r0ct = collapseType(pR0Type->tag);
1006 if (r0ct != TY_DOUBLE) {
1007 o4(0xE92D0001); // stmfd sp!,{r0}
1008 mStackUse += 4;
1009 } else {
1010 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1011 mStackUse += 8;
1012 }
Jack Palevich8df46192009-07-07 14:48:51 -07001013 pushType();
-b master422972c2009-06-17 19:13:52 -07001014 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001015 }
1016
Jack Palevich58c30ee2009-07-17 16:35:23 -07001017 virtual void popR0() {
1018 Type* pTOSType = getTOSType();
1019 switch (collapseType(pTOSType->tag)){
1020 case TY_INT:
1021 case TY_FLOAT:
1022 o4(0xE8BD0001); // ldmfd sp!,{r0}
1023 mStackUse -= 4;
1024 break;
1025 case TY_DOUBLE:
1026 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1027 mStackUse -= 8;
1028 break;
1029 default:
1030 error("Can't pop this type.");
1031 break;
1032 }
1033 popType();
1034 LOG_STACK("popR0: %d\n", mStackUse);
1035 }
1036
1037 virtual void storeR0ToTOS() {
1038 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001039 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001040 o4(0xE8BD0004); // ldmfd sp!,{r2}
1041 popType();
-b master422972c2009-06-17 19:13:52 -07001042 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001043 switch (pPointerType->pHead->tag) {
1044 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 case TY_FLOAT:
1046 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001047 break;
1048 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001049 o4(0xE5C20000); // strb r0, [r2]
1050 break;
1051 case TY_DOUBLE:
1052 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001053 break;
1054 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001055 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001056 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001057 }
Jack Palevich22305132009-05-13 10:58:45 -07001058 }
1059
Jack Palevich58c30ee2009-07-17 16:35:23 -07001060 virtual void loadR0FromR0() {
1061 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001062 assert(pPointerType->tag == TY_POINTER);
1063 switch (pPointerType->pHead->tag) {
1064 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001065 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001066 o4(0xE5900000); // ldr r0, [r0]
1067 break;
1068 case TY_CHAR:
1069 o4(0xE5D00000); // ldrb r0, [r0]
1070 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001071 case TY_DOUBLE:
1072 o4(0xE1C000D0); // ldrd r0, [r0]
1073 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001074 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001075 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001076 break;
1077 }
Jack Palevich8df46192009-07-07 14:48:51 -07001078 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001079 }
1080
Jack Palevich8df46192009-07-07 14:48:51 -07001081 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001082 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001083 // Local, fp relative
1084 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1085 error("Offset out of range: %08x", ea);
1086 }
1087 if (ea < 0) {
1088 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1089 } else {
1090 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1091 }
Jack Palevichbd894902009-05-14 19:35:31 -07001092 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001093 // Global, absolute.
1094 o4(0xE59F0000); // ldr r0, .L1
1095 o4(0xEA000000); // b .L99
1096 o4(ea); // .L1: .word 0
1097 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001098 }
Jack Palevich8df46192009-07-07 14:48:51 -07001099 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001100 }
1101
Jack Palevich9cbd2262009-07-08 16:48:41 -07001102 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001103 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 TypeTag tag = pType->tag;
1105 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001106 case TY_CHAR:
1107 if (ea > -LOCAL && ea < LOCAL) {
1108 // Local, fp relative
1109 if (ea < -4095 || ea > 4095) {
1110 error("Offset out of range: %08x", ea);
1111 }
1112 if (ea < 0) {
1113 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1114 } else {
1115 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1116 }
1117 } else{
1118 // Global, absolute
1119 o4(0xE59F1000); // ldr r1, .L1
1120 o4(0xEA000000); // b .L99
1121 o4(ea); // .L1: .word 0
1122 o4(0xE5C10000); // .L99: strb r0, [r1]
1123 }
1124 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001125 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001126 case TY_INT:
1127 case TY_FLOAT:
1128 if (ea > -LOCAL && ea < LOCAL) {
1129 // Local, fp relative
1130 if (ea < -4095 || ea > 4095) {
1131 error("Offset out of range: %08x", ea);
1132 }
1133 if (ea < 0) {
1134 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1135 } else {
1136 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1137 }
1138 } else{
1139 // Global, absolute
1140 o4(0xE59F1000); // ldr r1, .L1
1141 o4(0xEA000000); // b .L99
1142 o4(ea); // .L1: .word 0
1143 o4(0xE5810000); // .L99: str r0, [r1]
1144 }
1145 break;
1146 case TY_DOUBLE:
1147 if ((ea & 0x7) != 0) {
1148 error("double address is not aligned: %d", ea);
1149 }
1150 if (ea > -LOCAL && ea < LOCAL) {
1151 // Local, fp relative
1152 if (ea < -4095 || ea > 4095) {
1153 error("Offset out of range: %08x", ea);
1154 }
1155 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001156 o4(0xE50B0000 | (0xfff & (4-ea))); // str r0, [fp,#-ea]
1157 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001158#if 0
1159 // strd doesn't seem to work. Is encoding wrong?
1160 } else if (ea < 0) {
1161 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1162 } else if (ea < 256) {
1163 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1164#endif
1165 } else {
1166 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1167 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1168 }
1169 } else{
1170 // Global, absolute
1171 o4(0xE59F2000); // ldr r2, .L1
1172 o4(0xEA000000); // b .L99
1173 o4(ea); // .L1: .word 0
1174 o4(0xE1C200F0); // .L99: strd r0, [r2]
1175 }
1176 break;
1177 default:
1178 error("Unable to store to type %d", tag);
1179 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001180 }
Jack Palevich22305132009-05-13 10:58:45 -07001181 }
1182
Jack Palevich58c30ee2009-07-17 16:35:23 -07001183 virtual void loadR0(int ea, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001184 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001185 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001186 case TY_CHAR:
1187 if (ea < LOCAL) {
1188 // Local, fp relative
1189 if (ea < -4095 || ea > 4095) {
1190 error("Offset out of range: %08x", ea);
1191 }
1192 if (ea < 0) {
1193 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1194 } else {
1195 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1196 }
1197 } else {
1198 // Global, absolute
1199 o4(0xE59F2000); // ldr r2, .L1
1200 o4(0xEA000000); // b .L99
1201 o4(ea); // .L1: .word ea
1202 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1203 }
Jack Palevich25c0cca2009-07-13 16:56:28 -07001204 break;
1205 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001206 case TY_INT:
1207 case TY_FLOAT:
1208 if (ea < LOCAL) {
1209 // Local, fp relative
1210 if (ea < -4095 || ea > 4095) {
1211 error("Offset out of range: %08x", ea);
1212 }
1213 if (ea < 0) {
1214 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1215 } else {
1216 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1217 }
1218 } else {
1219 // Global, absolute
1220 o4(0xE59F2000); // ldr r2, .L1
1221 o4(0xEA000000); // b .L99
1222 o4(ea); // .L1: .word ea
1223 o4(0xE5920000); // .L99: ldr r0, [r2]
1224 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001225 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001226 case TY_DOUBLE:
1227 if ((ea & 0x7) != 0) {
1228 error("double address is not aligned: %d", ea);
1229 }
1230 if (ea < LOCAL) {
1231 // Local, fp relative
1232 if (ea < -4095 || ea > 4095) {
1233 error("Offset out of range: %08x", ea);
1234 }
1235 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001236 o4(0xE51B0000 | (0xfff & (4-ea))); // ldr r0, [fp,#-ea]
1237 o4(0xE51B1000 | (0xfff & (-ea))); // ldr r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001238 } else {
1239 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1240 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1241 }
1242 } else {
1243 // Global, absolute
1244 o4(0xE59F2000); // ldr r2, .L1
1245 o4(0xEA000000); // b .L99
1246 o4(ea); // .L1: .word ea
1247 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1248 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001249 break;
1250 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001251 error("Unable to load type %d", tag);
1252 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001253 }
Jack Palevich8df46192009-07-07 14:48:51 -07001254 setR0Type(pType);
1255 }
1256
1257 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001258 Type* pR0Type = getR0Type();
1259 if (bitsSame(pType, pR0Type)) {
1260 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001261 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001262 TypeTag r0Tag = collapseType(pR0Type->tag);
1263 TypeTag destTag = collapseType(pType->tag);
1264 if (r0Tag == TY_INT) {
1265 if (destTag == TY_FLOAT) {
1266 callRuntime((void*) runtime_int_to_float);
1267 } else {
1268 assert(destTag == TY_DOUBLE);
1269 callRuntime((void*) runtime_int_to_double);
1270 }
1271 } else if (r0Tag == TY_FLOAT) {
1272 if (destTag == TY_INT) {
1273 callRuntime((void*) runtime_float_to_int);
1274 } else {
1275 assert(destTag == TY_DOUBLE);
1276 callRuntime((void*) runtime_float_to_double);
1277 }
1278 } else {
1279 assert (r0Tag == TY_DOUBLE);
1280 if (destTag == TY_INT) {
1281 callRuntime((void*) runtime_double_to_int);
1282 } else {
1283 assert(destTag == TY_FLOAT);
1284 callRuntime((void*) runtime_double_to_float);
1285 }
1286 }
Jack Palevich8df46192009-07-07 14:48:51 -07001287 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001288 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001289 }
1290
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001291 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001292 return o4(0xE24DDF00); // Placeholder
1293 }
1294
Jack Palevich8148c5b2009-07-16 18:24:47 -07001295 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001296 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001297 Type* pR0Type = getR0Type();
1298 TypeTag r0ct = collapseType(pR0Type->tag);
1299 switch(r0ct) {
1300 case TY_INT:
1301 case TY_FLOAT:
1302 if (l < 0 || l > 4096-4) {
1303 error("l out of range for stack offset: 0x%08x", l);
1304 }
1305 o4(0xE58D0000 + l); // str r0, [sp, #l]
1306 return 4;
1307 case TY_DOUBLE: {
1308 // Align to 8 byte boundary
1309 int l2 = (l + 7) & ~7;
1310 if (l2 < 0 || l2 > 4096-8) {
1311 error("l out of range for stack offset: 0x%08x", l);
1312 }
1313 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1314 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1315 return (l2 - l) + 8;
1316 }
1317 default:
1318 assert(false);
1319 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001320 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001321 }
1322
Jack Palevichb7718b92009-07-09 22:00:24 -07001323 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001324 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001325 // Have to calculate register arg count from actual stack size,
1326 // in order to properly handle ... functions.
1327 int regArgCount = l >> 2;
1328 if (regArgCount > 4) {
1329 regArgCount = 4;
1330 }
1331 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001332 argumentStackUse -= regArgCount * 4;
1333 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1334 }
1335 mStackUse += argumentStackUse;
1336
1337 // Align stack.
1338 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1339 * STACK_ALIGNMENT);
1340 mStackAlignmentAdjustment = 0;
1341 if (missalignment > 0) {
1342 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1343 }
1344 l += mStackAlignmentAdjustment;
1345
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001346 if (l < 0 || l > 0x3FC) {
1347 error("L out of range for stack adjustment: 0x%08x", l);
1348 }
1349 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001350 mStackUse += mStackAlignmentAdjustment;
1351 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1352 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001353 }
1354
Jack Palevich8df46192009-07-07 14:48:51 -07001355 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001356 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001357 // Forward calls are always short (local)
1358 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001359 }
1360
Jack Palevich8df46192009-07-07 14:48:51 -07001361 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001362 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001363 int abs = t + getPC() + jumpOffset();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001364 if (t >= - (1 << 25) && t < (1 << 25)) {
1365 o4(0xEB000000 | encodeAddress(t));
1366 } else {
1367 // Long call.
1368 o4(0xE59FC000); // ldr r12, .L1
1369 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001370 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001371 o4(0xE08CC00F); // .L99: add r12,pc
1372 o4(0xE12FFF3C); // blx r12
1373 }
Jack Palevich22305132009-05-13 10:58:45 -07001374 }
1375
Jack Palevich8df46192009-07-07 14:48:51 -07001376 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001377 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001378 int argCount = l >> 2;
1379 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001380 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001381 if (adjustedL < 0 || adjustedL > 4096-4) {
1382 error("l out of range for stack offset: 0x%08x", l);
1383 }
1384 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1385 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001386 }
1387
Jack Palevichb7718b92009-07-09 22:00:24 -07001388 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001389 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001390 // Have to calculate register arg count from actual stack size,
1391 // in order to properly handle ... functions.
1392 int regArgCount = l >> 2;
1393 if (regArgCount > 4) {
1394 regArgCount = 4;
1395 }
1396 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001397 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1398 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001399 if (stackUse) {
1400 if (stackUse < 0 || stackUse > 255) {
1401 error("L out of range for stack adjustment: 0x%08x", l);
1402 }
1403 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001404 mStackUse -= stackUse * 4;
1405 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001406 }
Jack Palevich22305132009-05-13 10:58:45 -07001407 }
1408
Jack Palevicha6535612009-05-13 16:24:17 -07001409 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001410 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001411 }
1412
1413 /* output a symbol and patch all calls to it */
1414 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001415 int n;
1416 int base = getBase();
1417 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001418 while (t) {
1419 int data = * (int*) t;
1420 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1421 if (decodedOffset == 0) {
1422 n = 0;
1423 } else {
1424 n = base + decodedOffset; /* next value */
1425 }
1426 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1427 | encodeRelAddress(pc - t - 8);
1428 t = n;
1429 }
1430 }
1431
Jack Palevich1cdef202009-05-22 12:06:27 -07001432 virtual int finishCompile() {
1433#if defined(__arm__)
1434 const long base = long(getBase());
1435 const long curr = long(getPC());
1436 int err = cacheflush(base, curr, 0);
1437 return err;
1438#else
1439 return 0;
1440#endif
1441 }
1442
Jack Palevicha6535612009-05-13 16:24:17 -07001443 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001444#ifdef ENABLE_ARM_DISASSEMBLY
1445 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001446 disasm_interface_t di;
1447 di.di_readword = disassemble_readword;
1448 di.di_printaddr = disassemble_printaddr;
1449 di.di_printf = disassemble_printf;
1450
1451 int base = getBase();
1452 int pc = getPC();
1453 for(int i = base; i < pc; i += 4) {
1454 fprintf(out, "%08x: %08x ", i, *(int*) i);
1455 ::disasm(&di, i, 0);
1456 }
Jack Palevich09555c72009-05-27 12:25:55 -07001457#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001458 return 0;
1459 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001460
Jack Palevich9eed7a22009-07-06 17:24:34 -07001461 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001462 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001463 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001464 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001465 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001466 case TY_CHAR:
1467 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001468 case TY_DOUBLE:
1469 return 8;
1470 default:
1471 return 4;
1472 }
1473 }
1474
1475 /**
1476 * Array element alignment (in bytes) for this type of data.
1477 */
1478 virtual size_t sizeOf(Type* pType){
1479 switch(pType->tag) {
1480 case TY_INT:
1481 return 4;
1482 case TY_CHAR:
1483 return 1;
1484 default:
1485 return 0;
1486 case TY_FLOAT:
1487 return 4;
1488 case TY_DOUBLE:
1489 return 8;
1490 case TY_POINTER:
1491 return 4;
1492 }
1493 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001494
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001495 virtual size_t stackAlignmentOf(Type* pType) {
1496 switch(pType->tag) {
1497 case TY_DOUBLE:
1498 return 8;
1499 default:
1500 return 4;
1501 }
1502 }
1503
Jack Palevich9cbd2262009-07-08 16:48:41 -07001504 virtual size_t stackSizeOf(Type* pType) {
1505 switch(pType->tag) {
1506 case TY_DOUBLE:
1507 return 8;
1508 default:
1509 return 4;
1510 }
1511 }
1512
Jack Palevich22305132009-05-13 10:58:45 -07001513 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001514 static FILE* disasmOut;
1515
1516 static u_int
1517 disassemble_readword(u_int address)
1518 {
1519 return(*((u_int *)address));
1520 }
1521
1522 static void
1523 disassemble_printaddr(u_int address)
1524 {
1525 fprintf(disasmOut, "0x%08x", address);
1526 }
1527
1528 static void
1529 disassemble_printf(const char *fmt, ...) {
1530 va_list ap;
1531 va_start(ap, fmt);
1532 vfprintf(disasmOut, fmt, ap);
1533 va_end(ap);
1534 }
1535
1536 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1537
1538 /** Encode a relative address that might also be
1539 * a label.
1540 */
1541 int encodeAddress(int value) {
1542 int base = getBase();
1543 if (value >= base && value <= getPC() ) {
1544 // This is a label, encode it relative to the base.
1545 value = value - base;
1546 }
1547 return encodeRelAddress(value);
1548 }
1549
1550 int encodeRelAddress(int value) {
1551 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1552 }
Jack Palevich22305132009-05-13 10:58:45 -07001553
Jack Palevichb7718b92009-07-09 22:00:24 -07001554 int calcRegArgCount(Type* pDecl) {
1555 int reg = 0;
1556 Type* pArgs = pDecl->pTail;
1557 while (pArgs && reg < 4) {
1558 Type* pArg = pArgs->pHead;
1559 if ( pArg->tag == TY_DOUBLE) {
1560 int evenReg = (reg + 1) & ~1;
1561 if (evenReg >= 4) {
1562 break;
1563 }
1564 reg = evenReg + 2;
1565 } else {
1566 reg++;
1567 }
1568 pArgs = pArgs->pTail;
1569 }
1570 return reg;
1571 }
1572
Jack Palevich58c30ee2009-07-17 16:35:23 -07001573 void setupIntPtrArgs() {
1574 o4(0xE8BD0002); // ldmfd sp!,{r1}
1575 mStackUse -= 4;
1576 popType();
1577 }
1578
Jack Palevichb7718b92009-07-09 22:00:24 -07001579 /* Pop TOS to R1
1580 * Make sure both R0 and TOS are floats. (Could be ints)
1581 * We know that at least one of R0 and TOS is already a float
1582 */
1583 void setupFloatArgs() {
1584 Type* pR0Type = getR0Type();
1585 Type* pTOSType = getTOSType();
1586 TypeTag tagR0 = collapseType(pR0Type->tag);
1587 TypeTag tagTOS = collapseType(pTOSType->tag);
1588 if (tagR0 != TY_FLOAT) {
1589 assert(tagR0 == TY_INT);
1590 callRuntime((void*) runtime_int_to_float);
1591 }
1592 if (tagTOS != TY_FLOAT) {
1593 assert(tagTOS == TY_INT);
1594 assert(tagR0 == TY_FLOAT);
1595 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1596 o4(0xE59D0004); // ldr r0, [sp, #4]
1597 callRuntime((void*) runtime_int_to_float);
1598 o4(0xE1A01000); // mov r1, r0
1599 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1600 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1601 } else {
1602 // Pop TOS
1603 o4(0xE8BD0002); // ldmfd sp!,{r1}
1604 }
1605 mStackUse -= 4;
1606 popType();
1607 }
1608
1609 /* Pop TOS into R2..R3
1610 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1611 * We know that at least one of R0 and TOS are already a double.
1612 */
1613
1614 void setupDoubleArgs() {
1615 Type* pR0Type = getR0Type();
1616 Type* pTOSType = getTOSType();
1617 TypeTag tagR0 = collapseType(pR0Type->tag);
1618 TypeTag tagTOS = collapseType(pTOSType->tag);
1619 if (tagR0 != TY_DOUBLE) {
1620 if (tagR0 == TY_INT) {
1621 callRuntime((void*) runtime_int_to_double);
1622 } else {
1623 assert(tagR0 == TY_FLOAT);
1624 callRuntime((void*) runtime_float_to_double);
1625 }
1626 }
1627 if (tagTOS != TY_DOUBLE) {
1628 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1629 o4(0xE59D0008); // ldr r0, [sp, #8]
1630 if (tagTOS == TY_INT) {
1631 callRuntime((void*) runtime_int_to_double);
1632 } else {
1633 assert(tagTOS == TY_FLOAT);
1634 callRuntime((void*) runtime_float_to_double);
1635 }
1636 o4(0xE1A02000); // mov r2, r0
1637 o4(0xE1A03001); // mov r3, r1
1638 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1639 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1640 mStackUse -= 4;
1641 } else {
1642 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1643 mStackUse -= 8;
1644 }
1645 popType();
1646 }
1647
Jack Palevicha8f427f2009-07-13 18:40:08 -07001648 void liReg(int t, int reg) {
1649 assert(reg >= 0 && reg < 16);
1650 int rN = (reg & 0xf) << 12;
1651 if (t >= 0 && t < 255) {
1652 o4((0xE3A00000 + t) | rN); // mov rN, #0
1653 } else if (t >= -256 && t < 0) {
1654 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001655 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001656 } else {
1657 o4(0xE51F0000 | rN); // ldr rN, .L3
1658 o4(0xEA000000); // b .L99
1659 o4(t); // .L3: .word 0
1660 // .L99:
1661 }
1662 }
1663
Jack Palevichb7718b92009-07-09 22:00:24 -07001664 void callRuntime(void* fn) {
1665 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001666 o4(0xEA000000); // b .L99
1667 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001668 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001669 }
1670
Jack Palevichb7718b92009-07-09 22:00:24 -07001671 // Integer math:
1672
1673 static int runtime_DIV(int b, int a) {
1674 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001675 }
1676
Jack Palevichb7718b92009-07-09 22:00:24 -07001677 static int runtime_MOD(int b, int a) {
1678 return a % b;
1679 }
1680
1681 // Comparison to zero
1682
1683 static int runtime_is_non_zero_f(float a) {
1684 return a != 0;
1685 }
1686
1687 static int runtime_is_non_zero_d(double a) {
1688 return a != 0;
1689 }
1690
1691 // Comparison to zero
1692
1693 static int runtime_is_zero_f(float a) {
1694 return a == 0;
1695 }
1696
1697 static int runtime_is_zero_d(double a) {
1698 return a == 0;
1699 }
1700
1701 // Type conversion
1702
1703 static int runtime_float_to_int(float a) {
1704 return (int) a;
1705 }
1706
1707 static double runtime_float_to_double(float a) {
1708 return (double) a;
1709 }
1710
1711 static int runtime_double_to_int(double a) {
1712 return (int) a;
1713 }
1714
1715 static float runtime_double_to_float(double a) {
1716 return (float) a;
1717 }
1718
1719 static float runtime_int_to_float(int a) {
1720 return (float) a;
1721 }
1722
1723 static double runtime_int_to_double(int a) {
1724 return (double) a;
1725 }
1726
1727 // Comparisons float
1728
1729 static int runtime_cmp_eq_ff(float b, float a) {
1730 return a == b;
1731 }
1732
1733 static int runtime_cmp_ne_ff(float b, float a) {
1734 return a != b;
1735 }
1736
1737 static int runtime_cmp_lt_ff(float b, float a) {
1738 return a < b;
1739 }
1740
1741 static int runtime_cmp_le_ff(float b, float a) {
1742 return a <= b;
1743 }
1744
1745 static int runtime_cmp_ge_ff(float b, float a) {
1746 return a >= b;
1747 }
1748
1749 static int runtime_cmp_gt_ff(float b, float a) {
1750 return a > b;
1751 }
1752
1753 // Comparisons double
1754
1755 static int runtime_cmp_eq_dd(double b, double a) {
1756 return a == b;
1757 }
1758
1759 static int runtime_cmp_ne_dd(double b, double a) {
1760 return a != b;
1761 }
1762
1763 static int runtime_cmp_lt_dd(double b, double a) {
1764 return a < b;
1765 }
1766
1767 static int runtime_cmp_le_dd(double b, double a) {
1768 return a <= b;
1769 }
1770
1771 static int runtime_cmp_ge_dd(double b, double a) {
1772 return a >= b;
1773 }
1774
1775 static int runtime_cmp_gt_dd(double b, double a) {
1776 return a > b;
1777 }
1778
1779 // Math float
1780
1781 static float runtime_op_add_ff(float b, float a) {
1782 return a + b;
1783 }
1784
1785 static float runtime_op_sub_ff(float b, float a) {
1786 return a - b;
1787 }
1788
1789 static float runtime_op_mul_ff(float b, float a) {
1790 return a * b;
1791 }
1792
1793 static float runtime_op_div_ff(float b, float a) {
1794 return a / b;
1795 }
1796
1797 static float runtime_op_neg_f(float a) {
1798 return -a;
1799 }
1800
1801 // Math double
1802
1803 static double runtime_op_add_dd(double b, double a) {
1804 return a + b;
1805 }
1806
1807 static double runtime_op_sub_dd(double b, double a) {
1808 return a - b;
1809 }
1810
1811 static double runtime_op_mul_dd(double b, double a) {
1812 return a * b;
1813 }
1814
1815 static double runtime_op_div_dd(double b, double a) {
1816 return a / b;
1817 }
1818
1819 static double runtime_op_neg_d(double a) {
1820 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001821 }
-b master422972c2009-06-17 19:13:52 -07001822
1823 static const int STACK_ALIGNMENT = 8;
1824 int mStackUse;
1825 // This variable holds the amount we adjusted the stack in the most
1826 // recent endFunctionCallArguments call. It's examined by the
1827 // following adjustStackAfterCall call.
1828 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001829 };
1830
Jack Palevich09555c72009-05-27 12:25:55 -07001831#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001832
1833#ifdef PROVIDE_X86_CODEGEN
1834
Jack Palevich21a15a22009-05-11 14:49:29 -07001835 class X86CodeGenerator : public CodeGenerator {
1836 public:
1837 X86CodeGenerator() {}
1838 virtual ~X86CodeGenerator() {}
1839
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001840 /* returns address to patch with local variable size
1841 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001842 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001843 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1844 return oad(0xec81, 0); /* sub $xxx, %esp */
1845 }
1846
Jack Palevichb7718b92009-07-09 22:00:24 -07001847 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001848 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001849 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001850 }
1851
Jack Palevich21a15a22009-05-11 14:49:29 -07001852 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001853 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001854 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001855 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001856 }
1857
Jack Palevich1a539db2009-07-08 13:04:41 -07001858 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001859 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001860 switch (pType->tag) {
1861 case TY_FLOAT:
1862 oad(0x05D9, address); // flds
1863 break;
1864 case TY_DOUBLE:
1865 oad(0x05DD, address); // fldl
1866 break;
1867 default:
1868 assert(false);
1869 break;
1870 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001871 }
1872
Jack Palevich22305132009-05-13 10:58:45 -07001873 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001874 return psym(0xe9, t);
1875 }
1876
1877 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001878 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001879 Type* pR0Type = getR0Type();
1880 TypeTag tagR0 = pR0Type->tag;
1881 bool isFloatR0 = isFloatTag(tagR0);
1882 if (isFloatR0) {
1883 o(0xeed9); // fldz
1884 o(0xe9da); // fucompp
1885 o(0xe0df); // fnstsw %ax
1886 o(0x9e); // sahf
1887 } else {
1888 o(0xc085); // test %eax, %eax
1889 }
1890 // Use two output statements to generate one instruction.
1891 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001892 return psym(0x84 + l, t);
1893 }
1894
Jack Palevich58c30ee2009-07-17 16:35:23 -07001895 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001896 Type* pR0Type = getR0Type();
1897 Type* pTOSType = getTOSType();
1898 TypeTag tagR0 = pR0Type->tag;
1899 TypeTag tagTOS = pTOSType->tag;
1900 bool isFloatR0 = isFloatTag(tagR0);
1901 bool isFloatTOS = isFloatTag(tagTOS);
1902 if (!isFloatR0 && !isFloatTOS) {
1903 int t = decodeOp(op);
1904 o(0x59); /* pop %ecx */
1905 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001906 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001907 o(0x0f); /* setxx %al */
1908 o(t + 0x90);
1909 o(0xc0);
1910 popType();
1911 } else {
1912 setupFloatOperands();
1913 switch (op) {
1914 case OP_EQUALS:
1915 o(0xe9da); // fucompp
1916 o(0xe0df); // fnstsw %ax
1917 o(0x9e); // sahf
1918 o(0xc0940f); // sete %al
1919 o(0xc29b0f); // setnp %dl
1920 o(0xd021); // andl %edx, %eax
1921 break;
1922 case OP_NOT_EQUALS:
1923 o(0xe9da); // fucompp
1924 o(0xe0df); // fnstsw %ax
1925 o(0x9e); // sahf
1926 o(0xc0950f); // setne %al
1927 o(0xc29a0f); // setp %dl
1928 o(0xd009); // orl %edx, %eax
1929 break;
1930 case OP_GREATER_EQUAL:
1931 o(0xe9da); // fucompp
1932 o(0xe0df); // fnstsw %ax
1933 o(0x05c4f6); // testb $5, %ah
1934 o(0xc0940f); // sete %al
1935 break;
1936 case OP_LESS:
1937 o(0xc9d9); // fxch %st(1)
1938 o(0xe9da); // fucompp
1939 o(0xe0df); // fnstsw %ax
1940 o(0x9e); // sahf
1941 o(0xc0970f); // seta %al
1942 break;
1943 case OP_LESS_EQUAL:
1944 o(0xc9d9); // fxch %st(1)
1945 o(0xe9da); // fucompp
1946 o(0xe0df); // fnstsw %ax
1947 o(0x9e); // sahf
1948 o(0xc0930f); // setea %al
1949 break;
1950 case OP_GREATER:
1951 o(0xe9da); // fucompp
1952 o(0xe0df); // fnstsw %ax
1953 o(0x45c4f6); // testb $69, %ah
1954 o(0xc0940f); // sete %al
1955 break;
1956 default:
1957 error("Unknown comparison op");
1958 }
1959 o(0xc0b60f); // movzbl %al, %eax
1960 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001961 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001962 }
1963
Jack Palevich546b2242009-05-13 15:10:04 -07001964 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001965 Type* pR0Type = getR0Type();
1966 Type* pTOSType = getTOSType();
1967 TypeTag tagR0 = pR0Type->tag;
1968 TypeTag tagTOS = pTOSType->tag;
1969 bool isFloatR0 = isFloatTag(tagR0);
1970 bool isFloatTOS = isFloatTag(tagTOS);
1971 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001972 bool isPtrR0 = tagR0 == TY_POINTER;
1973 bool isPtrTOS = tagTOS == TY_POINTER;
1974 if (isPtrR0 || isPtrTOS) {
1975 if (isPtrR0 && isPtrTOS) {
1976 if (op != OP_MINUS) {
1977 error("Unsupported pointer-pointer operation %d.", op);
1978 }
1979 if (! typeEqual(pR0Type, pTOSType)) {
1980 error("Incompatible pointer types for subtraction.");
1981 }
1982 o(0x59); /* pop %ecx */
1983 o(decodeOp(op));
1984 popType();
1985 setR0Type(mkpInt);
1986 int size = sizeOf(pR0Type->pHead);
1987 if (size != 1) {
1988 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001989 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001990 // TODO: Optimize for power-of-two.
1991 genOp(OP_DIV);
1992 }
1993 } else {
1994 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1995 error("Unsupported pointer-scalar operation %d", op);
1996 }
1997 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1998 o(0x59); /* pop %ecx */
1999 int size = sizeOf(pPtrType->pHead);
2000 if (size != 1) {
2001 // TODO: Optimize for power-of-two.
2002 if (isPtrR0) {
2003 oad(0xC969, size); // imull $size, %ecx
2004 } else {
2005 oad(0xC069, size); // mul $size, %eax
2006 }
2007 }
2008 o(decodeOp(op));
2009 popType();
2010 setR0Type(pPtrType);
2011 }
2012 } else {
2013 o(0x59); /* pop %ecx */
2014 o(decodeOp(op));
2015 if (op == OP_MOD)
2016 o(0x92); /* xchg %edx, %eax */
2017 popType();
2018 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002019 } else {
2020 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2021 setupFloatOperands();
2022 // Both float. x87 R0 == left hand, x87 R1 == right hand
2023 switch (op) {
2024 case OP_MUL:
2025 o(0xc9de); // fmulp
2026 break;
2027 case OP_DIV:
2028 o(0xf1de); // fdivp
2029 break;
2030 case OP_PLUS:
2031 o(0xc1de); // faddp
2032 break;
2033 case OP_MINUS:
2034 o(0xe1de); // fsubp
2035 break;
2036 default:
2037 error("Unsupported binary floating operation.");
2038 break;
2039 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002040 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002041 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002042 }
2043
Jack Palevich58c30ee2009-07-17 16:35:23 -07002044 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002045 if (op != OP_LOGICAL_NOT) {
2046 error("Unknown unary cmp %d", op);
2047 } else {
2048 Type* pR0Type = getR0Type();
2049 TypeTag tag = collapseType(pR0Type->tag);
2050 switch(tag) {
2051 case TY_INT: {
2052 oad(0xb9, 0); /* movl $0, %ecx */
2053 int t = decodeOp(op);
2054 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002055 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002056 o(0x0f); /* setxx %al */
2057 o(t + 0x90);
2058 o(0xc0);
2059 }
2060 break;
2061 case TY_FLOAT:
2062 case TY_DOUBLE:
2063 o(0xeed9); // fldz
2064 o(0xe9da); // fucompp
2065 o(0xe0df); // fnstsw %ax
2066 o(0x9e); // sahf
2067 o(0xc0950f); // setne %al
2068 o(0xc29a0f); // setp %dl
2069 o(0xd009); // orl %edx, %eax
2070 o(0xc0b60f); // movzbl %al, %eax
2071 o(0x01f083); // xorl $1, %eax
2072 break;
2073 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002074 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002075 break;
2076 }
2077 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002078 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002079 }
2080
2081 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002082 Type* pR0Type = getR0Type();
2083 TypeTag tag = collapseType(pR0Type->tag);
2084 switch(tag) {
2085 case TY_INT:
2086 oad(0xb9, 0); /* movl $0, %ecx */
2087 o(decodeOp(op));
2088 break;
2089 case TY_FLOAT:
2090 case TY_DOUBLE:
2091 switch (op) {
2092 case OP_MINUS:
2093 o(0xe0d9); // fchs
2094 break;
2095 case OP_BIT_NOT:
2096 error("Can't apply '~' operator to a float or double.");
2097 break;
2098 default:
2099 error("Unknown unary op %d\n", op);
2100 break;
2101 }
2102 break;
2103 default:
2104 error("genUnaryOp unsupported type");
2105 break;
2106 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002107 }
2108
Jack Palevich1cdef202009-05-22 12:06:27 -07002109 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002110 Type* pR0Type = getR0Type();
2111 TypeTag r0ct = collapseType(pR0Type->tag);
2112 switch(r0ct) {
2113 case TY_INT:
2114 o(0x50); /* push %eax */
2115 break;
2116 case TY_FLOAT:
2117 o(0x50); /* push %eax */
2118 o(0x241cd9); // fstps 0(%esp)
2119 break;
2120 case TY_DOUBLE:
2121 o(0x50); /* push %eax */
2122 o(0x50); /* push %eax */
2123 o(0x241cdd); // fstpl 0(%esp)
2124 break;
2125 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002126 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002127 break;
2128 }
Jack Palevich8df46192009-07-07 14:48:51 -07002129 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002130 }
2131
Jack Palevich58c30ee2009-07-17 16:35:23 -07002132 virtual void popR0() {
2133 Type* pR0Type = getR0Type();
2134 TypeTag r0ct = collapseType(pR0Type->tag);
2135 switch(r0ct) {
2136 case TY_INT:
2137 o(0x58); /* popl %eax */
2138 break;
2139 case TY_FLOAT:
2140 o(0x2404d9); // flds (%esp)
2141 o(0x58); /* popl %eax */
2142 break;
2143 case TY_DOUBLE:
2144 o(0x2404dd); // fldl (%esp)
2145 o(0x58); /* popl %eax */
2146 o(0x58); /* popl %eax */
2147 break;
2148 default:
2149 error("pushR0 unsupported type %d", r0ct);
2150 break;
2151 }
2152 popType();
2153 }
2154
2155 virtual void storeR0ToTOS() {
2156 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002157 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002158 Type* pTargetType = pPointerType->pHead;
2159 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002160 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002161 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002162 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002163 case TY_INT:
2164 o(0x0189); /* movl %eax/%al, (%ecx) */
2165 break;
2166 case TY_CHAR:
2167 o(0x0188); /* movl %eax/%al, (%ecx) */
2168 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002169 case TY_FLOAT:
2170 o(0x19d9); /* fstps (%ecx) */
2171 break;
2172 case TY_DOUBLE:
2173 o(0x19dd); /* fstpl (%ecx) */
2174 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002175 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002176 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002177 break;
2178 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002179 }
2180
Jack Palevich58c30ee2009-07-17 16:35:23 -07002181 virtual void loadR0FromR0() {
2182 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002183 assert(pPointerType->tag == TY_POINTER);
2184 switch (pPointerType->pHead->tag) {
2185 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002186 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002187 break;
2188 case TY_CHAR:
2189 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002190 ob(0); /* add zero in code */
2191 break;
2192 case TY_FLOAT:
2193 o2(0x00d9); // flds (%eax)
2194 break;
2195 case TY_DOUBLE:
2196 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002197 break;
2198 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002199 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002200 break;
2201 }
Jack Palevich8df46192009-07-07 14:48:51 -07002202 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002203 }
2204
Jack Palevich8df46192009-07-07 14:48:51 -07002205 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002206 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002207 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002208 }
2209
Jack Palevich9cbd2262009-07-08 16:48:41 -07002210 virtual void storeR0(int ea, Type* pType) {
2211 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002212 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002213 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002214 case TY_CHAR:
2215 if (ea < -LOCAL || ea > LOCAL) {
2216 oad(0xa2, ea); // movb %al,ea
2217 } else {
2218 oad(0x8588, ea); // movb %al,ea(%ebp)
2219 }
2220 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002221 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002222 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002223 gmov(6, ea); /* mov %eax, EA */
2224 break;
2225 case TY_FLOAT:
2226 if (ea < -LOCAL || ea > LOCAL) {
2227 oad(0x1dd9, ea); // fstps ea
2228 } else {
2229 oad(0x9dd9, ea); // fstps ea(%ebp)
2230 }
2231 break;
2232 case TY_DOUBLE:
2233 if (ea < -LOCAL || ea > LOCAL) {
2234 oad(0x1ddd, ea); // fstpl ea
2235 } else {
2236 oad(0x9ddd, ea); // fstpl ea(%ebp)
2237 }
2238 break;
2239 default:
2240 error("Unable to store to type %d", tag);
2241 break;
2242 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002243 }
2244
Jack Palevich58c30ee2009-07-17 16:35:23 -07002245 virtual void loadR0(int ea, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002246 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002247 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002248 case TY_CHAR:
2249 if (ea < -LOCAL || ea > LOCAL) {
2250 oad(0x05BE0F, ea); // movsbl ea,%eax
2251 } else {
2252 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2253 }
Jack Palevich25c0cca2009-07-13 16:56:28 -07002254 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002255 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002256 case TY_POINTER:
Jack Palevich58c30ee2009-07-17 16:35:23 -07002257 gmov(8, ea); /* mov EA, %eax */
Jack Palevich128ad2d2009-07-08 14:51:31 -07002258 break;
2259 case TY_FLOAT:
2260 if (ea < -LOCAL || ea > LOCAL) {
2261 oad(0x05d9, ea); // flds ea
2262 } else {
2263 oad(0x85d9, ea); // flds ea(%ebp)
2264 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002265 break;
2266 case TY_DOUBLE:
2267 if (ea < -LOCAL || ea > LOCAL) {
2268 oad(0x05dd, ea); // fldl ea
2269 } else {
2270 oad(0x85dd, ea); // fldl ea(%ebp)
2271 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002272 break;
2273 default:
2274 error("Unable to load type %d", tag);
2275 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002276 }
Jack Palevich8df46192009-07-07 14:48:51 -07002277 setR0Type(pType);
2278 }
2279
2280 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002281 Type* pR0Type = getR0Type();
2282 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002283 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002284 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002285 return;
2286 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002287 if (bitsSame(pType, pR0Type)) {
2288 // do nothing special
2289 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2290 // do nothing special, both held in same register on x87.
2291 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002292 TypeTag r0Tag = collapseType(pR0Type->tag);
2293 TypeTag destTag = collapseType(pType->tag);
2294 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2295 // Convert R0 from int to float
2296 o(0x50); // push %eax
2297 o(0x2404DB); // fildl 0(%esp)
2298 o(0x58); // pop %eax
2299 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2300 // Convert R0 from float to int. Complicated because
2301 // need to save and restore the rounding mode.
2302 o(0x50); // push %eax
2303 o(0x50); // push %eax
2304 o(0x02247cD9); // fnstcw 2(%esp)
2305 o(0x2444b70f); // movzwl 2(%esp), %eax
2306 o(0x02);
2307 o(0x0cb4); // movb $12, %ah
2308 o(0x24048966); // movw %ax, 0(%esp)
2309 o(0x242cd9); // fldcw 0(%esp)
2310 o(0x04245cdb); // fistpl 4(%esp)
2311 o(0x02246cd9); // fldcw 2(%esp)
2312 o(0x58); // pop %eax
2313 o(0x58); // pop %eax
2314 } else {
2315 error("Incompatible types old: %d new: %d",
2316 pR0Type->tag, pType->tag);
2317 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002318 }
2319 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002320 }
2321
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002322 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002323 return oad(0xec81, 0); /* sub $xxx, %esp */
2324 }
2325
Jack Palevich8148c5b2009-07-16 18:24:47 -07002326 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2327 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002328 Type* pR0Type = getR0Type();
2329 TypeTag r0ct = collapseType(pR0Type->tag);
2330 switch(r0ct) {
2331 case TY_INT:
2332 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2333 return 4;
2334 case TY_FLOAT:
2335 oad(0x249CD9, l); /* fstps xxx(%esp) */
2336 return 4;
2337 case TY_DOUBLE:
2338 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2339 return 8;
2340 default:
2341 assert(false);
2342 return 0;
2343 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002344 }
2345
Jack Palevichb7718b92009-07-09 22:00:24 -07002346 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002347 * (int*) a = l;
2348 }
2349
Jack Palevich8df46192009-07-07 14:48:51 -07002350 virtual int callForward(int symbol, Type* pFunc) {
2351 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 return psym(0xe8, symbol); /* call xxx */
2353 }
2354
Jack Palevich8df46192009-07-07 14:48:51 -07002355 virtual void callRelative(int t, Type* pFunc) {
2356 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002357 psym(0xe8, t); /* call xxx */
2358 }
2359
Jack Palevich8df46192009-07-07 14:48:51 -07002360 virtual void callIndirect(int l, Type* pFunc) {
2361 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002362 oad(0x2494ff, l); /* call *xxx(%esp) */
2363 }
2364
Jack Palevichb7718b92009-07-09 22:00:24 -07002365 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002366 if (isIndirect) {
2367 l += 4;
2368 }
-b master422972c2009-06-17 19:13:52 -07002369 if (l > 0) {
2370 oad(0xc481, l); /* add $xxx, %esp */
2371 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002372 }
2373
Jack Palevicha6535612009-05-13 16:24:17 -07002374 virtual int jumpOffset() {
2375 return 5;
2376 }
2377
2378 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002379 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002380 }
2381
Jack Paleviche7b59062009-05-19 17:12:17 -07002382 /* output a symbol and patch all calls to it */
2383 virtual void gsym(int t) {
2384 int n;
2385 int pc = getPC();
2386 while (t) {
2387 n = *(int *) t; /* next value */
2388 *(int *) t = pc - t - 4;
2389 t = n;
2390 }
2391 }
2392
Jack Palevich1cdef202009-05-22 12:06:27 -07002393 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002394 size_t pagesize = 4096;
2395 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2396 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2397 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2398 if (err) {
2399 error("mprotect() failed: %d", errno);
2400 }
2401 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002402 }
2403
Jack Palevich9eed7a22009-07-06 17:24:34 -07002404 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002405 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002406 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002407 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002408 switch (pType->tag) {
2409 case TY_CHAR:
2410 return 1;
2411 default:
2412 return 4;
2413 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002414 }
2415
2416 /**
2417 * Array element alignment (in bytes) for this type of data.
2418 */
2419 virtual size_t sizeOf(Type* pType){
2420 switch(pType->tag) {
2421 case TY_INT:
2422 return 4;
2423 case TY_CHAR:
2424 return 1;
2425 default:
2426 return 0;
2427 case TY_FLOAT:
2428 return 4;
2429 case TY_DOUBLE:
2430 return 8;
2431 case TY_POINTER:
2432 return 4;
2433 }
2434 }
2435
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002436 virtual size_t stackAlignmentOf(Type* pType){
2437 return 4;
2438 }
2439
Jack Palevich9cbd2262009-07-08 16:48:41 -07002440 virtual size_t stackSizeOf(Type* pType) {
2441 switch(pType->tag) {
2442 case TY_DOUBLE:
2443 return 8;
2444 default:
2445 return 4;
2446 }
2447 }
2448
Jack Palevich21a15a22009-05-11 14:49:29 -07002449 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002450
2451 /** Output 1 to 4 bytes.
2452 *
2453 */
2454 void o(int n) {
2455 /* cannot use unsigned, so we must do a hack */
2456 while (n && n != -1) {
2457 ob(n & 0xff);
2458 n = n >> 8;
2459 }
2460 }
2461
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002462 /* Output exactly 2 bytes
2463 */
2464 void o2(int n) {
2465 ob(n & 0xff);
2466 ob(0xff & (n >> 8));
2467 }
2468
Jack Paleviche7b59062009-05-19 17:12:17 -07002469 /* psym is used to put an instruction with a data field which is a
2470 reference to a symbol. It is in fact the same as oad ! */
2471 int psym(int n, int t) {
2472 return oad(n, t);
2473 }
2474
2475 /* instruction + address */
2476 int oad(int n, int t) {
2477 o(n);
2478 int result = getPC();
2479 o4(t);
2480 return result;
2481 }
2482
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002483 static const int operatorHelper[];
2484
2485 int decodeOp(int op) {
2486 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002487 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002488 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002489 }
2490 return operatorHelper[op];
2491 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002492
Jack Palevich546b2242009-05-13 15:10:04 -07002493 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002494 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002495 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002496 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002497
2498 void setupFloatOperands() {
2499 Type* pR0Type = getR0Type();
2500 Type* pTOSType = getTOSType();
2501 TypeTag tagR0 = pR0Type->tag;
2502 TypeTag tagTOS = pTOSType->tag;
2503 bool isFloatR0 = isFloatTag(tagR0);
2504 bool isFloatTOS = isFloatTag(tagTOS);
2505 if (! isFloatR0) {
2506 // Convert R0 from int to float
2507 o(0x50); // push %eax
2508 o(0x2404DB); // fildl 0(%esp)
2509 o(0x58); // pop %eax
2510 }
2511 if (! isFloatTOS){
2512 o(0x2404DB); // fildl 0(%esp);
2513 o(0x58); // pop %eax
2514 } else {
2515 if (tagTOS == TY_FLOAT) {
2516 o(0x2404d9); // flds (%esp)
2517 o(0x58); // pop %eax
2518 } else {
2519 o(0x2404dd); // fldl (%esp)
2520 o(0x58); // pop %eax
2521 o(0x58); // pop %eax
2522 }
2523 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002524 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002525 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002526 };
2527
Jack Paleviche7b59062009-05-19 17:12:17 -07002528#endif // PROVIDE_X86_CODEGEN
2529
Jack Palevichb67b18f2009-06-11 21:12:23 -07002530#ifdef PROVIDE_TRACE_CODEGEN
2531 class TraceCodeGenerator : public CodeGenerator {
2532 private:
2533 CodeGenerator* mpBase;
2534
2535 public:
2536 TraceCodeGenerator(CodeGenerator* pBase) {
2537 mpBase = pBase;
2538 }
2539
2540 virtual ~TraceCodeGenerator() {
2541 delete mpBase;
2542 }
2543
2544 virtual void init(CodeBuf* pCodeBuf) {
2545 mpBase->init(pCodeBuf);
2546 }
2547
2548 void setErrorSink(ErrorSink* pErrorSink) {
2549 mpBase->setErrorSink(pErrorSink);
2550 }
2551
2552 /* returns address to patch with local variable size
2553 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002554 virtual int functionEntry(Type* pDecl) {
2555 int result = mpBase->functionEntry(pDecl);
2556 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002557 return result;
2558 }
2559
Jack Palevichb7718b92009-07-09 22:00:24 -07002560 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2561 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2562 localVariableAddress, localVariableSize);
2563 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002564 }
2565
2566 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002567 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002568 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002569 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002570 }
2571
Jack Palevich1a539db2009-07-08 13:04:41 -07002572 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002573 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002574 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002575 }
2576
Jack Palevichb67b18f2009-06-11 21:12:23 -07002577 virtual int gjmp(int t) {
2578 int result = mpBase->gjmp(t);
2579 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2580 return result;
2581 }
2582
2583 /* l = 0: je, l == 1: jne */
2584 virtual int gtst(bool l, int t) {
2585 int result = mpBase->gtst(l, t);
2586 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2587 return result;
2588 }
2589
Jack Palevich58c30ee2009-07-17 16:35:23 -07002590 virtual void gcmp(int op) {
2591 fprintf(stderr, "gcmp(%d)\n", op);
2592 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002593 }
2594
2595 virtual void genOp(int op) {
2596 fprintf(stderr, "genOp(%d)\n", op);
2597 mpBase->genOp(op);
2598 }
2599
Jack Palevich9eed7a22009-07-06 17:24:34 -07002600
Jack Palevich58c30ee2009-07-17 16:35:23 -07002601 virtual void gUnaryCmp(int op) {
2602 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2603 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002604 }
2605
2606 virtual void genUnaryOp(int op) {
2607 fprintf(stderr, "genUnaryOp(%d)\n", op);
2608 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002609 }
2610
2611 virtual void pushR0() {
2612 fprintf(stderr, "pushR0()\n");
2613 mpBase->pushR0();
2614 }
2615
Jack Palevich58c30ee2009-07-17 16:35:23 -07002616 virtual void popR0() {
2617 fprintf(stderr, "popR0()\n");
2618 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002619 }
2620
Jack Palevich58c30ee2009-07-17 16:35:23 -07002621 virtual void storeR0ToTOS() {
2622 fprintf(stderr, "storeR0ToTOS()\n");
2623 mpBase->storeR0ToTOS();
2624 }
2625
2626 virtual void loadR0FromR0() {
2627 fprintf(stderr, "loadR0FromR0()\n");
2628 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002629 }
2630
Jack Palevich8df46192009-07-07 14:48:51 -07002631 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002632 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002633 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002634 }
2635
Jack Palevich9cbd2262009-07-08 16:48:41 -07002636 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002637 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002638 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002639 }
2640
Jack Palevich58c30ee2009-07-17 16:35:23 -07002641 virtual void loadR0(int ea, Type* pType) {
2642 fprintf(stderr, "loadR0(%d, pType)\n", ea);
2643 mpBase->loadR0(ea, pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002644 }
2645
2646 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002647 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002648 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002649 }
2650
2651 virtual int beginFunctionCallArguments() {
2652 int result = mpBase->beginFunctionCallArguments();
2653 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2654 return result;
2655 }
2656
Jack Palevich8148c5b2009-07-16 18:24:47 -07002657 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2658 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2659 pArgType->tag);
2660 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002661 }
2662
Jack Palevichb7718b92009-07-09 22:00:24 -07002663 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002664 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002665 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002666 }
2667
Jack Palevich8df46192009-07-07 14:48:51 -07002668 virtual int callForward(int symbol, Type* pFunc) {
2669 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002670 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2671 return result;
2672 }
2673
Jack Palevich8df46192009-07-07 14:48:51 -07002674 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002675 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002676 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002677 }
2678
Jack Palevich8df46192009-07-07 14:48:51 -07002679 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002680 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002681 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002682 }
2683
Jack Palevichb7718b92009-07-09 22:00:24 -07002684 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2685 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2686 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002687 }
2688
2689 virtual int jumpOffset() {
2690 return mpBase->jumpOffset();
2691 }
2692
2693 virtual int disassemble(FILE* out) {
2694 return mpBase->disassemble(out);
2695 }
2696
2697 /* output a symbol and patch all calls to it */
2698 virtual void gsym(int t) {
2699 fprintf(stderr, "gsym(%d)\n", t);
2700 mpBase->gsym(t);
2701 }
2702
2703 virtual int finishCompile() {
2704 int result = mpBase->finishCompile();
2705 fprintf(stderr, "finishCompile() = %d\n", result);
2706 return result;
2707 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002708
2709 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002710 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002711 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002712 virtual size_t alignmentOf(Type* pType){
2713 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002714 }
2715
2716 /**
2717 * Array element alignment (in bytes) for this type of data.
2718 */
2719 virtual size_t sizeOf(Type* pType){
2720 return mpBase->sizeOf(pType);
2721 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002722
Jack Palevich9cbd2262009-07-08 16:48:41 -07002723
2724 virtual size_t stackSizeOf(Type* pType) {
2725 return mpBase->stackSizeOf(pType);
2726 }
2727
2728
Jack Palevich1a539db2009-07-08 13:04:41 -07002729 virtual Type* getR0Type() {
2730 return mpBase->getR0Type();
2731 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002732 };
2733
2734#endif // PROVIDE_TRACE_CODEGEN
2735
Jack Palevich569f1352009-06-29 14:29:08 -07002736 class Arena {
2737 public:
2738 // Used to record a given allocation amount.
2739 // Used:
2740 // Mark mark = arena.mark();
2741 // ... lots of arena.allocate()
2742 // arena.free(mark);
2743
2744 struct Mark {
2745 size_t chunk;
2746 size_t offset;
2747 };
2748
2749 Arena() {
2750 mCurrentChunk = 0;
2751 Chunk start(CHUNK_SIZE);
2752 mData.push_back(start);
2753 }
2754
2755 ~Arena() {
2756 for(size_t i = 0; i < mData.size(); i++) {
2757 mData[i].free();
2758 }
2759 }
2760
2761 // Alloc using the standard alignment size safe for any variable
2762 void* alloc(size_t size) {
2763 return alloc(size, 8);
2764 }
2765
2766 Mark mark(){
2767 Mark result;
2768 result.chunk = mCurrentChunk;
2769 result.offset = mData[mCurrentChunk].mOffset;
2770 return result;
2771 }
2772
2773 void freeToMark(const Mark& mark) {
2774 mCurrentChunk = mark.chunk;
2775 mData[mCurrentChunk].mOffset = mark.offset;
2776 }
2777
2778 private:
2779 // Allocate memory aligned to a given size
2780 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2781 // Memory is not zero filled.
2782
2783 void* alloc(size_t size, size_t alignment) {
2784 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2785 if (mCurrentChunk + 1 < mData.size()) {
2786 mCurrentChunk++;
2787 } else {
2788 size_t allocSize = CHUNK_SIZE;
2789 if (allocSize < size + alignment - 1) {
2790 allocSize = size + alignment - 1;
2791 }
2792 Chunk chunk(allocSize);
2793 mData.push_back(chunk);
2794 mCurrentChunk++;
2795 }
2796 }
2797 return mData[mCurrentChunk].allocate(size, alignment);
2798 }
2799
2800 static const size_t CHUNK_SIZE = 128*1024;
2801 // Note: this class does not deallocate its
2802 // memory when it's destroyed. It depends upon
2803 // its parent to deallocate the memory.
2804 struct Chunk {
2805 Chunk() {
2806 mpData = 0;
2807 mSize = 0;
2808 mOffset = 0;
2809 }
2810
2811 Chunk(size_t size) {
2812 mSize = size;
2813 mpData = (char*) malloc(size);
2814 mOffset = 0;
2815 }
2816
2817 ~Chunk() {
2818 // Doesn't deallocate memory.
2819 }
2820
2821 void* allocate(size_t size, size_t alignment) {
2822 size_t alignedOffset = aligned(mOffset, alignment);
2823 void* result = mpData + alignedOffset;
2824 mOffset = alignedOffset + size;
2825 return result;
2826 }
2827
2828 void free() {
2829 if (mpData) {
2830 ::free(mpData);
2831 mpData = 0;
2832 }
2833 }
2834
2835 size_t remainingCapacity(size_t alignment) {
2836 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2837 }
2838
2839 // Assume alignment is a power of two
2840 inline size_t aligned(size_t v, size_t alignment) {
2841 size_t mask = alignment-1;
2842 return (v + mask) & ~mask;
2843 }
2844
2845 char* mpData;
2846 size_t mSize;
2847 size_t mOffset;
2848 };
2849
2850 size_t mCurrentChunk;
2851
2852 Vector<Chunk> mData;
2853 };
2854
Jack Palevich569f1352009-06-29 14:29:08 -07002855 struct VariableInfo;
2856
2857 struct Token {
2858 int hash;
2859 size_t length;
2860 char* pText;
2861 tokenid_t id;
2862
2863 // Current values for the token
2864 char* mpMacroDefinition;
2865 VariableInfo* mpVariableInfo;
2866 };
2867
2868 class TokenTable {
2869 public:
2870 // Don't use 0..0xff, allows characters and operators to be tokens too.
2871
2872 static const int TOKEN_BASE = 0x100;
2873 TokenTable() {
2874 mpMap = hashmapCreate(128, hashFn, equalsFn);
2875 }
2876
2877 ~TokenTable() {
2878 hashmapFree(mpMap);
2879 }
2880
2881 void setArena(Arena* pArena) {
2882 mpArena = pArena;
2883 }
2884
2885 // Returns a token for a given string of characters.
2886 tokenid_t intern(const char* pText, size_t length) {
2887 Token probe;
2888 int hash = hashmapHash((void*) pText, length);
2889 {
2890 Token probe;
2891 probe.hash = hash;
2892 probe.length = length;
2893 probe.pText = (char*) pText;
2894 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2895 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002896 return pValue->id;
2897 }
2898 }
2899
2900 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2901 memset(pToken, 0, sizeof(*pToken));
2902 pToken->hash = hash;
2903 pToken->length = length;
2904 pToken->pText = (char*) mpArena->alloc(length + 1);
2905 memcpy(pToken->pText, pText, length);
2906 pToken->pText[length] = 0;
2907 pToken->id = mTokens.size() + TOKEN_BASE;
2908 mTokens.push_back(pToken);
2909 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002910 return pToken->id;
2911 }
2912
2913 // Return the Token for a given tokenid.
2914 Token& operator[](tokenid_t id) {
2915 return *mTokens[id - TOKEN_BASE];
2916 }
2917
2918 inline size_t size() {
2919 return mTokens.size();
2920 }
2921
2922 private:
2923
2924 static int hashFn(void* pKey) {
2925 Token* pToken = (Token*) pKey;
2926 return pToken->hash;
2927 }
2928
2929 static bool equalsFn(void* keyA, void* keyB) {
2930 Token* pTokenA = (Token*) keyA;
2931 Token* pTokenB = (Token*) keyB;
2932 // Don't need to compare hash values, they should always be equal
2933 return pTokenA->length == pTokenB->length
2934 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2935 }
2936
2937 Hashmap* mpMap;
2938 Vector<Token*> mTokens;
2939 Arena* mpArena;
2940 };
2941
Jack Palevich1cdef202009-05-22 12:06:27 -07002942 class InputStream {
2943 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002944 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002945 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002946 };
2947
2948 class TextInputStream : public InputStream {
2949 public:
2950 TextInputStream(const char* text, size_t textLength)
2951 : pText(text), mTextLength(textLength), mPosition(0) {
2952 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002953
Jack Palevichdc456462009-07-16 16:50:56 -07002954 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002955 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2956 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002957
Jack Palevichdc456462009-07-16 16:50:56 -07002958 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002959 const char* pText;
2960 size_t mTextLength;
2961 size_t mPosition;
2962 };
2963
Jack Palevicheedf9d22009-06-04 16:23:40 -07002964 class String {
2965 public:
2966 String() {
2967 mpBase = 0;
2968 mUsed = 0;
2969 mSize = 0;
2970 }
2971
Jack Palevich303d8ff2009-06-11 19:06:24 -07002972 String(const char* item, int len, bool adopt) {
2973 if (len < 0) {
2974 len = strlen(item);
2975 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002976 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002977 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002978 mUsed = len;
2979 mSize = len + 1;
2980 } else {
2981 mpBase = 0;
2982 mUsed = 0;
2983 mSize = 0;
2984 appendBytes(item, len);
2985 }
2986 }
2987
Jack Palevich303d8ff2009-06-11 19:06:24 -07002988 String(const String& other) {
2989 mpBase = 0;
2990 mUsed = 0;
2991 mSize = 0;
2992 appendBytes(other.getUnwrapped(), other.len());
2993 }
2994
Jack Palevicheedf9d22009-06-04 16:23:40 -07002995 ~String() {
2996 if (mpBase) {
2997 free(mpBase);
2998 }
2999 }
3000
Jack Palevicha6baa232009-06-12 11:25:59 -07003001 String& operator=(const String& other) {
3002 clear();
3003 appendBytes(other.getUnwrapped(), other.len());
3004 return *this;
3005 }
3006
Jack Palevich303d8ff2009-06-11 19:06:24 -07003007 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003008 return mpBase;
3009 }
3010
Jack Palevich303d8ff2009-06-11 19:06:24 -07003011 void clear() {
3012 mUsed = 0;
3013 if (mSize > 0) {
3014 mpBase[0] = 0;
3015 }
3016 }
3017
Jack Palevicheedf9d22009-06-04 16:23:40 -07003018 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003019 appendBytes(s, strlen(s));
3020 }
3021
3022 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003023 memcpy(ensure(n), s, n + 1);
3024 }
3025
3026 void append(char c) {
3027 * ensure(1) = c;
3028 }
3029
Jack Palevich86351982009-06-30 18:09:56 -07003030 void append(String& other) {
3031 appendBytes(other.getUnwrapped(), other.len());
3032 }
3033
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003034 char* orphan() {
3035 char* result = mpBase;
3036 mpBase = 0;
3037 mUsed = 0;
3038 mSize = 0;
3039 return result;
3040 }
3041
Jack Palevicheedf9d22009-06-04 16:23:40 -07003042 void printf(const char* fmt,...) {
3043 va_list ap;
3044 va_start(ap, fmt);
3045 vprintf(fmt, ap);
3046 va_end(ap);
3047 }
3048
3049 void vprintf(const char* fmt, va_list ap) {
3050 char* temp;
3051 int numChars = vasprintf(&temp, fmt, ap);
3052 memcpy(ensure(numChars), temp, numChars+1);
3053 free(temp);
3054 }
3055
Jack Palevich303d8ff2009-06-11 19:06:24 -07003056 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003057 return mUsed;
3058 }
3059
3060 private:
3061 char* ensure(int n) {
3062 size_t newUsed = mUsed + n;
3063 if (newUsed > mSize) {
3064 size_t newSize = mSize * 2 + 10;
3065 if (newSize < newUsed) {
3066 newSize = newUsed;
3067 }
3068 mpBase = (char*) realloc(mpBase, newSize + 1);
3069 mSize = newSize;
3070 }
3071 mpBase[newUsed] = '\0';
3072 char* result = mpBase + mUsed;
3073 mUsed = newUsed;
3074 return result;
3075 }
3076
3077 char* mpBase;
3078 size_t mUsed;
3079 size_t mSize;
3080 };
3081
Jack Palevich569f1352009-06-29 14:29:08 -07003082 void internKeywords() {
3083 // Note: order has to match TOK_ constants
3084 static const char* keywords[] = {
3085 "int",
3086 "char",
3087 "void",
3088 "if",
3089 "else",
3090 "while",
3091 "break",
3092 "return",
3093 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003094 "auto",
3095 "case",
3096 "const",
3097 "continue",
3098 "default",
3099 "do",
3100 "double",
3101 "enum",
3102 "extern",
3103 "float",
3104 "goto",
3105 "long",
3106 "register",
3107 "short",
3108 "signed",
3109 "sizeof",
3110 "static",
3111 "struct",
3112 "switch",
3113 "typedef",
3114 "union",
3115 "unsigned",
3116 "volatile",
3117 "_Bool",
3118 "_Complex",
3119 "_Imaginary",
3120 "inline",
3121 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003122
3123 // predefined tokens that can also be symbols start here:
3124 "pragma",
3125 "define",
3126 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003127 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003128
Jack Palevich569f1352009-06-29 14:29:08 -07003129 for(int i = 0; keywords[i]; i++) {
3130 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003131 }
Jack Palevich569f1352009-06-29 14:29:08 -07003132 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003133
Jack Palevich36d94142009-06-08 15:55:32 -07003134 struct InputState {
3135 InputStream* pStream;
3136 int oldCh;
3137 };
3138
Jack Palevich2db168f2009-06-11 14:29:47 -07003139 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003140 void* pAddress;
3141 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003142 tokenid_t tok;
3143 size_t level;
3144 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003145 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003146 };
3147
Jack Palevich303d8ff2009-06-11 19:06:24 -07003148 class SymbolStack {
3149 public:
3150 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003151 mpArena = 0;
3152 mpTokenTable = 0;
3153 }
3154
3155 void setArena(Arena* pArena) {
3156 mpArena = pArena;
3157 }
3158
3159 void setTokenTable(TokenTable* pTokenTable) {
3160 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003161 }
3162
3163 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003164 Mark mark;
3165 mark.mArenaMark = mpArena->mark();
3166 mark.mSymbolHead = mStack.size();
3167 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003168 }
3169
3170 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003171 // Undo any shadowing that was done:
3172 Mark mark = mLevelStack.back();
3173 mLevelStack.pop_back();
3174 while (mStack.size() > mark.mSymbolHead) {
3175 VariableInfo* pV = mStack.back();
3176 mStack.pop_back();
3177 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003178 }
Jack Palevich569f1352009-06-29 14:29:08 -07003179 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003180 }
3181
Jack Palevich569f1352009-06-29 14:29:08 -07003182 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3183 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3184 return pV && pV->level == level();
3185 }
3186
3187 VariableInfo* add(tokenid_t tok) {
3188 Token& token = (*mpTokenTable)[tok];
3189 VariableInfo* pOldV = token.mpVariableInfo;
3190 VariableInfo* pNewV =
3191 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3192 memset(pNewV, 0, sizeof(VariableInfo));
3193 pNewV->tok = tok;
3194 pNewV->level = level();
3195 pNewV->pOldDefinition = pOldV;
3196 token.mpVariableInfo = pNewV;
3197 mStack.push_back(pNewV);
3198 return pNewV;
3199 }
3200
Jack Palevich86351982009-06-30 18:09:56 -07003201 VariableInfo* add(Type* pType) {
3202 VariableInfo* pVI = add(pType->id);
3203 pVI->pType = pType;
3204 return pVI;
3205 }
3206
Jack Palevich569f1352009-06-29 14:29:08 -07003207 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3208 for (size_t i = 0; i < mStack.size(); i++) {
3209 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003210 break;
3211 }
3212 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003213 }
3214
Jack Palevich303d8ff2009-06-11 19:06:24 -07003215 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003216 inline size_t level() {
3217 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003218 }
3219
Jack Palevich569f1352009-06-29 14:29:08 -07003220 struct Mark {
3221 Arena::Mark mArenaMark;
3222 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003223 };
3224
Jack Palevich569f1352009-06-29 14:29:08 -07003225 Arena* mpArena;
3226 TokenTable* mpTokenTable;
3227 Vector<VariableInfo*> mStack;
3228 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003229 };
Jack Palevich36d94142009-06-08 15:55:32 -07003230
3231 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003232 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003233 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003234 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003235 int tokl; // token operator level
3236 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003237 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003238 intptr_t loc; // local variable index
3239 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003240 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003241 char* dptr; // Macro state: Points to macro text during macro playback.
3242 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003243 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003244 ACCSymbolLookupFn mpSymbolLookupFn;
3245 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003246
3247 // Arena for the duration of the compile
3248 Arena mGlobalArena;
3249 // Arena for data that's only needed when compiling a single function
3250 Arena mLocalArena;
3251
Jack Palevich2ff5c222009-07-23 15:11:22 -07003252 Arena* mpCurrentArena;
3253
Jack Palevich569f1352009-06-29 14:29:08 -07003254 TokenTable mTokenTable;
3255 SymbolStack mGlobals;
3256 SymbolStack mLocals;
3257
Jack Palevich40600de2009-07-01 15:32:35 -07003258 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003259 Type* mkpInt; // int
3260 Type* mkpChar; // char
3261 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003262 Type* mkpFloat;
3263 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003264 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003265 Type* mkpIntPtr;
3266 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003267 Type* mkpFloatPtr;
3268 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003269 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003270
Jack Palevich36d94142009-06-08 15:55:32 -07003271 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003272 int mLineNumber;
3273 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003274
3275 CodeBuf codeBuf;
3276 CodeGenerator* pGen;
3277
Jack Palevicheedf9d22009-06-04 16:23:40 -07003278 String mErrorBuf;
3279
Jack Palevicheedf9d22009-06-04 16:23:40 -07003280 String mPragmas;
3281 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003282 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003283
Jack Palevich21a15a22009-05-11 14:49:29 -07003284 static const int ALLOC_SIZE = 99999;
3285
Jack Palevich303d8ff2009-06-11 19:06:24 -07003286 static const int TOK_DUMMY = 1;
3287 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003288 static const int TOK_NUM_FLOAT = 3;
3289 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003290
3291 // 3..255 are character and/or operators
3292
Jack Palevich2db168f2009-06-11 14:29:47 -07003293 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003294 // Order has to match string list in "internKeywords".
3295 enum {
3296 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3297 TOK_INT = TOK_KEYWORD,
3298 TOK_CHAR,
3299 TOK_VOID,
3300 TOK_IF,
3301 TOK_ELSE,
3302 TOK_WHILE,
3303 TOK_BREAK,
3304 TOK_RETURN,
3305 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003306 TOK_AUTO,
3307 TOK_CASE,
3308 TOK_CONST,
3309 TOK_CONTINUE,
3310 TOK_DEFAULT,
3311 TOK_DO,
3312 TOK_DOUBLE,
3313 TOK_ENUM,
3314 TOK_EXTERN,
3315 TOK_FLOAT,
3316 TOK_GOTO,
3317 TOK_LONG,
3318 TOK_REGISTER,
3319 TOK_SHORT,
3320 TOK_SIGNED,
3321 TOK_SIZEOF,
3322 TOK_STATIC,
3323 TOK_STRUCT,
3324 TOK_SWITCH,
3325 TOK_TYPEDEF,
3326 TOK_UNION,
3327 TOK_UNSIGNED,
3328 TOK_VOLATILE,
3329 TOK__BOOL,
3330 TOK__COMPLEX,
3331 TOK__IMAGINARY,
3332 TOK_INLINE,
3333 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003334
3335 // Symbols start after keywords
3336
3337 TOK_SYMBOL,
3338 TOK_PRAGMA = TOK_SYMBOL,
3339 TOK_DEFINE,
3340 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003341 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003342
3343 static const int LOCAL = 0x200;
3344
3345 static const int SYM_FORWARD = 0;
3346 static const int SYM_DEFINE = 1;
3347
3348 /* tokens in string heap */
3349 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003350
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003351 static const int OP_INCREMENT = 0;
3352 static const int OP_DECREMENT = 1;
3353 static const int OP_MUL = 2;
3354 static const int OP_DIV = 3;
3355 static const int OP_MOD = 4;
3356 static const int OP_PLUS = 5;
3357 static const int OP_MINUS = 6;
3358 static const int OP_SHIFT_LEFT = 7;
3359 static const int OP_SHIFT_RIGHT = 8;
3360 static const int OP_LESS_EQUAL = 9;
3361 static const int OP_GREATER_EQUAL = 10;
3362 static const int OP_LESS = 11;
3363 static const int OP_GREATER = 12;
3364 static const int OP_EQUALS = 13;
3365 static const int OP_NOT_EQUALS = 14;
3366 static const int OP_LOGICAL_AND = 15;
3367 static const int OP_LOGICAL_OR = 16;
3368 static const int OP_BIT_AND = 17;
3369 static const int OP_BIT_XOR = 18;
3370 static const int OP_BIT_OR = 19;
3371 static const int OP_BIT_NOT = 20;
3372 static const int OP_LOGICAL_NOT = 21;
3373 static const int OP_COUNT = 22;
3374
3375 /* Operators are searched from front, the two-character operators appear
3376 * before the single-character operators with the same first character.
3377 * @ is used to pad out single-character operators.
3378 */
3379 static const char* operatorChars;
3380 static const char operatorLevel[];
3381
Jack Palevich569f1352009-06-29 14:29:08 -07003382 /* Called when we detect an internal problem. Does nothing in production.
3383 *
3384 */
3385 void internalError() {
3386 * (char*) 0 = 0;
3387 }
3388
Jack Palevich86351982009-06-30 18:09:56 -07003389 void assert(bool isTrue) {
3390 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003391 internalError();
3392 }
Jack Palevich86351982009-06-30 18:09:56 -07003393 }
3394
Jack Palevich40600de2009-07-01 15:32:35 -07003395 bool isSymbol(tokenid_t t) {
3396 return t >= TOK_SYMBOL &&
3397 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3398 }
3399
3400 bool isSymbolOrKeyword(tokenid_t t) {
3401 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003402 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003403 }
3404
Jack Palevich86351982009-06-30 18:09:56 -07003405 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003406 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003407 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3408 if (pV && pV->tok != t) {
3409 internalError();
3410 }
3411 return pV;
3412 }
3413
3414 inline bool isDefined(tokenid_t t) {
3415 return t >= TOK_SYMBOL && VI(t) != 0;
3416 }
3417
Jack Palevich40600de2009-07-01 15:32:35 -07003418 const char* nameof(tokenid_t t) {
3419 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003420 return mTokenTable[t].pText;
3421 }
3422
Jack Palevich21a15a22009-05-11 14:49:29 -07003423 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003424 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003425 }
3426
3427 void inp() {
3428 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003429 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003430 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003431 dptr = 0;
3432 ch = dch;
3433 }
Jack Palevichdc456462009-07-16 16:50:56 -07003434 } else {
3435 if (mbBumpLine) {
3436 mLineNumber++;
3437 mbBumpLine = false;
3438 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003439 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003440 if (ch == '\n') {
3441 mbBumpLine = true;
3442 }
3443 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003444#if 0
3445 printf("ch='%c' 0x%x\n", ch, ch);
3446#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003447 }
3448
3449 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003450 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003451 }
3452
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003453 int decodeHex(int c) {
3454 if (isdigit(c)) {
3455 c -= '0';
3456 } else if (c <= 'F') {
3457 c = c - 'A' + 10;
3458 } else {
3459 c =c - 'a' + 10;
3460 }
3461 return c;
3462 }
3463
Jack Palevichb4758ff2009-06-12 12:49:14 -07003464 /* read a character constant, advances ch to after end of constant */
3465 int getq() {
3466 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003467 if (ch == '\\') {
3468 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003469 if (isoctal(ch)) {
3470 // 1 to 3 octal characters.
3471 val = 0;
3472 for(int i = 0; i < 3; i++) {
3473 if (isoctal(ch)) {
3474 val = (val << 3) + ch - '0';
3475 inp();
3476 }
3477 }
3478 return val;
3479 } else if (ch == 'x' || ch == 'X') {
3480 // N hex chars
3481 inp();
3482 if (! isxdigit(ch)) {
3483 error("'x' character escape requires at least one digit.");
3484 } else {
3485 val = 0;
3486 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003487 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003488 inp();
3489 }
3490 }
3491 } else {
3492 int val = ch;
3493 switch (ch) {
3494 case 'a':
3495 val = '\a';
3496 break;
3497 case 'b':
3498 val = '\b';
3499 break;
3500 case 'f':
3501 val = '\f';
3502 break;
3503 case 'n':
3504 val = '\n';
3505 break;
3506 case 'r':
3507 val = '\r';
3508 break;
3509 case 't':
3510 val = '\t';
3511 break;
3512 case 'v':
3513 val = '\v';
3514 break;
3515 case '\\':
3516 val = '\\';
3517 break;
3518 case '\'':
3519 val = '\'';
3520 break;
3521 case '"':
3522 val = '"';
3523 break;
3524 case '?':
3525 val = '?';
3526 break;
3527 default:
3528 error("Undefined character escape %c", ch);
3529 break;
3530 }
3531 inp();
3532 return val;
3533 }
3534 } else {
3535 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003536 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003537 return val;
3538 }
3539
3540 static bool isoctal(int ch) {
3541 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003542 }
3543
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003544 bool acceptCh(int c) {
3545 bool result = c == ch;
3546 if (result) {
3547 pdef(ch);
3548 inp();
3549 }
3550 return result;
3551 }
3552
3553 bool acceptDigitsCh() {
3554 bool result = false;
3555 while (isdigit(ch)) {
3556 result = true;
3557 pdef(ch);
3558 inp();
3559 }
3560 return result;
3561 }
3562
3563 void parseFloat() {
3564 tok = TOK_NUM_DOUBLE;
3565 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003566 if(mTokenString.len() == 0) {
3567 mTokenString.append('0');
3568 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003569 acceptCh('.');
3570 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003571 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003572 acceptCh('-') || acceptCh('+');
3573 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003574 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003575 if (ch == 'f' || ch == 'F') {
3576 tok = TOK_NUM_FLOAT;
3577 inp();
3578 } else if (ch == 'l' || ch == 'L') {
3579 inp();
3580 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003581 }
3582 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003583 char* pEnd = pText + strlen(pText);
3584 char* pEndPtr = 0;
3585 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003586 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003587 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003588 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003589 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003590 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003591 if (errno || pEndPtr != pEnd) {
3592 error("Can't parse constant: %s", pText);
3593 }
3594 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003595 }
3596
Jack Palevich21a15a22009-05-11 14:49:29 -07003597 void next() {
3598 int l, a;
3599
Jack Palevich546b2242009-05-13 15:10:04 -07003600 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003601 if (ch == '#') {
3602 inp();
3603 next();
3604 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003605 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003606 } else if (tok == TOK_PRAGMA) {
3607 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003608 } else if (tok == TOK_LINE) {
3609 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003610 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003611 error("Unsupported preprocessor directive \"%s\"",
3612 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003613 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003614 }
3615 inp();
3616 }
3617 tokl = 0;
3618 tok = ch;
3619 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003620 if (isdigit(ch) || ch == '.') {
3621 // Start of a numeric constant. Could be integer, float, or
3622 // double, won't know until we look further.
3623 mTokenString.clear();
3624 pdef(ch);
3625 inp();
3626 int base = 10;
3627 if (tok == '0') {
3628 if (ch == 'x' || ch == 'X') {
3629 base = 16;
3630 tok = TOK_NUM;
3631 tokc = 0;
3632 inp();
3633 while ( isxdigit(ch) ) {
3634 tokc = (tokc << 4) + decodeHex(ch);
3635 inp();
3636 }
3637 } else if (isoctal(ch)){
3638 base = 8;
3639 tok = TOK_NUM;
3640 tokc = 0;
3641 while ( isoctal(ch) ) {
3642 tokc = (tokc << 3) + (ch - '0');
3643 inp();
3644 }
3645 }
3646 } else if (isdigit(tok)){
3647 acceptDigitsCh();
3648 }
3649 if (base == 10) {
3650 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3651 parseFloat();
3652 } else {
3653 // It's an integer constant
3654 char* pText = mTokenString.getUnwrapped();
3655 char* pEnd = pText + strlen(pText);
3656 char* pEndPtr = 0;
3657 errno = 0;
3658 tokc = strtol(pText, &pEndPtr, base);
3659 if (errno || pEndPtr != pEnd) {
3660 error("Can't parse constant: %s %d %d", pText, base, errno);
3661 }
3662 tok = TOK_NUM;
3663 }
3664 }
3665 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003666 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003667 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003668 pdef(ch);
3669 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003670 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003671 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3672 // Is this a macro?
3673 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3674 if (pMacroDefinition) {
3675 // Yes, it is a macro
3676 dptr = pMacroDefinition;
3677 dch = ch;
3678 inp();
3679 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003680 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003681 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003682 inp();
3683 if (tok == '\'') {
3684 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003685 tokc = getq();
3686 if (ch != '\'') {
3687 error("Expected a ' character, got %c", ch);
3688 } else {
3689 inp();
3690 }
Jack Palevich546b2242009-05-13 15:10:04 -07003691 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003692 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003693 while (ch && ch != EOF) {
3694 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003695 inp();
3696 inp();
3697 if (ch == '/')
3698 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003699 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003700 if (ch == EOF) {
3701 error("End of file inside comment.");
3702 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003703 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003704 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003705 } else if ((tok == '/') & (ch == '/')) {
3706 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003707 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003708 inp();
3709 }
3710 inp();
3711 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003712 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003713 const char* t = operatorChars;
3714 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003715 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003716 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003717 tokl = operatorLevel[opIndex];
3718 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003719 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003720#if 0
3721 printf("%c%c -> tokl=%d tokc=0x%x\n",
3722 l, a, tokl, tokc);
3723#endif
3724 if (a == ch) {
3725 inp();
3726 tok = TOK_DUMMY; /* dummy token for double tokens */
3727 }
3728 break;
3729 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003730 opIndex++;
3731 }
3732 if (l == 0) {
3733 tokl = 0;
3734 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003735 }
3736 }
3737 }
3738#if 0
3739 {
Jack Palevich569f1352009-06-29 14:29:08 -07003740 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003741 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003742 fprintf(stderr, "%s\n", buf.getUnwrapped());
3743 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003744#endif
3745 }
3746
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003747 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003748 next();
3749 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003750 String* pName = new String();
3751 while (isspace(ch)) {
3752 inp();
3753 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003754 if (ch == '(') {
3755 delete pName;
3756 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003757 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003758 }
3759 while (isspace(ch)) {
3760 inp();
3761 }
Jack Palevich569f1352009-06-29 14:29:08 -07003762 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003763 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003764 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003765 inp();
3766 }
Jack Palevich569f1352009-06-29 14:29:08 -07003767 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3768 memcpy(pDefn, value.getUnwrapped(), value.len());
3769 pDefn[value.len()] = 0;
3770 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003771 }
3772
Jack Palevicheedf9d22009-06-04 16:23:40 -07003773 void doPragma() {
3774 // # pragma name(val)
3775 int state = 0;
3776 while(ch != EOF && ch != '\n' && state < 10) {
3777 switch(state) {
3778 case 0:
3779 if (isspace(ch)) {
3780 inp();
3781 } else {
3782 state++;
3783 }
3784 break;
3785 case 1:
3786 if (isalnum(ch)) {
3787 mPragmas.append(ch);
3788 inp();
3789 } else if (ch == '(') {
3790 mPragmas.append(0);
3791 inp();
3792 state++;
3793 } else {
3794 state = 11;
3795 }
3796 break;
3797 case 2:
3798 if (isalnum(ch)) {
3799 mPragmas.append(ch);
3800 inp();
3801 } else if (ch == ')') {
3802 mPragmas.append(0);
3803 inp();
3804 state = 10;
3805 } else {
3806 state = 11;
3807 }
3808 break;
3809 }
3810 }
3811 if(state != 10) {
3812 error("Unexpected pragma syntax");
3813 }
3814 mPragmaStringCount += 2;
3815 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003816
Jack Palevichdc456462009-07-16 16:50:56 -07003817 void doLine() {
3818 // # line number { "filename "}
3819 next();
3820 if (tok != TOK_NUM) {
3821 error("Expected a line-number");
3822 } else {
3823 mLineNumber = tokc-1; // The end-of-line will increment it.
3824 }
3825 while(ch != EOF && ch != '\n') {
3826 inp();
3827 }
3828 }
3829
Jack Palevichac0e95e2009-05-29 13:53:44 -07003830 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003831 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003832 mErrorBuf.vprintf(fmt, ap);
3833 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003834 }
3835
Jack Palevich8b0624c2009-05-20 12:12:06 -07003836 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003837 if (tok != c) {
3838 error("'%c' expected", c);
3839 }
3840 next();
3841 }
3842
Jack Palevich86351982009-06-30 18:09:56 -07003843 bool accept(intptr_t c) {
3844 if (tok == c) {
3845 next();
3846 return true;
3847 }
3848 return false;
3849 }
3850
Jack Palevich40600de2009-07-01 15:32:35 -07003851 bool acceptStringLiteral() {
3852 if (tok == '"') {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003853 pGen->leaR0((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003854 // This while loop merges multiple adjacent string constants.
3855 while (tok == '"') {
3856 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003857 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003858 }
3859 if (ch != '"') {
3860 error("Unterminated string constant.");
3861 }
3862 inp();
3863 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003864 }
Jack Palevich40600de2009-07-01 15:32:35 -07003865 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003866 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003867 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003868 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003869
3870 return true;
3871 }
3872 return false;
3873 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003874
Jack Palevichb1544ca2009-07-16 15:09:20 -07003875 void linkGlobal(tokenid_t t, bool isFunction) {
3876 VariableInfo* pVI = VI(t);
3877 void* n = NULL;
3878 if (mpSymbolLookupFn) {
3879 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3880 }
3881 if (pVI->pType == NULL) {
3882 if (isFunction) {
3883 pVI->pType = mkpIntFn;
3884 } else {
3885 pVI->pType = mkpInt;
3886 }
3887 }
3888 pVI->pAddress = n;
3889 }
3890
Jack Palevich40600de2009-07-01 15:32:35 -07003891 /* Parse and evaluate a unary expression.
3892 * allowAssignment is true if '=' parsing wanted (quick hack)
3893 */
3894 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003895 tokenid_t t;
3896 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003897 t = 0;
3898 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3899 if (acceptStringLiteral()) {
3900 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003901 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003902 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003903 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003904 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003905 t = tok;
3906 next();
3907 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003908 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003909 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003910 // Align to 4-byte boundary
3911 glo = (char*) (((intptr_t) glo + 3) & -4);
3912 * (float*) glo = (float) ad;
3913 pGen->loadFloat((int) glo, mkpFloat);
3914 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003915 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003916 // Align to 8-byte boundary
3917 glo = (char*) (((intptr_t) glo + 7) & -8);
3918 * (double*) glo = ad;
3919 pGen->loadFloat((int) glo, mkpDouble);
3920 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003921 } else if (c == 2) {
3922 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003923 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003924 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003925 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003926 else if (t == '+') {
3927 // ignore unary plus.
3928 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003929 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003930 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003931 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003932 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003933 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003934 if (pCast) {
3935 skip(')');
3936 unary(false);
3937 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003938 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003939 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003940 skip(')');
3941 }
3942 } else if (t == '*') {
3943 /* This is a pointer dereference.
3944 */
3945 unary(false);
3946 Type* pR0Type = pGen->getR0Type();
3947 if (pR0Type->tag != TY_POINTER) {
3948 error("Expected a pointer type.");
3949 } else {
3950 if (pR0Type->pHead->tag == TY_FUNC) {
3951 t = 0;
3952 }
3953 if (accept('=')) {
3954 pGen->pushR0();
3955 expr();
Jack Palevich58c30ee2009-07-17 16:35:23 -07003956 pGen->storeR0ToTOS();
Jack Palevich45431bc2009-07-13 15:57:26 -07003957 } else if (t) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003958 pGen->loadR0FromR0();
Jack Palevich45431bc2009-07-13 15:57:26 -07003959 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003960 }
Jack Palevich3f226492009-07-02 14:46:19 -07003961 // Else we fall through to the function call below, with
3962 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003963 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003964 VariableInfo* pVI = VI(tok);
Jack Palevich2ff5c222009-07-23 15:11:22 -07003965 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType));
Jack Palevich21a15a22009-05-11 14:49:29 -07003966 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003967 } else if (t == EOF ) {
3968 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003969 } else if (t == ';') {
3970 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003971 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003972 // Don't have to do anything special here, the error
3973 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003974 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003975 if (!isDefined(t)) {
3976 mGlobals.add(t);
3977 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003978 }
Jack Palevich8df46192009-07-07 14:48:51 -07003979 VariableInfo* pVI = VI(t);
3980 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003981 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003982 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003983 linkGlobal(t, tok == '(');
3984 n = (intptr_t) pVI->pAddress;
3985 if (!n && tok != '(') {
3986 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003987 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003988 }
Jack Palevich40600de2009-07-01 15:32:35 -07003989 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003990 /* assignment */
3991 next();
3992 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003993 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 } else if (tok != '(') {
3995 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003996 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003997 linkGlobal(t, false);
3998 n = (intptr_t) pVI->pAddress;
3999 if (!n) {
4000 error("Undeclared variable %s\n", nameof(t));
4001 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004002 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07004003 // load a variable
4004 pGen->loadR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004005 if (tokl == 11) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004006 // post inc / post dec
4007 pGen->pushR0();
4008 impInc(tokc);
4009 pGen->storeR0(n, pVI->pType);
4010 pGen->popR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07004011 next();
4012 }
4013 }
4014 }
4015 }
4016
4017 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07004018 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07004019 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07004020 VariableInfo* pVI = NULL;
4021 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07004022 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07004023 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07004024 } else {
4025 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07004026 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07004027 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004028 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07004029 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07004030 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004031 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07004032 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004033 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004034 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004035 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004036 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004037 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004039 Type* pTargetType;
4040 if (pArgList) {
4041 pTargetType = pArgList->pHead;
4042 pArgList = pArgList->pTail;
4043 } else {
4044 pTargetType = pGen->getR0Type();
4045 if (pTargetType->tag == TY_FLOAT) {
4046 pTargetType = mkpDouble;
4047 }
4048 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004049 if (pTargetType->tag == TY_VOID) {
4050 error("Can't pass void value for argument %d",
4051 argCount + 1);
4052 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004053 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004054 }
Jack Palevich95727a02009-07-06 12:07:15 -07004055 if (accept(',')) {
4056 // fine
4057 } else if ( tok != ')') {
4058 error("Expected ',' or ')'");
4059 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004060 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004061 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004062 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004063 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004064 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004065 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004066 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004067 if (!n) {
4068 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004069 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4070 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004071 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004072 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004073 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004074 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4075 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004076 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004077 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004078 }
4079 }
4080
Jack Palevich58c30ee2009-07-17 16:35:23 -07004081 /* Increment / decrement R0 */
4082
4083 void impInc(int op) {
4084 Type* pType = pGen->getR0Type();
4085 int lit = 1;
4086 if (op == OP_DECREMENT) {
4087 lit = -1;
4088 }
4089 switch (pType->tag) {
4090 case TY_INT:
4091 case TY_CHAR:
4092 case TY_POINTER:
4093 pGen->pushR0();
4094 pGen->li(lit);
4095 pGen->genOp(OP_PLUS);
4096 break;
4097 default:
4098 error("++/-- illegal for this type.");
4099 break;
4100 }
4101 }
4102
Jack Palevich40600de2009-07-01 15:32:35 -07004103 /* Recursive descent parser for binary operations.
4104 */
4105 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004106 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004107 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004108 if (level-- == 1)
4109 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004110 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004111 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004112 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004113 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004114 t = tokc;
4115 next();
4116
Jack Palevich40600de2009-07-01 15:32:35 -07004117 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004118 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004119 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004120 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004121 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004122 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004123 // Check for syntax error.
4124 if (pGen->getR0Type() == NULL) {
4125 // We failed to parse a right-hand argument.
4126 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004127 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004128 }
Jack Palevich40600de2009-07-01 15:32:35 -07004129 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004130 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004131 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004132 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 }
4134 }
4135 }
4136 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004137 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004138 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004139 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07004140 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004141 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004142 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07004143 }
4144 }
4145 }
4146
4147 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004148 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004149 }
4150
4151 int test_expr() {
4152 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004153 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 }
4155
Jack Palevicha6baa232009-06-12 11:25:59 -07004156 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004157 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004158
Jack Palevich95727a02009-07-06 12:07:15 -07004159 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004160 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004161 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004162 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004163 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004164 next();
4165 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004166 a = test_expr();
4167 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004168 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004169 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004170 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004171 n = pGen->gjmp(0); /* jmp */
4172 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004173 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004174 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004175 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004176 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004177 }
Jack Palevich546b2242009-05-13 15:10:04 -07004178 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004179 t = tok;
4180 next();
4181 skip('(');
4182 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004183 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004184 a = test_expr();
4185 } else {
4186 if (tok != ';')
4187 expr();
4188 skip(';');
4189 n = codeBuf.getPC();
4190 a = 0;
4191 if (tok != ';')
4192 a = test_expr();
4193 skip(';');
4194 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004195 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004196 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004197 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004198 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004199 n = t + 4;
4200 }
4201 }
4202 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004203 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004204 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004205 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004206 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004207 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004208 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004209 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004210 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004211 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004212 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004213 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004214 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004215 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004216 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004217 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004218 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004219 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004220 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004221 if (pReturnType->tag == TY_VOID) {
4222 error("Must not return a value from a void function");
4223 } else {
4224 pGen->convertR0(pReturnType);
4225 }
4226 } else {
4227 if (pReturnType->tag != TY_VOID) {
4228 error("Must specify a value here");
4229 }
Jack Palevich8df46192009-07-07 14:48:51 -07004230 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004231 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004232 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004233 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004234 } else if (tok != ';')
4235 expr();
4236 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004237 }
4238 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004239
Jack Palevicha8f427f2009-07-13 18:40:08 -07004240 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004241 if (a == b) {
4242 return true;
4243 }
4244 if (a == NULL || b == NULL) {
4245 return false;
4246 }
4247 TypeTag at = a->tag;
4248 if (at != b->tag) {
4249 return false;
4250 }
4251 if (at == TY_POINTER) {
4252 return typeEqual(a->pHead, b->pHead);
4253 } else if (at == TY_FUNC || at == TY_PARAM) {
4254 return typeEqual(a->pHead, b->pHead)
4255 && typeEqual(a->pTail, b->pTail);
4256 }
4257 return true;
4258 }
4259
Jack Palevich2ff5c222009-07-23 15:11:22 -07004260 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004261 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004262 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004263 memset(pType, 0, sizeof(*pType));
4264 pType->tag = tag;
4265 pType->pHead = pHead;
4266 pType->pTail = pTail;
4267 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004268 }
4269
Jack Palevich2ff5c222009-07-23 15:11:22 -07004270 Type* createPtrType(Type* pType) {
4271 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004272 }
4273
4274 /**
4275 * Try to print a type in declaration order
4276 */
Jack Palevich86351982009-06-30 18:09:56 -07004277 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004278 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004279 if (pType == NULL) {
4280 buffer.appendCStr("null");
4281 return;
4282 }
Jack Palevich3f226492009-07-02 14:46:19 -07004283 decodeTypeImp(buffer, pType);
4284 }
4285
4286 void decodeTypeImp(String& buffer, Type* pType) {
4287 decodeTypeImpPrefix(buffer, pType);
4288
Jack Palevich86351982009-06-30 18:09:56 -07004289 String temp;
4290 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004291 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004292 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004293 }
4294
4295 decodeTypeImpPostfix(buffer, pType);
4296 }
4297
4298 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4299 TypeTag tag = pType->tag;
4300
Jack Palevich37c54bd2009-07-14 18:35:36 -07004301 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004302 switch (tag) {
4303 case TY_INT:
4304 buffer.appendCStr("int");
4305 break;
4306 case TY_CHAR:
4307 buffer.appendCStr("char");
4308 break;
4309 case TY_VOID:
4310 buffer.appendCStr("void");
4311 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004312 case TY_FLOAT:
4313 buffer.appendCStr("float");
4314 break;
4315 case TY_DOUBLE:
4316 buffer.appendCStr("double");
4317 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004318 default:
4319 break;
4320 }
Jack Palevich86351982009-06-30 18:09:56 -07004321 buffer.append(' ');
4322 }
Jack Palevich3f226492009-07-02 14:46:19 -07004323
4324 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004325 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004326 break;
4327 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004328 break;
4329 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004330 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004331 case TY_FLOAT:
4332 break;
4333 case TY_DOUBLE:
4334 break;
Jack Palevich86351982009-06-30 18:09:56 -07004335 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004336 decodeTypeImpPrefix(buffer, pType->pHead);
4337 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4338 buffer.append('(');
4339 }
4340 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004341 break;
4342 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004343 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004344 break;
4345 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004346 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004347 break;
4348 default:
4349 String temp;
4350 temp.printf("Unknown tag %d", pType->tag);
4351 buffer.append(temp);
4352 break;
4353 }
Jack Palevich3f226492009-07-02 14:46:19 -07004354 }
4355
4356 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4357 TypeTag tag = pType->tag;
4358
4359 switch(tag) {
4360 case TY_POINTER:
4361 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4362 buffer.append(')');
4363 }
4364 decodeTypeImpPostfix(buffer, pType->pHead);
4365 break;
4366 case TY_FUNC:
4367 buffer.append('(');
4368 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4369 decodeTypeImp(buffer, pArg);
4370 if (pArg->pTail) {
4371 buffer.appendCStr(", ");
4372 }
4373 }
4374 buffer.append(')');
4375 break;
4376 default:
4377 break;
Jack Palevich86351982009-06-30 18:09:56 -07004378 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004379 }
4380
Jack Palevich86351982009-06-30 18:09:56 -07004381 void printType(Type* pType) {
4382 String buffer;
4383 decodeType(buffer, pType);
4384 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004385 }
4386
Jack Palevich2ff5c222009-07-23 15:11:22 -07004387 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004388 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004389 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004390 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004391 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004392 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004393 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004394 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004395 } else if (tok == TOK_FLOAT) {
4396 pType = mkpFloat;
4397 } else if (tok == TOK_DOUBLE) {
4398 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004399 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004400 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004401 }
4402 next();
Jack Palevich86351982009-06-30 18:09:56 -07004403 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004404 }
4405
Jack Palevich2ff5c222009-07-23 15:11:22 -07004406 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004407 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004408 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004409 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004410 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004411 if (declName) {
4412 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004413 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004414
Jack Palevich86351982009-06-30 18:09:56 -07004415 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004416 }
Jack Palevich3f226492009-07-02 14:46:19 -07004417 // fprintf(stderr, "Parsed a declaration: ");
4418 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004419 if (reportFailure) {
4420 return NULL;
4421 }
Jack Palevich86351982009-06-30 18:09:56 -07004422 return pType;
4423 }
4424
Jack Palevich2ff5c222009-07-23 15:11:22 -07004425 Type* expectDeclaration(Type* pBaseType) {
4426 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004427 if (! pType) {
4428 error("Expected a declaration");
4429 }
4430 return pType;
4431 }
4432
Jack Palevich3f226492009-07-02 14:46:19 -07004433 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004434 Type* acceptCastTypeDeclaration() {
4435 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004436 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004437 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004438 }
Jack Palevich86351982009-06-30 18:09:56 -07004439 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004440 }
4441
Jack Palevich2ff5c222009-07-23 15:11:22 -07004442 Type* expectCastTypeDeclaration() {
4443 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004444 if (! pType) {
4445 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004446 }
Jack Palevich3f226492009-07-02 14:46:19 -07004447 return pType;
4448 }
4449
4450 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004451 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004452 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004453 int ptrCounter = 0;
4454 while (accept('*')) {
4455 ptrCounter++;
4456 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004457 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004458 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004459 while (ptrCounter-- > 0) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004460 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004461 }
4462 return pType;
4463 }
4464
4465 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004466 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004467 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004468 // direct-dcl :
4469 // name
4470 // (dcl)
4471 // direct-dcl()
4472 // direct-dcl[]
4473 Type* pNewHead = NULL;
4474 if (accept('(')) {
4475 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004476 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004477 skip(')');
4478 } else if ((declName = acceptSymbol()) != 0) {
4479 if (nameAllowed == false && declName) {
4480 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004481 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004482 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004483 } else if (nameRequired && ! declName) {
4484 String temp;
4485 decodeToken(temp, tok, true);
4486 error("Expected name. Got %s", temp.getUnwrapped());
4487 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004488 }
4489 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004490 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004491 Type* pTail = acceptArgs(nameAllowed);
4492 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004493 skip(')');
4494 }
Jack Palevich3f226492009-07-02 14:46:19 -07004495
4496 if (pNewHead) {
4497 Type* pA = pNewHead;
4498 while (pA->pHead) {
4499 pA = pA->pHead;
4500 }
4501 pA->pHead = pType;
4502 pType = pNewHead;
4503 }
Jack Palevich86351982009-06-30 18:09:56 -07004504 return pType;
4505 }
4506
Jack Palevich2ff5c222009-07-23 15:11:22 -07004507 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004508 Type* pHead = NULL;
4509 Type* pTail = NULL;
4510 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004511 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004512 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004513 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004514 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004515 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004516 if (!pHead) {
4517 pHead = pParam;
4518 pTail = pParam;
4519 } else {
4520 pTail->pTail = pParam;
4521 pTail = pParam;
4522 }
4523 }
4524 }
4525 if (! accept(',')) {
4526 break;
4527 }
4528 }
4529 return pHead;
4530 }
4531
Jack Palevich2ff5c222009-07-23 15:11:22 -07004532 Type* expectPrimitiveType() {
4533 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004534 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004535 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004536 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004537 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004538 }
Jack Palevich86351982009-06-30 18:09:56 -07004539 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004540 }
4541
Jack Palevich86351982009-06-30 18:09:56 -07004542 void addGlobalSymbol(Type* pDecl) {
4543 tokenid_t t = pDecl->id;
4544 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004545 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004546 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004547 }
Jack Palevich86351982009-06-30 18:09:56 -07004548 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004549 }
4550
Jack Palevich86351982009-06-30 18:09:56 -07004551 void reportDuplicate(tokenid_t t) {
4552 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004553 }
4554
Jack Palevich86351982009-06-30 18:09:56 -07004555 void addLocalSymbol(Type* pDecl) {
4556 tokenid_t t = pDecl->id;
4557 if (mLocals.isDefinedAtCurrentLevel(t)) {
4558 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004559 }
Jack Palevich86351982009-06-30 18:09:56 -07004560 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004561 }
4562
Jack Palevich95727a02009-07-06 12:07:15 -07004563 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004564 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004565
Jack Palevich95727a02009-07-06 12:07:15 -07004566 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004567 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004568 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004569 if (!pDecl) {
4570 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004571 }
Jack Palevich86351982009-06-30 18:09:56 -07004572 int variableAddress = 0;
4573 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004574 size_t alignment = pGen->stackAlignmentOf(pDecl);
4575 size_t alignmentMask = ~ (alignment - 1);
4576 size_t sizeOf = pGen->sizeOf(pDecl);
4577 loc = (loc + alignment - 1) & alignmentMask;
4578 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4579 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004580 variableAddress = -loc;
4581 VI(pDecl->id)->pAddress = (void*) variableAddress;
4582 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004583 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004584 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004585 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004586 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004587 if (tok == ',')
4588 next();
4589 }
4590 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004591 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004592 }
4593 }
4594
Jack Palevichf1728be2009-06-12 13:53:51 -07004595 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004596 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004597 }
4598
Jack Palevich37c54bd2009-07-14 18:35:36 -07004599 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004600 if (token == EOF ) {
4601 buffer.printf("EOF");
4602 } else if (token == TOK_NUM) {
4603 buffer.printf("numeric constant");
4604 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004605 if (token < 32) {
4606 buffer.printf("'\\x%02x'", token);
4607 } else {
4608 buffer.printf("'%c'", token);
4609 }
Jack Palevich569f1352009-06-29 14:29:08 -07004610 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004611 if (quote) {
4612 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4613 buffer.printf("keyword \"%s\"", nameof(token));
4614 } else {
4615 buffer.printf("symbol \"%s\"", nameof(token));
4616 }
4617 } else {
4618 buffer.printf("%s", nameof(token));
4619 }
Jack Palevich569f1352009-06-29 14:29:08 -07004620 }
4621 }
4622
Jack Palevich40600de2009-07-01 15:32:35 -07004623 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004624 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004625 if (!result) {
4626 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004627 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004628 error("Expected symbol. Got %s", temp.getUnwrapped());
4629 }
4630 return result;
4631 }
4632
Jack Palevich86351982009-06-30 18:09:56 -07004633 tokenid_t acceptSymbol() {
4634 tokenid_t result = 0;
4635 if (tok >= TOK_SYMBOL) {
4636 result = tok;
4637 next();
Jack Palevich86351982009-06-30 18:09:56 -07004638 }
4639 return result;
4640 }
4641
Jack Palevichb7c81e92009-06-04 19:56:13 -07004642 void globalDeclarations() {
4643 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004644 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004645 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004646 break;
4647 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004648 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004649 if (!pDecl) {
4650 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004651 }
Jack Palevich86351982009-06-30 18:09:56 -07004652 if (! isDefined(pDecl->id)) {
4653 addGlobalSymbol(pDecl);
4654 }
4655 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004656 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004657 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004658 }
Jack Palevich86351982009-06-30 18:09:56 -07004659 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004660 // it's a variable declaration
4661 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004662 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004663 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004664 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004665 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004666 }
Jack Palevich86351982009-06-30 18:09:56 -07004667 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004668 if (tok == TOK_NUM) {
4669 if (name) {
4670 * (int*) name->pAddress = tokc;
4671 }
4672 next();
4673 } else {
4674 error("Expected an integer constant");
4675 }
4676 }
Jack Palevich86351982009-06-30 18:09:56 -07004677 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004678 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004679 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004680 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004681 if (!pDecl) {
4682 break;
4683 }
4684 if (! isDefined(pDecl->id)) {
4685 addGlobalSymbol(pDecl);
4686 }
4687 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 }
4689 skip(';');
4690 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004691 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004692 if (accept(';')) {
4693 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004694 } else if (tok != '{') {
4695 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004696 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004697 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004698 if (name) {
4699 /* patch forward references (XXX: does not work for function
4700 pointers) */
4701 pGen->gsym((int) name->pForward);
4702 /* put function address */
4703 name->pAddress = (void*) codeBuf.getPC();
4704 }
4705 // Calculate stack offsets for parameters
4706 mLocals.pushLevel();
4707 intptr_t a = 8;
4708 int argCount = 0;
4709 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4710 Type* pArg = pP->pHead;
4711 addLocalSymbol(pArg);
4712 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004713 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004714 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004715 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004716 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004717 argCount++;
4718 }
4719 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004720 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004721 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004722 block(0, true);
4723 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004724 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004725 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004726 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004727 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004728 }
4729 }
4730 }
4731
Jack Palevich9cbd2262009-07-08 16:48:41 -07004732 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4733 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4734 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004735 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004736 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004737 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004738 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004739 char* result = (char*) base;
4740 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004741 return result;
4742 }
4743
Jack Palevich21a15a22009-05-11 14:49:29 -07004744 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004745 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004746 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004747 pGlobalBase = 0;
4748 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004749 if (pGen) {
4750 delete pGen;
4751 pGen = 0;
4752 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004753 if (file) {
4754 delete file;
4755 file = 0;
4756 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004757 }
4758
Jack Palevich8c246a92009-07-14 21:14:10 -07004759 // One-time initialization, when class is constructed.
4760 void init() {
4761 mpSymbolLookupFn = 0;
4762 mpSymbolLookupContext = 0;
4763 }
4764
Jack Palevich21a15a22009-05-11 14:49:29 -07004765 void clear() {
4766 tok = 0;
4767 tokc = 0;
4768 tokl = 0;
4769 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004770 rsym = 0;
4771 loc = 0;
4772 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004773 dptr = 0;
4774 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004775 file = 0;
4776 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004777 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004778 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004779 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004780 mLineNumber = 1;
4781 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004782 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004783
Jack Palevich22305132009-05-13 10:58:45 -07004784 void setArchitecture(const char* architecture) {
4785 delete pGen;
4786 pGen = 0;
4787
4788 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004789#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004790 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004791 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004792 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004793#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004794#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004795 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004796 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004797 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004798#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004799 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004800 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004801 }
4802 }
4803
4804 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004805#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004806 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004807#elif defined(DEFAULT_X86_CODEGEN)
4808 pGen = new X86CodeGenerator();
4809#endif
4810 }
4811 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004812 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004813 } else {
4814 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004815 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004816 }
4817 }
4818
Jack Palevich77ae76e2009-05-10 19:59:24 -07004819public:
Jack Palevich22305132009-05-13 10:58:45 -07004820 struct args {
4821 args() {
4822 architecture = 0;
4823 }
4824 const char* architecture;
4825 };
4826
Jack Paleviche7b59062009-05-19 17:12:17 -07004827 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004828 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004829 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004830 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004831
Jack Paleviche7b59062009-05-19 17:12:17 -07004832 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004833 cleanup();
4834 }
4835
Jack Palevich8c246a92009-07-14 21:14:10 -07004836 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4837 mpSymbolLookupFn = pFn;
4838 mpSymbolLookupContext = pContext;
4839 }
4840
Jack Palevich1cdef202009-05-22 12:06:27 -07004841 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004842 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004843
Jack Palevich2ff5c222009-07-23 15:11:22 -07004844 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004845 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004846 cleanup();
4847 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004848 mTokenTable.setArena(&mGlobalArena);
4849 mGlobals.setArena(&mGlobalArena);
4850 mGlobals.setTokenTable(&mTokenTable);
4851 mLocals.setArena(&mLocalArena);
4852 mLocals.setTokenTable(&mTokenTable);
4853
4854 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004855 codeBuf.init(ALLOC_SIZE);
4856 setArchitecture(NULL);
4857 if (!pGen) {
4858 return -1;
4859 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004860#ifdef PROVIDE_TRACE_CODEGEN
4861 pGen = new TraceCodeGenerator(pGen);
4862#endif
4863 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004864 pGen->init(&codeBuf);
4865 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004866 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4867 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004868 inp();
4869 next();
4870 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004871 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004872 result = pGen->finishCompile();
4873 if (result == 0) {
4874 if (mErrorBuf.len()) {
4875 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004876 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004877 }
Jack Palevichce105a92009-07-16 14:30:33 -07004878 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004879 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004880 }
4881
Jack Palevich86351982009-06-30 18:09:56 -07004882 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004883 mkpInt = createType(TY_INT, NULL, NULL);
4884 mkpChar = createType(TY_CHAR, NULL, NULL);
4885 mkpVoid = createType(TY_VOID, NULL, NULL);
4886 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4887 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4888 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4889 mkpIntPtr = createPtrType(mkpInt);
4890 mkpCharPtr = createPtrType(mkpChar);
4891 mkpFloatPtr = createPtrType(mkpFloat);
4892 mkpDoublePtr = createPtrType(mkpDouble);
4893 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004894 }
4895
Jack Palevicha6baa232009-06-12 11:25:59 -07004896 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004897 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004898 }
4899
Jack Palevich569f1352009-06-29 14:29:08 -07004900 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004901 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004902 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004903 }
4904
Jack Palevich569f1352009-06-29 14:29:08 -07004905 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004906 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004907 error("Undefined forward reference: %s",
4908 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004909 }
4910 return true;
4911 }
4912
Jack Palevich21a15a22009-05-11 14:49:29 -07004913 int dump(FILE* out) {
4914 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4915 return 0;
4916 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004917
Jack Palevicha6535612009-05-13 16:24:17 -07004918 int disassemble(FILE* out) {
4919 return pGen->disassemble(out);
4920 }
4921
Jack Palevich1cdef202009-05-22 12:06:27 -07004922 /* Look through the symbol table to find a symbol.
4923 * If found, return its value.
4924 */
4925 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004926 if (mCompileResult == 0) {
4927 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4928 VariableInfo* pVariableInfo = VI(tok);
4929 if (pVariableInfo) {
4930 return pVariableInfo->pAddress;
4931 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004932 }
4933 return NULL;
4934 }
4935
Jack Palevicheedf9d22009-06-04 16:23:40 -07004936 void getPragmas(ACCsizei* actualStringCount,
4937 ACCsizei maxStringCount, ACCchar** strings) {
4938 int stringCount = mPragmaStringCount;
4939 if (actualStringCount) {
4940 *actualStringCount = stringCount;
4941 }
4942 if (stringCount > maxStringCount) {
4943 stringCount = maxStringCount;
4944 }
4945 if (strings) {
4946 char* pPragmas = mPragmas.getUnwrapped();
4947 while (stringCount-- > 0) {
4948 *strings++ = pPragmas;
4949 pPragmas += strlen(pPragmas) + 1;
4950 }
4951 }
4952 }
4953
Jack Palevichac0e95e2009-05-29 13:53:44 -07004954 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004955 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004956 }
4957
Jack Palevich77ae76e2009-05-10 19:59:24 -07004958};
4959
Jack Paleviche7b59062009-05-19 17:12:17 -07004960const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004961 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4962
Jack Paleviche7b59062009-05-19 17:12:17 -07004963const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004964 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4965 5, 5, /* ==, != */
4966 9, 10, /* &&, || */
4967 6, 7, 8, /* & ^ | */
4968 2, 2 /* ~ ! */
4969 };
4970
Jack Palevich8b0624c2009-05-20 12:12:06 -07004971#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004972FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004973#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004974
Jack Palevich8b0624c2009-05-20 12:12:06 -07004975#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004976const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004977 0x1, // ++
4978 0xff, // --
4979 0xc1af0f, // *
4980 0xf9f79991, // /
4981 0xf9f79991, // % (With manual assist to swap results)
4982 0xc801, // +
4983 0xd8f7c829, // -
4984 0xe0d391, // <<
4985 0xf8d391, // >>
4986 0xe, // <=
4987 0xd, // >=
4988 0xc, // <
4989 0xf, // >
4990 0x4, // ==
4991 0x5, // !=
4992 0x0, // &&
4993 0x1, // ||
4994 0xc821, // &
4995 0xc831, // ^
4996 0xc809, // |
4997 0xd0f7, // ~
4998 0x4 // !
4999};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005000#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005001
Jack Palevich1cdef202009-05-22 12:06:27 -07005002struct ACCscript {
5003 ACCscript() {
5004 text = 0;
5005 textLength = 0;
5006 accError = ACC_NO_ERROR;
5007 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005008
Jack Palevich1cdef202009-05-22 12:06:27 -07005009 ~ACCscript() {
5010 delete text;
5011 }
Jack Palevich546b2242009-05-13 15:10:04 -07005012
Jack Palevich8c246a92009-07-14 21:14:10 -07005013 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5014 compiler.registerSymbolCallback(pFn, pContext);
5015 }
5016
Jack Palevich1cdef202009-05-22 12:06:27 -07005017 void setError(ACCenum error) {
5018 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5019 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005020 }
5021 }
5022
Jack Palevich1cdef202009-05-22 12:06:27 -07005023 ACCenum getError() {
5024 ACCenum result = accError;
5025 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005026 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005027 }
5028
Jack Palevich1cdef202009-05-22 12:06:27 -07005029 Compiler compiler;
5030 char* text;
5031 int textLength;
5032 ACCenum accError;
5033};
5034
5035
5036extern "C"
5037ACCscript* accCreateScript() {
5038 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005039}
Jack Palevich1cdef202009-05-22 12:06:27 -07005040
5041extern "C"
5042ACCenum accGetError( ACCscript* script ) {
5043 return script->getError();
5044}
5045
5046extern "C"
5047void accDeleteScript(ACCscript* script) {
5048 delete script;
5049}
5050
5051extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005052void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5053 ACCvoid* pContext) {
5054 script->registerSymbolCallback(pFn, pContext);
5055}
5056
5057extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005058void accScriptSource(ACCscript* script,
5059 ACCsizei count,
5060 const ACCchar ** string,
5061 const ACCint * length) {
5062 int totalLength = 0;
5063 for(int i = 0; i < count; i++) {
5064 int len = -1;
5065 const ACCchar* s = string[i];
5066 if (length) {
5067 len = length[i];
5068 }
5069 if (len < 0) {
5070 len = strlen(s);
5071 }
5072 totalLength += len;
5073 }
5074 delete script->text;
5075 char* text = new char[totalLength + 1];
5076 script->text = text;
5077 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005078 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005079 for(int i = 0; i < count; i++) {
5080 int len = -1;
5081 const ACCchar* s = string[i];
5082 if (length) {
5083 len = length[i];
5084 }
5085 if (len < 0) {
5086 len = strlen(s);
5087 }
Jack Palevich09555c72009-05-27 12:25:55 -07005088 memcpy(dest, s, len);
5089 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005090 }
5091 text[totalLength] = '\0';
5092}
5093
5094extern "C"
5095void accCompileScript(ACCscript* script) {
5096 int result = script->compiler.compile(script->text, script->textLength);
5097 if (result) {
5098 script->setError(ACC_INVALID_OPERATION);
5099 }
5100}
5101
5102extern "C"
5103void accGetScriptiv(ACCscript* script,
5104 ACCenum pname,
5105 ACCint * params) {
5106 switch (pname) {
5107 case ACC_INFO_LOG_LENGTH:
5108 *params = 0;
5109 break;
5110 }
5111}
5112
5113extern "C"
5114void accGetScriptInfoLog(ACCscript* script,
5115 ACCsizei maxLength,
5116 ACCsizei * length,
5117 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005118 char* message = script->compiler.getErrorMessage();
5119 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005120 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005121 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005122 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005123 if (infoLog && maxLength > 0) {
5124 int trimmedLength = maxLength < messageLength ?
5125 maxLength : messageLength;
5126 memcpy(infoLog, message, trimmedLength);
5127 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005128 }
5129}
5130
5131extern "C"
5132void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5133 ACCvoid ** address) {
5134 void* value = script->compiler.lookup(name);
5135 if (value) {
5136 *address = value;
5137 } else {
5138 script->setError(ACC_INVALID_VALUE);
5139 }
5140}
5141
Jack Palevicheedf9d22009-06-04 16:23:40 -07005142extern "C"
5143void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5144 ACCsizei maxStringCount, ACCchar** strings){
5145 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5146}
5147
-b master422972c2009-06-17 19:13:52 -07005148extern "C"
5149void accDisassemble(ACCscript* script) {
5150 script->compiler.disassemble(stderr);
5151}
5152
Jack Palevicheedf9d22009-06-04 16:23:40 -07005153
Jack Palevich1cdef202009-05-22 12:06:27 -07005154} // namespace acc
5155