blob: 250f4897af6459a147ae2434f408428501836009 [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 Palevicha8f427f2009-07-13 18:40:08 -0700285 void setTypes(Type* pInt) {
286 mkpInt = pInt;
287 }
288
Jack Palevich1cdef202009-05-22 12:06:27 -0700289 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700290 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700291 * Save the old value of the FP.
292 * Set the new value of the FP.
293 * Convert from the native platform calling convention to
294 * our stack-based calling convention. This may require
295 * pushing arguments from registers to the stack.
296 * Allocate "N" bytes of stack space. N isn't known yet, so
297 * just emit the instructions for adjusting the stack, and return
298 * the address to patch up. The patching will be done in
299 * functionExit().
300 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700301 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700302 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700303
Jack Palevich1cdef202009-05-22 12:06:27 -0700304 /* Emit a function epilog.
305 * Restore the old SP and FP register values.
306 * Return to the calling function.
307 * argCount - the number of arguments to the function.
308 * localVariableAddress - returned from functionEntry()
309 * localVariableSize - the size in bytes of the local variables.
310 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700311 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700312 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700313
Jack Palevich1cdef202009-05-22 12:06:27 -0700314 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700315 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700316
Jack Palevich1a539db2009-07-08 13:04:41 -0700317 /* Load floating point value from global address. */
318 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700319
Jack Palevich1cdef202009-05-22 12:06:27 -0700320 /* Jump to a target, and return the address of the word that
321 * holds the target data, in case it needs to be fixed up later.
322 */
Jack Palevich22305132009-05-13 10:58:45 -0700323 virtual int gjmp(int t) = 0;
324
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 /* Test R0 and jump to a target if the test succeeds.
326 * l = 0: je, l == 1: jne
327 * Return the address of the word that holds the targed data, in
328 * case it needs to be fixed up later.
329 */
Jack Palevich22305132009-05-13 10:58:45 -0700330 virtual int gtst(bool l, int t) = 0;
331
Jack Palevich9eed7a22009-07-06 17:24:34 -0700332 /* Compare TOS against R0, and store the boolean result in R0.
333 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700334 * op specifies the comparison.
335 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700336 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700337
Jack Palevich9eed7a22009-07-06 17:24:34 -0700338 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700340 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700341 */
Jack Palevich546b2242009-05-13 15:10:04 -0700342 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich9eed7a22009-07-06 17:24:34 -0700344 /* Compare 0 against R0, and store the boolean result in R0.
345 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700346 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700347 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348
349 /* Perform the arithmetic op specified by op. 0 is the
350 * left argument, R0 is the right argument.
351 */
352 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700353
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 /* Push R0 onto the stack.
355 */
356 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700357
Jack Palevich9eed7a22009-07-06 17:24:34 -0700358 /* Store R0 to the address stored in TOS.
359 * The TOS is popped.
360 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700362 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700363
Jack Palevich1cdef202009-05-22 12:06:27 -0700364 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700365 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700366 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700367 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 /* Load the absolute address of a variable to R0.
370 * If ea <= LOCAL, then this is a local variable, or an
371 * argument, addressed relative to FP.
372 * else it is an absolute global address.
373 */
Jack Palevich8df46192009-07-07 14:48:51 -0700374 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich1cdef202009-05-22 12:06:27 -0700376 /* Store R0 to a variable.
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 Palevich9cbd2262009-07-08 16:48:41 -0700381 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700382
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 /* load R0 from 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 * If isIncDec is true, then the stored variable's value
388 * should be post-incremented or post-decremented, based
389 * on the value of op.
390 */
Jack Palevich8df46192009-07-07 14:48:51 -0700391 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
392
393 /**
394 * Convert R0 to the given type.
395 */
396 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700397
Jack Palevich1cdef202009-05-22 12:06:27 -0700398 /* Emit code to adjust the stack for a function call. Return the
399 * label for the address of the instruction that adjusts the
400 * stack size. This will be passed as argument "a" to
401 * endFunctionCallArguments.
402 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700403 virtual int beginFunctionCallArguments() = 0;
404
Jack Palevich1cdef202009-05-22 12:06:27 -0700405 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700406 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700408 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Patch the function call preamble.
411 * a is the address returned from beginFunctionCallArguments
412 * l is the number of bytes the arguments took on the stack.
413 * Typically you would also emit code to convert the argument
414 * list into whatever the native function calling convention is.
415 * On ARM for example you would pop the first 5 arguments into
416 * R0..R4
417 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700418 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 /* Emit a call to an unknown function. The argument "symbol" needs to
421 * be stored in the location where the address should go. It forms
422 * a chain. The address will be patched later.
423 * Return the address of the word that has to be patched.
424 */
Jack Palevich8df46192009-07-07 14:48:51 -0700425 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Call a function using PC-relative addressing. t is the PC-relative
428 * address of the function. It has already been adjusted for the
429 * architectural jump offset, so just store it as-is.
430 */
Jack Palevich8df46192009-07-07 14:48:51 -0700431 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700432
Jack Palevich1cdef202009-05-22 12:06:27 -0700433 /* Call a function pointer. L is the number of bytes the arguments
434 * take on the stack. The address of the function is stored at
435 * location SP + l.
436 */
Jack Palevich8df46192009-07-07 14:48:51 -0700437 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700438
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 /* Adjust SP after returning from a function call. l is the
440 * number of bytes of arguments stored on the stack. isIndirect
441 * is true if this was an indirect call. (In which case the
442 * address of the function is stored at location SP + l.)
443 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700444 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700445
Jack Palevich1cdef202009-05-22 12:06:27 -0700446 /* Print a disassembly of the assembled code to out. Return
447 * non-zero if there is an error.
448 */
Jack Palevicha6535612009-05-13 16:24:17 -0700449 virtual int disassemble(FILE* out) = 0;
450
Jack Palevich1cdef202009-05-22 12:06:27 -0700451 /* Generate a symbol at the current PC. t is the head of a
452 * linked list of addresses to patch.
453 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700454 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700455
Jack Palevich1cdef202009-05-22 12:06:27 -0700456 /*
457 * Do any cleanup work required at the end of a compile.
458 * For example, an instruction cache might need to be
459 * invalidated.
460 * Return non-zero if there is an error.
461 */
462 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700463
Jack Palevicha6535612009-05-13 16:24:17 -0700464 /**
465 * Adjust relative branches by this amount.
466 */
467 virtual int jumpOffset() = 0;
468
Jack Palevich9eed7a22009-07-06 17:24:34 -0700469 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700470 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700471 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700472 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700473
474 /**
475 * Array element alignment (in bytes) for this type of data.
476 */
477 virtual size_t sizeOf(Type* type) = 0;
478
Jack Palevich9cbd2262009-07-08 16:48:41 -0700479 /**
480 * Stack argument size of this data type.
481 */
482 virtual size_t stackSizeOf(Type* pType) = 0;
483
Jack Palevich1a539db2009-07-08 13:04:41 -0700484 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700485 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700486 }
487
Jack Palevich21a15a22009-05-11 14:49:29 -0700488 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700489 /*
490 * Output a byte. Handles all values, 0..ff.
491 */
492 void ob(int n) {
493 pCodeBuf->ob(n);
494 }
495
Jack Palevich8b0624c2009-05-20 12:12:06 -0700496 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700497 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700498 }
499
Jack Palevich8b0624c2009-05-20 12:12:06 -0700500 intptr_t getBase() {
501 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700502 }
503
Jack Palevich8b0624c2009-05-20 12:12:06 -0700504 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700505 return pCodeBuf->getPC();
506 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700507
508 intptr_t getSize() {
509 return pCodeBuf->getSize();
510 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700511
512 void error(const char* fmt,...) {
513 va_list ap;
514 va_start(ap, fmt);
515 mErrorSink->verror(fmt, ap);
516 va_end(ap);
517 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700518
519 void assert(bool test) {
520 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700521 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700522 error("code generator assertion failed.");
523 }
524 }
Jack Palevich8df46192009-07-07 14:48:51 -0700525
526 void setR0Type(Type* pType) {
Jack Palevichba929a42009-07-17 10:20:32 -0700527 mExpressionStack.back().pType = pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700528 }
529
Jack Palevich8df46192009-07-07 14:48:51 -0700530 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700531 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700532 }
533
534 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700535 if (mExpressionStack.size()) {
536 mExpressionStack.push_back(mExpressionStack.back());
537 } else {
538 mExpressionStack.push_back(ExpressionValue());
539 }
540
Jack Palevich8df46192009-07-07 14:48:51 -0700541 }
542
543 void popType() {
544 mExpressionStack.pop_back();
545 }
546
547 bool bitsSame(Type* pA, Type* pB) {
548 return collapseType(pA->tag) == collapseType(pB->tag);
549 }
550
551 TypeTag collapseType(TypeTag tag) {
552 static const TypeTag collapsedTag[] = {
553 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
554 TY_VOID, TY_VOID};
555 return collapsedTag[tag];
556 }
557
Jack Palevich1a539db2009-07-08 13:04:41 -0700558 TypeTag collapseTypeR0() {
559 return collapseType(getR0Type()->tag);
560 }
561
562 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700563 return isFloatTag(pType->tag);
564 }
565
566 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700567 return tag == TY_FLOAT || tag == TY_DOUBLE;
568 }
569
Jack Palevicha8f427f2009-07-13 18:40:08 -0700570 Type* mkpInt;
571
Jack Palevich21a15a22009-05-11 14:49:29 -0700572 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700573 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700574 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700575 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700576 };
577
Jack Paleviche7b59062009-05-19 17:12:17 -0700578#ifdef PROVIDE_ARM_CODEGEN
579
Jack Palevich22305132009-05-13 10:58:45 -0700580 class ARMCodeGenerator : public CodeGenerator {
581 public:
582 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700583
Jack Palevich22305132009-05-13 10:58:45 -0700584 virtual ~ARMCodeGenerator() {}
585
586 /* returns address to patch with local variable size
587 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700588 virtual int functionEntry(Type* pDecl) {
589 LOG_API("functionEntry(%d);\n", pDecl);
-b master422972c2009-06-17 19:13:52 -0700590 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700591 // sp -> arg4 arg5 ...
592 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700593 int regArgCount = calcRegArgCount(pDecl);
594 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700595 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700596 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700597 }
598 // sp -> arg0 arg1 ...
599 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700600 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700601 // sp, fp -> oldfp, retadr, arg0 arg1 ....
602 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700603 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700604 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700605 // We don't know how many local variables we are going to use,
606 // but we will round the allocation up to a multiple of
607 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700608 }
609
Jack Palevichb7718b92009-07-09 22:00:24 -0700610 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700611 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700612 // Round local variable size up to a multiple of stack alignment
613 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
614 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700615 // Patch local variable allocation code:
616 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700617 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700618 }
Jack Palevich69796b62009-05-14 15:42:26 -0700619 *(char*) (localVariableAddress) = localVariableSize;
620
621 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
622 o4(0xE1A0E00B); // mov lr, fp
623 o4(0xE59BB000); // ldr fp, [fp]
624 o4(0xE28ED004); // add sp, lr, #4
625 // sp -> retadr, arg0, ...
626 o4(0xE8BD4000); // ldmfd sp!, {lr}
627 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700628
629 // We store the PC into the lr so we can adjust the sp before
630 // returning. We need to pull off the registers we pushed
631 // earlier. We don't need to actually store them anywhere,
632 // just adjust the stack.
633 int regArgCount = calcRegArgCount(pDecl);
634 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700635 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
636 }
637 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700638 }
639
640 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700641 virtual void li(int t, Type* pType) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700642 liReg(t, 0);
Jack Palevich8df46192009-07-07 14:48:51 -0700643 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700644 }
645
Jack Palevich1a539db2009-07-08 13:04:41 -0700646 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700647 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700648 // Global, absolute address
649 o4(0xE59F0000); // ldr r0, .L1
650 o4(0xEA000000); // b .L99
651 o4(address); // .L1: .word ea
652 // .L99:
653
654 switch (pType->tag) {
655 case TY_FLOAT:
656 o4(0xE5900000); // ldr r0, [r0]
657 break;
658 case TY_DOUBLE:
659 o4(0xE1C000D0); // ldrd r0, [r0]
660 break;
661 default:
662 assert(false);
663 break;
664 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700665 }
666
Jack Palevich22305132009-05-13 10:58:45 -0700667 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700668 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700669 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700670 }
671
672 /* l = 0: je, l == 1: jne */
673 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700674 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevichb7718b92009-07-09 22:00:24 -0700675 Type* pR0Type = getR0Type();
676 TypeTag tagR0 = pR0Type->tag;
677 switch(tagR0) {
678 case TY_FLOAT:
679 callRuntime((void*) runtime_is_non_zero_f);
680 break;
681 case TY_DOUBLE:
682 callRuntime((void*) runtime_is_non_zero_d);
683 break;
684 default:
685 break;
686 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700687 o4(0xE3500000); // cmp r0,#0
688 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
689 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700690 }
691
Jack Palevicha39749f2009-07-08 20:40:31 -0700692 virtual void gcmp(int op, Type* pResultType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700693 LOG_API("gcmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700694 Type* pR0Type = getR0Type();
695 Type* pTOSType = getTOSType();
696 TypeTag tagR0 = collapseType(pR0Type->tag);
697 TypeTag tagTOS = collapseType(pTOSType->tag);
698 if (tagR0 == TY_INT && tagTOS == TY_INT) {
699 o4(0xE8BD0002); // ldmfd sp!,{r1}
700 mStackUse -= 4;
701 o4(0xE1510000); // cmp r1, r1
702 switch(op) {
703 case OP_EQUALS:
704 o4(0x03A00001); // moveq r0,#1
705 o4(0x13A00000); // movne r0,#0
706 break;
707 case OP_NOT_EQUALS:
708 o4(0x03A00000); // moveq r0,#0
709 o4(0x13A00001); // movne r0,#1
710 break;
711 case OP_LESS_EQUAL:
712 o4(0xD3A00001); // movle r0,#1
713 o4(0xC3A00000); // movgt r0,#0
714 break;
715 case OP_GREATER:
716 o4(0xD3A00000); // movle r0,#0
717 o4(0xC3A00001); // movgt r0,#1
718 break;
719 case OP_GREATER_EQUAL:
720 o4(0xA3A00001); // movge r0,#1
721 o4(0xB3A00000); // movlt r0,#0
722 break;
723 case OP_LESS:
724 o4(0xA3A00000); // movge r0,#0
725 o4(0xB3A00001); // movlt r0,#1
726 break;
727 default:
728 error("Unknown comparison op %d", op);
729 break;
730 }
731 popType();
732 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
733 setupDoubleArgs();
734 switch(op) {
735 case OP_EQUALS:
736 callRuntime((void*) runtime_cmp_eq_dd);
737 break;
738 case OP_NOT_EQUALS:
739 callRuntime((void*) runtime_cmp_ne_dd);
740 break;
741 case OP_LESS_EQUAL:
742 callRuntime((void*) runtime_cmp_le_dd);
743 break;
744 case OP_GREATER:
745 callRuntime((void*) runtime_cmp_gt_dd);
746 break;
747 case OP_GREATER_EQUAL:
748 callRuntime((void*) runtime_cmp_ge_dd);
749 break;
750 case OP_LESS:
751 callRuntime((void*) runtime_cmp_lt_dd);
752 break;
753 default:
754 error("Unknown comparison op %d", op);
755 break;
756 }
757 } else {
758 setupFloatArgs();
759 switch(op) {
760 case OP_EQUALS:
761 callRuntime((void*) runtime_cmp_eq_ff);
762 break;
763 case OP_NOT_EQUALS:
764 callRuntime((void*) runtime_cmp_ne_ff);
765 break;
766 case OP_LESS_EQUAL:
767 callRuntime((void*) runtime_cmp_le_ff);
768 break;
769 case OP_GREATER:
770 callRuntime((void*) runtime_cmp_gt_ff);
771 break;
772 case OP_GREATER_EQUAL:
773 callRuntime((void*) runtime_cmp_ge_ff);
774 break;
775 case OP_LESS:
776 callRuntime((void*) runtime_cmp_lt_ff);
777 break;
778 default:
779 error("Unknown comparison op %d", op);
780 break;
781 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700782 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700783 setR0Type(pResultType);
Jack Palevich22305132009-05-13 10:58:45 -0700784 }
785
Jack Palevich546b2242009-05-13 15:10:04 -0700786 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700787 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700788 Type* pR0Type = getR0Type();
789 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700790 TypeTag tagR0 = pR0Type->tag;
791 TypeTag tagTOS = pTOSType->tag;
792 bool isFloatR0 = isFloatTag(tagR0);
793 bool isFloatTOS = isFloatTag(tagTOS);
794 if (!isFloatR0 && !isFloatTOS) {
795 bool isPtrR0 = tagR0 == TY_POINTER;
796 bool isPtrTOS = tagTOS == TY_POINTER;
797 if (isPtrR0 || isPtrTOS) {
798 if (isPtrR0 && isPtrTOS) {
799 if (op != OP_MINUS) {
800 error("Unsupported pointer-pointer operation %d.", op);
801 }
802 if (! typeEqual(pR0Type, pTOSType)) {
803 error("Incompatible pointer types for subtraction.");
804 }
805 o4(0xE8BD0002); // ldmfd sp!,{r1}
806 o4(0xE0410000); // sub r0,r1,r0
807 popType();
808 setR0Type(mkpInt);
809 int size = sizeOf(pR0Type->pHead);
810 if (size != 1) {
811 pushR0();
812 li(size, mkpInt);
813 // TODO: Optimize for power-of-two.
814 genOp(OP_DIV);
815 }
816 } else {
817 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
818 error("Unsupported pointer-scalar operation %d", op);
819 }
820 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
821 o4(0xE8BD0002); // ldmfd sp!,{r1}
822 int size = sizeOf(pPtrType->pHead);
823 if (size != 1) {
824 // TODO: Optimize for power-of-two.
825 liReg(size, 2);
826 if (isPtrR0) {
827 o4(0x0E0010192); // mul r1,r2,r1
828 } else {
829 o4(0x0E0000092); // mul r0,r2,r0
830 }
831 }
832 switch(op) {
833 case OP_PLUS:
834 o4(0xE0810000); // add r0,r1,r0
835 break;
836 case OP_MINUS:
837 o4(0xE0410000); // sub r0,r1,r0
838 break;
839 }
840 popType();
841 setR0Type(pPtrType);
842 }
843 } else {
844 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevichb7718b92009-07-09 22:00:24 -0700845 mStackUse -= 4;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700846 switch(op) {
847 case OP_MUL:
848 o4(0x0E0000091); // mul r0,r1,r0
849 break;
850 case OP_DIV:
851 callRuntime((void*) runtime_DIV);
852 break;
853 case OP_MOD:
854 callRuntime((void*) runtime_MOD);
855 break;
856 case OP_PLUS:
857 o4(0xE0810000); // add r0,r1,r0
858 break;
859 case OP_MINUS:
860 o4(0xE0410000); // sub r0,r1,r0
861 break;
862 case OP_SHIFT_LEFT:
863 o4(0xE1A00011); // lsl r0,r1,r0
864 break;
865 case OP_SHIFT_RIGHT:
866 o4(0xE1A00051); // asr r0,r1,r0
867 break;
868 case OP_BIT_AND:
869 o4(0xE0010000); // and r0,r1,r0
870 break;
871 case OP_BIT_XOR:
872 o4(0xE0210000); // eor r0,r1,r0
873 break;
874 case OP_BIT_OR:
875 o4(0xE1810000); // orr r0,r1,r0
876 break;
877 case OP_BIT_NOT:
878 o4(0xE1E00000); // mvn r0, r0
879 break;
880 default:
881 error("Unimplemented op %d\n", op);
882 break;
883 }
884 popType();
Jack Palevichb7718b92009-07-09 22:00:24 -0700885 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700886 } else {
887 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
888 if (pResultType->tag == TY_DOUBLE) {
889 setupDoubleArgs();
890 switch(op) {
891 case OP_MUL:
892 callRuntime((void*) runtime_op_mul_dd);
893 break;
894 case OP_DIV:
895 callRuntime((void*) runtime_op_div_dd);
896 break;
897 case OP_PLUS:
898 callRuntime((void*) runtime_op_add_dd);
899 break;
900 case OP_MINUS:
901 callRuntime((void*) runtime_op_sub_dd);
902 break;
903 default:
904 error("Unsupported binary floating operation %d\n", op);
905 break;
906 }
907 } else {
908 setupFloatArgs();
909 switch(op) {
910 case OP_MUL:
911 callRuntime((void*) runtime_op_mul_ff);
912 break;
913 case OP_DIV:
914 callRuntime((void*) runtime_op_div_ff);
915 break;
916 case OP_PLUS:
917 callRuntime((void*) runtime_op_add_ff);
918 break;
919 case OP_MINUS:
920 callRuntime((void*) runtime_op_sub_ff);
921 break;
922 default:
923 error("Unsupported binary floating operation %d\n", op);
924 break;
925 }
926 }
927 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700928 }
Jack Palevich22305132009-05-13 10:58:45 -0700929 }
930
Jack Palevicha39749f2009-07-08 20:40:31 -0700931 virtual void gUnaryCmp(int op, Type* pResultType) {
932 LOG_API("gUnaryCmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700933 if (op != OP_LOGICAL_NOT) {
934 error("Unknown unary cmp %d", op);
935 } else {
936 Type* pR0Type = getR0Type();
937 TypeTag tag = collapseType(pR0Type->tag);
938 switch(tag) {
939 case TY_INT:
940 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700941 o4(0xE1510000); // cmp r1, r0
942 o4(0x03A00001); // moveq r0,#1
943 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700944 break;
945 case TY_FLOAT:
946 callRuntime((void*) runtime_is_zero_f);
947 break;
948 case TY_DOUBLE:
949 callRuntime((void*) runtime_is_zero_d);
950 break;
951 default:
952 error("gUnaryCmp unsupported type");
953 break;
954 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700955 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700956 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700957 }
958
959 virtual void genUnaryOp(int op) {
960 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700961 Type* pR0Type = getR0Type();
962 TypeTag tag = collapseType(pR0Type->tag);
963 switch(tag) {
964 case TY_INT:
965 switch(op) {
966 case OP_MINUS:
967 o4(0xE3A01000); // mov r1, #0
968 o4(0xE0410000); // sub r0,r1,r0
969 break;
970 case OP_BIT_NOT:
971 o4(0xE1E00000); // mvn r0, r0
972 break;
973 default:
974 error("Unknown unary op %d\n", op);
975 break;
976 }
977 break;
978 case TY_FLOAT:
979 case TY_DOUBLE:
980 switch (op) {
981 case OP_MINUS:
982 if (tag == TY_FLOAT) {
983 callRuntime((void*) runtime_op_neg_f);
984 } else {
985 callRuntime((void*) runtime_op_neg_d);
986 }
987 break;
988 case OP_BIT_NOT:
989 error("Can't apply '~' operator to a float or double.");
990 break;
991 default:
992 error("Unknown unary op %d\n", op);
993 break;
994 }
995 break;
996 default:
997 error("genUnaryOp unsupported type");
998 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700999 }
Jack Palevich22305132009-05-13 10:58:45 -07001000 }
1001
Jack Palevich1cdef202009-05-22 12:06:27 -07001002 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -07001003 LOG_API("pushR0();\n");
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 Palevich9eed7a22009-07-06 17:24:34 -07001017 virtual void storeR0ToTOS(Type* pPointerType) {
1018 LOG_API("storeR0ToTOS(%d);\n", isInt);
1019 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001020 o4(0xE8BD0004); // ldmfd sp!,{r2}
1021 popType();
-b master422972c2009-06-17 19:13:52 -07001022 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001023 switch (pPointerType->pHead->tag) {
1024 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001025 case TY_FLOAT:
1026 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001027 break;
1028 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001029 o4(0xE5C20000); // strb r0, [r2]
1030 break;
1031 case TY_DOUBLE:
1032 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001033 break;
1034 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001035 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001036 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001037 }
Jack Palevich22305132009-05-13 10:58:45 -07001038 }
1039
Jack Palevich9eed7a22009-07-06 17:24:34 -07001040 virtual void loadR0FromR0(Type* pPointerType) {
1041 LOG_API("loadR0FromR0(%d);\n", pPointerType);
1042 assert(pPointerType->tag == TY_POINTER);
1043 switch (pPointerType->pHead->tag) {
1044 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001046 o4(0xE5900000); // ldr r0, [r0]
1047 break;
1048 case TY_CHAR:
1049 o4(0xE5D00000); // ldrb r0, [r0]
1050 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001051 case TY_DOUBLE:
1052 o4(0xE1C000D0); // ldrd r0, [r0]
1053 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001054 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001055 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001056 break;
1057 }
Jack Palevich8df46192009-07-07 14:48:51 -07001058 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001059 }
1060
Jack Palevich8df46192009-07-07 14:48:51 -07001061 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001062 LOG_API("leaR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001063 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001064 // Local, fp relative
1065 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1066 error("Offset out of range: %08x", ea);
1067 }
1068 if (ea < 0) {
1069 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1070 } else {
1071 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1072 }
Jack Palevichbd894902009-05-14 19:35:31 -07001073 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001074 // Global, absolute.
1075 o4(0xE59F0000); // ldr r0, .L1
1076 o4(0xEA000000); // b .L99
1077 o4(ea); // .L1: .word 0
1078 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001079 }
Jack Palevich8df46192009-07-07 14:48:51 -07001080 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001081 }
1082
Jack Palevich9cbd2262009-07-08 16:48:41 -07001083 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001084 LOG_API("storeR0(%d);\n", ea);
Jack Palevich8148c5b2009-07-16 18:24:47 -07001085 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001086 TypeTag tag = pType->tag;
1087 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001088 case TY_CHAR:
1089 if (ea > -LOCAL && ea < LOCAL) {
1090 // Local, fp relative
1091 if (ea < -4095 || ea > 4095) {
1092 error("Offset out of range: %08x", ea);
1093 }
1094 if (ea < 0) {
1095 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1096 } else {
1097 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1098 }
1099 } else{
1100 // Global, absolute
1101 o4(0xE59F1000); // ldr r1, .L1
1102 o4(0xEA000000); // b .L99
1103 o4(ea); // .L1: .word 0
1104 o4(0xE5C10000); // .L99: strb r0, [r1]
1105 }
1106 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001107 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001108 case TY_INT:
1109 case TY_FLOAT:
1110 if (ea > -LOCAL && ea < LOCAL) {
1111 // Local, fp relative
1112 if (ea < -4095 || ea > 4095) {
1113 error("Offset out of range: %08x", ea);
1114 }
1115 if (ea < 0) {
1116 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1117 } else {
1118 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1119 }
1120 } else{
1121 // Global, absolute
1122 o4(0xE59F1000); // ldr r1, .L1
1123 o4(0xEA000000); // b .L99
1124 o4(ea); // .L1: .word 0
1125 o4(0xE5810000); // .L99: str r0, [r1]
1126 }
1127 break;
1128 case TY_DOUBLE:
1129 if ((ea & 0x7) != 0) {
1130 error("double address is not aligned: %d", ea);
1131 }
1132 if (ea > -LOCAL && ea < LOCAL) {
1133 // Local, fp relative
1134 if (ea < -4095 || ea > 4095) {
1135 error("Offset out of range: %08x", ea);
1136 }
1137 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001138 o4(0xE50B0000 | (0xfff & (4-ea))); // str r0, [fp,#-ea]
1139 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001140#if 0
1141 // strd doesn't seem to work. Is encoding wrong?
1142 } else if (ea < 0) {
1143 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1144 } else if (ea < 256) {
1145 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1146#endif
1147 } else {
1148 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1149 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1150 }
1151 } else{
1152 // Global, absolute
1153 o4(0xE59F2000); // ldr r2, .L1
1154 o4(0xEA000000); // b .L99
1155 o4(ea); // .L1: .word 0
1156 o4(0xE1C200F0); // .L99: strd r0, [r2]
1157 }
1158 break;
1159 default:
1160 error("Unable to store to type %d", tag);
1161 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001162 }
Jack Palevich22305132009-05-13 10:58:45 -07001163 }
1164
Jack Palevich8df46192009-07-07 14:48:51 -07001165 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001166 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich25c0cca2009-07-13 16:56:28 -07001167 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001168 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001169 case TY_CHAR:
1170 if (ea < LOCAL) {
1171 // Local, fp relative
1172 if (ea < -4095 || ea > 4095) {
1173 error("Offset out of range: %08x", ea);
1174 }
1175 if (ea < 0) {
1176 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1177 } else {
1178 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1179 }
1180 } else {
1181 // Global, absolute
1182 o4(0xE59F2000); // ldr r2, .L1
1183 o4(0xEA000000); // b .L99
1184 o4(ea); // .L1: .word ea
1185 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1186 }
1187
1188 if (isIncDec) {
1189 error("inc/dec not implemented for char.");
1190 }
1191 break;
1192 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001193 case TY_INT:
1194 case TY_FLOAT:
1195 if (ea < LOCAL) {
1196 // Local, fp relative
1197 if (ea < -4095 || ea > 4095) {
1198 error("Offset out of range: %08x", ea);
1199 }
1200 if (ea < 0) {
1201 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1202 } else {
1203 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1204 }
1205 } else {
1206 // Global, absolute
1207 o4(0xE59F2000); // ldr r2, .L1
1208 o4(0xEA000000); // b .L99
1209 o4(ea); // .L1: .word ea
1210 o4(0xE5920000); // .L99: ldr r0, [r2]
1211 }
Jack Palevich22305132009-05-13 10:58:45 -07001212
Jack Palevichb7718b92009-07-09 22:00:24 -07001213 if (isIncDec) {
1214 if (tag == TY_INT) {
1215 switch (op) {
1216 case OP_INCREMENT:
1217 o4(0xE2801001); // add r1, r0, #1
1218 break;
1219 case OP_DECREMENT:
1220 o4(0xE2401001); // sub r1, r0, #1
1221 break;
1222 default:
1223 error("unknown opcode: %d", op);
1224 }
1225 if (ea < LOCAL) {
1226 // Local, fp relative
1227 // Don't need range check, was already checked above
1228 if (ea < 0) {
1229 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1230 } else {
1231 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1232 }
1233 } else{
1234 // Global, absolute
1235 // r2 is already set up from before.
1236 o4(0xE5821000); // str r1, [r2]
1237 }
1238 }
1239 else {
1240 error("inc/dec not implemented for float.");
1241 }
1242 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001243 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001244 case TY_DOUBLE:
1245 if ((ea & 0x7) != 0) {
1246 error("double address is not aligned: %d", ea);
1247 }
1248 if (ea < LOCAL) {
1249 // Local, fp relative
1250 if (ea < -4095 || ea > 4095) {
1251 error("Offset out of range: %08x", ea);
1252 }
1253 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001254 o4(0xE51B0000 | (0xfff & (4-ea))); // ldr r0, [fp,#-ea]
1255 o4(0xE51B1000 | (0xfff & (-ea))); // ldr r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001256 } else {
1257 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1258 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1259 }
1260 } else {
1261 // Global, absolute
1262 o4(0xE59F2000); // ldr r2, .L1
1263 o4(0xEA000000); // b .L99
1264 o4(ea); // .L1: .word ea
1265 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1266 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001267 break;
1268 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001269 error("Unable to load type %d", tag);
1270 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001271 }
Jack Palevich8df46192009-07-07 14:48:51 -07001272 setR0Type(pType);
1273 }
1274
1275 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001276 Type* pR0Type = getR0Type();
1277 if (bitsSame(pType, pR0Type)) {
1278 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001279 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001280 TypeTag r0Tag = collapseType(pR0Type->tag);
1281 TypeTag destTag = collapseType(pType->tag);
1282 if (r0Tag == TY_INT) {
1283 if (destTag == TY_FLOAT) {
1284 callRuntime((void*) runtime_int_to_float);
1285 } else {
1286 assert(destTag == TY_DOUBLE);
1287 callRuntime((void*) runtime_int_to_double);
1288 }
1289 } else if (r0Tag == TY_FLOAT) {
1290 if (destTag == TY_INT) {
1291 callRuntime((void*) runtime_float_to_int);
1292 } else {
1293 assert(destTag == TY_DOUBLE);
1294 callRuntime((void*) runtime_float_to_double);
1295 }
1296 } else {
1297 assert (r0Tag == TY_DOUBLE);
1298 if (destTag == TY_INT) {
1299 callRuntime((void*) runtime_double_to_int);
1300 } else {
1301 assert(destTag == TY_FLOAT);
1302 callRuntime((void*) runtime_double_to_float);
1303 }
1304 }
Jack Palevich8df46192009-07-07 14:48:51 -07001305 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001306 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001307 }
1308
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001309 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001310 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001311 return o4(0xE24DDF00); // Placeholder
1312 }
1313
Jack Palevich8148c5b2009-07-16 18:24:47 -07001314 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001315 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich8148c5b2009-07-16 18:24:47 -07001316 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001317 Type* pR0Type = getR0Type();
1318 TypeTag r0ct = collapseType(pR0Type->tag);
1319 switch(r0ct) {
1320 case TY_INT:
1321 case TY_FLOAT:
1322 if (l < 0 || l > 4096-4) {
1323 error("l out of range for stack offset: 0x%08x", l);
1324 }
1325 o4(0xE58D0000 + l); // str r0, [sp, #l]
1326 return 4;
1327 case TY_DOUBLE: {
1328 // Align to 8 byte boundary
1329 int l2 = (l + 7) & ~7;
1330 if (l2 < 0 || l2 > 4096-8) {
1331 error("l out of range for stack offset: 0x%08x", l);
1332 }
1333 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1334 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1335 return (l2 - l) + 8;
1336 }
1337 default:
1338 assert(false);
1339 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001340 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001341 }
1342
Jack Palevichb7718b92009-07-09 22:00:24 -07001343 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001344 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001345 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001346 // Have to calculate register arg count from actual stack size,
1347 // in order to properly handle ... functions.
1348 int regArgCount = l >> 2;
1349 if (regArgCount > 4) {
1350 regArgCount = 4;
1351 }
1352 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001353 argumentStackUse -= regArgCount * 4;
1354 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1355 }
1356 mStackUse += argumentStackUse;
1357
1358 // Align stack.
1359 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1360 * STACK_ALIGNMENT);
1361 mStackAlignmentAdjustment = 0;
1362 if (missalignment > 0) {
1363 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1364 }
1365 l += mStackAlignmentAdjustment;
1366
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001367 if (l < 0 || l > 0x3FC) {
1368 error("L out of range for stack adjustment: 0x%08x", l);
1369 }
1370 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001371 mStackUse += mStackAlignmentAdjustment;
1372 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1373 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001374 }
1375
Jack Palevich8df46192009-07-07 14:48:51 -07001376 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001377 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001378 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001379 // Forward calls are always short (local)
1380 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001381 }
1382
Jack Palevich8df46192009-07-07 14:48:51 -07001383 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001384 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001385 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001386 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001387 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001388 if (t >= - (1 << 25) && t < (1 << 25)) {
1389 o4(0xEB000000 | encodeAddress(t));
1390 } else {
1391 // Long call.
1392 o4(0xE59FC000); // ldr r12, .L1
1393 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001394 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001395 o4(0xE08CC00F); // .L99: add r12,pc
1396 o4(0xE12FFF3C); // blx r12
1397 }
Jack Palevich22305132009-05-13 10:58:45 -07001398 }
1399
Jack Palevich8df46192009-07-07 14:48:51 -07001400 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001401 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001402 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001403 int argCount = l >> 2;
1404 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001405 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001406 if (adjustedL < 0 || adjustedL > 4096-4) {
1407 error("l out of range for stack offset: 0x%08x", l);
1408 }
1409 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1410 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001411 }
1412
Jack Palevichb7718b92009-07-09 22:00:24 -07001413 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001414 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001415 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001416 // Have to calculate register arg count from actual stack size,
1417 // in order to properly handle ... functions.
1418 int regArgCount = l >> 2;
1419 if (regArgCount > 4) {
1420 regArgCount = 4;
1421 }
1422 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001423 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1424 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001425 if (stackUse) {
1426 if (stackUse < 0 || stackUse > 255) {
1427 error("L out of range for stack adjustment: 0x%08x", l);
1428 }
1429 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001430 mStackUse -= stackUse * 4;
1431 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001432 }
Jack Palevich22305132009-05-13 10:58:45 -07001433 }
1434
Jack Palevicha6535612009-05-13 16:24:17 -07001435 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001436 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001437 }
1438
1439 /* output a symbol and patch all calls to it */
1440 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001441 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001442 int n;
1443 int base = getBase();
1444 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001445 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001446 while (t) {
1447 int data = * (int*) t;
1448 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1449 if (decodedOffset == 0) {
1450 n = 0;
1451 } else {
1452 n = base + decodedOffset; /* next value */
1453 }
1454 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1455 | encodeRelAddress(pc - t - 8);
1456 t = n;
1457 }
1458 }
1459
Jack Palevich1cdef202009-05-22 12:06:27 -07001460 virtual int finishCompile() {
1461#if defined(__arm__)
1462 const long base = long(getBase());
1463 const long curr = long(getPC());
1464 int err = cacheflush(base, curr, 0);
1465 return err;
1466#else
1467 return 0;
1468#endif
1469 }
1470
Jack Palevicha6535612009-05-13 16:24:17 -07001471 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001472#ifdef ENABLE_ARM_DISASSEMBLY
1473 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001474 disasm_interface_t di;
1475 di.di_readword = disassemble_readword;
1476 di.di_printaddr = disassemble_printaddr;
1477 di.di_printf = disassemble_printf;
1478
1479 int base = getBase();
1480 int pc = getPC();
1481 for(int i = base; i < pc; i += 4) {
1482 fprintf(out, "%08x: %08x ", i, *(int*) i);
1483 ::disasm(&di, i, 0);
1484 }
Jack Palevich09555c72009-05-27 12:25:55 -07001485#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001486 return 0;
1487 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001488
Jack Palevich9eed7a22009-07-06 17:24:34 -07001489 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001490 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001491 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001492 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001493 switch(pType->tag) {
1494 case TY_DOUBLE:
1495 return 8;
1496 default:
1497 return 4;
1498 }
1499 }
1500
1501 /**
1502 * Array element alignment (in bytes) for this type of data.
1503 */
1504 virtual size_t sizeOf(Type* pType){
1505 switch(pType->tag) {
1506 case TY_INT:
1507 return 4;
1508 case TY_CHAR:
1509 return 1;
1510 default:
1511 return 0;
1512 case TY_FLOAT:
1513 return 4;
1514 case TY_DOUBLE:
1515 return 8;
1516 case TY_POINTER:
1517 return 4;
1518 }
1519 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001520
1521 virtual size_t stackSizeOf(Type* pType) {
1522 switch(pType->tag) {
1523 case TY_DOUBLE:
1524 return 8;
1525 default:
1526 return 4;
1527 }
1528 }
1529
Jack Palevich22305132009-05-13 10:58:45 -07001530 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001531 static FILE* disasmOut;
1532
1533 static u_int
1534 disassemble_readword(u_int address)
1535 {
1536 return(*((u_int *)address));
1537 }
1538
1539 static void
1540 disassemble_printaddr(u_int address)
1541 {
1542 fprintf(disasmOut, "0x%08x", address);
1543 }
1544
1545 static void
1546 disassemble_printf(const char *fmt, ...) {
1547 va_list ap;
1548 va_start(ap, fmt);
1549 vfprintf(disasmOut, fmt, ap);
1550 va_end(ap);
1551 }
1552
1553 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1554
1555 /** Encode a relative address that might also be
1556 * a label.
1557 */
1558 int encodeAddress(int value) {
1559 int base = getBase();
1560 if (value >= base && value <= getPC() ) {
1561 // This is a label, encode it relative to the base.
1562 value = value - base;
1563 }
1564 return encodeRelAddress(value);
1565 }
1566
1567 int encodeRelAddress(int value) {
1568 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1569 }
Jack Palevich22305132009-05-13 10:58:45 -07001570
Jack Palevichb7718b92009-07-09 22:00:24 -07001571 int calcRegArgCount(Type* pDecl) {
1572 int reg = 0;
1573 Type* pArgs = pDecl->pTail;
1574 while (pArgs && reg < 4) {
1575 Type* pArg = pArgs->pHead;
1576 if ( pArg->tag == TY_DOUBLE) {
1577 int evenReg = (reg + 1) & ~1;
1578 if (evenReg >= 4) {
1579 break;
1580 }
1581 reg = evenReg + 2;
1582 } else {
1583 reg++;
1584 }
1585 pArgs = pArgs->pTail;
1586 }
1587 return reg;
1588 }
1589
1590 /* Pop TOS to R1
1591 * Make sure both R0 and TOS are floats. (Could be ints)
1592 * We know that at least one of R0 and TOS is already a float
1593 */
1594 void setupFloatArgs() {
1595 Type* pR0Type = getR0Type();
1596 Type* pTOSType = getTOSType();
1597 TypeTag tagR0 = collapseType(pR0Type->tag);
1598 TypeTag tagTOS = collapseType(pTOSType->tag);
1599 if (tagR0 != TY_FLOAT) {
1600 assert(tagR0 == TY_INT);
1601 callRuntime((void*) runtime_int_to_float);
1602 }
1603 if (tagTOS != TY_FLOAT) {
1604 assert(tagTOS == TY_INT);
1605 assert(tagR0 == TY_FLOAT);
1606 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1607 o4(0xE59D0004); // ldr r0, [sp, #4]
1608 callRuntime((void*) runtime_int_to_float);
1609 o4(0xE1A01000); // mov r1, r0
1610 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1611 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1612 } else {
1613 // Pop TOS
1614 o4(0xE8BD0002); // ldmfd sp!,{r1}
1615 }
1616 mStackUse -= 4;
1617 popType();
1618 }
1619
1620 /* Pop TOS into R2..R3
1621 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1622 * We know that at least one of R0 and TOS are already a double.
1623 */
1624
1625 void setupDoubleArgs() {
1626 Type* pR0Type = getR0Type();
1627 Type* pTOSType = getTOSType();
1628 TypeTag tagR0 = collapseType(pR0Type->tag);
1629 TypeTag tagTOS = collapseType(pTOSType->tag);
1630 if (tagR0 != TY_DOUBLE) {
1631 if (tagR0 == TY_INT) {
1632 callRuntime((void*) runtime_int_to_double);
1633 } else {
1634 assert(tagR0 == TY_FLOAT);
1635 callRuntime((void*) runtime_float_to_double);
1636 }
1637 }
1638 if (tagTOS != TY_DOUBLE) {
1639 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1640 o4(0xE59D0008); // ldr r0, [sp, #8]
1641 if (tagTOS == TY_INT) {
1642 callRuntime((void*) runtime_int_to_double);
1643 } else {
1644 assert(tagTOS == TY_FLOAT);
1645 callRuntime((void*) runtime_float_to_double);
1646 }
1647 o4(0xE1A02000); // mov r2, r0
1648 o4(0xE1A03001); // mov r3, r1
1649 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1650 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1651 mStackUse -= 4;
1652 } else {
1653 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1654 mStackUse -= 8;
1655 }
1656 popType();
1657 }
1658
Jack Palevicha8f427f2009-07-13 18:40:08 -07001659 void liReg(int t, int reg) {
1660 assert(reg >= 0 && reg < 16);
1661 int rN = (reg & 0xf) << 12;
1662 if (t >= 0 && t < 255) {
1663 o4((0xE3A00000 + t) | rN); // mov rN, #0
1664 } else if (t >= -256 && t < 0) {
1665 // mvn means move constant ^ ~0
1666 o4((0xE3E00001 - t) | rN); // mvn rN, #0
1667 } else {
1668 o4(0xE51F0000 | rN); // ldr rN, .L3
1669 o4(0xEA000000); // b .L99
1670 o4(t); // .L3: .word 0
1671 // .L99:
1672 }
1673 }
1674
Jack Palevichb7718b92009-07-09 22:00:24 -07001675 void callRuntime(void* fn) {
1676 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001677 o4(0xEA000000); // b .L99
1678 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001679 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001680 }
1681
Jack Palevichb7718b92009-07-09 22:00:24 -07001682 // Integer math:
1683
1684 static int runtime_DIV(int b, int a) {
1685 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001686 }
1687
Jack Palevichb7718b92009-07-09 22:00:24 -07001688 static int runtime_MOD(int b, int a) {
1689 return a % b;
1690 }
1691
1692 // Comparison to zero
1693
1694 static int runtime_is_non_zero_f(float a) {
1695 return a != 0;
1696 }
1697
1698 static int runtime_is_non_zero_d(double a) {
1699 return a != 0;
1700 }
1701
1702 // Comparison to zero
1703
1704 static int runtime_is_zero_f(float a) {
1705 return a == 0;
1706 }
1707
1708 static int runtime_is_zero_d(double a) {
1709 return a == 0;
1710 }
1711
1712 // Type conversion
1713
1714 static int runtime_float_to_int(float a) {
1715 return (int) a;
1716 }
1717
1718 static double runtime_float_to_double(float a) {
1719 return (double) a;
1720 }
1721
1722 static int runtime_double_to_int(double a) {
1723 return (int) a;
1724 }
1725
1726 static float runtime_double_to_float(double a) {
1727 return (float) a;
1728 }
1729
1730 static float runtime_int_to_float(int a) {
1731 return (float) a;
1732 }
1733
1734 static double runtime_int_to_double(int a) {
1735 return (double) a;
1736 }
1737
1738 // Comparisons float
1739
1740 static int runtime_cmp_eq_ff(float b, float a) {
1741 return a == b;
1742 }
1743
1744 static int runtime_cmp_ne_ff(float b, float a) {
1745 return a != b;
1746 }
1747
1748 static int runtime_cmp_lt_ff(float b, float a) {
1749 return a < b;
1750 }
1751
1752 static int runtime_cmp_le_ff(float b, float a) {
1753 return a <= b;
1754 }
1755
1756 static int runtime_cmp_ge_ff(float b, float a) {
1757 return a >= b;
1758 }
1759
1760 static int runtime_cmp_gt_ff(float b, float a) {
1761 return a > b;
1762 }
1763
1764 // Comparisons double
1765
1766 static int runtime_cmp_eq_dd(double b, double a) {
1767 return a == b;
1768 }
1769
1770 static int runtime_cmp_ne_dd(double b, double a) {
1771 return a != b;
1772 }
1773
1774 static int runtime_cmp_lt_dd(double b, double a) {
1775 return a < b;
1776 }
1777
1778 static int runtime_cmp_le_dd(double b, double a) {
1779 return a <= b;
1780 }
1781
1782 static int runtime_cmp_ge_dd(double b, double a) {
1783 return a >= b;
1784 }
1785
1786 static int runtime_cmp_gt_dd(double b, double a) {
1787 return a > b;
1788 }
1789
1790 // Math float
1791
1792 static float runtime_op_add_ff(float b, float a) {
1793 return a + b;
1794 }
1795
1796 static float runtime_op_sub_ff(float b, float a) {
1797 return a - b;
1798 }
1799
1800 static float runtime_op_mul_ff(float b, float a) {
1801 return a * b;
1802 }
1803
1804 static float runtime_op_div_ff(float b, float a) {
1805 return a / b;
1806 }
1807
1808 static float runtime_op_neg_f(float a) {
1809 return -a;
1810 }
1811
1812 // Math double
1813
1814 static double runtime_op_add_dd(double b, double a) {
1815 return a + b;
1816 }
1817
1818 static double runtime_op_sub_dd(double b, double a) {
1819 return a - b;
1820 }
1821
1822 static double runtime_op_mul_dd(double b, double a) {
1823 return a * b;
1824 }
1825
1826 static double runtime_op_div_dd(double b, double a) {
1827 return a / b;
1828 }
1829
1830 static double runtime_op_neg_d(double a) {
1831 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001832 }
-b master422972c2009-06-17 19:13:52 -07001833
1834 static const int STACK_ALIGNMENT = 8;
1835 int mStackUse;
1836 // This variable holds the amount we adjusted the stack in the most
1837 // recent endFunctionCallArguments call. It's examined by the
1838 // following adjustStackAfterCall call.
1839 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001840 };
1841
Jack Palevich09555c72009-05-27 12:25:55 -07001842#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001843
1844#ifdef PROVIDE_X86_CODEGEN
1845
Jack Palevich21a15a22009-05-11 14:49:29 -07001846 class X86CodeGenerator : public CodeGenerator {
1847 public:
1848 X86CodeGenerator() {}
1849 virtual ~X86CodeGenerator() {}
1850
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001851 /* returns address to patch with local variable size
1852 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001853 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001854 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1855 return oad(0xec81, 0); /* sub $xxx, %esp */
1856 }
1857
Jack Palevichb7718b92009-07-09 22:00:24 -07001858 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001859 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001860 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001861 }
1862
Jack Palevich21a15a22009-05-11 14:49:29 -07001863 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001864 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001865 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001866 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001867 }
1868
Jack Palevich1a539db2009-07-08 13:04:41 -07001869 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001870 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001871 switch (pType->tag) {
1872 case TY_FLOAT:
1873 oad(0x05D9, address); // flds
1874 break;
1875 case TY_DOUBLE:
1876 oad(0x05DD, address); // fldl
1877 break;
1878 default:
1879 assert(false);
1880 break;
1881 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001882 }
1883
Jack Palevich22305132009-05-13 10:58:45 -07001884 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001885 return psym(0xe9, t);
1886 }
1887
1888 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001889 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001890 Type* pR0Type = getR0Type();
1891 TypeTag tagR0 = pR0Type->tag;
1892 bool isFloatR0 = isFloatTag(tagR0);
1893 if (isFloatR0) {
1894 o(0xeed9); // fldz
1895 o(0xe9da); // fucompp
1896 o(0xe0df); // fnstsw %ax
1897 o(0x9e); // sahf
1898 } else {
1899 o(0xc085); // test %eax, %eax
1900 }
1901 // Use two output statements to generate one instruction.
1902 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001903 return psym(0x84 + l, t);
1904 }
1905
Jack Palevicha39749f2009-07-08 20:40:31 -07001906 virtual void gcmp(int op, Type* pResultType) {
1907 Type* pR0Type = getR0Type();
1908 Type* pTOSType = getTOSType();
1909 TypeTag tagR0 = pR0Type->tag;
1910 TypeTag tagTOS = pTOSType->tag;
1911 bool isFloatR0 = isFloatTag(tagR0);
1912 bool isFloatTOS = isFloatTag(tagTOS);
1913 if (!isFloatR0 && !isFloatTOS) {
1914 int t = decodeOp(op);
1915 o(0x59); /* pop %ecx */
1916 o(0xc139); /* cmp %eax,%ecx */
1917 li(0, NULL);
1918 o(0x0f); /* setxx %al */
1919 o(t + 0x90);
1920 o(0xc0);
1921 popType();
1922 } else {
1923 setupFloatOperands();
1924 switch (op) {
1925 case OP_EQUALS:
1926 o(0xe9da); // fucompp
1927 o(0xe0df); // fnstsw %ax
1928 o(0x9e); // sahf
1929 o(0xc0940f); // sete %al
1930 o(0xc29b0f); // setnp %dl
1931 o(0xd021); // andl %edx, %eax
1932 break;
1933 case OP_NOT_EQUALS:
1934 o(0xe9da); // fucompp
1935 o(0xe0df); // fnstsw %ax
1936 o(0x9e); // sahf
1937 o(0xc0950f); // setne %al
1938 o(0xc29a0f); // setp %dl
1939 o(0xd009); // orl %edx, %eax
1940 break;
1941 case OP_GREATER_EQUAL:
1942 o(0xe9da); // fucompp
1943 o(0xe0df); // fnstsw %ax
1944 o(0x05c4f6); // testb $5, %ah
1945 o(0xc0940f); // sete %al
1946 break;
1947 case OP_LESS:
1948 o(0xc9d9); // fxch %st(1)
1949 o(0xe9da); // fucompp
1950 o(0xe0df); // fnstsw %ax
1951 o(0x9e); // sahf
1952 o(0xc0970f); // seta %al
1953 break;
1954 case OP_LESS_EQUAL:
1955 o(0xc9d9); // fxch %st(1)
1956 o(0xe9da); // fucompp
1957 o(0xe0df); // fnstsw %ax
1958 o(0x9e); // sahf
1959 o(0xc0930f); // setea %al
1960 break;
1961 case OP_GREATER:
1962 o(0xe9da); // fucompp
1963 o(0xe0df); // fnstsw %ax
1964 o(0x45c4f6); // testb $69, %ah
1965 o(0xc0940f); // sete %al
1966 break;
1967 default:
1968 error("Unknown comparison op");
1969 }
1970 o(0xc0b60f); // movzbl %al, %eax
1971 }
1972 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001973 }
1974
Jack Palevich546b2242009-05-13 15:10:04 -07001975 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001976 Type* pR0Type = getR0Type();
1977 Type* pTOSType = getTOSType();
1978 TypeTag tagR0 = pR0Type->tag;
1979 TypeTag tagTOS = pTOSType->tag;
1980 bool isFloatR0 = isFloatTag(tagR0);
1981 bool isFloatTOS = isFloatTag(tagTOS);
1982 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001983 bool isPtrR0 = tagR0 == TY_POINTER;
1984 bool isPtrTOS = tagTOS == TY_POINTER;
1985 if (isPtrR0 || isPtrTOS) {
1986 if (isPtrR0 && isPtrTOS) {
1987 if (op != OP_MINUS) {
1988 error("Unsupported pointer-pointer operation %d.", op);
1989 }
1990 if (! typeEqual(pR0Type, pTOSType)) {
1991 error("Incompatible pointer types for subtraction.");
1992 }
1993 o(0x59); /* pop %ecx */
1994 o(decodeOp(op));
1995 popType();
1996 setR0Type(mkpInt);
1997 int size = sizeOf(pR0Type->pHead);
1998 if (size != 1) {
1999 pushR0();
2000 li(size, mkpInt);
2001 // TODO: Optimize for power-of-two.
2002 genOp(OP_DIV);
2003 }
2004 } else {
2005 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2006 error("Unsupported pointer-scalar operation %d", op);
2007 }
2008 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
2009 o(0x59); /* pop %ecx */
2010 int size = sizeOf(pPtrType->pHead);
2011 if (size != 1) {
2012 // TODO: Optimize for power-of-two.
2013 if (isPtrR0) {
2014 oad(0xC969, size); // imull $size, %ecx
2015 } else {
2016 oad(0xC069, size); // mul $size, %eax
2017 }
2018 }
2019 o(decodeOp(op));
2020 popType();
2021 setR0Type(pPtrType);
2022 }
2023 } else {
2024 o(0x59); /* pop %ecx */
2025 o(decodeOp(op));
2026 if (op == OP_MOD)
2027 o(0x92); /* xchg %edx, %eax */
2028 popType();
2029 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002030 } else {
2031 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2032 setupFloatOperands();
2033 // Both float. x87 R0 == left hand, x87 R1 == right hand
2034 switch (op) {
2035 case OP_MUL:
2036 o(0xc9de); // fmulp
2037 break;
2038 case OP_DIV:
2039 o(0xf1de); // fdivp
2040 break;
2041 case OP_PLUS:
2042 o(0xc1de); // faddp
2043 break;
2044 case OP_MINUS:
2045 o(0xe1de); // fsubp
2046 break;
2047 default:
2048 error("Unsupported binary floating operation.");
2049 break;
2050 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002051 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002052 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002053 }
2054
Jack Palevicha39749f2009-07-08 20:40:31 -07002055 virtual void gUnaryCmp(int op, Type* pResultType) {
2056 if (op != OP_LOGICAL_NOT) {
2057 error("Unknown unary cmp %d", op);
2058 } else {
2059 Type* pR0Type = getR0Type();
2060 TypeTag tag = collapseType(pR0Type->tag);
2061 switch(tag) {
2062 case TY_INT: {
2063 oad(0xb9, 0); /* movl $0, %ecx */
2064 int t = decodeOp(op);
2065 o(0xc139); /* cmp %eax,%ecx */
2066 li(0, NULL);
2067 o(0x0f); /* setxx %al */
2068 o(t + 0x90);
2069 o(0xc0);
2070 }
2071 break;
2072 case TY_FLOAT:
2073 case TY_DOUBLE:
2074 o(0xeed9); // fldz
2075 o(0xe9da); // fucompp
2076 o(0xe0df); // fnstsw %ax
2077 o(0x9e); // sahf
2078 o(0xc0950f); // setne %al
2079 o(0xc29a0f); // setp %dl
2080 o(0xd009); // orl %edx, %eax
2081 o(0xc0b60f); // movzbl %al, %eax
2082 o(0x01f083); // xorl $1, %eax
2083 break;
2084 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002085 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002086 break;
2087 }
2088 }
2089 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002090 }
2091
2092 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002093 Type* pR0Type = getR0Type();
2094 TypeTag tag = collapseType(pR0Type->tag);
2095 switch(tag) {
2096 case TY_INT:
2097 oad(0xb9, 0); /* movl $0, %ecx */
2098 o(decodeOp(op));
2099 break;
2100 case TY_FLOAT:
2101 case TY_DOUBLE:
2102 switch (op) {
2103 case OP_MINUS:
2104 o(0xe0d9); // fchs
2105 break;
2106 case OP_BIT_NOT:
2107 error("Can't apply '~' operator to a float or double.");
2108 break;
2109 default:
2110 error("Unknown unary op %d\n", op);
2111 break;
2112 }
2113 break;
2114 default:
2115 error("genUnaryOp unsupported type");
2116 break;
2117 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002118 }
2119
Jack Palevich1cdef202009-05-22 12:06:27 -07002120 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002121 Type* pR0Type = getR0Type();
2122 TypeTag r0ct = collapseType(pR0Type->tag);
2123 switch(r0ct) {
2124 case TY_INT:
2125 o(0x50); /* push %eax */
2126 break;
2127 case TY_FLOAT:
2128 o(0x50); /* push %eax */
2129 o(0x241cd9); // fstps 0(%esp)
2130 break;
2131 case TY_DOUBLE:
2132 o(0x50); /* push %eax */
2133 o(0x50); /* push %eax */
2134 o(0x241cdd); // fstpl 0(%esp)
2135 break;
2136 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002137 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002138 break;
2139 }
Jack Palevich8df46192009-07-07 14:48:51 -07002140 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002141 }
2142
Jack Palevich9eed7a22009-07-06 17:24:34 -07002143 virtual void storeR0ToTOS(Type* pPointerType) {
2144 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002145 Type* pTargetType = pPointerType->pHead;
2146 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002147 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002148 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002149 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002150 case TY_INT:
2151 o(0x0189); /* movl %eax/%al, (%ecx) */
2152 break;
2153 case TY_CHAR:
2154 o(0x0188); /* movl %eax/%al, (%ecx) */
2155 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002156 case TY_FLOAT:
2157 o(0x19d9); /* fstps (%ecx) */
2158 break;
2159 case TY_DOUBLE:
2160 o(0x19dd); /* fstpl (%ecx) */
2161 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002162 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002163 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002164 break;
2165 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002166 }
2167
Jack Palevich9eed7a22009-07-06 17:24:34 -07002168 virtual void loadR0FromR0(Type* pPointerType) {
2169 assert(pPointerType->tag == TY_POINTER);
2170 switch (pPointerType->pHead->tag) {
2171 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002172 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002173 break;
2174 case TY_CHAR:
2175 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002176 ob(0); /* add zero in code */
2177 break;
2178 case TY_FLOAT:
2179 o2(0x00d9); // flds (%eax)
2180 break;
2181 case TY_DOUBLE:
2182 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002183 break;
2184 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002185 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002186 break;
2187 }
Jack Palevich8df46192009-07-07 14:48:51 -07002188 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002189 }
2190
Jack Palevich8df46192009-07-07 14:48:51 -07002191 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002192 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002193 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002194 }
2195
Jack Palevich9cbd2262009-07-08 16:48:41 -07002196 virtual void storeR0(int ea, Type* pType) {
2197 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002198 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002199 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002200 case TY_CHAR:
2201 if (ea < -LOCAL || ea > LOCAL) {
2202 oad(0xa2, ea); // movb %al,ea
2203 } else {
2204 oad(0x8588, ea); // movb %al,ea(%ebp)
2205 }
2206 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002207 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002208 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002209 gmov(6, ea); /* mov %eax, EA */
2210 break;
2211 case TY_FLOAT:
2212 if (ea < -LOCAL || ea > LOCAL) {
2213 oad(0x1dd9, ea); // fstps ea
2214 } else {
2215 oad(0x9dd9, ea); // fstps ea(%ebp)
2216 }
2217 break;
2218 case TY_DOUBLE:
2219 if (ea < -LOCAL || ea > LOCAL) {
2220 oad(0x1ddd, ea); // fstpl ea
2221 } else {
2222 oad(0x9ddd, ea); // fstpl ea(%ebp)
2223 }
2224 break;
2225 default:
2226 error("Unable to store to type %d", tag);
2227 break;
2228 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002229 }
2230
Jack Palevich8df46192009-07-07 14:48:51 -07002231 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002232 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002233 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002234 case TY_CHAR:
2235 if (ea < -LOCAL || ea > LOCAL) {
2236 oad(0x05BE0F, ea); // movsbl ea,%eax
2237 } else {
2238 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2239 }
2240 if (isIncDec) {
2241 error("inc/dec not implemented for char.");
2242 }
2243 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002244 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002245 case TY_POINTER:
2246 if (tag == TY_CHAR) {
2247 } else {
2248 gmov(8, ea); /* mov EA, %eax */
2249 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002250 if (isIncDec) {
2251 /* Implement post-increment or post decrement.
2252 */
2253 gmov(0, ea); /* 83 ADD */
2254 o(decodeOp(op));
2255 }
2256 break;
2257 case TY_FLOAT:
2258 if (ea < -LOCAL || ea > LOCAL) {
2259 oad(0x05d9, ea); // flds ea
2260 } else {
2261 oad(0x85d9, ea); // flds ea(%ebp)
2262 }
2263 if (isIncDec) {
2264 error("inc/dec not implemented for float.");
2265 }
2266 break;
2267 case TY_DOUBLE:
2268 if (ea < -LOCAL || ea > LOCAL) {
2269 oad(0x05dd, ea); // fldl ea
2270 } else {
2271 oad(0x85dd, ea); // fldl ea(%ebp)
2272 }
2273 if (isIncDec) {
2274 error("inc/dec not implemented for double.");
2275 }
2276 break;
2277 default:
2278 error("Unable to load type %d", tag);
2279 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002280 }
Jack Palevich8df46192009-07-07 14:48:51 -07002281 setR0Type(pType);
2282 }
2283
2284 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002285 Type* pR0Type = getR0Type();
2286 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002287 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002288 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002289 return;
2290 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002291 if (bitsSame(pType, pR0Type)) {
2292 // do nothing special
2293 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2294 // do nothing special, both held in same register on x87.
2295 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002296 TypeTag r0Tag = collapseType(pR0Type->tag);
2297 TypeTag destTag = collapseType(pType->tag);
2298 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2299 // Convert R0 from int to float
2300 o(0x50); // push %eax
2301 o(0x2404DB); // fildl 0(%esp)
2302 o(0x58); // pop %eax
2303 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2304 // Convert R0 from float to int. Complicated because
2305 // need to save and restore the rounding mode.
2306 o(0x50); // push %eax
2307 o(0x50); // push %eax
2308 o(0x02247cD9); // fnstcw 2(%esp)
2309 o(0x2444b70f); // movzwl 2(%esp), %eax
2310 o(0x02);
2311 o(0x0cb4); // movb $12, %ah
2312 o(0x24048966); // movw %ax, 0(%esp)
2313 o(0x242cd9); // fldcw 0(%esp)
2314 o(0x04245cdb); // fistpl 4(%esp)
2315 o(0x02246cd9); // fldcw 2(%esp)
2316 o(0x58); // pop %eax
2317 o(0x58); // pop %eax
2318 } else {
2319 error("Incompatible types old: %d new: %d",
2320 pR0Type->tag, pType->tag);
2321 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002322 }
2323 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002324 }
2325
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002326 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002327 return oad(0xec81, 0); /* sub $xxx, %esp */
2328 }
2329
Jack Palevich8148c5b2009-07-16 18:24:47 -07002330 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2331 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002332 Type* pR0Type = getR0Type();
2333 TypeTag r0ct = collapseType(pR0Type->tag);
2334 switch(r0ct) {
2335 case TY_INT:
2336 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2337 return 4;
2338 case TY_FLOAT:
2339 oad(0x249CD9, l); /* fstps xxx(%esp) */
2340 return 4;
2341 case TY_DOUBLE:
2342 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2343 return 8;
2344 default:
2345 assert(false);
2346 return 0;
2347 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002348 }
2349
Jack Palevichb7718b92009-07-09 22:00:24 -07002350 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002351 * (int*) a = l;
2352 }
2353
Jack Palevich8df46192009-07-07 14:48:51 -07002354 virtual int callForward(int symbol, Type* pFunc) {
2355 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002356 return psym(0xe8, symbol); /* call xxx */
2357 }
2358
Jack Palevich8df46192009-07-07 14:48:51 -07002359 virtual void callRelative(int t, Type* pFunc) {
2360 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002361 psym(0xe8, t); /* call xxx */
2362 }
2363
Jack Palevich8df46192009-07-07 14:48:51 -07002364 virtual void callIndirect(int l, Type* pFunc) {
2365 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002366 oad(0x2494ff, l); /* call *xxx(%esp) */
2367 }
2368
Jack Palevichb7718b92009-07-09 22:00:24 -07002369 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002370 if (isIndirect) {
2371 l += 4;
2372 }
-b master422972c2009-06-17 19:13:52 -07002373 if (l > 0) {
2374 oad(0xc481, l); /* add $xxx, %esp */
2375 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002376 }
2377
Jack Palevicha6535612009-05-13 16:24:17 -07002378 virtual int jumpOffset() {
2379 return 5;
2380 }
2381
2382 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002383 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002384 }
2385
Jack Paleviche7b59062009-05-19 17:12:17 -07002386 /* output a symbol and patch all calls to it */
2387 virtual void gsym(int t) {
2388 int n;
2389 int pc = getPC();
2390 while (t) {
2391 n = *(int *) t; /* next value */
2392 *(int *) t = pc - t - 4;
2393 t = n;
2394 }
2395 }
2396
Jack Palevich1cdef202009-05-22 12:06:27 -07002397 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002398 size_t pagesize = 4096;
2399 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2400 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2401 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2402 if (err) {
2403 error("mprotect() failed: %d", errno);
2404 }
2405 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002406 }
2407
Jack Palevich9eed7a22009-07-06 17:24:34 -07002408 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002409 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002410 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002411 virtual size_t alignmentOf(Type* pType){
2412 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002413 }
2414
2415 /**
2416 * Array element alignment (in bytes) for this type of data.
2417 */
2418 virtual size_t sizeOf(Type* pType){
2419 switch(pType->tag) {
2420 case TY_INT:
2421 return 4;
2422 case TY_CHAR:
2423 return 1;
2424 default:
2425 return 0;
2426 case TY_FLOAT:
2427 return 4;
2428 case TY_DOUBLE:
2429 return 8;
2430 case TY_POINTER:
2431 return 4;
2432 }
2433 }
2434
Jack Palevich9cbd2262009-07-08 16:48:41 -07002435 virtual size_t stackSizeOf(Type* pType) {
2436 switch(pType->tag) {
2437 case TY_DOUBLE:
2438 return 8;
2439 default:
2440 return 4;
2441 }
2442 }
2443
Jack Palevich21a15a22009-05-11 14:49:29 -07002444 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002445
2446 /** Output 1 to 4 bytes.
2447 *
2448 */
2449 void o(int n) {
2450 /* cannot use unsigned, so we must do a hack */
2451 while (n && n != -1) {
2452 ob(n & 0xff);
2453 n = n >> 8;
2454 }
2455 }
2456
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002457 /* Output exactly 2 bytes
2458 */
2459 void o2(int n) {
2460 ob(n & 0xff);
2461 ob(0xff & (n >> 8));
2462 }
2463
Jack Paleviche7b59062009-05-19 17:12:17 -07002464 /* psym is used to put an instruction with a data field which is a
2465 reference to a symbol. It is in fact the same as oad ! */
2466 int psym(int n, int t) {
2467 return oad(n, t);
2468 }
2469
2470 /* instruction + address */
2471 int oad(int n, int t) {
2472 o(n);
2473 int result = getPC();
2474 o4(t);
2475 return result;
2476 }
2477
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002478 static const int operatorHelper[];
2479
2480 int decodeOp(int op) {
2481 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002482 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002483 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002484 }
2485 return operatorHelper[op];
2486 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002487
Jack Palevich546b2242009-05-13 15:10:04 -07002488 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002489 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002490 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002491 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002492
2493 void setupFloatOperands() {
2494 Type* pR0Type = getR0Type();
2495 Type* pTOSType = getTOSType();
2496 TypeTag tagR0 = pR0Type->tag;
2497 TypeTag tagTOS = pTOSType->tag;
2498 bool isFloatR0 = isFloatTag(tagR0);
2499 bool isFloatTOS = isFloatTag(tagTOS);
2500 if (! isFloatR0) {
2501 // Convert R0 from int to float
2502 o(0x50); // push %eax
2503 o(0x2404DB); // fildl 0(%esp)
2504 o(0x58); // pop %eax
2505 }
2506 if (! isFloatTOS){
2507 o(0x2404DB); // fildl 0(%esp);
2508 o(0x58); // pop %eax
2509 } else {
2510 if (tagTOS == TY_FLOAT) {
2511 o(0x2404d9); // flds (%esp)
2512 o(0x58); // pop %eax
2513 } else {
2514 o(0x2404dd); // fldl (%esp)
2515 o(0x58); // pop %eax
2516 o(0x58); // pop %eax
2517 }
2518 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002519 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002520 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002521 };
2522
Jack Paleviche7b59062009-05-19 17:12:17 -07002523#endif // PROVIDE_X86_CODEGEN
2524
Jack Palevichb67b18f2009-06-11 21:12:23 -07002525#ifdef PROVIDE_TRACE_CODEGEN
2526 class TraceCodeGenerator : public CodeGenerator {
2527 private:
2528 CodeGenerator* mpBase;
2529
2530 public:
2531 TraceCodeGenerator(CodeGenerator* pBase) {
2532 mpBase = pBase;
2533 }
2534
2535 virtual ~TraceCodeGenerator() {
2536 delete mpBase;
2537 }
2538
2539 virtual void init(CodeBuf* pCodeBuf) {
2540 mpBase->init(pCodeBuf);
2541 }
2542
2543 void setErrorSink(ErrorSink* pErrorSink) {
2544 mpBase->setErrorSink(pErrorSink);
2545 }
2546
2547 /* returns address to patch with local variable size
2548 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002549 virtual int functionEntry(Type* pDecl) {
2550 int result = mpBase->functionEntry(pDecl);
2551 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002552 return result;
2553 }
2554
Jack Palevichb7718b92009-07-09 22:00:24 -07002555 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2556 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2557 localVariableAddress, localVariableSize);
2558 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002559 }
2560
2561 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002562 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002563 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002564 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002565 }
2566
Jack Palevich1a539db2009-07-08 13:04:41 -07002567 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002568 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002569 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002570 }
2571
Jack Palevichb67b18f2009-06-11 21:12:23 -07002572 virtual int gjmp(int t) {
2573 int result = mpBase->gjmp(t);
2574 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2575 return result;
2576 }
2577
2578 /* l = 0: je, l == 1: jne */
2579 virtual int gtst(bool l, int t) {
2580 int result = mpBase->gtst(l, t);
2581 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2582 return result;
2583 }
2584
Jack Palevicha39749f2009-07-08 20:40:31 -07002585 virtual void gcmp(int op, Type* pResultType) {
2586 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2587 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002588 }
2589
2590 virtual void genOp(int op) {
2591 fprintf(stderr, "genOp(%d)\n", op);
2592 mpBase->genOp(op);
2593 }
2594
Jack Palevich9eed7a22009-07-06 17:24:34 -07002595
Jack Palevicha39749f2009-07-08 20:40:31 -07002596 virtual void gUnaryCmp(int op, Type* pResultType) {
2597 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2598 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002599 }
2600
2601 virtual void genUnaryOp(int op) {
2602 fprintf(stderr, "genUnaryOp(%d)\n", op);
2603 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002604 }
2605
2606 virtual void pushR0() {
2607 fprintf(stderr, "pushR0()\n");
2608 mpBase->pushR0();
2609 }
2610
Jack Palevich9eed7a22009-07-06 17:24:34 -07002611 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002612 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002613 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002614 }
2615
Jack Palevich9eed7a22009-07-06 17:24:34 -07002616 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002617 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002618 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002619 }
2620
Jack Palevich8df46192009-07-07 14:48:51 -07002621 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002622 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002623 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002624 }
2625
Jack Palevich9cbd2262009-07-08 16:48:41 -07002626 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002627 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002628 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002629 }
2630
Jack Palevich8df46192009-07-07 14:48:51 -07002631 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002632 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002633 mpBase->loadR0(ea, isIncDec, op, pType);
2634 }
2635
2636 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002637 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002638 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002639 }
2640
2641 virtual int beginFunctionCallArguments() {
2642 int result = mpBase->beginFunctionCallArguments();
2643 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2644 return result;
2645 }
2646
Jack Palevich8148c5b2009-07-16 18:24:47 -07002647 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2648 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2649 pArgType->tag);
2650 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002651 }
2652
Jack Palevichb7718b92009-07-09 22:00:24 -07002653 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002654 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002655 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002656 }
2657
Jack Palevich8df46192009-07-07 14:48:51 -07002658 virtual int callForward(int symbol, Type* pFunc) {
2659 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002660 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2661 return result;
2662 }
2663
Jack Palevich8df46192009-07-07 14:48:51 -07002664 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002665 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002666 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002667 }
2668
Jack Palevich8df46192009-07-07 14:48:51 -07002669 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002670 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002671 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002672 }
2673
Jack Palevichb7718b92009-07-09 22:00:24 -07002674 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2675 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2676 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002677 }
2678
2679 virtual int jumpOffset() {
2680 return mpBase->jumpOffset();
2681 }
2682
2683 virtual int disassemble(FILE* out) {
2684 return mpBase->disassemble(out);
2685 }
2686
2687 /* output a symbol and patch all calls to it */
2688 virtual void gsym(int t) {
2689 fprintf(stderr, "gsym(%d)\n", t);
2690 mpBase->gsym(t);
2691 }
2692
2693 virtual int finishCompile() {
2694 int result = mpBase->finishCompile();
2695 fprintf(stderr, "finishCompile() = %d\n", result);
2696 return result;
2697 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002698
2699 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002700 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002701 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002702 virtual size_t alignmentOf(Type* pType){
2703 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002704 }
2705
2706 /**
2707 * Array element alignment (in bytes) for this type of data.
2708 */
2709 virtual size_t sizeOf(Type* pType){
2710 return mpBase->sizeOf(pType);
2711 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002712
Jack Palevich9cbd2262009-07-08 16:48:41 -07002713
2714 virtual size_t stackSizeOf(Type* pType) {
2715 return mpBase->stackSizeOf(pType);
2716 }
2717
2718
Jack Palevich1a539db2009-07-08 13:04:41 -07002719 virtual Type* getR0Type() {
2720 return mpBase->getR0Type();
2721 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002722 };
2723
2724#endif // PROVIDE_TRACE_CODEGEN
2725
Jack Palevich569f1352009-06-29 14:29:08 -07002726 class Arena {
2727 public:
2728 // Used to record a given allocation amount.
2729 // Used:
2730 // Mark mark = arena.mark();
2731 // ... lots of arena.allocate()
2732 // arena.free(mark);
2733
2734 struct Mark {
2735 size_t chunk;
2736 size_t offset;
2737 };
2738
2739 Arena() {
2740 mCurrentChunk = 0;
2741 Chunk start(CHUNK_SIZE);
2742 mData.push_back(start);
2743 }
2744
2745 ~Arena() {
2746 for(size_t i = 0; i < mData.size(); i++) {
2747 mData[i].free();
2748 }
2749 }
2750
2751 // Alloc using the standard alignment size safe for any variable
2752 void* alloc(size_t size) {
2753 return alloc(size, 8);
2754 }
2755
2756 Mark mark(){
2757 Mark result;
2758 result.chunk = mCurrentChunk;
2759 result.offset = mData[mCurrentChunk].mOffset;
2760 return result;
2761 }
2762
2763 void freeToMark(const Mark& mark) {
2764 mCurrentChunk = mark.chunk;
2765 mData[mCurrentChunk].mOffset = mark.offset;
2766 }
2767
2768 private:
2769 // Allocate memory aligned to a given size
2770 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2771 // Memory is not zero filled.
2772
2773 void* alloc(size_t size, size_t alignment) {
2774 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2775 if (mCurrentChunk + 1 < mData.size()) {
2776 mCurrentChunk++;
2777 } else {
2778 size_t allocSize = CHUNK_SIZE;
2779 if (allocSize < size + alignment - 1) {
2780 allocSize = size + alignment - 1;
2781 }
2782 Chunk chunk(allocSize);
2783 mData.push_back(chunk);
2784 mCurrentChunk++;
2785 }
2786 }
2787 return mData[mCurrentChunk].allocate(size, alignment);
2788 }
2789
2790 static const size_t CHUNK_SIZE = 128*1024;
2791 // Note: this class does not deallocate its
2792 // memory when it's destroyed. It depends upon
2793 // its parent to deallocate the memory.
2794 struct Chunk {
2795 Chunk() {
2796 mpData = 0;
2797 mSize = 0;
2798 mOffset = 0;
2799 }
2800
2801 Chunk(size_t size) {
2802 mSize = size;
2803 mpData = (char*) malloc(size);
2804 mOffset = 0;
2805 }
2806
2807 ~Chunk() {
2808 // Doesn't deallocate memory.
2809 }
2810
2811 void* allocate(size_t size, size_t alignment) {
2812 size_t alignedOffset = aligned(mOffset, alignment);
2813 void* result = mpData + alignedOffset;
2814 mOffset = alignedOffset + size;
2815 return result;
2816 }
2817
2818 void free() {
2819 if (mpData) {
2820 ::free(mpData);
2821 mpData = 0;
2822 }
2823 }
2824
2825 size_t remainingCapacity(size_t alignment) {
2826 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2827 }
2828
2829 // Assume alignment is a power of two
2830 inline size_t aligned(size_t v, size_t alignment) {
2831 size_t mask = alignment-1;
2832 return (v + mask) & ~mask;
2833 }
2834
2835 char* mpData;
2836 size_t mSize;
2837 size_t mOffset;
2838 };
2839
2840 size_t mCurrentChunk;
2841
2842 Vector<Chunk> mData;
2843 };
2844
Jack Palevich569f1352009-06-29 14:29:08 -07002845 struct VariableInfo;
2846
2847 struct Token {
2848 int hash;
2849 size_t length;
2850 char* pText;
2851 tokenid_t id;
2852
2853 // Current values for the token
2854 char* mpMacroDefinition;
2855 VariableInfo* mpVariableInfo;
2856 };
2857
2858 class TokenTable {
2859 public:
2860 // Don't use 0..0xff, allows characters and operators to be tokens too.
2861
2862 static const int TOKEN_BASE = 0x100;
2863 TokenTable() {
2864 mpMap = hashmapCreate(128, hashFn, equalsFn);
2865 }
2866
2867 ~TokenTable() {
2868 hashmapFree(mpMap);
2869 }
2870
2871 void setArena(Arena* pArena) {
2872 mpArena = pArena;
2873 }
2874
2875 // Returns a token for a given string of characters.
2876 tokenid_t intern(const char* pText, size_t length) {
2877 Token probe;
2878 int hash = hashmapHash((void*) pText, length);
2879 {
2880 Token probe;
2881 probe.hash = hash;
2882 probe.length = length;
2883 probe.pText = (char*) pText;
2884 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2885 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002886 return pValue->id;
2887 }
2888 }
2889
2890 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2891 memset(pToken, 0, sizeof(*pToken));
2892 pToken->hash = hash;
2893 pToken->length = length;
2894 pToken->pText = (char*) mpArena->alloc(length + 1);
2895 memcpy(pToken->pText, pText, length);
2896 pToken->pText[length] = 0;
2897 pToken->id = mTokens.size() + TOKEN_BASE;
2898 mTokens.push_back(pToken);
2899 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002900 return pToken->id;
2901 }
2902
2903 // Return the Token for a given tokenid.
2904 Token& operator[](tokenid_t id) {
2905 return *mTokens[id - TOKEN_BASE];
2906 }
2907
2908 inline size_t size() {
2909 return mTokens.size();
2910 }
2911
2912 private:
2913
2914 static int hashFn(void* pKey) {
2915 Token* pToken = (Token*) pKey;
2916 return pToken->hash;
2917 }
2918
2919 static bool equalsFn(void* keyA, void* keyB) {
2920 Token* pTokenA = (Token*) keyA;
2921 Token* pTokenB = (Token*) keyB;
2922 // Don't need to compare hash values, they should always be equal
2923 return pTokenA->length == pTokenB->length
2924 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2925 }
2926
2927 Hashmap* mpMap;
2928 Vector<Token*> mTokens;
2929 Arena* mpArena;
2930 };
2931
Jack Palevich1cdef202009-05-22 12:06:27 -07002932 class InputStream {
2933 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002934 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002935 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002936 };
2937
2938 class TextInputStream : public InputStream {
2939 public:
2940 TextInputStream(const char* text, size_t textLength)
2941 : pText(text), mTextLength(textLength), mPosition(0) {
2942 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002943
Jack Palevichdc456462009-07-16 16:50:56 -07002944 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002945 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2946 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002947
Jack Palevichdc456462009-07-16 16:50:56 -07002948 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002949 const char* pText;
2950 size_t mTextLength;
2951 size_t mPosition;
2952 };
2953
Jack Palevicheedf9d22009-06-04 16:23:40 -07002954 class String {
2955 public:
2956 String() {
2957 mpBase = 0;
2958 mUsed = 0;
2959 mSize = 0;
2960 }
2961
Jack Palevich303d8ff2009-06-11 19:06:24 -07002962 String(const char* item, int len, bool adopt) {
2963 if (len < 0) {
2964 len = strlen(item);
2965 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002966 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002967 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002968 mUsed = len;
2969 mSize = len + 1;
2970 } else {
2971 mpBase = 0;
2972 mUsed = 0;
2973 mSize = 0;
2974 appendBytes(item, len);
2975 }
2976 }
2977
Jack Palevich303d8ff2009-06-11 19:06:24 -07002978 String(const String& other) {
2979 mpBase = 0;
2980 mUsed = 0;
2981 mSize = 0;
2982 appendBytes(other.getUnwrapped(), other.len());
2983 }
2984
Jack Palevicheedf9d22009-06-04 16:23:40 -07002985 ~String() {
2986 if (mpBase) {
2987 free(mpBase);
2988 }
2989 }
2990
Jack Palevicha6baa232009-06-12 11:25:59 -07002991 String& operator=(const String& other) {
2992 clear();
2993 appendBytes(other.getUnwrapped(), other.len());
2994 return *this;
2995 }
2996
Jack Palevich303d8ff2009-06-11 19:06:24 -07002997 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002998 return mpBase;
2999 }
3000
Jack Palevich303d8ff2009-06-11 19:06:24 -07003001 void clear() {
3002 mUsed = 0;
3003 if (mSize > 0) {
3004 mpBase[0] = 0;
3005 }
3006 }
3007
Jack Palevicheedf9d22009-06-04 16:23:40 -07003008 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003009 appendBytes(s, strlen(s));
3010 }
3011
3012 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003013 memcpy(ensure(n), s, n + 1);
3014 }
3015
3016 void append(char c) {
3017 * ensure(1) = c;
3018 }
3019
Jack Palevich86351982009-06-30 18:09:56 -07003020 void append(String& other) {
3021 appendBytes(other.getUnwrapped(), other.len());
3022 }
3023
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003024 char* orphan() {
3025 char* result = mpBase;
3026 mpBase = 0;
3027 mUsed = 0;
3028 mSize = 0;
3029 return result;
3030 }
3031
Jack Palevicheedf9d22009-06-04 16:23:40 -07003032 void printf(const char* fmt,...) {
3033 va_list ap;
3034 va_start(ap, fmt);
3035 vprintf(fmt, ap);
3036 va_end(ap);
3037 }
3038
3039 void vprintf(const char* fmt, va_list ap) {
3040 char* temp;
3041 int numChars = vasprintf(&temp, fmt, ap);
3042 memcpy(ensure(numChars), temp, numChars+1);
3043 free(temp);
3044 }
3045
Jack Palevich303d8ff2009-06-11 19:06:24 -07003046 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003047 return mUsed;
3048 }
3049
3050 private:
3051 char* ensure(int n) {
3052 size_t newUsed = mUsed + n;
3053 if (newUsed > mSize) {
3054 size_t newSize = mSize * 2 + 10;
3055 if (newSize < newUsed) {
3056 newSize = newUsed;
3057 }
3058 mpBase = (char*) realloc(mpBase, newSize + 1);
3059 mSize = newSize;
3060 }
3061 mpBase[newUsed] = '\0';
3062 char* result = mpBase + mUsed;
3063 mUsed = newUsed;
3064 return result;
3065 }
3066
3067 char* mpBase;
3068 size_t mUsed;
3069 size_t mSize;
3070 };
3071
Jack Palevich569f1352009-06-29 14:29:08 -07003072 void internKeywords() {
3073 // Note: order has to match TOK_ constants
3074 static const char* keywords[] = {
3075 "int",
3076 "char",
3077 "void",
3078 "if",
3079 "else",
3080 "while",
3081 "break",
3082 "return",
3083 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003084 "auto",
3085 "case",
3086 "const",
3087 "continue",
3088 "default",
3089 "do",
3090 "double",
3091 "enum",
3092 "extern",
3093 "float",
3094 "goto",
3095 "long",
3096 "register",
3097 "short",
3098 "signed",
3099 "sizeof",
3100 "static",
3101 "struct",
3102 "switch",
3103 "typedef",
3104 "union",
3105 "unsigned",
3106 "volatile",
3107 "_Bool",
3108 "_Complex",
3109 "_Imaginary",
3110 "inline",
3111 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003112
3113 // predefined tokens that can also be symbols start here:
3114 "pragma",
3115 "define",
3116 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003117 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003118
Jack Palevich569f1352009-06-29 14:29:08 -07003119 for(int i = 0; keywords[i]; i++) {
3120 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003121 }
Jack Palevich569f1352009-06-29 14:29:08 -07003122 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003123
Jack Palevich36d94142009-06-08 15:55:32 -07003124 struct InputState {
3125 InputStream* pStream;
3126 int oldCh;
3127 };
3128
Jack Palevich2db168f2009-06-11 14:29:47 -07003129 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003130 void* pAddress;
3131 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003132 tokenid_t tok;
3133 size_t level;
3134 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003135 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003136 };
3137
Jack Palevich303d8ff2009-06-11 19:06:24 -07003138 class SymbolStack {
3139 public:
3140 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003141 mpArena = 0;
3142 mpTokenTable = 0;
3143 }
3144
3145 void setArena(Arena* pArena) {
3146 mpArena = pArena;
3147 }
3148
3149 void setTokenTable(TokenTable* pTokenTable) {
3150 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003151 }
3152
3153 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003154 Mark mark;
3155 mark.mArenaMark = mpArena->mark();
3156 mark.mSymbolHead = mStack.size();
3157 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003158 }
3159
3160 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003161 // Undo any shadowing that was done:
3162 Mark mark = mLevelStack.back();
3163 mLevelStack.pop_back();
3164 while (mStack.size() > mark.mSymbolHead) {
3165 VariableInfo* pV = mStack.back();
3166 mStack.pop_back();
3167 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003168 }
Jack Palevich569f1352009-06-29 14:29:08 -07003169 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003170 }
3171
Jack Palevich569f1352009-06-29 14:29:08 -07003172 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3173 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3174 return pV && pV->level == level();
3175 }
3176
3177 VariableInfo* add(tokenid_t tok) {
3178 Token& token = (*mpTokenTable)[tok];
3179 VariableInfo* pOldV = token.mpVariableInfo;
3180 VariableInfo* pNewV =
3181 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3182 memset(pNewV, 0, sizeof(VariableInfo));
3183 pNewV->tok = tok;
3184 pNewV->level = level();
3185 pNewV->pOldDefinition = pOldV;
3186 token.mpVariableInfo = pNewV;
3187 mStack.push_back(pNewV);
3188 return pNewV;
3189 }
3190
Jack Palevich86351982009-06-30 18:09:56 -07003191 VariableInfo* add(Type* pType) {
3192 VariableInfo* pVI = add(pType->id);
3193 pVI->pType = pType;
3194 return pVI;
3195 }
3196
Jack Palevich569f1352009-06-29 14:29:08 -07003197 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3198 for (size_t i = 0; i < mStack.size(); i++) {
3199 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003200 break;
3201 }
3202 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003203 }
3204
Jack Palevich303d8ff2009-06-11 19:06:24 -07003205 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003206 inline size_t level() {
3207 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003208 }
3209
Jack Palevich569f1352009-06-29 14:29:08 -07003210 struct Mark {
3211 Arena::Mark mArenaMark;
3212 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003213 };
3214
Jack Palevich569f1352009-06-29 14:29:08 -07003215 Arena* mpArena;
3216 TokenTable* mpTokenTable;
3217 Vector<VariableInfo*> mStack;
3218 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003219 };
Jack Palevich36d94142009-06-08 15:55:32 -07003220
3221 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003222 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003223 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003224 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003225 int tokl; // token operator level
3226 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003227 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003228 intptr_t loc; // local variable index
3229 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003230 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003231 char* dptr; // Macro state: Points to macro text during macro playback.
3232 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003233 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003234 ACCSymbolLookupFn mpSymbolLookupFn;
3235 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003236
3237 // Arena for the duration of the compile
3238 Arena mGlobalArena;
3239 // Arena for data that's only needed when compiling a single function
3240 Arena mLocalArena;
3241
3242 TokenTable mTokenTable;
3243 SymbolStack mGlobals;
3244 SymbolStack mLocals;
3245
Jack Palevich40600de2009-07-01 15:32:35 -07003246 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003247 Type* mkpInt; // int
3248 Type* mkpChar; // char
3249 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003250 Type* mkpFloat;
3251 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003252 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003253 Type* mkpIntPtr;
3254 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003255 Type* mkpFloatPtr;
3256 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003257 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003258
Jack Palevich36d94142009-06-08 15:55:32 -07003259 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003260 int mLineNumber;
3261 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003262
3263 CodeBuf codeBuf;
3264 CodeGenerator* pGen;
3265
Jack Palevicheedf9d22009-06-04 16:23:40 -07003266 String mErrorBuf;
3267
Jack Palevicheedf9d22009-06-04 16:23:40 -07003268 String mPragmas;
3269 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003270 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003271
Jack Palevich21a15a22009-05-11 14:49:29 -07003272 static const int ALLOC_SIZE = 99999;
3273
Jack Palevich303d8ff2009-06-11 19:06:24 -07003274 static const int TOK_DUMMY = 1;
3275 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003276 static const int TOK_NUM_FLOAT = 3;
3277 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003278
3279 // 3..255 are character and/or operators
3280
Jack Palevich2db168f2009-06-11 14:29:47 -07003281 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003282 // Order has to match string list in "internKeywords".
3283 enum {
3284 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3285 TOK_INT = TOK_KEYWORD,
3286 TOK_CHAR,
3287 TOK_VOID,
3288 TOK_IF,
3289 TOK_ELSE,
3290 TOK_WHILE,
3291 TOK_BREAK,
3292 TOK_RETURN,
3293 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003294 TOK_AUTO,
3295 TOK_CASE,
3296 TOK_CONST,
3297 TOK_CONTINUE,
3298 TOK_DEFAULT,
3299 TOK_DO,
3300 TOK_DOUBLE,
3301 TOK_ENUM,
3302 TOK_EXTERN,
3303 TOK_FLOAT,
3304 TOK_GOTO,
3305 TOK_LONG,
3306 TOK_REGISTER,
3307 TOK_SHORT,
3308 TOK_SIGNED,
3309 TOK_SIZEOF,
3310 TOK_STATIC,
3311 TOK_STRUCT,
3312 TOK_SWITCH,
3313 TOK_TYPEDEF,
3314 TOK_UNION,
3315 TOK_UNSIGNED,
3316 TOK_VOLATILE,
3317 TOK__BOOL,
3318 TOK__COMPLEX,
3319 TOK__IMAGINARY,
3320 TOK_INLINE,
3321 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003322
3323 // Symbols start after keywords
3324
3325 TOK_SYMBOL,
3326 TOK_PRAGMA = TOK_SYMBOL,
3327 TOK_DEFINE,
3328 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003329 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003330
3331 static const int LOCAL = 0x200;
3332
3333 static const int SYM_FORWARD = 0;
3334 static const int SYM_DEFINE = 1;
3335
3336 /* tokens in string heap */
3337 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003338
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003339 static const int OP_INCREMENT = 0;
3340 static const int OP_DECREMENT = 1;
3341 static const int OP_MUL = 2;
3342 static const int OP_DIV = 3;
3343 static const int OP_MOD = 4;
3344 static const int OP_PLUS = 5;
3345 static const int OP_MINUS = 6;
3346 static const int OP_SHIFT_LEFT = 7;
3347 static const int OP_SHIFT_RIGHT = 8;
3348 static const int OP_LESS_EQUAL = 9;
3349 static const int OP_GREATER_EQUAL = 10;
3350 static const int OP_LESS = 11;
3351 static const int OP_GREATER = 12;
3352 static const int OP_EQUALS = 13;
3353 static const int OP_NOT_EQUALS = 14;
3354 static const int OP_LOGICAL_AND = 15;
3355 static const int OP_LOGICAL_OR = 16;
3356 static const int OP_BIT_AND = 17;
3357 static const int OP_BIT_XOR = 18;
3358 static const int OP_BIT_OR = 19;
3359 static const int OP_BIT_NOT = 20;
3360 static const int OP_LOGICAL_NOT = 21;
3361 static const int OP_COUNT = 22;
3362
3363 /* Operators are searched from front, the two-character operators appear
3364 * before the single-character operators with the same first character.
3365 * @ is used to pad out single-character operators.
3366 */
3367 static const char* operatorChars;
3368 static const char operatorLevel[];
3369
Jack Palevich569f1352009-06-29 14:29:08 -07003370 /* Called when we detect an internal problem. Does nothing in production.
3371 *
3372 */
3373 void internalError() {
3374 * (char*) 0 = 0;
3375 }
3376
Jack Palevich86351982009-06-30 18:09:56 -07003377 void assert(bool isTrue) {
3378 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003379 internalError();
3380 }
Jack Palevich86351982009-06-30 18:09:56 -07003381 }
3382
Jack Palevich40600de2009-07-01 15:32:35 -07003383 bool isSymbol(tokenid_t t) {
3384 return t >= TOK_SYMBOL &&
3385 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3386 }
3387
3388 bool isSymbolOrKeyword(tokenid_t t) {
3389 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003390 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003391 }
3392
Jack Palevich86351982009-06-30 18:09:56 -07003393 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003394 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003395 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3396 if (pV && pV->tok != t) {
3397 internalError();
3398 }
3399 return pV;
3400 }
3401
3402 inline bool isDefined(tokenid_t t) {
3403 return t >= TOK_SYMBOL && VI(t) != 0;
3404 }
3405
Jack Palevich40600de2009-07-01 15:32:35 -07003406 const char* nameof(tokenid_t t) {
3407 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003408 return mTokenTable[t].pText;
3409 }
3410
Jack Palevich21a15a22009-05-11 14:49:29 -07003411 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003412 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003413 }
3414
3415 void inp() {
3416 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003417 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003418 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003419 dptr = 0;
3420 ch = dch;
3421 }
Jack Palevichdc456462009-07-16 16:50:56 -07003422 } else {
3423 if (mbBumpLine) {
3424 mLineNumber++;
3425 mbBumpLine = false;
3426 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003427 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003428 if (ch == '\n') {
3429 mbBumpLine = true;
3430 }
3431 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003432#if 0
3433 printf("ch='%c' 0x%x\n", ch, ch);
3434#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003435 }
3436
3437 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003438 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003439 }
3440
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003441 int decodeHex(int c) {
3442 if (isdigit(c)) {
3443 c -= '0';
3444 } else if (c <= 'F') {
3445 c = c - 'A' + 10;
3446 } else {
3447 c =c - 'a' + 10;
3448 }
3449 return c;
3450 }
3451
Jack Palevichb4758ff2009-06-12 12:49:14 -07003452 /* read a character constant, advances ch to after end of constant */
3453 int getq() {
3454 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003455 if (ch == '\\') {
3456 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003457 if (isoctal(ch)) {
3458 // 1 to 3 octal characters.
3459 val = 0;
3460 for(int i = 0; i < 3; i++) {
3461 if (isoctal(ch)) {
3462 val = (val << 3) + ch - '0';
3463 inp();
3464 }
3465 }
3466 return val;
3467 } else if (ch == 'x' || ch == 'X') {
3468 // N hex chars
3469 inp();
3470 if (! isxdigit(ch)) {
3471 error("'x' character escape requires at least one digit.");
3472 } else {
3473 val = 0;
3474 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003475 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003476 inp();
3477 }
3478 }
3479 } else {
3480 int val = ch;
3481 switch (ch) {
3482 case 'a':
3483 val = '\a';
3484 break;
3485 case 'b':
3486 val = '\b';
3487 break;
3488 case 'f':
3489 val = '\f';
3490 break;
3491 case 'n':
3492 val = '\n';
3493 break;
3494 case 'r':
3495 val = '\r';
3496 break;
3497 case 't':
3498 val = '\t';
3499 break;
3500 case 'v':
3501 val = '\v';
3502 break;
3503 case '\\':
3504 val = '\\';
3505 break;
3506 case '\'':
3507 val = '\'';
3508 break;
3509 case '"':
3510 val = '"';
3511 break;
3512 case '?':
3513 val = '?';
3514 break;
3515 default:
3516 error("Undefined character escape %c", ch);
3517 break;
3518 }
3519 inp();
3520 return val;
3521 }
3522 } else {
3523 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003524 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003525 return val;
3526 }
3527
3528 static bool isoctal(int ch) {
3529 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003530 }
3531
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003532 bool acceptCh(int c) {
3533 bool result = c == ch;
3534 if (result) {
3535 pdef(ch);
3536 inp();
3537 }
3538 return result;
3539 }
3540
3541 bool acceptDigitsCh() {
3542 bool result = false;
3543 while (isdigit(ch)) {
3544 result = true;
3545 pdef(ch);
3546 inp();
3547 }
3548 return result;
3549 }
3550
3551 void parseFloat() {
3552 tok = TOK_NUM_DOUBLE;
3553 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003554 if(mTokenString.len() == 0) {
3555 mTokenString.append('0');
3556 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003557 acceptCh('.');
3558 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003559 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003560 acceptCh('-') || acceptCh('+');
3561 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003562 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003563 if (ch == 'f' || ch == 'F') {
3564 tok = TOK_NUM_FLOAT;
3565 inp();
3566 } else if (ch == 'l' || ch == 'L') {
3567 inp();
3568 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003569 }
3570 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003571 char* pEnd = pText + strlen(pText);
3572 char* pEndPtr = 0;
3573 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003574 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003575 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003576 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003577 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003578 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003579 if (errno || pEndPtr != pEnd) {
3580 error("Can't parse constant: %s", pText);
3581 }
3582 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003583 }
3584
Jack Palevich21a15a22009-05-11 14:49:29 -07003585 void next() {
3586 int l, a;
3587
Jack Palevich546b2242009-05-13 15:10:04 -07003588 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003589 if (ch == '#') {
3590 inp();
3591 next();
3592 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003593 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003594 } else if (tok == TOK_PRAGMA) {
3595 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003596 } else if (tok == TOK_LINE) {
3597 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003598 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003599 error("Unsupported preprocessor directive \"%s\"",
3600 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003601 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003602 }
3603 inp();
3604 }
3605 tokl = 0;
3606 tok = ch;
3607 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003608 if (isdigit(ch) || ch == '.') {
3609 // Start of a numeric constant. Could be integer, float, or
3610 // double, won't know until we look further.
3611 mTokenString.clear();
3612 pdef(ch);
3613 inp();
3614 int base = 10;
3615 if (tok == '0') {
3616 if (ch == 'x' || ch == 'X') {
3617 base = 16;
3618 tok = TOK_NUM;
3619 tokc = 0;
3620 inp();
3621 while ( isxdigit(ch) ) {
3622 tokc = (tokc << 4) + decodeHex(ch);
3623 inp();
3624 }
3625 } else if (isoctal(ch)){
3626 base = 8;
3627 tok = TOK_NUM;
3628 tokc = 0;
3629 while ( isoctal(ch) ) {
3630 tokc = (tokc << 3) + (ch - '0');
3631 inp();
3632 }
3633 }
3634 } else if (isdigit(tok)){
3635 acceptDigitsCh();
3636 }
3637 if (base == 10) {
3638 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3639 parseFloat();
3640 } else {
3641 // It's an integer constant
3642 char* pText = mTokenString.getUnwrapped();
3643 char* pEnd = pText + strlen(pText);
3644 char* pEndPtr = 0;
3645 errno = 0;
3646 tokc = strtol(pText, &pEndPtr, base);
3647 if (errno || pEndPtr != pEnd) {
3648 error("Can't parse constant: %s %d %d", pText, base, errno);
3649 }
3650 tok = TOK_NUM;
3651 }
3652 }
3653 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003654 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003656 pdef(ch);
3657 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003658 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003659 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3660 // Is this a macro?
3661 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3662 if (pMacroDefinition) {
3663 // Yes, it is a macro
3664 dptr = pMacroDefinition;
3665 dch = ch;
3666 inp();
3667 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003668 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003669 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003670 inp();
3671 if (tok == '\'') {
3672 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003673 tokc = getq();
3674 if (ch != '\'') {
3675 error("Expected a ' character, got %c", ch);
3676 } else {
3677 inp();
3678 }
Jack Palevich546b2242009-05-13 15:10:04 -07003679 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003680 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003681 while (ch && ch != EOF) {
3682 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003683 inp();
3684 inp();
3685 if (ch == '/')
3686 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003687 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003688 if (ch == EOF) {
3689 error("End of file inside comment.");
3690 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003691 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003692 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003693 } else if ((tok == '/') & (ch == '/')) {
3694 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003695 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003696 inp();
3697 }
3698 inp();
3699 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003700 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003701 const char* t = operatorChars;
3702 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003703 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003704 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003705 tokl = operatorLevel[opIndex];
3706 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003707 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003708#if 0
3709 printf("%c%c -> tokl=%d tokc=0x%x\n",
3710 l, a, tokl, tokc);
3711#endif
3712 if (a == ch) {
3713 inp();
3714 tok = TOK_DUMMY; /* dummy token for double tokens */
3715 }
3716 break;
3717 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003718 opIndex++;
3719 }
3720 if (l == 0) {
3721 tokl = 0;
3722 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003723 }
3724 }
3725 }
3726#if 0
3727 {
Jack Palevich569f1352009-06-29 14:29:08 -07003728 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003729 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003730 fprintf(stderr, "%s\n", buf.getUnwrapped());
3731 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003732#endif
3733 }
3734
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003735 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003736 next();
3737 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003738 String* pName = new String();
3739 while (isspace(ch)) {
3740 inp();
3741 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003742 if (ch == '(') {
3743 delete pName;
3744 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003745 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003746 }
3747 while (isspace(ch)) {
3748 inp();
3749 }
Jack Palevich569f1352009-06-29 14:29:08 -07003750 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003751 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003752 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003753 inp();
3754 }
Jack Palevich569f1352009-06-29 14:29:08 -07003755 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3756 memcpy(pDefn, value.getUnwrapped(), value.len());
3757 pDefn[value.len()] = 0;
3758 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003759 }
3760
Jack Palevicheedf9d22009-06-04 16:23:40 -07003761 void doPragma() {
3762 // # pragma name(val)
3763 int state = 0;
3764 while(ch != EOF && ch != '\n' && state < 10) {
3765 switch(state) {
3766 case 0:
3767 if (isspace(ch)) {
3768 inp();
3769 } else {
3770 state++;
3771 }
3772 break;
3773 case 1:
3774 if (isalnum(ch)) {
3775 mPragmas.append(ch);
3776 inp();
3777 } else if (ch == '(') {
3778 mPragmas.append(0);
3779 inp();
3780 state++;
3781 } else {
3782 state = 11;
3783 }
3784 break;
3785 case 2:
3786 if (isalnum(ch)) {
3787 mPragmas.append(ch);
3788 inp();
3789 } else if (ch == ')') {
3790 mPragmas.append(0);
3791 inp();
3792 state = 10;
3793 } else {
3794 state = 11;
3795 }
3796 break;
3797 }
3798 }
3799 if(state != 10) {
3800 error("Unexpected pragma syntax");
3801 }
3802 mPragmaStringCount += 2;
3803 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003804
Jack Palevichdc456462009-07-16 16:50:56 -07003805 void doLine() {
3806 // # line number { "filename "}
3807 next();
3808 if (tok != TOK_NUM) {
3809 error("Expected a line-number");
3810 } else {
3811 mLineNumber = tokc-1; // The end-of-line will increment it.
3812 }
3813 while(ch != EOF && ch != '\n') {
3814 inp();
3815 }
3816 }
3817
Jack Palevichac0e95e2009-05-29 13:53:44 -07003818 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003819 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003820 mErrorBuf.vprintf(fmt, ap);
3821 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003822 }
3823
Jack Palevich8b0624c2009-05-20 12:12:06 -07003824 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003825 if (tok != c) {
3826 error("'%c' expected", c);
3827 }
3828 next();
3829 }
3830
Jack Palevich86351982009-06-30 18:09:56 -07003831 bool accept(intptr_t c) {
3832 if (tok == c) {
3833 next();
3834 return true;
3835 }
3836 return false;
3837 }
3838
Jack Palevich40600de2009-07-01 15:32:35 -07003839 bool acceptStringLiteral() {
3840 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003841 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003842 // This while loop merges multiple adjacent string constants.
3843 while (tok == '"') {
3844 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003845 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003846 }
3847 if (ch != '"') {
3848 error("Unterminated string constant.");
3849 }
3850 inp();
3851 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003852 }
Jack Palevich40600de2009-07-01 15:32:35 -07003853 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003854 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003855 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003856 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003857
3858 return true;
3859 }
3860 return false;
3861 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003862
Jack Palevichb1544ca2009-07-16 15:09:20 -07003863 void linkGlobal(tokenid_t t, bool isFunction) {
3864 VariableInfo* pVI = VI(t);
3865 void* n = NULL;
3866 if (mpSymbolLookupFn) {
3867 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3868 }
3869 if (pVI->pType == NULL) {
3870 if (isFunction) {
3871 pVI->pType = mkpIntFn;
3872 } else {
3873 pVI->pType = mkpInt;
3874 }
3875 }
3876 pVI->pAddress = n;
3877 }
3878
Jack Palevich40600de2009-07-01 15:32:35 -07003879 /* Parse and evaluate a unary expression.
3880 * allowAssignment is true if '=' parsing wanted (quick hack)
3881 */
3882 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003883 tokenid_t t;
3884 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003885 t = 0;
3886 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3887 if (acceptStringLiteral()) {
3888 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003889 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003890 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003892 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003893 t = tok;
3894 next();
3895 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003896 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003897 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003898 // Align to 4-byte boundary
3899 glo = (char*) (((intptr_t) glo + 3) & -4);
3900 * (float*) glo = (float) ad;
3901 pGen->loadFloat((int) glo, mkpFloat);
3902 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003903 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003904 // Align to 8-byte boundary
3905 glo = (char*) (((intptr_t) glo + 7) & -8);
3906 * (double*) glo = ad;
3907 pGen->loadFloat((int) glo, mkpDouble);
3908 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003909 } else if (c == 2) {
3910 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003911 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003913 pGen->gUnaryCmp(a, mkpInt);
3914 else if (t == '+') {
3915 // ignore unary plus.
3916 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003917 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003918 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003919 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003920 // It's either a cast or an expression
3921 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3922 if (pCast) {
3923 skip(')');
3924 unary(false);
3925 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003926 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003927 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003928 skip(')');
3929 }
3930 } else if (t == '*') {
3931 /* This is a pointer dereference.
3932 */
3933 unary(false);
3934 Type* pR0Type = pGen->getR0Type();
3935 if (pR0Type->tag != TY_POINTER) {
3936 error("Expected a pointer type.");
3937 } else {
3938 if (pR0Type->pHead->tag == TY_FUNC) {
3939 t = 0;
3940 }
3941 if (accept('=')) {
3942 pGen->pushR0();
3943 expr();
3944 pGen->storeR0ToTOS(pR0Type);
3945 } else if (t) {
3946 pGen->loadR0FromR0(pR0Type);
3947 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003948 }
Jack Palevich3f226492009-07-02 14:46:19 -07003949 // Else we fall through to the function call below, with
3950 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003951 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003952 VariableInfo* pVI = VI(tok);
3953 pGen->leaR0((int) pVI->pAddress,
3954 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003955 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003956 } else if (t == EOF ) {
3957 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003958 } else if (t == ';') {
3959 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003960 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003961 // Don't have to do anything special here, the error
3962 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003963 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003964 if (!isDefined(t)) {
3965 mGlobals.add(t);
3966 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003967 }
Jack Palevich8df46192009-07-07 14:48:51 -07003968 VariableInfo* pVI = VI(t);
3969 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003970 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003971 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003972 linkGlobal(t, tok == '(');
3973 n = (intptr_t) pVI->pAddress;
3974 if (!n && tok != '(') {
3975 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003976 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003977 }
Jack Palevich40600de2009-07-01 15:32:35 -07003978 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003979 /* assignment */
3980 next();
3981 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003982 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003983 } else if (tok != '(') {
3984 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003985 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003986 linkGlobal(t, false);
3987 n = (intptr_t) pVI->pAddress;
3988 if (!n) {
3989 error("Undeclared variable %s\n", nameof(t));
3990 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003991 }
Jack Palevich8df46192009-07-07 14:48:51 -07003992 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003993 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 next();
3995 }
3996 }
3997 }
3998 }
3999
4000 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07004001 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07004002 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07004003 VariableInfo* pVI = NULL;
4004 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07004005 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07004006 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07004007 } else {
4008 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07004009 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07004010 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004011 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07004012 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07004013 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004014 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07004015 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004016 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004017 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004018 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004019 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004020 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004021 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004022 Type* pTargetType;
4023 if (pArgList) {
4024 pTargetType = pArgList->pHead;
4025 pArgList = pArgList->pTail;
4026 } else {
4027 pTargetType = pGen->getR0Type();
4028 if (pTargetType->tag == TY_FLOAT) {
4029 pTargetType = mkpDouble;
4030 }
4031 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004032 if (pTargetType->tag == TY_VOID) {
4033 error("Can't pass void value for argument %d",
4034 argCount + 1);
4035 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004036 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004037 }
Jack Palevich95727a02009-07-06 12:07:15 -07004038 if (accept(',')) {
4039 // fine
4040 } else if ( tok != ')') {
4041 error("Expected ',' or ')'");
4042 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004043 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004044 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004045 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004046 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004047 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004048 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004049 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004050 if (!n) {
4051 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004052 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4053 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004054 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004055 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004057 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4058 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004059 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004060 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004061 }
4062 }
4063
Jack Palevich40600de2009-07-01 15:32:35 -07004064 /* Recursive descent parser for binary operations.
4065 */
4066 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004067 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004068 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004069 if (level-- == 1)
4070 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004071 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004072 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004073 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004074 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 t = tokc;
4076 next();
4077
Jack Palevich40600de2009-07-01 15:32:35 -07004078 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004079 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004080 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004081 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004082 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004083 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004084 // Check for syntax error.
4085 if (pGen->getR0Type() == NULL) {
4086 // We failed to parse a right-hand argument.
4087 // Push a dummy value so we don't fail
4088 pGen->li(0, mkpInt);
4089 }
Jack Palevich40600de2009-07-01 15:32:35 -07004090 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004091 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004092 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004093 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004094 }
4095 }
4096 }
4097 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004098 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004099 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004100 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004101 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004102 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004103 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004104 }
4105 }
4106 }
4107
4108 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004109 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004110 }
4111
4112 int test_expr() {
4113 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004114 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004115 }
4116
Jack Palevicha6baa232009-06-12 11:25:59 -07004117 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004118 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004119
Jack Palevich95727a02009-07-06 12:07:15 -07004120 Type* pBaseType;
4121 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004122 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004123 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004124 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004125 next();
4126 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004127 a = test_expr();
4128 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004129 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004130 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004131 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004132 n = pGen->gjmp(0); /* jmp */
4133 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004134 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004135 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004136 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004137 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004138 }
Jack Palevich546b2242009-05-13 15:10:04 -07004139 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004140 t = tok;
4141 next();
4142 skip('(');
4143 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004144 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004145 a = test_expr();
4146 } else {
4147 if (tok != ';')
4148 expr();
4149 skip(';');
4150 n = codeBuf.getPC();
4151 a = 0;
4152 if (tok != ';')
4153 a = test_expr();
4154 skip(';');
4155 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004156 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004157 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004158 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004159 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004160 n = t + 4;
4161 }
4162 }
4163 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004164 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004165 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004166 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004167 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004168 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004169 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004170 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004171 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004172 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004173 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004174 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004175 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004176 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004177 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004178 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004179 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004180 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004181 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004182 if (pReturnType->tag == TY_VOID) {
4183 error("Must not return a value from a void function");
4184 } else {
4185 pGen->convertR0(pReturnType);
4186 }
4187 } else {
4188 if (pReturnType->tag != TY_VOID) {
4189 error("Must specify a value here");
4190 }
Jack Palevich8df46192009-07-07 14:48:51 -07004191 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004192 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004193 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004194 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004195 } else if (tok != ';')
4196 expr();
4197 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004198 }
4199 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004200
Jack Palevicha8f427f2009-07-13 18:40:08 -07004201 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004202 if (a == b) {
4203 return true;
4204 }
4205 if (a == NULL || b == NULL) {
4206 return false;
4207 }
4208 TypeTag at = a->tag;
4209 if (at != b->tag) {
4210 return false;
4211 }
4212 if (at == TY_POINTER) {
4213 return typeEqual(a->pHead, b->pHead);
4214 } else if (at == TY_FUNC || at == TY_PARAM) {
4215 return typeEqual(a->pHead, b->pHead)
4216 && typeEqual(a->pTail, b->pTail);
4217 }
4218 return true;
4219 }
4220
Jack Palevich86351982009-06-30 18:09:56 -07004221 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4222 assert(tag >= TY_INT && tag <= TY_PARAM);
4223 Type* pType = (Type*) arena.alloc(sizeof(Type));
4224 memset(pType, 0, sizeof(*pType));
4225 pType->tag = tag;
4226 pType->pHead = pHead;
4227 pType->pTail = pTail;
4228 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004229 }
4230
Jack Palevich3f226492009-07-02 14:46:19 -07004231 Type* createPtrType(Type* pType, Arena& arena) {
4232 return createType(TY_POINTER, pType, NULL, arena);
4233 }
4234
4235 /**
4236 * Try to print a type in declaration order
4237 */
Jack Palevich86351982009-06-30 18:09:56 -07004238 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004239 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004240 if (pType == NULL) {
4241 buffer.appendCStr("null");
4242 return;
4243 }
Jack Palevich3f226492009-07-02 14:46:19 -07004244 decodeTypeImp(buffer, pType);
4245 }
4246
4247 void decodeTypeImp(String& buffer, Type* pType) {
4248 decodeTypeImpPrefix(buffer, pType);
4249
Jack Palevich86351982009-06-30 18:09:56 -07004250 String temp;
4251 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004252 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004253 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004254 }
4255
4256 decodeTypeImpPostfix(buffer, pType);
4257 }
4258
4259 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4260 TypeTag tag = pType->tag;
4261
Jack Palevich37c54bd2009-07-14 18:35:36 -07004262 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004263 switch (tag) {
4264 case TY_INT:
4265 buffer.appendCStr("int");
4266 break;
4267 case TY_CHAR:
4268 buffer.appendCStr("char");
4269 break;
4270 case TY_VOID:
4271 buffer.appendCStr("void");
4272 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004273 case TY_FLOAT:
4274 buffer.appendCStr("float");
4275 break;
4276 case TY_DOUBLE:
4277 buffer.appendCStr("double");
4278 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004279 default:
4280 break;
4281 }
Jack Palevich86351982009-06-30 18:09:56 -07004282 buffer.append(' ');
4283 }
Jack Palevich3f226492009-07-02 14:46:19 -07004284
4285 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004286 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004287 break;
4288 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004289 break;
4290 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004291 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004292 case TY_FLOAT:
4293 break;
4294 case TY_DOUBLE:
4295 break;
Jack Palevich86351982009-06-30 18:09:56 -07004296 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004297 decodeTypeImpPrefix(buffer, pType->pHead);
4298 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4299 buffer.append('(');
4300 }
4301 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004302 break;
4303 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004304 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004305 break;
4306 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004307 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004308 break;
4309 default:
4310 String temp;
4311 temp.printf("Unknown tag %d", pType->tag);
4312 buffer.append(temp);
4313 break;
4314 }
Jack Palevich3f226492009-07-02 14:46:19 -07004315 }
4316
4317 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4318 TypeTag tag = pType->tag;
4319
4320 switch(tag) {
4321 case TY_POINTER:
4322 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4323 buffer.append(')');
4324 }
4325 decodeTypeImpPostfix(buffer, pType->pHead);
4326 break;
4327 case TY_FUNC:
4328 buffer.append('(');
4329 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4330 decodeTypeImp(buffer, pArg);
4331 if (pArg->pTail) {
4332 buffer.appendCStr(", ");
4333 }
4334 }
4335 buffer.append(')');
4336 break;
4337 default:
4338 break;
Jack Palevich86351982009-06-30 18:09:56 -07004339 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004340 }
4341
Jack Palevich86351982009-06-30 18:09:56 -07004342 void printType(Type* pType) {
4343 String buffer;
4344 decodeType(buffer, pType);
4345 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004346 }
4347
Jack Palevich86351982009-06-30 18:09:56 -07004348 Type* acceptPrimitiveType(Arena& arena) {
4349 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004350 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004351 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004352 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004353 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004354 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004355 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004356 } else if (tok == TOK_FLOAT) {
4357 pType = mkpFloat;
4358 } else if (tok == TOK_DOUBLE) {
4359 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004360 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004361 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004362 }
4363 next();
Jack Palevich86351982009-06-30 18:09:56 -07004364 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004365 }
4366
Jack Palevich3f226492009-07-02 14:46:19 -07004367 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4368 Arena& arena) {
4369 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004370 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004371 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004372 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004373 if (declName) {
4374 // Clone the parent type so we can set a unique ID
4375 pType = createType(pType->tag, pType->pHead,
4376 pType->pTail, arena);
4377
Jack Palevich86351982009-06-30 18:09:56 -07004378 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004379 }
Jack Palevich3f226492009-07-02 14:46:19 -07004380 // fprintf(stderr, "Parsed a declaration: ");
4381 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004382 if (reportFailure) {
4383 return NULL;
4384 }
Jack Palevich86351982009-06-30 18:09:56 -07004385 return pType;
4386 }
4387
Jack Palevich3f226492009-07-02 14:46:19 -07004388 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4389 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004390 if (! pType) {
4391 error("Expected a declaration");
4392 }
4393 return pType;
4394 }
4395
Jack Palevich3f226492009-07-02 14:46:19 -07004396 /* Used for accepting types that appear in casts */
4397 Type* acceptCastTypeDeclaration(Arena& arena) {
4398 Type* pType = acceptPrimitiveType(arena);
4399 if (pType) {
4400 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004401 }
Jack Palevich86351982009-06-30 18:09:56 -07004402 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004403 }
4404
Jack Palevich3f226492009-07-02 14:46:19 -07004405 Type* expectCastTypeDeclaration(Arena& arena) {
4406 Type* pType = acceptCastTypeDeclaration(arena);
4407 if (! pType) {
4408 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004409 }
Jack Palevich3f226492009-07-02 14:46:19 -07004410 return pType;
4411 }
4412
4413 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004414 bool nameAllowed, bool nameRequired, Arena& arena,
4415 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004416 int ptrCounter = 0;
4417 while (accept('*')) {
4418 ptrCounter++;
4419 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004420 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena,
4421 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004422 while (ptrCounter-- > 0) {
4423 pType = createType(TY_POINTER, pType, NULL, arena);
4424 }
4425 return pType;
4426 }
4427
4428 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004429 bool nameAllowed, bool nameRequired, Arena& arena,
4430 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004431 // direct-dcl :
4432 // name
4433 // (dcl)
4434 // direct-dcl()
4435 // direct-dcl[]
4436 Type* pNewHead = NULL;
4437 if (accept('(')) {
4438 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004439 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004440 skip(')');
4441 } else if ((declName = acceptSymbol()) != 0) {
4442 if (nameAllowed == false && declName) {
4443 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004444 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004445 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004446 } else if (nameRequired && ! declName) {
4447 String temp;
4448 decodeToken(temp, tok, true);
4449 error("Expected name. Got %s", temp.getUnwrapped());
4450 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004451 }
4452 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004453 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004454 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004455 pType = createType(TY_FUNC, pType, pTail, arena);
4456 skip(')');
4457 }
Jack Palevich3f226492009-07-02 14:46:19 -07004458
4459 if (pNewHead) {
4460 Type* pA = pNewHead;
4461 while (pA->pHead) {
4462 pA = pA->pHead;
4463 }
4464 pA->pHead = pType;
4465 pType = pNewHead;
4466 }
Jack Palevich86351982009-06-30 18:09:56 -07004467 return pType;
4468 }
4469
Jack Palevich3f226492009-07-02 14:46:19 -07004470 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004471 Type* pHead = NULL;
4472 Type* pTail = NULL;
4473 for(;;) {
4474 Type* pBaseArg = acceptPrimitiveType(arena);
4475 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004476 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4477 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004478 if (pArg) {
4479 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4480 if (!pHead) {
4481 pHead = pParam;
4482 pTail = pParam;
4483 } else {
4484 pTail->pTail = pParam;
4485 pTail = pParam;
4486 }
4487 }
4488 }
4489 if (! accept(',')) {
4490 break;
4491 }
4492 }
4493 return pHead;
4494 }
4495
4496 Type* expectPrimitiveType(Arena& arena) {
4497 Type* pType = acceptPrimitiveType(arena);
4498 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004499 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004500 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004501 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004502 }
Jack Palevich86351982009-06-30 18:09:56 -07004503 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004504 }
4505
Jack Palevich86351982009-06-30 18:09:56 -07004506 void addGlobalSymbol(Type* pDecl) {
4507 tokenid_t t = pDecl->id;
4508 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004509 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004510 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004511 }
Jack Palevich86351982009-06-30 18:09:56 -07004512 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004513 }
4514
Jack Palevich86351982009-06-30 18:09:56 -07004515 void reportDuplicate(tokenid_t t) {
4516 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004517 }
4518
Jack Palevich86351982009-06-30 18:09:56 -07004519 void addLocalSymbol(Type* pDecl) {
4520 tokenid_t t = pDecl->id;
4521 if (mLocals.isDefinedAtCurrentLevel(t)) {
4522 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004523 }
Jack Palevich86351982009-06-30 18:09:56 -07004524 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004525 }
4526
Jack Palevich95727a02009-07-06 12:07:15 -07004527 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004528 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004529
Jack Palevich95727a02009-07-06 12:07:15 -07004530 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004531 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004532 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4533 if (!pDecl) {
4534 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004535 }
Jack Palevich86351982009-06-30 18:09:56 -07004536 int variableAddress = 0;
4537 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004538 size_t alignment = pGen->alignmentOf(pDecl);
4539 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004540 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004541 variableAddress = -loc;
4542 VI(pDecl->id)->pAddress = (void*) variableAddress;
4543 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004544 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004545 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004546 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004547 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004548 if (tok == ',')
4549 next();
4550 }
4551 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004552 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004553 }
4554 }
4555
Jack Palevichf1728be2009-06-12 13:53:51 -07004556 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004557 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004558 }
4559
Jack Palevich37c54bd2009-07-14 18:35:36 -07004560 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004561 if (token == EOF ) {
4562 buffer.printf("EOF");
4563 } else if (token == TOK_NUM) {
4564 buffer.printf("numeric constant");
4565 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004566 if (token < 32) {
4567 buffer.printf("'\\x%02x'", token);
4568 } else {
4569 buffer.printf("'%c'", token);
4570 }
Jack Palevich569f1352009-06-29 14:29:08 -07004571 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004572 if (quote) {
4573 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4574 buffer.printf("keyword \"%s\"", nameof(token));
4575 } else {
4576 buffer.printf("symbol \"%s\"", nameof(token));
4577 }
4578 } else {
4579 buffer.printf("%s", nameof(token));
4580 }
Jack Palevich569f1352009-06-29 14:29:08 -07004581 }
4582 }
4583
Jack Palevich40600de2009-07-01 15:32:35 -07004584 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004585 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004586 if (!result) {
4587 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004588 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004589 error("Expected symbol. Got %s", temp.getUnwrapped());
4590 }
4591 return result;
4592 }
4593
Jack Palevich86351982009-06-30 18:09:56 -07004594 tokenid_t acceptSymbol() {
4595 tokenid_t result = 0;
4596 if (tok >= TOK_SYMBOL) {
4597 result = tok;
4598 next();
Jack Palevich86351982009-06-30 18:09:56 -07004599 }
4600 return result;
4601 }
4602
Jack Palevichb7c81e92009-06-04 19:56:13 -07004603 void globalDeclarations() {
4604 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004605 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4606 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004607 break;
4608 }
Jack Palevich86351982009-06-30 18:09:56 -07004609 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4610 if (!pDecl) {
4611 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004612 }
Jack Palevich86351982009-06-30 18:09:56 -07004613 if (! isDefined(pDecl->id)) {
4614 addGlobalSymbol(pDecl);
4615 }
4616 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004617 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004618 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004619 }
Jack Palevich86351982009-06-30 18:09:56 -07004620 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004621 // it's a variable declaration
4622 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004623 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004624 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004625 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004626 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004627 }
Jack Palevich86351982009-06-30 18:09:56 -07004628 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004629 if (tok == TOK_NUM) {
4630 if (name) {
4631 * (int*) name->pAddress = tokc;
4632 }
4633 next();
4634 } else {
4635 error("Expected an integer constant");
4636 }
4637 }
Jack Palevich86351982009-06-30 18:09:56 -07004638 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004639 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004640 }
Jack Palevich86351982009-06-30 18:09:56 -07004641 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4642 if (!pDecl) {
4643 break;
4644 }
4645 if (! isDefined(pDecl->id)) {
4646 addGlobalSymbol(pDecl);
4647 }
4648 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004649 }
4650 skip(';');
4651 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004652 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004653 if (accept(';')) {
4654 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004655 } else if (tok != '{') {
4656 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004657 } else {
4658 if (name) {
4659 /* patch forward references (XXX: does not work for function
4660 pointers) */
4661 pGen->gsym((int) name->pForward);
4662 /* put function address */
4663 name->pAddress = (void*) codeBuf.getPC();
4664 }
4665 // Calculate stack offsets for parameters
4666 mLocals.pushLevel();
4667 intptr_t a = 8;
4668 int argCount = 0;
4669 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4670 Type* pArg = pP->pHead;
4671 addLocalSymbol(pArg);
4672 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004673 size_t alignment = pGen->alignmentOf(pArg);
4674 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004675 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004676 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004677 argCount++;
4678 }
4679 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004680 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004681 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004682 block(0, true);
4683 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004684 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004685 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004686 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004687 }
4688 }
4689 }
4690
Jack Palevich9cbd2262009-07-08 16:48:41 -07004691 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4692 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4693 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004694 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004695 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004696 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004697 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004698 char* result = (char*) base;
4699 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004700 return result;
4701 }
4702
Jack Palevich21a15a22009-05-11 14:49:29 -07004703 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004704 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004705 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004706 pGlobalBase = 0;
4707 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 if (pGen) {
4709 delete pGen;
4710 pGen = 0;
4711 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004712 if (file) {
4713 delete file;
4714 file = 0;
4715 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004716 }
4717
Jack Palevich8c246a92009-07-14 21:14:10 -07004718 // One-time initialization, when class is constructed.
4719 void init() {
4720 mpSymbolLookupFn = 0;
4721 mpSymbolLookupContext = 0;
4722 }
4723
Jack Palevich21a15a22009-05-11 14:49:29 -07004724 void clear() {
4725 tok = 0;
4726 tokc = 0;
4727 tokl = 0;
4728 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004729 rsym = 0;
4730 loc = 0;
4731 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004732 dptr = 0;
4733 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004734 file = 0;
4735 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004736 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004737 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004738 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004739 mLineNumber = 1;
4740 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004741 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004742
Jack Palevich22305132009-05-13 10:58:45 -07004743 void setArchitecture(const char* architecture) {
4744 delete pGen;
4745 pGen = 0;
4746
4747 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004748#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004749 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004750 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004751 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004752#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004753#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004754 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004755 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004756 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004757#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004758 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004759 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004760 }
4761 }
4762
4763 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004764#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004765 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004766#elif defined(DEFAULT_X86_CODEGEN)
4767 pGen = new X86CodeGenerator();
4768#endif
4769 }
4770 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004771 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004772 } else {
4773 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004774 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004775 }
4776 }
4777
Jack Palevich77ae76e2009-05-10 19:59:24 -07004778public:
Jack Palevich22305132009-05-13 10:58:45 -07004779 struct args {
4780 args() {
4781 architecture = 0;
4782 }
4783 const char* architecture;
4784 };
4785
Jack Paleviche7b59062009-05-19 17:12:17 -07004786 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004787 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004788 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004789 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004790
Jack Paleviche7b59062009-05-19 17:12:17 -07004791 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004792 cleanup();
4793 }
4794
Jack Palevich8c246a92009-07-14 21:14:10 -07004795 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4796 mpSymbolLookupFn = pFn;
4797 mpSymbolLookupContext = pContext;
4798 }
4799
Jack Palevich1cdef202009-05-22 12:06:27 -07004800 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004801 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004802
Jack Palevicha8f427f2009-07-13 18:40:08 -07004803 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004804 cleanup();
4805 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004806 mTokenTable.setArena(&mGlobalArena);
4807 mGlobals.setArena(&mGlobalArena);
4808 mGlobals.setTokenTable(&mTokenTable);
4809 mLocals.setArena(&mLocalArena);
4810 mLocals.setTokenTable(&mTokenTable);
4811
4812 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004813 codeBuf.init(ALLOC_SIZE);
4814 setArchitecture(NULL);
4815 if (!pGen) {
4816 return -1;
4817 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004818#ifdef PROVIDE_TRACE_CODEGEN
4819 pGen = new TraceCodeGenerator(pGen);
4820#endif
4821 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004822 pGen->init(&codeBuf);
4823 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004824 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4825 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004826 inp();
4827 next();
4828 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004829 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004830 result = pGen->finishCompile();
4831 if (result == 0) {
4832 if (mErrorBuf.len()) {
4833 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004834 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004835 }
Jack Palevichce105a92009-07-16 14:30:33 -07004836 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004837 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004838 }
4839
Jack Palevich86351982009-06-30 18:09:56 -07004840 void createPrimitiveTypes() {
4841 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4842 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4843 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004844 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4845 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004846 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004847 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4848 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004849 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4850 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004851 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004852 }
4853
Jack Palevicha6baa232009-06-12 11:25:59 -07004854 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004855 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004856 }
4857
Jack Palevich569f1352009-06-29 14:29:08 -07004858 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004859 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004860 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004861 }
4862
Jack Palevich569f1352009-06-29 14:29:08 -07004863 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004864 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004865 error("Undefined forward reference: %s",
4866 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004867 }
4868 return true;
4869 }
4870
Jack Palevich21a15a22009-05-11 14:49:29 -07004871 int dump(FILE* out) {
4872 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4873 return 0;
4874 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004875
Jack Palevicha6535612009-05-13 16:24:17 -07004876 int disassemble(FILE* out) {
4877 return pGen->disassemble(out);
4878 }
4879
Jack Palevich1cdef202009-05-22 12:06:27 -07004880 /* Look through the symbol table to find a symbol.
4881 * If found, return its value.
4882 */
4883 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004884 if (mCompileResult == 0) {
4885 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4886 VariableInfo* pVariableInfo = VI(tok);
4887 if (pVariableInfo) {
4888 return pVariableInfo->pAddress;
4889 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004890 }
4891 return NULL;
4892 }
4893
Jack Palevicheedf9d22009-06-04 16:23:40 -07004894 void getPragmas(ACCsizei* actualStringCount,
4895 ACCsizei maxStringCount, ACCchar** strings) {
4896 int stringCount = mPragmaStringCount;
4897 if (actualStringCount) {
4898 *actualStringCount = stringCount;
4899 }
4900 if (stringCount > maxStringCount) {
4901 stringCount = maxStringCount;
4902 }
4903 if (strings) {
4904 char* pPragmas = mPragmas.getUnwrapped();
4905 while (stringCount-- > 0) {
4906 *strings++ = pPragmas;
4907 pPragmas += strlen(pPragmas) + 1;
4908 }
4909 }
4910 }
4911
Jack Palevichac0e95e2009-05-29 13:53:44 -07004912 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004913 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004914 }
4915
Jack Palevich77ae76e2009-05-10 19:59:24 -07004916};
4917
Jack Paleviche7b59062009-05-19 17:12:17 -07004918const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004919 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4920
Jack Paleviche7b59062009-05-19 17:12:17 -07004921const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004922 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4923 5, 5, /* ==, != */
4924 9, 10, /* &&, || */
4925 6, 7, 8, /* & ^ | */
4926 2, 2 /* ~ ! */
4927 };
4928
Jack Palevich8b0624c2009-05-20 12:12:06 -07004929#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004930FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004931#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004932
Jack Palevich8b0624c2009-05-20 12:12:06 -07004933#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004934const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004935 0x1, // ++
4936 0xff, // --
4937 0xc1af0f, // *
4938 0xf9f79991, // /
4939 0xf9f79991, // % (With manual assist to swap results)
4940 0xc801, // +
4941 0xd8f7c829, // -
4942 0xe0d391, // <<
4943 0xf8d391, // >>
4944 0xe, // <=
4945 0xd, // >=
4946 0xc, // <
4947 0xf, // >
4948 0x4, // ==
4949 0x5, // !=
4950 0x0, // &&
4951 0x1, // ||
4952 0xc821, // &
4953 0xc831, // ^
4954 0xc809, // |
4955 0xd0f7, // ~
4956 0x4 // !
4957};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004958#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004959
Jack Palevich1cdef202009-05-22 12:06:27 -07004960struct ACCscript {
4961 ACCscript() {
4962 text = 0;
4963 textLength = 0;
4964 accError = ACC_NO_ERROR;
4965 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004966
Jack Palevich1cdef202009-05-22 12:06:27 -07004967 ~ACCscript() {
4968 delete text;
4969 }
Jack Palevich546b2242009-05-13 15:10:04 -07004970
Jack Palevich8c246a92009-07-14 21:14:10 -07004971 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4972 compiler.registerSymbolCallback(pFn, pContext);
4973 }
4974
Jack Palevich1cdef202009-05-22 12:06:27 -07004975 void setError(ACCenum error) {
4976 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4977 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004978 }
4979 }
4980
Jack Palevich1cdef202009-05-22 12:06:27 -07004981 ACCenum getError() {
4982 ACCenum result = accError;
4983 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004984 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004985 }
4986
Jack Palevich1cdef202009-05-22 12:06:27 -07004987 Compiler compiler;
4988 char* text;
4989 int textLength;
4990 ACCenum accError;
4991};
4992
4993
4994extern "C"
4995ACCscript* accCreateScript() {
4996 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004997}
Jack Palevich1cdef202009-05-22 12:06:27 -07004998
4999extern "C"
5000ACCenum accGetError( ACCscript* script ) {
5001 return script->getError();
5002}
5003
5004extern "C"
5005void accDeleteScript(ACCscript* script) {
5006 delete script;
5007}
5008
5009extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005010void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5011 ACCvoid* pContext) {
5012 script->registerSymbolCallback(pFn, pContext);
5013}
5014
5015extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005016void accScriptSource(ACCscript* script,
5017 ACCsizei count,
5018 const ACCchar ** string,
5019 const ACCint * length) {
5020 int totalLength = 0;
5021 for(int i = 0; i < count; i++) {
5022 int len = -1;
5023 const ACCchar* s = string[i];
5024 if (length) {
5025 len = length[i];
5026 }
5027 if (len < 0) {
5028 len = strlen(s);
5029 }
5030 totalLength += len;
5031 }
5032 delete script->text;
5033 char* text = new char[totalLength + 1];
5034 script->text = text;
5035 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005036 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005037 for(int i = 0; i < count; i++) {
5038 int len = -1;
5039 const ACCchar* s = string[i];
5040 if (length) {
5041 len = length[i];
5042 }
5043 if (len < 0) {
5044 len = strlen(s);
5045 }
Jack Palevich09555c72009-05-27 12:25:55 -07005046 memcpy(dest, s, len);
5047 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005048 }
5049 text[totalLength] = '\0';
5050}
5051
5052extern "C"
5053void accCompileScript(ACCscript* script) {
5054 int result = script->compiler.compile(script->text, script->textLength);
5055 if (result) {
5056 script->setError(ACC_INVALID_OPERATION);
5057 }
5058}
5059
5060extern "C"
5061void accGetScriptiv(ACCscript* script,
5062 ACCenum pname,
5063 ACCint * params) {
5064 switch (pname) {
5065 case ACC_INFO_LOG_LENGTH:
5066 *params = 0;
5067 break;
5068 }
5069}
5070
5071extern "C"
5072void accGetScriptInfoLog(ACCscript* script,
5073 ACCsizei maxLength,
5074 ACCsizei * length,
5075 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005076 char* message = script->compiler.getErrorMessage();
5077 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005078 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005079 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005080 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005081 if (infoLog && maxLength > 0) {
5082 int trimmedLength = maxLength < messageLength ?
5083 maxLength : messageLength;
5084 memcpy(infoLog, message, trimmedLength);
5085 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005086 }
5087}
5088
5089extern "C"
5090void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5091 ACCvoid ** address) {
5092 void* value = script->compiler.lookup(name);
5093 if (value) {
5094 *address = value;
5095 } else {
5096 script->setError(ACC_INVALID_VALUE);
5097 }
5098}
5099
Jack Palevicheedf9d22009-06-04 16:23:40 -07005100extern "C"
5101void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5102 ACCsizei maxStringCount, ACCchar** strings){
5103 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5104}
5105
-b master422972c2009-06-17 19:13:52 -07005106extern "C"
5107void accDisassemble(ACCscript* script) {
5108 script->compiler.disassemble(stderr);
5109}
5110
Jack Palevicheedf9d22009-06-04 16:23:40 -07005111
Jack Palevich1cdef202009-05-22 12:06:27 -07005112} // namespace acc
5113