blob: 0a164892b693707827cb361ee5b43852c52d53ba [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
Jack Palevich9f51a262009-07-29 16:22:26 -070051#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 {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700136 TY_INT, // 0
137 TY_CHAR, // 1
138 TY_SHORT, // 2
139 TY_VOID, // 3
140 TY_FLOAT, // 4
141 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700142 TY_POINTER, // 6
143 TY_ARRAY, // 7
144 TY_STRUCT, // 8
145 TY_FUNC, // 9
146 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700147 };
148
149 struct Type {
150 TypeTag tag;
Jack Palevichb6154502009-08-04 14:56:09 -0700151 tokenid_t id; // For function arguments, local vars
152 int length; // length of array
Jack Palevich8df46192009-07-07 14:48:51 -0700153 Type* pHead;
154 Type* pTail;
155 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700156
Jack Palevichba929a42009-07-17 10:20:32 -0700157 enum ExpressionType {
158 ET_RVALUE,
159 ET_LVALUE
160 };
161
162 struct ExpressionValue {
163 ExpressionValue() {
164 et = ET_RVALUE;
165 pType = NULL;
166 }
167 ExpressionType et;
168 Type* pType;
169 };
170
Jack Palevich21a15a22009-05-11 14:49:29 -0700171 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700172 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700174 ErrorSink* mErrorSink;
175 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700176 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700177
Jack Palevich21a15a22009-05-11 14:49:29 -0700178 void release() {
179 if (pProgramBase != 0) {
180 free(pProgramBase);
181 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700182 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700183 }
184
Jack Palevich0a280a02009-06-11 10:53:51 -0700185 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700186 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700187 bool overflow = newSize > mSize;
188 if (overflow && !mOverflowed) {
189 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700190 if (mErrorSink) {
191 mErrorSink->error("Code too large: %d bytes", newSize);
192 }
193 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700194 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700195 }
196
Jack Palevich21a15a22009-05-11 14:49:29 -0700197 public:
198 CodeBuf() {
199 pProgramBase = 0;
200 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700201 mErrorSink = 0;
202 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700203 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700204 }
205
206 ~CodeBuf() {
207 release();
208 }
209
210 void init(int size) {
211 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700212 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700213 pProgramBase = (char*) calloc(1, size);
214 ind = pProgramBase;
215 }
216
Jack Palevichac0e95e2009-05-29 13:53:44 -0700217 void setErrorSink(ErrorSink* pErrorSink) {
218 mErrorSink = pErrorSink;
219 }
220
Jack Palevich546b2242009-05-13 15:10:04 -0700221 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700222 if(check(4)) {
223 return 0;
224 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700225 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700226 * (int*) ind = n;
227 ind += 4;
228 return result;
229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 /*
232 * Output a byte. Handles all values, 0..ff.
233 */
234 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700235 if(check(1)) {
236 return;
237 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700238 *ind++ = n;
239 }
240
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 inline void* getBase() {
242 return (void*) pProgramBase;
243 }
244
Jack Palevich8b0624c2009-05-20 12:12:06 -0700245 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700246 return ind - pProgramBase;
247 }
248
Jack Palevich8b0624c2009-05-20 12:12:06 -0700249 intptr_t getPC() {
250 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 }
252 };
253
Jack Palevich1cdef202009-05-22 12:06:27 -0700254 /**
255 * A code generator creates an in-memory program, generating the code on
256 * the fly. There is one code generator implementation for each supported
257 * architecture.
258 *
259 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700260 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 * FP - a frame pointer for accessing function arguments and local
262 * variables.
263 * SP - a stack pointer for storing intermediate results while evaluating
264 * expressions. The stack pointer grows downwards.
265 *
266 * The function calling convention is that all arguments are placed on the
267 * stack such that the first argument has the lowest address.
268 * After the call, the result is in R0. The caller is responsible for
269 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700270 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 * FP and SP registers are saved.
272 */
273
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 class CodeGenerator {
275 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700276 CodeGenerator() {
277 mErrorSink = 0;
278 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700279 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700280 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700281 virtual ~CodeGenerator() {}
282
Jack Palevich22305132009-05-13 10:58:45 -0700283 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700284 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700285 pCodeBuf->setErrorSink(mErrorSink);
286 }
287
Jack Palevichb67b18f2009-06-11 21:12:23 -0700288 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700289 mErrorSink = pErrorSink;
290 if (pCodeBuf) {
291 pCodeBuf->setErrorSink(mErrorSink);
292 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700293 }
294
Jack Palevich58c30ee2009-07-17 16:35:23 -0700295 /* Give the code generator some utility types so it can
296 * use its own types as needed for the results of some
297 * operations like gcmp.
298 */
299
Jack Palevicha8f427f2009-07-13 18:40:08 -0700300 void setTypes(Type* pInt) {
301 mkpInt = pInt;
302 }
303
Jack Palevich1cdef202009-05-22 12:06:27 -0700304 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700305 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 * Save the old value of the FP.
307 * Set the new value of the FP.
308 * Convert from the native platform calling convention to
309 * our stack-based calling convention. This may require
310 * pushing arguments from registers to the stack.
311 * Allocate "N" bytes of stack space. N isn't known yet, so
312 * just emit the instructions for adjusting the stack, and return
313 * the address to patch up. The patching will be done in
314 * functionExit().
315 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700316 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700317 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700318
Jack Palevich1cdef202009-05-22 12:06:27 -0700319 /* Emit a function epilog.
320 * Restore the old SP and FP register values.
321 * Return to the calling function.
322 * argCount - the number of arguments to the function.
323 * localVariableAddress - returned from functionEntry()
324 * localVariableSize - the size in bytes of the local variables.
325 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700326 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700327 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700328
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700330 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700331
Jack Palevich1a539db2009-07-08 13:04:41 -0700332 /* Load floating point value from global address. */
333 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700334
Jack Palevich1cdef202009-05-22 12:06:27 -0700335 /* Jump to a target, and return the address of the word that
336 * holds the target data, in case it needs to be fixed up later.
337 */
Jack Palevich22305132009-05-13 10:58:45 -0700338 virtual int gjmp(int t) = 0;
339
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 /* Test R0 and jump to a target if the test succeeds.
341 * l = 0: je, l == 1: jne
342 * Return the address of the word that holds the targed data, in
343 * case it needs to be fixed up later.
344 */
Jack Palevich22305132009-05-13 10:58:45 -0700345 virtual int gtst(bool l, int t) = 0;
346
Jack Palevich9eed7a22009-07-06 17:24:34 -0700347 /* Compare TOS against R0, and store the boolean result in R0.
348 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 * op specifies the comparison.
350 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700351 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700352
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700355 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700356 */
Jack Palevich546b2242009-05-13 15:10:04 -0700357 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevich9eed7a22009-07-06 17:24:34 -0700359 /* Compare 0 against R0, and store the boolean result in R0.
360 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700362 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700363
364 /* Perform the arithmetic op specified by op. 0 is the
365 * left argument, R0 is the right argument.
366 */
367 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700369 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 */
371 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700372
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700373 /* Turn R0, TOS into R0 TOS R0 */
374
375 virtual void over() = 0;
376
377 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700378 */
379 virtual void popR0() = 0;
380
Jack Palevich9eed7a22009-07-06 17:24:34 -0700381 /* Store R0 to the address stored in TOS.
382 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700384 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700385
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700388 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 /* Load the absolute address of a variable to R0.
391 * If ea <= LOCAL, then this is a local variable, or an
392 * argument, addressed relative to FP.
393 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700394 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700395 * et is ET_RVALUE for things like string constants, ET_LVALUE for
396 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700397 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700398 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700399
Jack Palevich9f51a262009-07-29 16:22:26 -0700400 /* Load the pc-relative address of a forward-referenced variable to R0.
401 * Return the address of the 4-byte constant so that it can be filled
402 * in later.
403 */
404 virtual int leaForward(int ea, Type* pPointerType) = 0;
405
Jack Palevich8df46192009-07-07 14:48:51 -0700406 /**
407 * Convert R0 to the given type.
408 */
Jack Palevichb6154502009-08-04 14:56:09 -0700409
410 void convertR0(Type* pType) {
411 convertR0Imp(pType, false);
412 }
413
414 void castR0(Type* pType) {
415 convertR0Imp(pType, true);
416 }
417
418 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 /* Emit code to adjust the stack for a function call. Return the
421 * label for the address of the instruction that adjusts the
422 * stack size. This will be passed as argument "a" to
423 * endFunctionCallArguments.
424 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700425 virtual int beginFunctionCallArguments() = 0;
426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700428 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700430 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700431
Jack Palevich1cdef202009-05-22 12:06:27 -0700432 /* Patch the function call preamble.
433 * a is the address returned from beginFunctionCallArguments
434 * l is the number of bytes the arguments took on the stack.
435 * Typically you would also emit code to convert the argument
436 * list into whatever the native function calling convention is.
437 * On ARM for example you would pop the first 5 arguments into
438 * R0..R4
439 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700440 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700441
Jack Palevich1cdef202009-05-22 12:06:27 -0700442 /* Emit a call to an unknown function. The argument "symbol" needs to
443 * be stored in the location where the address should go. It forms
444 * a chain. The address will be patched later.
445 * Return the address of the word that has to be patched.
446 */
Jack Palevich8df46192009-07-07 14:48:51 -0700447 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700448
Jack Palevich1cdef202009-05-22 12:06:27 -0700449 /* Call a function pointer. L is the number of bytes the arguments
450 * take on the stack. The address of the function is stored at
451 * location SP + l.
452 */
Jack Palevich8df46192009-07-07 14:48:51 -0700453 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700454
Jack Palevich1cdef202009-05-22 12:06:27 -0700455 /* Adjust SP after returning from a function call. l is the
456 * number of bytes of arguments stored on the stack. isIndirect
457 * is true if this was an indirect call. (In which case the
458 * address of the function is stored at location SP + l.)
459 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700460 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700461
Jack Palevich1cdef202009-05-22 12:06:27 -0700462 /* Print a disassembly of the assembled code to out. Return
463 * non-zero if there is an error.
464 */
Jack Palevicha6535612009-05-13 16:24:17 -0700465 virtual int disassemble(FILE* out) = 0;
466
Jack Palevich1cdef202009-05-22 12:06:27 -0700467 /* Generate a symbol at the current PC. t is the head of a
468 * linked list of addresses to patch.
469 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700470 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700471
Jack Palevich9f51a262009-07-29 16:22:26 -0700472 /* Resolve a forward reference function at the current PC.
473 * t is the head of a
474 * linked list of addresses to patch.
475 * (Like gsym, but using absolute address, not PC relative address.)
476 */
477 virtual void resolveForward(int t) = 0;
478
Jack Palevich1cdef202009-05-22 12:06:27 -0700479 /*
480 * Do any cleanup work required at the end of a compile.
481 * For example, an instruction cache might need to be
482 * invalidated.
483 * Return non-zero if there is an error.
484 */
485 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700486
Jack Palevicha6535612009-05-13 16:24:17 -0700487 /**
488 * Adjust relative branches by this amount.
489 */
490 virtual int jumpOffset() = 0;
491
Jack Palevich9eed7a22009-07-06 17:24:34 -0700492 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700493 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700494 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700495 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700496
497 /**
498 * Array element alignment (in bytes) for this type of data.
499 */
500 virtual size_t sizeOf(Type* type) = 0;
501
Jack Palevich9cbd2262009-07-08 16:48:41 -0700502 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700503 * Stack alignment of this type of data
504 */
505 virtual size_t stackAlignmentOf(Type* pType) = 0;
506
507 /**
508 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700509 */
510 virtual size_t stackSizeOf(Type* pType) = 0;
511
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700512 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700513 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700514 }
515
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700516 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700517 return mExpressionStack.back().et;
518 }
519
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700520 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700521 mExpressionStack.back().et = et;
522 }
523
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700524 virtual size_t getExpressionStackDepth() {
525 return mExpressionStack.size();
526 }
527
Jack Palevichb5e33312009-07-30 19:06:34 -0700528 virtual void forceR0RVal() {
529 if (getR0ExpressionType() == ET_LVALUE) {
530 loadR0FromR0();
531 }
532 }
533
Jack Palevich21a15a22009-05-11 14:49:29 -0700534 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700535 /*
536 * Output a byte. Handles all values, 0..ff.
537 */
538 void ob(int n) {
539 pCodeBuf->ob(n);
540 }
541
Jack Palevich8b0624c2009-05-20 12:12:06 -0700542 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700543 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700544 }
545
Jack Palevich8b0624c2009-05-20 12:12:06 -0700546 intptr_t getBase() {
547 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700548 }
549
Jack Palevich8b0624c2009-05-20 12:12:06 -0700550 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700551 return pCodeBuf->getPC();
552 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700553
554 intptr_t getSize() {
555 return pCodeBuf->getSize();
556 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700557
558 void error(const char* fmt,...) {
559 va_list ap;
560 va_start(ap, fmt);
561 mErrorSink->verror(fmt, ap);
562 va_end(ap);
563 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700564
565 void assert(bool test) {
566 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700567 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700568 error("code generator assertion failed.");
569 }
570 }
Jack Palevich8df46192009-07-07 14:48:51 -0700571
572 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700573 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700574 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700575 mExpressionStack.back().et = ET_RVALUE;
576 }
577
578 void setR0Type(Type* pType, ExpressionType et) {
579 assert(pType != NULL);
580 mExpressionStack.back().pType = pType;
581 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700582 }
583
Jack Palevich8df46192009-07-07 14:48:51 -0700584 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700585 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700586 }
587
588 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700589 if (mExpressionStack.size()) {
590 mExpressionStack.push_back(mExpressionStack.back());
591 } else {
592 mExpressionStack.push_back(ExpressionValue());
593 }
594
Jack Palevich8df46192009-07-07 14:48:51 -0700595 }
596
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700597 void overType() {
598 size_t size = mExpressionStack.size();
599 if (size >= 2) {
600 mExpressionStack.push_back(mExpressionStack.back());
601 mExpressionStack[size-1] = mExpressionStack[size-2];
602 mExpressionStack[size-2] = mExpressionStack[size];
603 }
604 }
605
Jack Palevich8df46192009-07-07 14:48:51 -0700606 void popType() {
607 mExpressionStack.pop_back();
608 }
609
610 bool bitsSame(Type* pA, Type* pB) {
611 return collapseType(pA->tag) == collapseType(pB->tag);
612 }
613
614 TypeTag collapseType(TypeTag tag) {
615 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700616 TY_INT,
617 TY_INT,
618 TY_INT,
619 TY_VOID,
620 TY_FLOAT,
621 TY_DOUBLE,
622 TY_INT,
623 TY_INT,
624 TY_VOID,
625 TY_VOID,
626 TY_VOID
627 };
Jack Palevich8df46192009-07-07 14:48:51 -0700628 return collapsedTag[tag];
629 }
630
Jack Palevich1a539db2009-07-08 13:04:41 -0700631 TypeTag collapseTypeR0() {
632 return collapseType(getR0Type()->tag);
633 }
634
Jack Palevichb6154502009-08-04 14:56:09 -0700635 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700636 return isFloatTag(pType->tag);
637 }
638
Jack Palevichb6154502009-08-04 14:56:09 -0700639 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700640 return tag == TY_FLOAT || tag == TY_DOUBLE;
641 }
642
Jack Palevichb6154502009-08-04 14:56:09 -0700643 static bool isPointerType(Type* pType) {
644 return isPointerTag(pType->tag);
645 }
646
647 static bool isPointerTag(TypeTag tag) {
648 return tag == TY_POINTER || tag == TY_ARRAY;
649 }
650
651 Type* getPointerArithmeticResultType(Type* a, Type* b) {
652 TypeTag aTag = a->tag;
653 TypeTag bTag = b->tag;
654 if (aTag == TY_POINTER) {
655 return a;
656 }
657 if (bTag == TY_POINTER) {
658 return b;
659 }
660 if (aTag == TY_ARRAY) {
661 return a->pTail;
662 }
663 if (bTag == TY_ARRAY) {
664 return b->pTail;
665 }
666 return NULL;
667 }
668
Jack Palevicha8f427f2009-07-13 18:40:08 -0700669 Type* mkpInt;
670
Jack Palevich21a15a22009-05-11 14:49:29 -0700671 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700672 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700673 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700674 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700675 };
676
Jack Paleviche7b59062009-05-19 17:12:17 -0700677#ifdef PROVIDE_ARM_CODEGEN
678
Jack Palevich22305132009-05-13 10:58:45 -0700679 class ARMCodeGenerator : public CodeGenerator {
680 public:
681 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700682
Jack Palevich22305132009-05-13 10:58:45 -0700683 virtual ~ARMCodeGenerator() {}
684
685 /* returns address to patch with local variable size
686 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700687 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700688 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700689 // sp -> arg4 arg5 ...
690 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700691 int regArgCount = calcRegArgCount(pDecl);
692 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700693 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700694 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700695 }
696 // sp -> arg0 arg1 ...
697 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700698 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700699 // sp, fp -> oldfp, retadr, arg0 arg1 ....
700 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700701 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700702 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700703 // We don't know how many local variables we are going to use,
704 // but we will round the allocation up to a multiple of
705 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700706 }
707
Jack Palevichb7718b92009-07-09 22:00:24 -0700708 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700709 // Round local variable size up to a multiple of stack alignment
710 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
711 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700712 // Patch local variable allocation code:
713 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700714 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700715 }
Jack Palevich69796b62009-05-14 15:42:26 -0700716 *(char*) (localVariableAddress) = localVariableSize;
717
718 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
719 o4(0xE1A0E00B); // mov lr, fp
720 o4(0xE59BB000); // ldr fp, [fp]
721 o4(0xE28ED004); // add sp, lr, #4
722 // sp -> retadr, arg0, ...
723 o4(0xE8BD4000); // ldmfd sp!, {lr}
724 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700725
726 // We store the PC into the lr so we can adjust the sp before
727 // returning. We need to pull off the registers we pushed
728 // earlier. We don't need to actually store them anywhere,
729 // just adjust the stack.
730 int regArgCount = calcRegArgCount(pDecl);
731 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700732 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
733 }
734 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700735 }
736
737 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700738 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700739 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700740 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700741 }
742
Jack Palevich1a539db2009-07-08 13:04:41 -0700743 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700744 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700745 // Global, absolute address
746 o4(0xE59F0000); // ldr r0, .L1
747 o4(0xEA000000); // b .L99
748 o4(address); // .L1: .word ea
749 // .L99:
750
751 switch (pType->tag) {
752 case TY_FLOAT:
753 o4(0xE5900000); // ldr r0, [r0]
754 break;
755 case TY_DOUBLE:
756 o4(0xE1C000D0); // ldrd r0, [r0]
757 break;
758 default:
759 assert(false);
760 break;
761 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700762 }
763
Jack Palevich22305132009-05-13 10:58:45 -0700764 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700765 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700766 }
767
768 /* l = 0: je, l == 1: jne */
769 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700770 Type* pR0Type = getR0Type();
771 TypeTag tagR0 = pR0Type->tag;
772 switch(tagR0) {
773 case TY_FLOAT:
774 callRuntime((void*) runtime_is_non_zero_f);
775 break;
776 case TY_DOUBLE:
777 callRuntime((void*) runtime_is_non_zero_d);
778 break;
779 default:
780 break;
781 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700782 o4(0xE3500000); // cmp r0,#0
783 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
784 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700785 }
786
Jack Palevich58c30ee2009-07-17 16:35:23 -0700787 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700788 Type* pR0Type = getR0Type();
789 Type* pTOSType = getTOSType();
790 TypeTag tagR0 = collapseType(pR0Type->tag);
791 TypeTag tagTOS = collapseType(pTOSType->tag);
792 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700793 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700794 o4(0xE1510000); // cmp r1, r1
795 switch(op) {
796 case OP_EQUALS:
797 o4(0x03A00001); // moveq r0,#1
798 o4(0x13A00000); // movne r0,#0
799 break;
800 case OP_NOT_EQUALS:
801 o4(0x03A00000); // moveq r0,#0
802 o4(0x13A00001); // movne r0,#1
803 break;
804 case OP_LESS_EQUAL:
805 o4(0xD3A00001); // movle r0,#1
806 o4(0xC3A00000); // movgt r0,#0
807 break;
808 case OP_GREATER:
809 o4(0xD3A00000); // movle r0,#0
810 o4(0xC3A00001); // movgt r0,#1
811 break;
812 case OP_GREATER_EQUAL:
813 o4(0xA3A00001); // movge r0,#1
814 o4(0xB3A00000); // movlt r0,#0
815 break;
816 case OP_LESS:
817 o4(0xA3A00000); // movge r0,#0
818 o4(0xB3A00001); // movlt r0,#1
819 break;
820 default:
821 error("Unknown comparison op %d", op);
822 break;
823 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700824 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
825 setupDoubleArgs();
826 switch(op) {
827 case OP_EQUALS:
828 callRuntime((void*) runtime_cmp_eq_dd);
829 break;
830 case OP_NOT_EQUALS:
831 callRuntime((void*) runtime_cmp_ne_dd);
832 break;
833 case OP_LESS_EQUAL:
834 callRuntime((void*) runtime_cmp_le_dd);
835 break;
836 case OP_GREATER:
837 callRuntime((void*) runtime_cmp_gt_dd);
838 break;
839 case OP_GREATER_EQUAL:
840 callRuntime((void*) runtime_cmp_ge_dd);
841 break;
842 case OP_LESS:
843 callRuntime((void*) runtime_cmp_lt_dd);
844 break;
845 default:
846 error("Unknown comparison op %d", op);
847 break;
848 }
849 } else {
850 setupFloatArgs();
851 switch(op) {
852 case OP_EQUALS:
853 callRuntime((void*) runtime_cmp_eq_ff);
854 break;
855 case OP_NOT_EQUALS:
856 callRuntime((void*) runtime_cmp_ne_ff);
857 break;
858 case OP_LESS_EQUAL:
859 callRuntime((void*) runtime_cmp_le_ff);
860 break;
861 case OP_GREATER:
862 callRuntime((void*) runtime_cmp_gt_ff);
863 break;
864 case OP_GREATER_EQUAL:
865 callRuntime((void*) runtime_cmp_ge_ff);
866 break;
867 case OP_LESS:
868 callRuntime((void*) runtime_cmp_lt_ff);
869 break;
870 default:
871 error("Unknown comparison op %d", op);
872 break;
873 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700874 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700875 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700876 }
877
Jack Palevich546b2242009-05-13 15:10:04 -0700878 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700879 Type* pR0Type = getR0Type();
880 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700881 TypeTag tagR0 = pR0Type->tag;
882 TypeTag tagTOS = pTOSType->tag;
883 bool isFloatR0 = isFloatTag(tagR0);
884 bool isFloatTOS = isFloatTag(tagTOS);
885 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700886 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -0700887 bool isPtrR0 = isPointerTag(tagR0);
888 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700889 if (isPtrR0 || isPtrTOS) {
890 if (isPtrR0 && isPtrTOS) {
891 if (op != OP_MINUS) {
892 error("Unsupported pointer-pointer operation %d.", op);
893 }
894 if (! typeEqual(pR0Type, pTOSType)) {
895 error("Incompatible pointer types for subtraction.");
896 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700897 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700898 setR0Type(mkpInt);
899 int size = sizeOf(pR0Type->pHead);
900 if (size != 1) {
901 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700902 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700903 // TODO: Optimize for power-of-two.
904 genOp(OP_DIV);
905 }
906 } else {
907 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
908 error("Unsupported pointer-scalar operation %d", op);
909 }
Jack Palevichb6154502009-08-04 14:56:09 -0700910 Type* pPtrType = getPointerArithmeticResultType(
911 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700912 int size = sizeOf(pPtrType->pHead);
913 if (size != 1) {
914 // TODO: Optimize for power-of-two.
915 liReg(size, 2);
916 if (isPtrR0) {
917 o4(0x0E0010192); // mul r1,r2,r1
918 } else {
919 o4(0x0E0000092); // mul r0,r2,r0
920 }
921 }
922 switch(op) {
923 case OP_PLUS:
924 o4(0xE0810000); // add r0,r1,r0
925 break;
926 case OP_MINUS:
927 o4(0xE0410000); // sub r0,r1,r0
928 break;
929 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700930 setR0Type(pPtrType);
931 }
932 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700933 switch(op) {
934 case OP_MUL:
935 o4(0x0E0000091); // mul r0,r1,r0
936 break;
937 case OP_DIV:
938 callRuntime((void*) runtime_DIV);
939 break;
940 case OP_MOD:
941 callRuntime((void*) runtime_MOD);
942 break;
943 case OP_PLUS:
944 o4(0xE0810000); // add r0,r1,r0
945 break;
946 case OP_MINUS:
947 o4(0xE0410000); // sub r0,r1,r0
948 break;
949 case OP_SHIFT_LEFT:
950 o4(0xE1A00011); // lsl r0,r1,r0
951 break;
952 case OP_SHIFT_RIGHT:
953 o4(0xE1A00051); // asr r0,r1,r0
954 break;
955 case OP_BIT_AND:
956 o4(0xE0010000); // and r0,r1,r0
957 break;
958 case OP_BIT_XOR:
959 o4(0xE0210000); // eor r0,r1,r0
960 break;
961 case OP_BIT_OR:
962 o4(0xE1810000); // orr r0,r1,r0
963 break;
964 case OP_BIT_NOT:
965 o4(0xE1E00000); // mvn r0, r0
966 break;
967 default:
968 error("Unimplemented op %d\n", op);
969 break;
970 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700971 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700972 } else {
973 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
974 if (pResultType->tag == TY_DOUBLE) {
975 setupDoubleArgs();
976 switch(op) {
977 case OP_MUL:
978 callRuntime((void*) runtime_op_mul_dd);
979 break;
980 case OP_DIV:
981 callRuntime((void*) runtime_op_div_dd);
982 break;
983 case OP_PLUS:
984 callRuntime((void*) runtime_op_add_dd);
985 break;
986 case OP_MINUS:
987 callRuntime((void*) runtime_op_sub_dd);
988 break;
989 default:
990 error("Unsupported binary floating operation %d\n", op);
991 break;
992 }
993 } else {
994 setupFloatArgs();
995 switch(op) {
996 case OP_MUL:
997 callRuntime((void*) runtime_op_mul_ff);
998 break;
999 case OP_DIV:
1000 callRuntime((void*) runtime_op_div_ff);
1001 break;
1002 case OP_PLUS:
1003 callRuntime((void*) runtime_op_add_ff);
1004 break;
1005 case OP_MINUS:
1006 callRuntime((void*) runtime_op_sub_ff);
1007 break;
1008 default:
1009 error("Unsupported binary floating operation %d\n", op);
1010 break;
1011 }
1012 }
1013 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001014 }
Jack Palevich22305132009-05-13 10:58:45 -07001015 }
1016
Jack Palevich58c30ee2009-07-17 16:35:23 -07001017 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001018 if (op != OP_LOGICAL_NOT) {
1019 error("Unknown unary cmp %d", op);
1020 } else {
1021 Type* pR0Type = getR0Type();
1022 TypeTag tag = collapseType(pR0Type->tag);
1023 switch(tag) {
1024 case TY_INT:
1025 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001026 o4(0xE1510000); // cmp r1, r0
1027 o4(0x03A00001); // moveq r0,#1
1028 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001029 break;
1030 case TY_FLOAT:
1031 callRuntime((void*) runtime_is_zero_f);
1032 break;
1033 case TY_DOUBLE:
1034 callRuntime((void*) runtime_is_zero_d);
1035 break;
1036 default:
1037 error("gUnaryCmp unsupported type");
1038 break;
1039 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001040 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001041 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001042 }
1043
1044 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 Type* pR0Type = getR0Type();
1046 TypeTag tag = collapseType(pR0Type->tag);
1047 switch(tag) {
1048 case TY_INT:
1049 switch(op) {
1050 case OP_MINUS:
1051 o4(0xE3A01000); // mov r1, #0
1052 o4(0xE0410000); // sub r0,r1,r0
1053 break;
1054 case OP_BIT_NOT:
1055 o4(0xE1E00000); // mvn r0, r0
1056 break;
1057 default:
1058 error("Unknown unary op %d\n", op);
1059 break;
1060 }
1061 break;
1062 case TY_FLOAT:
1063 case TY_DOUBLE:
1064 switch (op) {
1065 case OP_MINUS:
1066 if (tag == TY_FLOAT) {
1067 callRuntime((void*) runtime_op_neg_f);
1068 } else {
1069 callRuntime((void*) runtime_op_neg_d);
1070 }
1071 break;
1072 case OP_BIT_NOT:
1073 error("Can't apply '~' operator to a float or double.");
1074 break;
1075 default:
1076 error("Unknown unary op %d\n", op);
1077 break;
1078 }
1079 break;
1080 default:
1081 error("genUnaryOp unsupported type");
1082 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001083 }
Jack Palevich22305132009-05-13 10:58:45 -07001084 }
1085
Jack Palevich1cdef202009-05-22 12:06:27 -07001086 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001087 Type* pR0Type = getR0Type();
1088 TypeTag r0ct = collapseType(pR0Type->tag);
1089 if (r0ct != TY_DOUBLE) {
1090 o4(0xE92D0001); // stmfd sp!,{r0}
1091 mStackUse += 4;
1092 } else {
1093 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1094 mStackUse += 8;
1095 }
Jack Palevich8df46192009-07-07 14:48:51 -07001096 pushType();
-b master422972c2009-06-17 19:13:52 -07001097 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001098 }
1099
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001100 virtual void over() {
1101 // We know it's only used for int-ptr ops (++/--)
1102
1103 Type* pR0Type = getR0Type();
1104 TypeTag r0ct = collapseType(pR0Type->tag);
1105
1106 Type* pTOSType = getTOSType();
1107 TypeTag tosct = collapseType(pTOSType->tag);
1108
1109 assert (r0ct == TY_INT && tosct == TY_INT);
1110
1111 o4(0xE8BD0002); // ldmfd sp!,{r1}
1112 o4(0xE92D0001); // stmfd sp!,{r0}
1113 o4(0xE92D0002); // stmfd sp!,{r1}
1114 overType();
1115 mStackUse += 4;
1116 }
1117
Jack Palevich58c30ee2009-07-17 16:35:23 -07001118 virtual void popR0() {
1119 Type* pTOSType = getTOSType();
1120 switch (collapseType(pTOSType->tag)){
1121 case TY_INT:
1122 case TY_FLOAT:
1123 o4(0xE8BD0001); // ldmfd sp!,{r0}
1124 mStackUse -= 4;
1125 break;
1126 case TY_DOUBLE:
1127 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1128 mStackUse -= 8;
1129 break;
1130 default:
1131 error("Can't pop this type.");
1132 break;
1133 }
1134 popType();
1135 LOG_STACK("popR0: %d\n", mStackUse);
1136 }
1137
1138 virtual void storeR0ToTOS() {
1139 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001140 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001141 Type* pDestType = pPointerType->pHead;
1142 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001143 o4(0xE8BD0004); // ldmfd sp!,{r2}
1144 popType();
-b master422972c2009-06-17 19:13:52 -07001145 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001146 switch (pDestType->tag) {
1147 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001148 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 case TY_FLOAT:
1150 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001151 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001152 case TY_SHORT:
1153 o4(0xE1C200B0); // strh r0, [r2]
1154 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001155 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001156 o4(0xE5C20000); // strb r0, [r2]
1157 break;
1158 case TY_DOUBLE:
1159 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001160 break;
1161 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001162 error("storeR0ToTOS: unimplemented type %d",
1163 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001164 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001165 }
Jack Palevich22305132009-05-13 10:58:45 -07001166 }
1167
Jack Palevich58c30ee2009-07-17 16:35:23 -07001168 virtual void loadR0FromR0() {
1169 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001170 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb6154502009-08-04 14:56:09 -07001171 TypeTag tag = pPointerType->pHead->tag;
1172 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001173 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001174 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001175 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001176 o4(0xE5900000); // ldr r0, [r0]
1177 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001178 case TY_SHORT:
1179 o4(0xE1D000F0); // ldrsh r0, [r0]
1180 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001181 case TY_CHAR:
1182 o4(0xE5D00000); // ldrb r0, [r0]
1183 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001184 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001185 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001186 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001187 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001188 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001189 break;
1190 }
Jack Palevich8df46192009-07-07 14:48:51 -07001191 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001192 }
1193
Jack Palevichb5e33312009-07-30 19:06:34 -07001194 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001195 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001196 // Local, fp relative
1197 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1198 error("Offset out of range: %08x", ea);
1199 }
1200 if (ea < 0) {
1201 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1202 } else {
1203 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1204 }
Jack Palevichbd894902009-05-14 19:35:31 -07001205 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001206 // Global, absolute.
1207 o4(0xE59F0000); // ldr r0, .L1
1208 o4(0xEA000000); // b .L99
1209 o4(ea); // .L1: .word 0
1210 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001211 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001212 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001213 }
1214
Jack Palevich9f51a262009-07-29 16:22:26 -07001215 virtual int leaForward(int ea, Type* pPointerType) {
1216 setR0Type(pPointerType);
1217 int result = ea;
1218 int pc = getPC();
1219 int offset = 0;
1220 if (ea) {
1221 offset = (pc - ea - 8) >> 2;
1222 if ((offset & 0xffff) != offset) {
1223 error("function forward reference out of bounds");
1224 }
1225 } else {
1226 offset = 0;
1227 }
1228 o4(0xE59F0000 | offset); // ldr r0, .L1
1229
1230 if (ea == 0) {
1231 o4(0xEA000000); // b .L99
1232 result = o4(ea); // .L1: .word 0
1233 // .L99:
1234 }
1235 return result;
1236 }
1237
Jack Palevichb6154502009-08-04 14:56:09 -07001238 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001239 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001240 if (isPointerType(pType) && isPointerType(pR0Type)) {
1241 Type* pA = pR0Type;
1242 Type* pB = pType;
1243 // Array decays to pointer
1244 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1245 pA = pA->pTail;
1246 }
1247 if (typeEqual(pA, pB)) {
1248 return; // OK
1249 }
1250 if (pB->pHead->tag == TY_VOID) {
1251 return; // convert to void* is OK.
1252 }
1253 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
1254 && isCast) {
1255 return; // OK
1256 }
1257 error("Incompatible pointer or array types");
1258 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001259 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001260 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001261 TypeTag r0Tag = collapseType(pR0Type->tag);
1262 TypeTag destTag = collapseType(pType->tag);
1263 if (r0Tag == TY_INT) {
1264 if (destTag == TY_FLOAT) {
1265 callRuntime((void*) runtime_int_to_float);
1266 } else {
1267 assert(destTag == TY_DOUBLE);
1268 callRuntime((void*) runtime_int_to_double);
1269 }
1270 } else if (r0Tag == TY_FLOAT) {
1271 if (destTag == TY_INT) {
1272 callRuntime((void*) runtime_float_to_int);
1273 } else {
1274 assert(destTag == TY_DOUBLE);
1275 callRuntime((void*) runtime_float_to_double);
1276 }
1277 } else {
1278 assert (r0Tag == TY_DOUBLE);
1279 if (destTag == TY_INT) {
1280 callRuntime((void*) runtime_double_to_int);
1281 } else {
1282 assert(destTag == TY_FLOAT);
1283 callRuntime((void*) runtime_double_to_float);
1284 }
1285 }
Jack Palevich8df46192009-07-07 14:48:51 -07001286 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001287 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001288 }
1289
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001290 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001291 return o4(0xE24DDF00); // Placeholder
1292 }
1293
Jack Palevich8148c5b2009-07-16 18:24:47 -07001294 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001295 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001296 Type* pR0Type = getR0Type();
1297 TypeTag r0ct = collapseType(pR0Type->tag);
1298 switch(r0ct) {
1299 case TY_INT:
1300 case TY_FLOAT:
1301 if (l < 0 || l > 4096-4) {
1302 error("l out of range for stack offset: 0x%08x", l);
1303 }
1304 o4(0xE58D0000 + l); // str r0, [sp, #l]
1305 return 4;
1306 case TY_DOUBLE: {
1307 // Align to 8 byte boundary
1308 int l2 = (l + 7) & ~7;
1309 if (l2 < 0 || l2 > 4096-8) {
1310 error("l out of range for stack offset: 0x%08x", l);
1311 }
1312 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1313 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1314 return (l2 - l) + 8;
1315 }
1316 default:
1317 assert(false);
1318 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001319 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001320 }
1321
Jack Palevichb7718b92009-07-09 22:00:24 -07001322 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001323 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001324 // Have to calculate register arg count from actual stack size,
1325 // in order to properly handle ... functions.
1326 int regArgCount = l >> 2;
1327 if (regArgCount > 4) {
1328 regArgCount = 4;
1329 }
1330 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001331 argumentStackUse -= regArgCount * 4;
1332 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1333 }
1334 mStackUse += argumentStackUse;
1335
1336 // Align stack.
1337 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1338 * STACK_ALIGNMENT);
1339 mStackAlignmentAdjustment = 0;
1340 if (missalignment > 0) {
1341 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1342 }
1343 l += mStackAlignmentAdjustment;
1344
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001345 if (l < 0 || l > 0x3FC) {
1346 error("L out of range for stack adjustment: 0x%08x", l);
1347 }
1348 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001349 mStackUse += mStackAlignmentAdjustment;
1350 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1351 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001352 }
1353
Jack Palevich8df46192009-07-07 14:48:51 -07001354 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001355 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001356 // Forward calls are always short (local)
1357 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001358 }
1359
Jack Palevich8df46192009-07-07 14:48:51 -07001360 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001361 assert(pFunc->tag == TY_FUNC);
1362 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001363 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001364 int argCount = l >> 2;
1365 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001366 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001367 if (adjustedL < 0 || adjustedL > 4096-4) {
1368 error("l out of range for stack offset: 0x%08x", l);
1369 }
1370 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1371 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001372 }
1373
Jack Palevichb7718b92009-07-09 22:00:24 -07001374 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001375 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001376 // Have to calculate register arg count from actual stack size,
1377 // in order to properly handle ... functions.
1378 int regArgCount = l >> 2;
1379 if (regArgCount > 4) {
1380 regArgCount = 4;
1381 }
1382 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001383 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1384 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001385 if (stackUse) {
1386 if (stackUse < 0 || stackUse > 255) {
1387 error("L out of range for stack adjustment: 0x%08x", l);
1388 }
1389 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001390 mStackUse -= stackUse * 4;
1391 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001392 }
Jack Palevich22305132009-05-13 10:58:45 -07001393 }
1394
Jack Palevicha6535612009-05-13 16:24:17 -07001395 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001396 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001397 }
1398
1399 /* output a symbol and patch all calls to it */
1400 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001401 int n;
1402 int base = getBase();
1403 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001404 while (t) {
1405 int data = * (int*) t;
1406 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1407 if (decodedOffset == 0) {
1408 n = 0;
1409 } else {
1410 n = base + decodedOffset; /* next value */
1411 }
1412 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1413 | encodeRelAddress(pc - t - 8);
1414 t = n;
1415 }
1416 }
1417
Jack Palevich9f51a262009-07-29 16:22:26 -07001418 /* output a symbol and patch all calls to it */
1419 virtual void resolveForward(int t) {
1420 if (t) {
1421 int pc = getPC();
1422 *(int *) t = pc;
1423 }
1424 }
1425
Jack Palevich1cdef202009-05-22 12:06:27 -07001426 virtual int finishCompile() {
1427#if defined(__arm__)
1428 const long base = long(getBase());
1429 const long curr = long(getPC());
1430 int err = cacheflush(base, curr, 0);
1431 return err;
1432#else
1433 return 0;
1434#endif
1435 }
1436
Jack Palevicha6535612009-05-13 16:24:17 -07001437 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001438#ifdef ENABLE_ARM_DISASSEMBLY
1439 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001440 disasm_interface_t di;
1441 di.di_readword = disassemble_readword;
1442 di.di_printaddr = disassemble_printaddr;
1443 di.di_printf = disassemble_printf;
1444
1445 int base = getBase();
1446 int pc = getPC();
1447 for(int i = base; i < pc; i += 4) {
1448 fprintf(out, "%08x: %08x ", i, *(int*) i);
1449 ::disasm(&di, i, 0);
1450 }
Jack Palevich09555c72009-05-27 12:25:55 -07001451#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001452 return 0;
1453 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001454
Jack Palevich9eed7a22009-07-06 17:24:34 -07001455 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001456 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001457 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001458 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001459 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001460 case TY_CHAR:
1461 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001462 case TY_SHORT:
1463 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001464 case TY_DOUBLE:
1465 return 8;
1466 default:
1467 return 4;
1468 }
1469 }
1470
1471 /**
1472 * Array element alignment (in bytes) for this type of data.
1473 */
1474 virtual size_t sizeOf(Type* pType){
1475 switch(pType->tag) {
1476 case TY_INT:
1477 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001478 case TY_SHORT:
1479 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001480 case TY_CHAR:
1481 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001482 case TY_FLOAT:
1483 return 4;
1484 case TY_DOUBLE:
1485 return 8;
1486 case TY_POINTER:
1487 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001488 case TY_ARRAY:
1489 return pType->length * sizeOf(pType->pHead);
1490 default:
1491 error("Unsupported type %d", pType->tag);
1492 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001493 }
1494 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001495
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001496 virtual size_t stackAlignmentOf(Type* pType) {
1497 switch(pType->tag) {
1498 case TY_DOUBLE:
1499 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001500 case TY_ARRAY:
1501 return stackAlignmentOf(pType->pHead);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001502 default:
1503 return 4;
1504 }
1505 }
1506
Jack Palevich9cbd2262009-07-08 16:48:41 -07001507 virtual size_t stackSizeOf(Type* pType) {
1508 switch(pType->tag) {
1509 case TY_DOUBLE:
1510 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001511 case TY_ARRAY:
1512 return sizeOf(pType);
1513 case TY_FUNC:
1514 error("stackSizeOf func not supported");
1515 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001516 default:
1517 return 4;
1518 }
1519 }
1520
Jack Palevich22305132009-05-13 10:58:45 -07001521 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001522 static FILE* disasmOut;
1523
1524 static u_int
1525 disassemble_readword(u_int address)
1526 {
1527 return(*((u_int *)address));
1528 }
1529
1530 static void
1531 disassemble_printaddr(u_int address)
1532 {
1533 fprintf(disasmOut, "0x%08x", address);
1534 }
1535
1536 static void
1537 disassemble_printf(const char *fmt, ...) {
1538 va_list ap;
1539 va_start(ap, fmt);
1540 vfprintf(disasmOut, fmt, ap);
1541 va_end(ap);
1542 }
1543
1544 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1545
1546 /** Encode a relative address that might also be
1547 * a label.
1548 */
1549 int encodeAddress(int value) {
1550 int base = getBase();
1551 if (value >= base && value <= getPC() ) {
1552 // This is a label, encode it relative to the base.
1553 value = value - base;
1554 }
1555 return encodeRelAddress(value);
1556 }
1557
1558 int encodeRelAddress(int value) {
1559 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1560 }
Jack Palevich22305132009-05-13 10:58:45 -07001561
Jack Palevichb7718b92009-07-09 22:00:24 -07001562 int calcRegArgCount(Type* pDecl) {
1563 int reg = 0;
1564 Type* pArgs = pDecl->pTail;
1565 while (pArgs && reg < 4) {
1566 Type* pArg = pArgs->pHead;
1567 if ( pArg->tag == TY_DOUBLE) {
1568 int evenReg = (reg + 1) & ~1;
1569 if (evenReg >= 4) {
1570 break;
1571 }
1572 reg = evenReg + 2;
1573 } else {
1574 reg++;
1575 }
1576 pArgs = pArgs->pTail;
1577 }
1578 return reg;
1579 }
1580
Jack Palevich58c30ee2009-07-17 16:35:23 -07001581 void setupIntPtrArgs() {
1582 o4(0xE8BD0002); // ldmfd sp!,{r1}
1583 mStackUse -= 4;
1584 popType();
1585 }
1586
Jack Palevichb7718b92009-07-09 22:00:24 -07001587 /* Pop TOS to R1
1588 * Make sure both R0 and TOS are floats. (Could be ints)
1589 * We know that at least one of R0 and TOS is already a float
1590 */
1591 void setupFloatArgs() {
1592 Type* pR0Type = getR0Type();
1593 Type* pTOSType = getTOSType();
1594 TypeTag tagR0 = collapseType(pR0Type->tag);
1595 TypeTag tagTOS = collapseType(pTOSType->tag);
1596 if (tagR0 != TY_FLOAT) {
1597 assert(tagR0 == TY_INT);
1598 callRuntime((void*) runtime_int_to_float);
1599 }
1600 if (tagTOS != TY_FLOAT) {
1601 assert(tagTOS == TY_INT);
1602 assert(tagR0 == TY_FLOAT);
1603 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1604 o4(0xE59D0004); // ldr r0, [sp, #4]
1605 callRuntime((void*) runtime_int_to_float);
1606 o4(0xE1A01000); // mov r1, r0
1607 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1608 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1609 } else {
1610 // Pop TOS
1611 o4(0xE8BD0002); // ldmfd sp!,{r1}
1612 }
1613 mStackUse -= 4;
1614 popType();
1615 }
1616
1617 /* Pop TOS into R2..R3
1618 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1619 * We know that at least one of R0 and TOS are already a double.
1620 */
1621
1622 void setupDoubleArgs() {
1623 Type* pR0Type = getR0Type();
1624 Type* pTOSType = getTOSType();
1625 TypeTag tagR0 = collapseType(pR0Type->tag);
1626 TypeTag tagTOS = collapseType(pTOSType->tag);
1627 if (tagR0 != TY_DOUBLE) {
1628 if (tagR0 == TY_INT) {
1629 callRuntime((void*) runtime_int_to_double);
1630 } else {
1631 assert(tagR0 == TY_FLOAT);
1632 callRuntime((void*) runtime_float_to_double);
1633 }
1634 }
1635 if (tagTOS != TY_DOUBLE) {
1636 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1637 o4(0xE59D0008); // ldr r0, [sp, #8]
1638 if (tagTOS == TY_INT) {
1639 callRuntime((void*) runtime_int_to_double);
1640 } else {
1641 assert(tagTOS == TY_FLOAT);
1642 callRuntime((void*) runtime_float_to_double);
1643 }
1644 o4(0xE1A02000); // mov r2, r0
1645 o4(0xE1A03001); // mov r3, r1
1646 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1647 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1648 mStackUse -= 4;
1649 } else {
1650 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1651 mStackUse -= 8;
1652 }
1653 popType();
1654 }
1655
Jack Palevicha8f427f2009-07-13 18:40:08 -07001656 void liReg(int t, int reg) {
1657 assert(reg >= 0 && reg < 16);
1658 int rN = (reg & 0xf) << 12;
1659 if (t >= 0 && t < 255) {
1660 o4((0xE3A00000 + t) | rN); // mov rN, #0
1661 } else if (t >= -256 && t < 0) {
1662 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001663 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001664 } else {
1665 o4(0xE51F0000 | rN); // ldr rN, .L3
1666 o4(0xEA000000); // b .L99
1667 o4(t); // .L3: .word 0
1668 // .L99:
1669 }
1670 }
1671
Jack Palevichb7718b92009-07-09 22:00:24 -07001672 void callRuntime(void* fn) {
1673 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001674 o4(0xEA000000); // b .L99
1675 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001676 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001677 }
1678
Jack Palevichb7718b92009-07-09 22:00:24 -07001679 // Integer math:
1680
1681 static int runtime_DIV(int b, int a) {
1682 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001683 }
1684
Jack Palevichb7718b92009-07-09 22:00:24 -07001685 static int runtime_MOD(int b, int a) {
1686 return a % b;
1687 }
1688
1689 // Comparison to zero
1690
1691 static int runtime_is_non_zero_f(float a) {
1692 return a != 0;
1693 }
1694
1695 static int runtime_is_non_zero_d(double a) {
1696 return a != 0;
1697 }
1698
1699 // Comparison to zero
1700
1701 static int runtime_is_zero_f(float a) {
1702 return a == 0;
1703 }
1704
1705 static int runtime_is_zero_d(double a) {
1706 return a == 0;
1707 }
1708
1709 // Type conversion
1710
1711 static int runtime_float_to_int(float a) {
1712 return (int) a;
1713 }
1714
1715 static double runtime_float_to_double(float a) {
1716 return (double) a;
1717 }
1718
1719 static int runtime_double_to_int(double a) {
1720 return (int) a;
1721 }
1722
1723 static float runtime_double_to_float(double a) {
1724 return (float) a;
1725 }
1726
1727 static float runtime_int_to_float(int a) {
1728 return (float) a;
1729 }
1730
1731 static double runtime_int_to_double(int a) {
1732 return (double) a;
1733 }
1734
1735 // Comparisons float
1736
1737 static int runtime_cmp_eq_ff(float b, float a) {
1738 return a == b;
1739 }
1740
1741 static int runtime_cmp_ne_ff(float b, float a) {
1742 return a != b;
1743 }
1744
1745 static int runtime_cmp_lt_ff(float b, float a) {
1746 return a < b;
1747 }
1748
1749 static int runtime_cmp_le_ff(float b, float a) {
1750 return a <= b;
1751 }
1752
1753 static int runtime_cmp_ge_ff(float b, float a) {
1754 return a >= b;
1755 }
1756
1757 static int runtime_cmp_gt_ff(float b, float a) {
1758 return a > b;
1759 }
1760
1761 // Comparisons double
1762
1763 static int runtime_cmp_eq_dd(double b, double a) {
1764 return a == b;
1765 }
1766
1767 static int runtime_cmp_ne_dd(double b, double a) {
1768 return a != b;
1769 }
1770
1771 static int runtime_cmp_lt_dd(double b, double a) {
1772 return a < b;
1773 }
1774
1775 static int runtime_cmp_le_dd(double b, double a) {
1776 return a <= b;
1777 }
1778
1779 static int runtime_cmp_ge_dd(double b, double a) {
1780 return a >= b;
1781 }
1782
1783 static int runtime_cmp_gt_dd(double b, double a) {
1784 return a > b;
1785 }
1786
1787 // Math float
1788
1789 static float runtime_op_add_ff(float b, float a) {
1790 return a + b;
1791 }
1792
1793 static float runtime_op_sub_ff(float b, float a) {
1794 return a - b;
1795 }
1796
1797 static float runtime_op_mul_ff(float b, float a) {
1798 return a * b;
1799 }
1800
1801 static float runtime_op_div_ff(float b, float a) {
1802 return a / b;
1803 }
1804
1805 static float runtime_op_neg_f(float a) {
1806 return -a;
1807 }
1808
1809 // Math double
1810
1811 static double runtime_op_add_dd(double b, double a) {
1812 return a + b;
1813 }
1814
1815 static double runtime_op_sub_dd(double b, double a) {
1816 return a - b;
1817 }
1818
1819 static double runtime_op_mul_dd(double b, double a) {
1820 return a * b;
1821 }
1822
1823 static double runtime_op_div_dd(double b, double a) {
1824 return a / b;
1825 }
1826
1827 static double runtime_op_neg_d(double a) {
1828 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001829 }
-b master422972c2009-06-17 19:13:52 -07001830
1831 static const int STACK_ALIGNMENT = 8;
1832 int mStackUse;
1833 // This variable holds the amount we adjusted the stack in the most
1834 // recent endFunctionCallArguments call. It's examined by the
1835 // following adjustStackAfterCall call.
1836 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001837 };
1838
Jack Palevich09555c72009-05-27 12:25:55 -07001839#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001840
1841#ifdef PROVIDE_X86_CODEGEN
1842
Jack Palevich21a15a22009-05-11 14:49:29 -07001843 class X86CodeGenerator : public CodeGenerator {
1844 public:
1845 X86CodeGenerator() {}
1846 virtual ~X86CodeGenerator() {}
1847
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001848 /* returns address to patch with local variable size
1849 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001850 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001851 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1852 return oad(0xec81, 0); /* sub $xxx, %esp */
1853 }
1854
Jack Palevichb7718b92009-07-09 22:00:24 -07001855 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001856 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001857 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001858 }
1859
Jack Palevich21a15a22009-05-11 14:49:29 -07001860 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001861 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001862 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001863 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001864 }
1865
Jack Palevich1a539db2009-07-08 13:04:41 -07001866 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001867 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001868 switch (pType->tag) {
1869 case TY_FLOAT:
1870 oad(0x05D9, address); // flds
1871 break;
1872 case TY_DOUBLE:
1873 oad(0x05DD, address); // fldl
1874 break;
1875 default:
1876 assert(false);
1877 break;
1878 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001879 }
1880
Jack Palevich22305132009-05-13 10:58:45 -07001881 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001882 return psym(0xe9, t);
1883 }
1884
1885 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001886 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001887 Type* pR0Type = getR0Type();
1888 TypeTag tagR0 = pR0Type->tag;
1889 bool isFloatR0 = isFloatTag(tagR0);
1890 if (isFloatR0) {
1891 o(0xeed9); // fldz
1892 o(0xe9da); // fucompp
1893 o(0xe0df); // fnstsw %ax
1894 o(0x9e); // sahf
1895 } else {
1896 o(0xc085); // test %eax, %eax
1897 }
1898 // Use two output statements to generate one instruction.
1899 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001900 return psym(0x84 + l, t);
1901 }
1902
Jack Palevich58c30ee2009-07-17 16:35:23 -07001903 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001904 Type* pR0Type = getR0Type();
1905 Type* pTOSType = getTOSType();
1906 TypeTag tagR0 = pR0Type->tag;
1907 TypeTag tagTOS = pTOSType->tag;
1908 bool isFloatR0 = isFloatTag(tagR0);
1909 bool isFloatTOS = isFloatTag(tagTOS);
1910 if (!isFloatR0 && !isFloatTOS) {
1911 int t = decodeOp(op);
1912 o(0x59); /* pop %ecx */
1913 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001914 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001915 o(0x0f); /* setxx %al */
1916 o(t + 0x90);
1917 o(0xc0);
1918 popType();
1919 } else {
1920 setupFloatOperands();
1921 switch (op) {
1922 case OP_EQUALS:
1923 o(0xe9da); // fucompp
1924 o(0xe0df); // fnstsw %ax
1925 o(0x9e); // sahf
1926 o(0xc0940f); // sete %al
1927 o(0xc29b0f); // setnp %dl
1928 o(0xd021); // andl %edx, %eax
1929 break;
1930 case OP_NOT_EQUALS:
1931 o(0xe9da); // fucompp
1932 o(0xe0df); // fnstsw %ax
1933 o(0x9e); // sahf
1934 o(0xc0950f); // setne %al
1935 o(0xc29a0f); // setp %dl
1936 o(0xd009); // orl %edx, %eax
1937 break;
1938 case OP_GREATER_EQUAL:
1939 o(0xe9da); // fucompp
1940 o(0xe0df); // fnstsw %ax
1941 o(0x05c4f6); // testb $5, %ah
1942 o(0xc0940f); // sete %al
1943 break;
1944 case OP_LESS:
1945 o(0xc9d9); // fxch %st(1)
1946 o(0xe9da); // fucompp
1947 o(0xe0df); // fnstsw %ax
1948 o(0x9e); // sahf
1949 o(0xc0970f); // seta %al
1950 break;
1951 case OP_LESS_EQUAL:
1952 o(0xc9d9); // fxch %st(1)
1953 o(0xe9da); // fucompp
1954 o(0xe0df); // fnstsw %ax
1955 o(0x9e); // sahf
1956 o(0xc0930f); // setea %al
1957 break;
1958 case OP_GREATER:
1959 o(0xe9da); // fucompp
1960 o(0xe0df); // fnstsw %ax
1961 o(0x45c4f6); // testb $69, %ah
1962 o(0xc0940f); // sete %al
1963 break;
1964 default:
1965 error("Unknown comparison op");
1966 }
1967 o(0xc0b60f); // movzbl %al, %eax
1968 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001969 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001970 }
1971
Jack Palevich546b2242009-05-13 15:10:04 -07001972 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001973 Type* pR0Type = getR0Type();
1974 Type* pTOSType = getTOSType();
1975 TypeTag tagR0 = pR0Type->tag;
1976 TypeTag tagTOS = pTOSType->tag;
1977 bool isFloatR0 = isFloatTag(tagR0);
1978 bool isFloatTOS = isFloatTag(tagTOS);
1979 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07001980 bool isPtrR0 = isPointerTag(tagR0);
1981 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001982 if (isPtrR0 || isPtrTOS) {
1983 if (isPtrR0 && isPtrTOS) {
1984 if (op != OP_MINUS) {
1985 error("Unsupported pointer-pointer operation %d.", op);
1986 }
1987 if (! typeEqual(pR0Type, pTOSType)) {
1988 error("Incompatible pointer types for subtraction.");
1989 }
1990 o(0x59); /* pop %ecx */
1991 o(decodeOp(op));
1992 popType();
1993 setR0Type(mkpInt);
1994 int size = sizeOf(pR0Type->pHead);
1995 if (size != 1) {
1996 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001997 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001998 // TODO: Optimize for power-of-two.
1999 genOp(OP_DIV);
2000 }
2001 } else {
2002 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2003 error("Unsupported pointer-scalar operation %d", op);
2004 }
Jack Palevichb6154502009-08-04 14:56:09 -07002005 Type* pPtrType = getPointerArithmeticResultType(
2006 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002007 o(0x59); /* pop %ecx */
2008 int size = sizeOf(pPtrType->pHead);
2009 if (size != 1) {
2010 // TODO: Optimize for power-of-two.
2011 if (isPtrR0) {
2012 oad(0xC969, size); // imull $size, %ecx
2013 } else {
2014 oad(0xC069, size); // mul $size, %eax
2015 }
2016 }
2017 o(decodeOp(op));
2018 popType();
2019 setR0Type(pPtrType);
2020 }
2021 } else {
2022 o(0x59); /* pop %ecx */
2023 o(decodeOp(op));
2024 if (op == OP_MOD)
2025 o(0x92); /* xchg %edx, %eax */
2026 popType();
2027 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002028 } else {
2029 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2030 setupFloatOperands();
2031 // Both float. x87 R0 == left hand, x87 R1 == right hand
2032 switch (op) {
2033 case OP_MUL:
2034 o(0xc9de); // fmulp
2035 break;
2036 case OP_DIV:
2037 o(0xf1de); // fdivp
2038 break;
2039 case OP_PLUS:
2040 o(0xc1de); // faddp
2041 break;
2042 case OP_MINUS:
2043 o(0xe1de); // fsubp
2044 break;
2045 default:
2046 error("Unsupported binary floating operation.");
2047 break;
2048 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002049 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002050 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002051 }
2052
Jack Palevich58c30ee2009-07-17 16:35:23 -07002053 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002054 if (op != OP_LOGICAL_NOT) {
2055 error("Unknown unary cmp %d", op);
2056 } else {
2057 Type* pR0Type = getR0Type();
2058 TypeTag tag = collapseType(pR0Type->tag);
2059 switch(tag) {
2060 case TY_INT: {
2061 oad(0xb9, 0); /* movl $0, %ecx */
2062 int t = decodeOp(op);
2063 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002064 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002065 o(0x0f); /* setxx %al */
2066 o(t + 0x90);
2067 o(0xc0);
2068 }
2069 break;
2070 case TY_FLOAT:
2071 case TY_DOUBLE:
2072 o(0xeed9); // fldz
2073 o(0xe9da); // fucompp
2074 o(0xe0df); // fnstsw %ax
2075 o(0x9e); // sahf
2076 o(0xc0950f); // setne %al
2077 o(0xc29a0f); // setp %dl
2078 o(0xd009); // orl %edx, %eax
2079 o(0xc0b60f); // movzbl %al, %eax
2080 o(0x01f083); // xorl $1, %eax
2081 break;
2082 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002083 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002084 break;
2085 }
2086 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002087 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002088 }
2089
2090 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002091 Type* pR0Type = getR0Type();
2092 TypeTag tag = collapseType(pR0Type->tag);
2093 switch(tag) {
2094 case TY_INT:
2095 oad(0xb9, 0); /* movl $0, %ecx */
2096 o(decodeOp(op));
2097 break;
2098 case TY_FLOAT:
2099 case TY_DOUBLE:
2100 switch (op) {
2101 case OP_MINUS:
2102 o(0xe0d9); // fchs
2103 break;
2104 case OP_BIT_NOT:
2105 error("Can't apply '~' operator to a float or double.");
2106 break;
2107 default:
2108 error("Unknown unary op %d\n", op);
2109 break;
2110 }
2111 break;
2112 default:
2113 error("genUnaryOp unsupported type");
2114 break;
2115 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002116 }
2117
Jack Palevich1cdef202009-05-22 12:06:27 -07002118 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002119 Type* pR0Type = getR0Type();
2120 TypeTag r0ct = collapseType(pR0Type->tag);
2121 switch(r0ct) {
2122 case TY_INT:
2123 o(0x50); /* push %eax */
2124 break;
2125 case TY_FLOAT:
2126 o(0x50); /* push %eax */
2127 o(0x241cd9); // fstps 0(%esp)
2128 break;
2129 case TY_DOUBLE:
2130 o(0x50); /* push %eax */
2131 o(0x50); /* push %eax */
2132 o(0x241cdd); // fstpl 0(%esp)
2133 break;
2134 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002135 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002136 break;
2137 }
Jack Palevich8df46192009-07-07 14:48:51 -07002138 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002139 }
2140
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002141 virtual void over() {
2142 // We know it's only used for int-ptr ops (++/--)
2143
2144 Type* pR0Type = getR0Type();
2145 TypeTag r0ct = collapseType(pR0Type->tag);
2146
2147 Type* pTOSType = getTOSType();
2148 TypeTag tosct = collapseType(pTOSType->tag);
2149
2150 assert (r0ct == TY_INT && tosct == TY_INT);
2151
2152 o(0x59); /* pop %ecx */
2153 o(0x50); /* push %eax */
2154 o(0x51); /* push %ecx */
2155
2156 overType();
2157 }
2158
Jack Palevich58c30ee2009-07-17 16:35:23 -07002159 virtual void popR0() {
2160 Type* pR0Type = getR0Type();
2161 TypeTag r0ct = collapseType(pR0Type->tag);
2162 switch(r0ct) {
2163 case TY_INT:
2164 o(0x58); /* popl %eax */
2165 break;
2166 case TY_FLOAT:
2167 o(0x2404d9); // flds (%esp)
2168 o(0x58); /* popl %eax */
2169 break;
2170 case TY_DOUBLE:
2171 o(0x2404dd); // fldl (%esp)
2172 o(0x58); /* popl %eax */
2173 o(0x58); /* popl %eax */
2174 break;
2175 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002176 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002177 break;
2178 }
2179 popType();
2180 }
2181
2182 virtual void storeR0ToTOS() {
2183 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002184 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002185 Type* pTargetType = pPointerType->pHead;
2186 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002187 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002188 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002189 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002190 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002191 case TY_INT:
2192 o(0x0189); /* movl %eax/%al, (%ecx) */
2193 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002194 case TY_SHORT:
2195 o(0x018966); /* movw %ax, (%ecx) */
2196 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002197 case TY_CHAR:
2198 o(0x0188); /* movl %eax/%al, (%ecx) */
2199 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002200 case TY_FLOAT:
2201 o(0x19d9); /* fstps (%ecx) */
2202 break;
2203 case TY_DOUBLE:
2204 o(0x19dd); /* fstpl (%ecx) */
2205 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002206 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002207 error("storeR0ToTOS: unsupported type %d",
2208 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002209 break;
2210 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002211 }
2212
Jack Palevich58c30ee2009-07-17 16:35:23 -07002213 virtual void loadR0FromR0() {
2214 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002215 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb6154502009-08-04 14:56:09 -07002216 TypeTag tag = pPointerType->pHead->tag;
2217 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002218 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002219 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002220 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002221 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002222 case TY_SHORT:
2223 o(0xbf0f); /* movswl (%eax), %eax */
2224 ob(0);
2225 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002226 case TY_CHAR:
2227 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002228 ob(0); /* add zero in code */
2229 break;
2230 case TY_FLOAT:
2231 o2(0x00d9); // flds (%eax)
2232 break;
2233 case TY_DOUBLE:
2234 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002235 break;
2236 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002237 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002238 break;
2239 }
Jack Palevich8df46192009-07-07 14:48:51 -07002240 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002241 }
2242
Jack Palevichb5e33312009-07-30 19:06:34 -07002243 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002244 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002245 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002246 }
2247
Jack Palevich9f51a262009-07-29 16:22:26 -07002248 virtual int leaForward(int ea, Type* pPointerType) {
2249 oad(0xb8, ea); /* mov $xx, %eax */
2250 setR0Type(pPointerType);
2251 return getPC() - 4;
2252 }
2253
Jack Palevichb6154502009-08-04 14:56:09 -07002254 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002255 Type* pR0Type = getR0Type();
2256 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002257 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002258 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002259 return;
2260 }
Jack Palevichb6154502009-08-04 14:56:09 -07002261 if (isPointerType(pType) && isPointerType(pR0Type)) {
2262 Type* pA = pR0Type;
2263 Type* pB = pType;
2264 // Array decays to pointer
2265 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2266 pA = pA->pTail;
2267 }
2268 if (typeEqual(pA, pB)) {
2269 return; // OK
2270 }
2271 if (pB->pHead->tag == TY_VOID) {
2272 return; // convert to void* is OK.
2273 }
2274 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
2275 && isCast) {
2276 return; // OK
2277 }
2278 error("Incompatible pointer or array types");
2279 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002280 // do nothing special
2281 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2282 // do nothing special, both held in same register on x87.
2283 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002284 TypeTag r0Tag = collapseType(pR0Type->tag);
2285 TypeTag destTag = collapseType(pType->tag);
2286 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2287 // Convert R0 from int to float
2288 o(0x50); // push %eax
2289 o(0x2404DB); // fildl 0(%esp)
2290 o(0x58); // pop %eax
2291 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2292 // Convert R0 from float to int. Complicated because
2293 // need to save and restore the rounding mode.
2294 o(0x50); // push %eax
2295 o(0x50); // push %eax
2296 o(0x02247cD9); // fnstcw 2(%esp)
2297 o(0x2444b70f); // movzwl 2(%esp), %eax
2298 o(0x02);
2299 o(0x0cb4); // movb $12, %ah
2300 o(0x24048966); // movw %ax, 0(%esp)
2301 o(0x242cd9); // fldcw 0(%esp)
2302 o(0x04245cdb); // fistpl 4(%esp)
2303 o(0x02246cd9); // fldcw 2(%esp)
2304 o(0x58); // pop %eax
2305 o(0x58); // pop %eax
2306 } else {
2307 error("Incompatible types old: %d new: %d",
2308 pR0Type->tag, pType->tag);
2309 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002310 }
2311 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002312 }
2313
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002314 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002315 return oad(0xec81, 0); /* sub $xxx, %esp */
2316 }
2317
Jack Palevich8148c5b2009-07-16 18:24:47 -07002318 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2319 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002320 Type* pR0Type = getR0Type();
2321 TypeTag r0ct = collapseType(pR0Type->tag);
2322 switch(r0ct) {
2323 case TY_INT:
2324 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2325 return 4;
2326 case TY_FLOAT:
2327 oad(0x249CD9, l); /* fstps xxx(%esp) */
2328 return 4;
2329 case TY_DOUBLE:
2330 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2331 return 8;
2332 default:
2333 assert(false);
2334 return 0;
2335 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002336 }
2337
Jack Palevichb7718b92009-07-09 22:00:24 -07002338 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002339 * (int*) a = l;
2340 }
2341
Jack Palevich8df46192009-07-07 14:48:51 -07002342 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002343 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002344 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002345 return psym(0xe8, symbol); /* call xxx */
2346 }
2347
Jack Palevich8df46192009-07-07 14:48:51 -07002348 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002349 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002350 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002351 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002352 oad(0x2494ff, l); /* call *xxx(%esp) */
2353 }
2354
Jack Palevichb7718b92009-07-09 22:00:24 -07002355 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002356 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002357 if (isIndirect) {
2358 l += 4;
2359 }
-b master422972c2009-06-17 19:13:52 -07002360 if (l > 0) {
2361 oad(0xc481, l); /* add $xxx, %esp */
2362 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002363 }
2364
Jack Palevicha6535612009-05-13 16:24:17 -07002365 virtual int jumpOffset() {
2366 return 5;
2367 }
2368
2369 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002370 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002371 }
2372
Jack Paleviche7b59062009-05-19 17:12:17 -07002373 /* output a symbol and patch all calls to it */
2374 virtual void gsym(int t) {
2375 int n;
2376 int pc = getPC();
2377 while (t) {
2378 n = *(int *) t; /* next value */
2379 *(int *) t = pc - t - 4;
2380 t = n;
2381 }
2382 }
2383
Jack Palevich9f51a262009-07-29 16:22:26 -07002384 /* output a symbol and patch all calls to it, using absolute address */
2385 virtual void resolveForward(int t) {
2386 int n;
2387 int pc = getPC();
2388 while (t) {
2389 n = *(int *) t; /* next value */
2390 *(int *) t = pc;
2391 t = n;
2392 }
2393 }
2394
Jack Palevich1cdef202009-05-22 12:06:27 -07002395 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002396 size_t pagesize = 4096;
2397 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2398 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2399 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2400 if (err) {
2401 error("mprotect() failed: %d", errno);
2402 }
2403 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002404 }
2405
Jack Palevich9eed7a22009-07-06 17:24:34 -07002406 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002407 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002408 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002409 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002410 switch (pType->tag) {
2411 case TY_CHAR:
2412 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002413 case TY_SHORT:
2414 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002415 case TY_ARRAY:
2416 return alignmentOf(pType->pHead);
2417 case TY_FUNC:
2418 error("alignment of func not supported");
2419 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002420 default:
2421 return 4;
2422 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002423 }
2424
2425 /**
2426 * Array element alignment (in bytes) for this type of data.
2427 */
2428 virtual size_t sizeOf(Type* pType){
2429 switch(pType->tag) {
2430 case TY_INT:
2431 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002432 case TY_SHORT:
2433 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002434 case TY_CHAR:
2435 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002436 case TY_FLOAT:
2437 return 4;
2438 case TY_DOUBLE:
2439 return 8;
2440 case TY_POINTER:
2441 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002442 case TY_ARRAY:
2443 return pType->length * sizeOf(pType->pHead);
2444 default:
2445 error("Unsupported type %d", pType->tag);
2446 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002447 }
2448 }
2449
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002450 virtual size_t stackAlignmentOf(Type* pType){
2451 return 4;
2452 }
2453
Jack Palevich9cbd2262009-07-08 16:48:41 -07002454 virtual size_t stackSizeOf(Type* pType) {
2455 switch(pType->tag) {
2456 case TY_DOUBLE:
2457 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07002458 case TY_ARRAY:
2459 return sizeOf(pType);
2460 case TY_FUNC:
2461 error("stackSizeOf func not supported");
2462 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002463 default:
2464 return 4;
2465 }
2466 }
2467
Jack Palevich21a15a22009-05-11 14:49:29 -07002468 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002469
2470 /** Output 1 to 4 bytes.
2471 *
2472 */
2473 void o(int n) {
2474 /* cannot use unsigned, so we must do a hack */
2475 while (n && n != -1) {
2476 ob(n & 0xff);
2477 n = n >> 8;
2478 }
2479 }
2480
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002481 /* Output exactly 2 bytes
2482 */
2483 void o2(int n) {
2484 ob(n & 0xff);
2485 ob(0xff & (n >> 8));
2486 }
2487
Jack Paleviche7b59062009-05-19 17:12:17 -07002488 /* psym is used to put an instruction with a data field which is a
2489 reference to a symbol. It is in fact the same as oad ! */
2490 int psym(int n, int t) {
2491 return oad(n, t);
2492 }
2493
2494 /* instruction + address */
2495 int oad(int n, int t) {
2496 o(n);
2497 int result = getPC();
2498 o4(t);
2499 return result;
2500 }
2501
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002502 static const int operatorHelper[];
2503
2504 int decodeOp(int op) {
2505 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002506 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002507 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002508 }
2509 return operatorHelper[op];
2510 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002511
Jack Palevich546b2242009-05-13 15:10:04 -07002512 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002513 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002514 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002515 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002516
2517 void setupFloatOperands() {
2518 Type* pR0Type = getR0Type();
2519 Type* pTOSType = getTOSType();
2520 TypeTag tagR0 = pR0Type->tag;
2521 TypeTag tagTOS = pTOSType->tag;
2522 bool isFloatR0 = isFloatTag(tagR0);
2523 bool isFloatTOS = isFloatTag(tagTOS);
2524 if (! isFloatR0) {
2525 // Convert R0 from int to float
2526 o(0x50); // push %eax
2527 o(0x2404DB); // fildl 0(%esp)
2528 o(0x58); // pop %eax
2529 }
2530 if (! isFloatTOS){
2531 o(0x2404DB); // fildl 0(%esp);
2532 o(0x58); // pop %eax
2533 } else {
2534 if (tagTOS == TY_FLOAT) {
2535 o(0x2404d9); // flds (%esp)
2536 o(0x58); // pop %eax
2537 } else {
2538 o(0x2404dd); // fldl (%esp)
2539 o(0x58); // pop %eax
2540 o(0x58); // pop %eax
2541 }
2542 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002543 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002544 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002545 };
2546
Jack Paleviche7b59062009-05-19 17:12:17 -07002547#endif // PROVIDE_X86_CODEGEN
2548
Jack Palevichb67b18f2009-06-11 21:12:23 -07002549#ifdef PROVIDE_TRACE_CODEGEN
2550 class TraceCodeGenerator : public CodeGenerator {
2551 private:
2552 CodeGenerator* mpBase;
2553
2554 public:
2555 TraceCodeGenerator(CodeGenerator* pBase) {
2556 mpBase = pBase;
2557 }
2558
2559 virtual ~TraceCodeGenerator() {
2560 delete mpBase;
2561 }
2562
2563 virtual void init(CodeBuf* pCodeBuf) {
2564 mpBase->init(pCodeBuf);
2565 }
2566
2567 void setErrorSink(ErrorSink* pErrorSink) {
2568 mpBase->setErrorSink(pErrorSink);
2569 }
2570
2571 /* returns address to patch with local variable size
2572 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002573 virtual int functionEntry(Type* pDecl) {
2574 int result = mpBase->functionEntry(pDecl);
2575 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002576 return result;
2577 }
2578
Jack Palevichb7718b92009-07-09 22:00:24 -07002579 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2580 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2581 localVariableAddress, localVariableSize);
2582 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002583 }
2584
2585 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002586 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002587 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002588 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002589 }
2590
Jack Palevich1a539db2009-07-08 13:04:41 -07002591 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002592 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002593 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002594 }
2595
Jack Palevichb67b18f2009-06-11 21:12:23 -07002596 virtual int gjmp(int t) {
2597 int result = mpBase->gjmp(t);
2598 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2599 return result;
2600 }
2601
2602 /* l = 0: je, l == 1: jne */
2603 virtual int gtst(bool l, int t) {
2604 int result = mpBase->gtst(l, t);
2605 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2606 return result;
2607 }
2608
Jack Palevich58c30ee2009-07-17 16:35:23 -07002609 virtual void gcmp(int op) {
2610 fprintf(stderr, "gcmp(%d)\n", op);
2611 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002612 }
2613
2614 virtual void genOp(int op) {
2615 fprintf(stderr, "genOp(%d)\n", op);
2616 mpBase->genOp(op);
2617 }
2618
Jack Palevich9eed7a22009-07-06 17:24:34 -07002619
Jack Palevich58c30ee2009-07-17 16:35:23 -07002620 virtual void gUnaryCmp(int op) {
2621 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2622 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002623 }
2624
2625 virtual void genUnaryOp(int op) {
2626 fprintf(stderr, "genUnaryOp(%d)\n", op);
2627 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002628 }
2629
2630 virtual void pushR0() {
2631 fprintf(stderr, "pushR0()\n");
2632 mpBase->pushR0();
2633 }
2634
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002635 virtual void over() {
2636 fprintf(stderr, "over()\n");
2637 mpBase->over();
2638 }
2639
Jack Palevich58c30ee2009-07-17 16:35:23 -07002640 virtual void popR0() {
2641 fprintf(stderr, "popR0()\n");
2642 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002643 }
2644
Jack Palevich58c30ee2009-07-17 16:35:23 -07002645 virtual void storeR0ToTOS() {
2646 fprintf(stderr, "storeR0ToTOS()\n");
2647 mpBase->storeR0ToTOS();
2648 }
2649
2650 virtual void loadR0FromR0() {
2651 fprintf(stderr, "loadR0FromR0()\n");
2652 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002653 }
2654
Jack Palevichb5e33312009-07-30 19:06:34 -07002655 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2656 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
2657 pPointerType->pHead->tag, et);
2658 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002659 }
2660
Jack Palevich9f51a262009-07-29 16:22:26 -07002661 virtual int leaForward(int ea, Type* pPointerType) {
2662 fprintf(stderr, "leaForward(%d)\n", ea);
2663 return mpBase->leaForward(ea, pPointerType);
2664 }
2665
Jack Palevich8df46192009-07-07 14:48:51 -07002666 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002667 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002668 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002669 }
2670
2671 virtual int beginFunctionCallArguments() {
2672 int result = mpBase->beginFunctionCallArguments();
2673 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2674 return result;
2675 }
2676
Jack Palevich8148c5b2009-07-16 18:24:47 -07002677 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2678 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2679 pArgType->tag);
2680 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002681 }
2682
Jack Palevichb7718b92009-07-09 22:00:24 -07002683 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002684 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002685 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002686 }
2687
Jack Palevich8df46192009-07-07 14:48:51 -07002688 virtual int callForward(int symbol, Type* pFunc) {
2689 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002690 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2691 return result;
2692 }
2693
Jack Palevich8df46192009-07-07 14:48:51 -07002694 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002695 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2696 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002697 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002698 }
2699
Jack Palevichb7718b92009-07-09 22:00:24 -07002700 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2701 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2702 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002703 }
2704
2705 virtual int jumpOffset() {
2706 return mpBase->jumpOffset();
2707 }
2708
2709 virtual int disassemble(FILE* out) {
2710 return mpBase->disassemble(out);
2711 }
2712
2713 /* output a symbol and patch all calls to it */
2714 virtual void gsym(int t) {
2715 fprintf(stderr, "gsym(%d)\n", t);
2716 mpBase->gsym(t);
2717 }
2718
Jack Palevich9f51a262009-07-29 16:22:26 -07002719 virtual void resolveForward(int t) {
2720 mpBase->resolveForward(t);
2721 }
2722
Jack Palevichb67b18f2009-06-11 21:12:23 -07002723 virtual int finishCompile() {
2724 int result = mpBase->finishCompile();
2725 fprintf(stderr, "finishCompile() = %d\n", result);
2726 return result;
2727 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002728
2729 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002730 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002731 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002732 virtual size_t alignmentOf(Type* pType){
2733 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002734 }
2735
2736 /**
2737 * Array element alignment (in bytes) for this type of data.
2738 */
2739 virtual size_t sizeOf(Type* pType){
2740 return mpBase->sizeOf(pType);
2741 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002742
Jack Palevich9cbd2262009-07-08 16:48:41 -07002743
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002744 virtual size_t stackAlignmentOf(Type* pType) {
2745 return mpBase->stackAlignmentOf(pType);
2746 }
2747
2748
Jack Palevich9cbd2262009-07-08 16:48:41 -07002749 virtual size_t stackSizeOf(Type* pType) {
2750 return mpBase->stackSizeOf(pType);
2751 }
2752
Jack Palevich1a539db2009-07-08 13:04:41 -07002753 virtual Type* getR0Type() {
2754 return mpBase->getR0Type();
2755 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002756
2757 virtual ExpressionType getR0ExpressionType() {
2758 return mpBase->getR0ExpressionType();
2759 }
2760
2761 virtual void setR0ExpressionType(ExpressionType et) {
2762 mpBase->setR0ExpressionType(et);
2763 }
2764
2765 virtual size_t getExpressionStackDepth() {
2766 return mpBase->getExpressionStackDepth();
2767 }
Jack Palevichb5e33312009-07-30 19:06:34 -07002768
2769 virtual void forceR0RVal() {
2770 return mpBase->forceR0RVal();
2771 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002772 };
2773
2774#endif // PROVIDE_TRACE_CODEGEN
2775
Jack Palevich569f1352009-06-29 14:29:08 -07002776 class Arena {
2777 public:
2778 // Used to record a given allocation amount.
2779 // Used:
2780 // Mark mark = arena.mark();
2781 // ... lots of arena.allocate()
2782 // arena.free(mark);
2783
2784 struct Mark {
2785 size_t chunk;
2786 size_t offset;
2787 };
2788
2789 Arena() {
2790 mCurrentChunk = 0;
2791 Chunk start(CHUNK_SIZE);
2792 mData.push_back(start);
2793 }
2794
2795 ~Arena() {
2796 for(size_t i = 0; i < mData.size(); i++) {
2797 mData[i].free();
2798 }
2799 }
2800
2801 // Alloc using the standard alignment size safe for any variable
2802 void* alloc(size_t size) {
2803 return alloc(size, 8);
2804 }
2805
2806 Mark mark(){
2807 Mark result;
2808 result.chunk = mCurrentChunk;
2809 result.offset = mData[mCurrentChunk].mOffset;
2810 return result;
2811 }
2812
2813 void freeToMark(const Mark& mark) {
2814 mCurrentChunk = mark.chunk;
2815 mData[mCurrentChunk].mOffset = mark.offset;
2816 }
2817
2818 private:
2819 // Allocate memory aligned to a given size
2820 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2821 // Memory is not zero filled.
2822
2823 void* alloc(size_t size, size_t alignment) {
2824 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2825 if (mCurrentChunk + 1 < mData.size()) {
2826 mCurrentChunk++;
2827 } else {
2828 size_t allocSize = CHUNK_SIZE;
2829 if (allocSize < size + alignment - 1) {
2830 allocSize = size + alignment - 1;
2831 }
2832 Chunk chunk(allocSize);
2833 mData.push_back(chunk);
2834 mCurrentChunk++;
2835 }
2836 }
2837 return mData[mCurrentChunk].allocate(size, alignment);
2838 }
2839
2840 static const size_t CHUNK_SIZE = 128*1024;
2841 // Note: this class does not deallocate its
2842 // memory when it's destroyed. It depends upon
2843 // its parent to deallocate the memory.
2844 struct Chunk {
2845 Chunk() {
2846 mpData = 0;
2847 mSize = 0;
2848 mOffset = 0;
2849 }
2850
2851 Chunk(size_t size) {
2852 mSize = size;
2853 mpData = (char*) malloc(size);
2854 mOffset = 0;
2855 }
2856
2857 ~Chunk() {
2858 // Doesn't deallocate memory.
2859 }
2860
2861 void* allocate(size_t size, size_t alignment) {
2862 size_t alignedOffset = aligned(mOffset, alignment);
2863 void* result = mpData + alignedOffset;
2864 mOffset = alignedOffset + size;
2865 return result;
2866 }
2867
2868 void free() {
2869 if (mpData) {
2870 ::free(mpData);
2871 mpData = 0;
2872 }
2873 }
2874
2875 size_t remainingCapacity(size_t alignment) {
2876 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2877 }
2878
2879 // Assume alignment is a power of two
2880 inline size_t aligned(size_t v, size_t alignment) {
2881 size_t mask = alignment-1;
2882 return (v + mask) & ~mask;
2883 }
2884
2885 char* mpData;
2886 size_t mSize;
2887 size_t mOffset;
2888 };
2889
2890 size_t mCurrentChunk;
2891
2892 Vector<Chunk> mData;
2893 };
2894
Jack Palevich569f1352009-06-29 14:29:08 -07002895 struct VariableInfo;
2896
2897 struct Token {
2898 int hash;
2899 size_t length;
2900 char* pText;
2901 tokenid_t id;
2902
2903 // Current values for the token
2904 char* mpMacroDefinition;
2905 VariableInfo* mpVariableInfo;
2906 };
2907
2908 class TokenTable {
2909 public:
2910 // Don't use 0..0xff, allows characters and operators to be tokens too.
2911
2912 static const int TOKEN_BASE = 0x100;
2913 TokenTable() {
2914 mpMap = hashmapCreate(128, hashFn, equalsFn);
2915 }
2916
2917 ~TokenTable() {
2918 hashmapFree(mpMap);
2919 }
2920
2921 void setArena(Arena* pArena) {
2922 mpArena = pArena;
2923 }
2924
2925 // Returns a token for a given string of characters.
2926 tokenid_t intern(const char* pText, size_t length) {
2927 Token probe;
2928 int hash = hashmapHash((void*) pText, length);
2929 {
2930 Token probe;
2931 probe.hash = hash;
2932 probe.length = length;
2933 probe.pText = (char*) pText;
2934 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2935 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002936 return pValue->id;
2937 }
2938 }
2939
2940 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2941 memset(pToken, 0, sizeof(*pToken));
2942 pToken->hash = hash;
2943 pToken->length = length;
2944 pToken->pText = (char*) mpArena->alloc(length + 1);
2945 memcpy(pToken->pText, pText, length);
2946 pToken->pText[length] = 0;
2947 pToken->id = mTokens.size() + TOKEN_BASE;
2948 mTokens.push_back(pToken);
2949 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002950 return pToken->id;
2951 }
2952
2953 // Return the Token for a given tokenid.
2954 Token& operator[](tokenid_t id) {
2955 return *mTokens[id - TOKEN_BASE];
2956 }
2957
2958 inline size_t size() {
2959 return mTokens.size();
2960 }
2961
2962 private:
2963
2964 static int hashFn(void* pKey) {
2965 Token* pToken = (Token*) pKey;
2966 return pToken->hash;
2967 }
2968
2969 static bool equalsFn(void* keyA, void* keyB) {
2970 Token* pTokenA = (Token*) keyA;
2971 Token* pTokenB = (Token*) keyB;
2972 // Don't need to compare hash values, they should always be equal
2973 return pTokenA->length == pTokenB->length
2974 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2975 }
2976
2977 Hashmap* mpMap;
2978 Vector<Token*> mTokens;
2979 Arena* mpArena;
2980 };
2981
Jack Palevich1cdef202009-05-22 12:06:27 -07002982 class InputStream {
2983 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002984 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002985 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002986 };
2987
2988 class TextInputStream : public InputStream {
2989 public:
2990 TextInputStream(const char* text, size_t textLength)
2991 : pText(text), mTextLength(textLength), mPosition(0) {
2992 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002993
Jack Palevichdc456462009-07-16 16:50:56 -07002994 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002995 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2996 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002997
Jack Palevichdc456462009-07-16 16:50:56 -07002998 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002999 const char* pText;
3000 size_t mTextLength;
3001 size_t mPosition;
3002 };
3003
Jack Palevicheedf9d22009-06-04 16:23:40 -07003004 class String {
3005 public:
3006 String() {
3007 mpBase = 0;
3008 mUsed = 0;
3009 mSize = 0;
3010 }
3011
Jack Palevich303d8ff2009-06-11 19:06:24 -07003012 String(const char* item, int len, bool adopt) {
3013 if (len < 0) {
3014 len = strlen(item);
3015 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003016 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003017 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003018 mUsed = len;
3019 mSize = len + 1;
3020 } else {
3021 mpBase = 0;
3022 mUsed = 0;
3023 mSize = 0;
3024 appendBytes(item, len);
3025 }
3026 }
3027
Jack Palevich303d8ff2009-06-11 19:06:24 -07003028 String(const String& other) {
3029 mpBase = 0;
3030 mUsed = 0;
3031 mSize = 0;
3032 appendBytes(other.getUnwrapped(), other.len());
3033 }
3034
Jack Palevicheedf9d22009-06-04 16:23:40 -07003035 ~String() {
3036 if (mpBase) {
3037 free(mpBase);
3038 }
3039 }
3040
Jack Palevicha6baa232009-06-12 11:25:59 -07003041 String& operator=(const String& other) {
3042 clear();
3043 appendBytes(other.getUnwrapped(), other.len());
3044 return *this;
3045 }
3046
Jack Palevich303d8ff2009-06-11 19:06:24 -07003047 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003048 return mpBase;
3049 }
3050
Jack Palevich303d8ff2009-06-11 19:06:24 -07003051 void clear() {
3052 mUsed = 0;
3053 if (mSize > 0) {
3054 mpBase[0] = 0;
3055 }
3056 }
3057
Jack Palevicheedf9d22009-06-04 16:23:40 -07003058 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003059 appendBytes(s, strlen(s));
3060 }
3061
3062 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003063 memcpy(ensure(n), s, n + 1);
3064 }
3065
3066 void append(char c) {
3067 * ensure(1) = c;
3068 }
3069
Jack Palevich86351982009-06-30 18:09:56 -07003070 void append(String& other) {
3071 appendBytes(other.getUnwrapped(), other.len());
3072 }
3073
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003074 char* orphan() {
3075 char* result = mpBase;
3076 mpBase = 0;
3077 mUsed = 0;
3078 mSize = 0;
3079 return result;
3080 }
3081
Jack Palevicheedf9d22009-06-04 16:23:40 -07003082 void printf(const char* fmt,...) {
3083 va_list ap;
3084 va_start(ap, fmt);
3085 vprintf(fmt, ap);
3086 va_end(ap);
3087 }
3088
3089 void vprintf(const char* fmt, va_list ap) {
3090 char* temp;
3091 int numChars = vasprintf(&temp, fmt, ap);
3092 memcpy(ensure(numChars), temp, numChars+1);
3093 free(temp);
3094 }
3095
Jack Palevich303d8ff2009-06-11 19:06:24 -07003096 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003097 return mUsed;
3098 }
3099
3100 private:
3101 char* ensure(int n) {
3102 size_t newUsed = mUsed + n;
3103 if (newUsed > mSize) {
3104 size_t newSize = mSize * 2 + 10;
3105 if (newSize < newUsed) {
3106 newSize = newUsed;
3107 }
3108 mpBase = (char*) realloc(mpBase, newSize + 1);
3109 mSize = newSize;
3110 }
3111 mpBase[newUsed] = '\0';
3112 char* result = mpBase + mUsed;
3113 mUsed = newUsed;
3114 return result;
3115 }
3116
3117 char* mpBase;
3118 size_t mUsed;
3119 size_t mSize;
3120 };
3121
Jack Palevich569f1352009-06-29 14:29:08 -07003122 void internKeywords() {
3123 // Note: order has to match TOK_ constants
3124 static const char* keywords[] = {
3125 "int",
3126 "char",
3127 "void",
3128 "if",
3129 "else",
3130 "while",
3131 "break",
3132 "return",
3133 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003134 "auto",
3135 "case",
3136 "const",
3137 "continue",
3138 "default",
3139 "do",
3140 "double",
3141 "enum",
3142 "extern",
3143 "float",
3144 "goto",
3145 "long",
3146 "register",
3147 "short",
3148 "signed",
3149 "sizeof",
3150 "static",
3151 "struct",
3152 "switch",
3153 "typedef",
3154 "union",
3155 "unsigned",
3156 "volatile",
3157 "_Bool",
3158 "_Complex",
3159 "_Imaginary",
3160 "inline",
3161 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003162
3163 // predefined tokens that can also be symbols start here:
3164 "pragma",
3165 "define",
3166 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003167 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003168
Jack Palevich569f1352009-06-29 14:29:08 -07003169 for(int i = 0; keywords[i]; i++) {
3170 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003171 }
Jack Palevich569f1352009-06-29 14:29:08 -07003172 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003173
Jack Palevich36d94142009-06-08 15:55:32 -07003174 struct InputState {
3175 InputStream* pStream;
3176 int oldCh;
3177 };
3178
Jack Palevich2db168f2009-06-11 14:29:47 -07003179 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003180 void* pAddress;
3181 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003182 tokenid_t tok;
3183 size_t level;
3184 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003185 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003186 };
3187
Jack Palevich303d8ff2009-06-11 19:06:24 -07003188 class SymbolStack {
3189 public:
3190 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003191 mpArena = 0;
3192 mpTokenTable = 0;
3193 }
3194
3195 void setArena(Arena* pArena) {
3196 mpArena = pArena;
3197 }
3198
3199 void setTokenTable(TokenTable* pTokenTable) {
3200 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003201 }
3202
3203 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003204 Mark mark;
3205 mark.mArenaMark = mpArena->mark();
3206 mark.mSymbolHead = mStack.size();
3207 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003208 }
3209
3210 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003211 // Undo any shadowing that was done:
3212 Mark mark = mLevelStack.back();
3213 mLevelStack.pop_back();
3214 while (mStack.size() > mark.mSymbolHead) {
3215 VariableInfo* pV = mStack.back();
3216 mStack.pop_back();
3217 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003218 }
Jack Palevich569f1352009-06-29 14:29:08 -07003219 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003220 }
3221
Jack Palevich569f1352009-06-29 14:29:08 -07003222 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3223 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3224 return pV && pV->level == level();
3225 }
3226
3227 VariableInfo* add(tokenid_t tok) {
3228 Token& token = (*mpTokenTable)[tok];
3229 VariableInfo* pOldV = token.mpVariableInfo;
3230 VariableInfo* pNewV =
3231 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3232 memset(pNewV, 0, sizeof(VariableInfo));
3233 pNewV->tok = tok;
3234 pNewV->level = level();
3235 pNewV->pOldDefinition = pOldV;
3236 token.mpVariableInfo = pNewV;
3237 mStack.push_back(pNewV);
3238 return pNewV;
3239 }
3240
Jack Palevich86351982009-06-30 18:09:56 -07003241 VariableInfo* add(Type* pType) {
3242 VariableInfo* pVI = add(pType->id);
3243 pVI->pType = pType;
3244 return pVI;
3245 }
3246
Jack Palevich569f1352009-06-29 14:29:08 -07003247 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3248 for (size_t i = 0; i < mStack.size(); i++) {
3249 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003250 break;
3251 }
3252 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003253 }
3254
Jack Palevich303d8ff2009-06-11 19:06:24 -07003255 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003256 inline size_t level() {
3257 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003258 }
3259
Jack Palevich569f1352009-06-29 14:29:08 -07003260 struct Mark {
3261 Arena::Mark mArenaMark;
3262 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003263 };
3264
Jack Palevich569f1352009-06-29 14:29:08 -07003265 Arena* mpArena;
3266 TokenTable* mpTokenTable;
3267 Vector<VariableInfo*> mStack;
3268 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003269 };
Jack Palevich36d94142009-06-08 15:55:32 -07003270
3271 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003272 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003273 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003274 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003275 int tokl; // token operator level
3276 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003277 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003278 intptr_t loc; // local variable index
3279 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003280 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003281 char* dptr; // Macro state: Points to macro text during macro playback.
3282 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003283 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003284 ACCSymbolLookupFn mpSymbolLookupFn;
3285 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003286
3287 // Arena for the duration of the compile
3288 Arena mGlobalArena;
3289 // Arena for data that's only needed when compiling a single function
3290 Arena mLocalArena;
3291
Jack Palevich2ff5c222009-07-23 15:11:22 -07003292 Arena* mpCurrentArena;
3293
Jack Palevich569f1352009-06-29 14:29:08 -07003294 TokenTable mTokenTable;
3295 SymbolStack mGlobals;
3296 SymbolStack mLocals;
3297
Jack Palevich40600de2009-07-01 15:32:35 -07003298 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003299 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003300 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003301 Type* mkpChar; // char
3302 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003303 Type* mkpFloat;
3304 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003305 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003306 Type* mkpIntPtr;
3307 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003308 Type* mkpFloatPtr;
3309 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003310 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003311
Jack Palevich36d94142009-06-08 15:55:32 -07003312 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003313 int mLineNumber;
3314 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003315
3316 CodeBuf codeBuf;
3317 CodeGenerator* pGen;
3318
Jack Palevicheedf9d22009-06-04 16:23:40 -07003319 String mErrorBuf;
3320
Jack Palevicheedf9d22009-06-04 16:23:40 -07003321 String mPragmas;
3322 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003323 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003324
Jack Palevich21a15a22009-05-11 14:49:29 -07003325 static const int ALLOC_SIZE = 99999;
3326
Jack Palevich303d8ff2009-06-11 19:06:24 -07003327 static const int TOK_DUMMY = 1;
3328 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003329 static const int TOK_NUM_FLOAT = 3;
3330 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003331 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003332
3333 // 3..255 are character and/or operators
3334
Jack Palevich2db168f2009-06-11 14:29:47 -07003335 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003336 // Order has to match string list in "internKeywords".
3337 enum {
3338 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3339 TOK_INT = TOK_KEYWORD,
3340 TOK_CHAR,
3341 TOK_VOID,
3342 TOK_IF,
3343 TOK_ELSE,
3344 TOK_WHILE,
3345 TOK_BREAK,
3346 TOK_RETURN,
3347 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003348 TOK_AUTO,
3349 TOK_CASE,
3350 TOK_CONST,
3351 TOK_CONTINUE,
3352 TOK_DEFAULT,
3353 TOK_DO,
3354 TOK_DOUBLE,
3355 TOK_ENUM,
3356 TOK_EXTERN,
3357 TOK_FLOAT,
3358 TOK_GOTO,
3359 TOK_LONG,
3360 TOK_REGISTER,
3361 TOK_SHORT,
3362 TOK_SIGNED,
3363 TOK_SIZEOF,
3364 TOK_STATIC,
3365 TOK_STRUCT,
3366 TOK_SWITCH,
3367 TOK_TYPEDEF,
3368 TOK_UNION,
3369 TOK_UNSIGNED,
3370 TOK_VOLATILE,
3371 TOK__BOOL,
3372 TOK__COMPLEX,
3373 TOK__IMAGINARY,
3374 TOK_INLINE,
3375 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003376
3377 // Symbols start after keywords
3378
3379 TOK_SYMBOL,
3380 TOK_PRAGMA = TOK_SYMBOL,
3381 TOK_DEFINE,
3382 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003383 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003384
3385 static const int LOCAL = 0x200;
3386
3387 static const int SYM_FORWARD = 0;
3388 static const int SYM_DEFINE = 1;
3389
3390 /* tokens in string heap */
3391 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003392
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003393 static const int OP_INCREMENT = 0;
3394 static const int OP_DECREMENT = 1;
3395 static const int OP_MUL = 2;
3396 static const int OP_DIV = 3;
3397 static const int OP_MOD = 4;
3398 static const int OP_PLUS = 5;
3399 static const int OP_MINUS = 6;
3400 static const int OP_SHIFT_LEFT = 7;
3401 static const int OP_SHIFT_RIGHT = 8;
3402 static const int OP_LESS_EQUAL = 9;
3403 static const int OP_GREATER_EQUAL = 10;
3404 static const int OP_LESS = 11;
3405 static const int OP_GREATER = 12;
3406 static const int OP_EQUALS = 13;
3407 static const int OP_NOT_EQUALS = 14;
3408 static const int OP_LOGICAL_AND = 15;
3409 static const int OP_LOGICAL_OR = 16;
3410 static const int OP_BIT_AND = 17;
3411 static const int OP_BIT_XOR = 18;
3412 static const int OP_BIT_OR = 19;
3413 static const int OP_BIT_NOT = 20;
3414 static const int OP_LOGICAL_NOT = 21;
3415 static const int OP_COUNT = 22;
3416
3417 /* Operators are searched from front, the two-character operators appear
3418 * before the single-character operators with the same first character.
3419 * @ is used to pad out single-character operators.
3420 */
3421 static const char* operatorChars;
3422 static const char operatorLevel[];
3423
Jack Palevich569f1352009-06-29 14:29:08 -07003424 /* Called when we detect an internal problem. Does nothing in production.
3425 *
3426 */
3427 void internalError() {
3428 * (char*) 0 = 0;
3429 }
3430
Jack Palevich86351982009-06-30 18:09:56 -07003431 void assert(bool isTrue) {
3432 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003433 internalError();
3434 }
Jack Palevich86351982009-06-30 18:09:56 -07003435 }
3436
Jack Palevich40600de2009-07-01 15:32:35 -07003437 bool isSymbol(tokenid_t t) {
3438 return t >= TOK_SYMBOL &&
3439 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3440 }
3441
3442 bool isSymbolOrKeyword(tokenid_t t) {
3443 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003444 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003445 }
3446
Jack Palevich86351982009-06-30 18:09:56 -07003447 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003448 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003449 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3450 if (pV && pV->tok != t) {
3451 internalError();
3452 }
3453 return pV;
3454 }
3455
3456 inline bool isDefined(tokenid_t t) {
3457 return t >= TOK_SYMBOL && VI(t) != 0;
3458 }
3459
Jack Palevich40600de2009-07-01 15:32:35 -07003460 const char* nameof(tokenid_t t) {
3461 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003462 return mTokenTable[t].pText;
3463 }
3464
Jack Palevich21a15a22009-05-11 14:49:29 -07003465 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003466 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003467 }
3468
3469 void inp() {
3470 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003471 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003472 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003473 dptr = 0;
3474 ch = dch;
3475 }
Jack Palevichdc456462009-07-16 16:50:56 -07003476 } else {
3477 if (mbBumpLine) {
3478 mLineNumber++;
3479 mbBumpLine = false;
3480 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003481 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003482 if (ch == '\n') {
3483 mbBumpLine = true;
3484 }
3485 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003486#if 0
3487 printf("ch='%c' 0x%x\n", ch, ch);
3488#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003489 }
3490
3491 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003492 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003493 }
3494
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003495 int decodeHex(int c) {
3496 if (isdigit(c)) {
3497 c -= '0';
3498 } else if (c <= 'F') {
3499 c = c - 'A' + 10;
3500 } else {
3501 c =c - 'a' + 10;
3502 }
3503 return c;
3504 }
3505
Jack Palevichb4758ff2009-06-12 12:49:14 -07003506 /* read a character constant, advances ch to after end of constant */
3507 int getq() {
3508 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003509 if (ch == '\\') {
3510 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003511 if (isoctal(ch)) {
3512 // 1 to 3 octal characters.
3513 val = 0;
3514 for(int i = 0; i < 3; i++) {
3515 if (isoctal(ch)) {
3516 val = (val << 3) + ch - '0';
3517 inp();
3518 }
3519 }
3520 return val;
3521 } else if (ch == 'x' || ch == 'X') {
3522 // N hex chars
3523 inp();
3524 if (! isxdigit(ch)) {
3525 error("'x' character escape requires at least one digit.");
3526 } else {
3527 val = 0;
3528 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003529 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003530 inp();
3531 }
3532 }
3533 } else {
3534 int val = ch;
3535 switch (ch) {
3536 case 'a':
3537 val = '\a';
3538 break;
3539 case 'b':
3540 val = '\b';
3541 break;
3542 case 'f':
3543 val = '\f';
3544 break;
3545 case 'n':
3546 val = '\n';
3547 break;
3548 case 'r':
3549 val = '\r';
3550 break;
3551 case 't':
3552 val = '\t';
3553 break;
3554 case 'v':
3555 val = '\v';
3556 break;
3557 case '\\':
3558 val = '\\';
3559 break;
3560 case '\'':
3561 val = '\'';
3562 break;
3563 case '"':
3564 val = '"';
3565 break;
3566 case '?':
3567 val = '?';
3568 break;
3569 default:
3570 error("Undefined character escape %c", ch);
3571 break;
3572 }
3573 inp();
3574 return val;
3575 }
3576 } else {
3577 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003578 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003579 return val;
3580 }
3581
3582 static bool isoctal(int ch) {
3583 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003584 }
3585
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003586 bool acceptCh(int c) {
3587 bool result = c == ch;
3588 if (result) {
3589 pdef(ch);
3590 inp();
3591 }
3592 return result;
3593 }
3594
3595 bool acceptDigitsCh() {
3596 bool result = false;
3597 while (isdigit(ch)) {
3598 result = true;
3599 pdef(ch);
3600 inp();
3601 }
3602 return result;
3603 }
3604
3605 void parseFloat() {
3606 tok = TOK_NUM_DOUBLE;
3607 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003608 if(mTokenString.len() == 0) {
3609 mTokenString.append('0');
3610 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003611 acceptCh('.');
3612 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003613 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003614 acceptCh('-') || acceptCh('+');
3615 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003616 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003617 if (ch == 'f' || ch == 'F') {
3618 tok = TOK_NUM_FLOAT;
3619 inp();
3620 } else if (ch == 'l' || ch == 'L') {
3621 inp();
3622 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003623 }
3624 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003625 char* pEnd = pText + strlen(pText);
3626 char* pEndPtr = 0;
3627 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003628 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003629 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003630 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003631 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003632 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003633 if (errno || pEndPtr != pEnd) {
3634 error("Can't parse constant: %s", pText);
3635 }
3636 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003637 }
3638
Jack Palevich21a15a22009-05-11 14:49:29 -07003639 void next() {
3640 int l, a;
3641
Jack Palevich546b2242009-05-13 15:10:04 -07003642 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003643 if (ch == '#') {
3644 inp();
3645 next();
3646 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003647 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003648 } else if (tok == TOK_PRAGMA) {
3649 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003650 } else if (tok == TOK_LINE) {
3651 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003652 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003653 error("Unsupported preprocessor directive \"%s\"",
3654 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003656 }
3657 inp();
3658 }
3659 tokl = 0;
3660 tok = ch;
3661 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003662 if (isdigit(ch) || ch == '.') {
3663 // Start of a numeric constant. Could be integer, float, or
3664 // double, won't know until we look further.
3665 mTokenString.clear();
3666 pdef(ch);
3667 inp();
3668 int base = 10;
3669 if (tok == '0') {
3670 if (ch == 'x' || ch == 'X') {
3671 base = 16;
3672 tok = TOK_NUM;
3673 tokc = 0;
3674 inp();
3675 while ( isxdigit(ch) ) {
3676 tokc = (tokc << 4) + decodeHex(ch);
3677 inp();
3678 }
3679 } else if (isoctal(ch)){
3680 base = 8;
3681 tok = TOK_NUM;
3682 tokc = 0;
3683 while ( isoctal(ch) ) {
3684 tokc = (tokc << 3) + (ch - '0');
3685 inp();
3686 }
3687 }
3688 } else if (isdigit(tok)){
3689 acceptDigitsCh();
3690 }
3691 if (base == 10) {
3692 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3693 parseFloat();
3694 } else {
3695 // It's an integer constant
3696 char* pText = mTokenString.getUnwrapped();
3697 char* pEnd = pText + strlen(pText);
3698 char* pEndPtr = 0;
3699 errno = 0;
3700 tokc = strtol(pText, &pEndPtr, base);
3701 if (errno || pEndPtr != pEnd) {
3702 error("Can't parse constant: %s %d %d", pText, base, errno);
3703 }
3704 tok = TOK_NUM;
3705 }
3706 }
3707 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003708 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003709 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003710 pdef(ch);
3711 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003712 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003713 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3714 // Is this a macro?
3715 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3716 if (pMacroDefinition) {
3717 // Yes, it is a macro
3718 dptr = pMacroDefinition;
3719 dch = ch;
3720 inp();
3721 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003722 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003723 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003724 inp();
3725 if (tok == '\'') {
3726 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003727 tokc = getq();
3728 if (ch != '\'') {
3729 error("Expected a ' character, got %c", ch);
3730 } else {
3731 inp();
3732 }
Jack Palevich546b2242009-05-13 15:10:04 -07003733 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003734 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003735 while (ch && ch != EOF) {
3736 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003737 inp();
3738 inp();
3739 if (ch == '/')
3740 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003741 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003742 if (ch == EOF) {
3743 error("End of file inside comment.");
3744 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003745 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003746 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003747 } else if ((tok == '/') & (ch == '/')) {
3748 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003749 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003750 inp();
3751 }
3752 inp();
3753 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003754 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003755 const char* t = operatorChars;
3756 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003757 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003758 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003759 tokl = operatorLevel[opIndex];
3760 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003761 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003762#if 0
3763 printf("%c%c -> tokl=%d tokc=0x%x\n",
3764 l, a, tokl, tokc);
3765#endif
3766 if (a == ch) {
3767 inp();
3768 tok = TOK_DUMMY; /* dummy token for double tokens */
3769 }
Jack Palevich0c017742009-07-31 12:00:39 -07003770 /* check for op=, valid for * / % + - << >> & ^ | */
3771 if (ch == '=' &&
3772 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07003773 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07003774 inp();
3775 tok = TOK_OP_ASSIGNMENT;
3776 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003777 break;
3778 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003779 opIndex++;
3780 }
3781 if (l == 0) {
3782 tokl = 0;
3783 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003784 }
3785 }
3786 }
3787#if 0
3788 {
Jack Palevich569f1352009-06-29 14:29:08 -07003789 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003790 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003791 fprintf(stderr, "%s\n", buf.getUnwrapped());
3792 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003793#endif
3794 }
3795
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003796 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003797 next();
3798 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003799 String* pName = new String();
3800 while (isspace(ch)) {
3801 inp();
3802 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003803 if (ch == '(') {
3804 delete pName;
3805 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003806 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003807 }
3808 while (isspace(ch)) {
3809 inp();
3810 }
Jack Palevich569f1352009-06-29 14:29:08 -07003811 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003812 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003813 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003814 inp();
3815 }
Jack Palevich569f1352009-06-29 14:29:08 -07003816 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3817 memcpy(pDefn, value.getUnwrapped(), value.len());
3818 pDefn[value.len()] = 0;
3819 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003820 }
3821
Jack Palevicheedf9d22009-06-04 16:23:40 -07003822 void doPragma() {
3823 // # pragma name(val)
3824 int state = 0;
3825 while(ch != EOF && ch != '\n' && state < 10) {
3826 switch(state) {
3827 case 0:
3828 if (isspace(ch)) {
3829 inp();
3830 } else {
3831 state++;
3832 }
3833 break;
3834 case 1:
3835 if (isalnum(ch)) {
3836 mPragmas.append(ch);
3837 inp();
3838 } else if (ch == '(') {
3839 mPragmas.append(0);
3840 inp();
3841 state++;
3842 } else {
3843 state = 11;
3844 }
3845 break;
3846 case 2:
3847 if (isalnum(ch)) {
3848 mPragmas.append(ch);
3849 inp();
3850 } else if (ch == ')') {
3851 mPragmas.append(0);
3852 inp();
3853 state = 10;
3854 } else {
3855 state = 11;
3856 }
3857 break;
3858 }
3859 }
3860 if(state != 10) {
3861 error("Unexpected pragma syntax");
3862 }
3863 mPragmaStringCount += 2;
3864 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003865
Jack Palevichdc456462009-07-16 16:50:56 -07003866 void doLine() {
3867 // # line number { "filename "}
3868 next();
3869 if (tok != TOK_NUM) {
3870 error("Expected a line-number");
3871 } else {
3872 mLineNumber = tokc-1; // The end-of-line will increment it.
3873 }
3874 while(ch != EOF && ch != '\n') {
3875 inp();
3876 }
3877 }
3878
Jack Palevichac0e95e2009-05-29 13:53:44 -07003879 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003880 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003881 mErrorBuf.vprintf(fmt, ap);
3882 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003883 }
3884
Jack Palevich8b0624c2009-05-20 12:12:06 -07003885 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 if (tok != c) {
3887 error("'%c' expected", c);
3888 }
3889 next();
3890 }
3891
Jack Palevich86351982009-06-30 18:09:56 -07003892 bool accept(intptr_t c) {
3893 if (tok == c) {
3894 next();
3895 return true;
3896 }
3897 return false;
3898 }
3899
Jack Palevich40600de2009-07-01 15:32:35 -07003900 bool acceptStringLiteral() {
3901 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003902 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003903 // This while loop merges multiple adjacent string constants.
3904 while (tok == '"') {
3905 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003906 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003907 }
3908 if (ch != '"') {
3909 error("Unterminated string constant.");
3910 }
3911 inp();
3912 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003913 }
Jack Palevich40600de2009-07-01 15:32:35 -07003914 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003915 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003916 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003917 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003918
3919 return true;
3920 }
3921 return false;
3922 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003923
Jack Palevichb1544ca2009-07-16 15:09:20 -07003924 void linkGlobal(tokenid_t t, bool isFunction) {
3925 VariableInfo* pVI = VI(t);
3926 void* n = NULL;
3927 if (mpSymbolLookupFn) {
3928 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3929 }
3930 if (pVI->pType == NULL) {
3931 if (isFunction) {
3932 pVI->pType = mkpIntFn;
3933 } else {
3934 pVI->pType = mkpInt;
3935 }
3936 }
3937 pVI->pAddress = n;
3938 }
3939
Jack Palevich29daf572009-07-30 19:38:55 -07003940 void unaryOrAssignment() {
3941 unary();
3942 if (accept('=')) {
3943 checkLVal();
3944 pGen->pushR0();
3945 expr();
3946 pGen->forceR0RVal();
3947 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003948 } else if (tok == TOK_OP_ASSIGNMENT) {
3949 int t = tokc;
3950 next();
3951 checkLVal();
3952 pGen->pushR0();
3953 pGen->forceR0RVal();
3954 pGen->pushR0();
3955 expr();
3956 pGen->forceR0RVal();
3957 pGen->genOp(t);
3958 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003959 }
3960 }
3961
Jack Palevich40600de2009-07-01 15:32:35 -07003962 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003963 */
Jack Palevich29daf572009-07-30 19:38:55 -07003964 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003965 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07003966 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07003967 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003968 if (acceptStringLiteral()) {
3969 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003970 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003971 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003972 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003973 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003974 t = tok;
3975 next();
3976 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003977 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003978 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003979 // Align to 4-byte boundary
3980 glo = (char*) (((intptr_t) glo + 3) & -4);
3981 * (float*) glo = (float) ad;
3982 pGen->loadFloat((int) glo, mkpFloat);
3983 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003984 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003985 // Align to 8-byte boundary
3986 glo = (char*) (((intptr_t) glo + 7) & -8);
3987 * (double*) glo = ad;
3988 pGen->loadFloat((int) glo, mkpDouble);
3989 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003990 } else if (c == 2) {
3991 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07003992 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07003993 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003995 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003996 else if (t == '+') {
3997 // ignore unary plus.
3998 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003999 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004000 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004001 } else if (c == 11) {
4002 // pre increment / pre decrement
4003 unary();
4004 doIncDec(a == OP_INCREMENT, 0);
4005 }
4006 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004007 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004008 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004009 if (pCast) {
4010 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004011 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004012 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004013 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004014 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004015 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004016 skip(')');
4017 }
4018 } else if (t == '*') {
4019 /* This is a pointer dereference.
4020 */
Jack Palevich29daf572009-07-30 19:38:55 -07004021 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004022 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004023 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004024 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004025 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4026 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004027 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004028 } else if (t == EOF ) {
4029 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004030 } else if (t == ';') {
4031 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004032 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004033 // Don't have to do anything special here, the error
4034 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004036 if (!isDefined(t)) {
4037 mGlobals.add(t);
4038 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004039 }
Jack Palevich8df46192009-07-07 14:48:51 -07004040 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004041 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004042 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004043 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004044 linkGlobal(t, tok == '(');
4045 n = (intptr_t) pVI->pAddress;
4046 if (!n && tok != '(') {
4047 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004048 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004049 }
Jack Palevich29daf572009-07-30 19:38:55 -07004050 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004051 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004052 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004053 linkGlobal(t, false);
4054 n = (intptr_t) pVI->pAddress;
4055 if (!n) {
4056 error("Undeclared variable %s\n", nameof(t));
4057 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004058 }
Jack Palevich5b659092009-07-31 14:55:07 -07004059 }
4060 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004061 Type* pVal;
4062 ExpressionType et;
4063 if (pVI->pType->tag == TY_ARRAY) {
4064 pVal = pVI->pType;
4065 et = ET_RVALUE;
4066 } else {
4067 pVal = createPtrType(pVI->pType);
4068 et = ET_LVALUE;
4069 }
Jack Palevich5b659092009-07-31 14:55:07 -07004070 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004071 int tag = pVal->pHead->tag;
4072 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004073 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004074 }
Jack Palevich5b659092009-07-31 14:55:07 -07004075 pGen->leaR0(n, pVal, et);
4076 } else {
4077 pVI->pForward = (void*) pGen->leaForward(
4078 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004079 }
4080 }
4081 }
4082
Jack Palevich5b659092009-07-31 14:55:07 -07004083 /* Now handle postfix operators */
4084 for(;;) {
4085 if (tokl == 11) {
4086 // post inc / post dec
4087 doIncDec(tokc == OP_INCREMENT, true);
4088 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004089 } else if (accept('[')) {
4090 // Array reference
4091 pGen->forceR0RVal();
4092 pGen->pushR0();
4093 commaExpr();
4094 pGen->forceR0RVal();
4095 pGen->genOp(OP_PLUS);
4096 doPointer();
4097 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004098 } else if (accept('(')) {
4099 /* function call */
4100 Type* pDecl = NULL;
4101 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004102 Type* pFn = pGen->getR0Type();
4103 assert(pFn->tag == TY_POINTER);
4104 assert(pFn->pHead->tag == TY_FUNC);
4105 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004106 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004107 Type* pArgList = pDecl->pTail;
4108 bool varArgs = pArgList == NULL;
4109 /* push args and invert order */
4110 a = pGen->beginFunctionCallArguments();
4111 int l = 0;
4112 int argCount = 0;
4113 while (tok != ')' && tok != EOF) {
4114 if (! varArgs && !pArgList) {
4115 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004116 }
Jack Palevich5b659092009-07-31 14:55:07 -07004117 expr();
4118 pGen->forceR0RVal();
4119 Type* pTargetType;
4120 if (pArgList) {
4121 pTargetType = pArgList->pHead;
4122 pArgList = pArgList->pTail;
4123 } else {
4124 // This is a ... function, just pass arguments in their
4125 // natural type.
4126 pTargetType = pGen->getR0Type();
4127 if (pTargetType->tag == TY_FLOAT) {
4128 pTargetType = mkpDouble;
4129 }
4130 }
4131 if (pTargetType->tag == TY_VOID) {
4132 error("Can't pass void value for argument %d",
4133 argCount + 1);
4134 } else {
4135 l += pGen->storeR0ToArg(l, pTargetType);
4136 }
4137 if (accept(',')) {
4138 // fine
4139 } else if ( tok != ')') {
4140 error("Expected ',' or ')'");
4141 }
4142 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004143 }
Jack Palevich5b659092009-07-31 14:55:07 -07004144 if (! varArgs && pArgList) {
4145 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004146 }
Jack Palevich5b659092009-07-31 14:55:07 -07004147 pGen->endFunctionCallArguments(pDecl, a, l);
4148 skip(')');
4149 pGen->callIndirect(l, pDecl);
4150 pGen->adjustStackAfterCall(pDecl, l, true);
4151 } else {
4152 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004153 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 }
4155 }
4156
Jack Palevichaaac9282009-07-31 14:34:34 -07004157 void doIncDec(int isInc, int isPost) {
4158 // R0 already has the lval
4159 checkLVal();
4160 int lit = isInc ? 1 : -1;
4161 pGen->pushR0();
4162 pGen->loadR0FromR0();
4163 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004164 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4165 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004166 error("++/-- illegal for this type. %d", tag);
4167 }
4168 if (isPost) {
4169 pGen->over();
4170 pGen->pushR0();
4171 pGen->li(lit);
4172 pGen->genOp(OP_PLUS);
4173 pGen->storeR0ToTOS();
4174 pGen->popR0();
4175 } else {
4176 pGen->pushR0();
4177 pGen->li(lit);
4178 pGen->genOp(OP_PLUS);
4179 pGen->over();
4180 pGen->storeR0ToTOS();
4181 pGen->popR0();
4182 }
4183 }
4184
Jack Palevich47cbea92009-07-31 15:25:53 -07004185 void doPointer() {
4186 pGen->forceR0RVal();
4187 Type* pR0Type = pGen->getR0Type();
4188 if (pR0Type->tag != TY_POINTER) {
4189 error("Expected a pointer type.");
4190 } else {
4191 if (pR0Type->pHead->tag != TY_FUNC) {
4192 pGen->setR0ExpressionType(ET_LVALUE);
4193 }
4194 }
4195 }
4196
Jack Palevich40600de2009-07-01 15:32:35 -07004197 /* Recursive descent parser for binary operations.
4198 */
4199 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004200 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004201 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004202 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004203 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004204 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004205 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004206 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004207 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004208 t = tokc;
4209 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004210 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004211 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004212 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004213 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004214 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004215 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004216 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004217 // Check for syntax error.
4218 if (pGen->getR0Type() == NULL) {
4219 // We failed to parse a right-hand argument.
4220 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004221 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004222 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004223 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004224 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004225 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004226 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004227 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004228 }
4229 }
4230 }
4231 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004232 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004233 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004234 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004235 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004236 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004237 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004238 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004239 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004240 }
4241 }
4242 }
4243
Jack Palevich43aaee32009-07-31 14:01:37 -07004244 void commaExpr() {
4245 for(;;) {
4246 expr();
4247 if (!accept(',')) {
4248 break;
4249 }
4250 }
4251 }
4252
Jack Palevich21a15a22009-05-11 14:49:29 -07004253 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004254 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004255 }
4256
4257 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004258 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004259 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004260 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004261 }
4262
Jack Palevicha6baa232009-06-12 11:25:59 -07004263 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004264 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004265
Jack Palevich95727a02009-07-06 12:07:15 -07004266 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004267 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004268 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004269 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004270 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004271 next();
4272 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004273 a = test_expr();
4274 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004275 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004276 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004277 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004278 n = pGen->gjmp(0); /* jmp */
4279 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004280 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004281 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004282 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004283 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004284 }
Jack Palevich546b2242009-05-13 15:10:04 -07004285 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004286 t = tok;
4287 next();
4288 skip('(');
4289 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004290 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004291 a = test_expr();
4292 } else {
4293 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004294 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004295 skip(';');
4296 n = codeBuf.getPC();
4297 a = 0;
4298 if (tok != ';')
4299 a = test_expr();
4300 skip(';');
4301 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004302 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004303 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004304 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004305 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004306 n = t + 4;
4307 }
4308 }
4309 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004310 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004311 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004312 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004313 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004314 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004315 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004316 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004317 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004318 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004319 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004320 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004321 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004322 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004323 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004324 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004325 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004326 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004327 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004328 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004329 if (pReturnType->tag == TY_VOID) {
4330 error("Must not return a value from a void function");
4331 } else {
4332 pGen->convertR0(pReturnType);
4333 }
4334 } else {
4335 if (pReturnType->tag != TY_VOID) {
4336 error("Must specify a value here");
4337 }
Jack Palevich8df46192009-07-07 14:48:51 -07004338 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004339 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004340 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004341 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004342 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004343 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004344 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004345 }
4346 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004347
Jack Palevicha8f427f2009-07-13 18:40:08 -07004348 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004349 if (a == b) {
4350 return true;
4351 }
4352 if (a == NULL || b == NULL) {
4353 return false;
4354 }
4355 TypeTag at = a->tag;
4356 if (at != b->tag) {
4357 return false;
4358 }
4359 if (at == TY_POINTER) {
4360 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004361 } else if (at == TY_ARRAY) {
4362 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004363 } else if (at == TY_FUNC || at == TY_PARAM) {
4364 return typeEqual(a->pHead, b->pHead)
4365 && typeEqual(a->pTail, b->pTail);
4366 }
4367 return true;
4368 }
4369
Jack Palevich2ff5c222009-07-23 15:11:22 -07004370 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004371 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004372 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004373 memset(pType, 0, sizeof(*pType));
4374 pType->tag = tag;
4375 pType->pHead = pHead;
4376 pType->pTail = pTail;
4377 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004378 }
4379
Jack Palevich2ff5c222009-07-23 15:11:22 -07004380 Type* createPtrType(Type* pType) {
4381 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004382 }
4383
4384 /**
4385 * Try to print a type in declaration order
4386 */
Jack Palevich86351982009-06-30 18:09:56 -07004387 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004388 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004389 if (pType == NULL) {
4390 buffer.appendCStr("null");
4391 return;
4392 }
Jack Palevich3f226492009-07-02 14:46:19 -07004393 decodeTypeImp(buffer, pType);
4394 }
4395
4396 void decodeTypeImp(String& buffer, Type* pType) {
4397 decodeTypeImpPrefix(buffer, pType);
4398
Jack Palevich86351982009-06-30 18:09:56 -07004399 String temp;
4400 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004401 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004402 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004403 }
4404
4405 decodeTypeImpPostfix(buffer, pType);
4406 }
4407
4408 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4409 TypeTag tag = pType->tag;
4410
Jack Palevich37c54bd2009-07-14 18:35:36 -07004411 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004412 switch (tag) {
4413 case TY_INT:
4414 buffer.appendCStr("int");
4415 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004416 case TY_SHORT:
4417 buffer.appendCStr("short");
4418 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004419 case TY_CHAR:
4420 buffer.appendCStr("char");
4421 break;
4422 case TY_VOID:
4423 buffer.appendCStr("void");
4424 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004425 case TY_FLOAT:
4426 buffer.appendCStr("float");
4427 break;
4428 case TY_DOUBLE:
4429 buffer.appendCStr("double");
4430 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004431 default:
4432 break;
4433 }
Jack Palevich86351982009-06-30 18:09:56 -07004434 buffer.append(' ');
4435 }
Jack Palevich3f226492009-07-02 14:46:19 -07004436
4437 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004438 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004439 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004440 case TY_SHORT:
4441 break;
Jack Palevich86351982009-06-30 18:09:56 -07004442 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004443 break;
4444 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004445 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004446 case TY_FLOAT:
4447 break;
4448 case TY_DOUBLE:
4449 break;
Jack Palevich86351982009-06-30 18:09:56 -07004450 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004451 decodeTypeImpPrefix(buffer, pType->pHead);
4452 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4453 buffer.append('(');
4454 }
4455 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004456 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004457 case TY_ARRAY:
4458 decodeTypeImpPrefix(buffer, pType->pHead);
4459 break;
Jack Palevich86351982009-06-30 18:09:56 -07004460 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004461 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004462 break;
4463 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004464 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004465 break;
4466 default:
4467 String temp;
4468 temp.printf("Unknown tag %d", pType->tag);
4469 buffer.append(temp);
4470 break;
4471 }
Jack Palevich3f226492009-07-02 14:46:19 -07004472 }
4473
4474 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4475 TypeTag tag = pType->tag;
4476
4477 switch(tag) {
4478 case TY_POINTER:
4479 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4480 buffer.append(')');
4481 }
4482 decodeTypeImpPostfix(buffer, pType->pHead);
4483 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004484 case TY_ARRAY:
4485 {
4486 String temp;
4487 temp.printf("[%d]", pType->length);
4488 buffer.append(temp);
4489 }
4490 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004491 case TY_FUNC:
4492 buffer.append('(');
4493 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4494 decodeTypeImp(buffer, pArg);
4495 if (pArg->pTail) {
4496 buffer.appendCStr(", ");
4497 }
4498 }
4499 buffer.append(')');
4500 break;
4501 default:
4502 break;
Jack Palevich86351982009-06-30 18:09:56 -07004503 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004504 }
4505
Jack Palevich86351982009-06-30 18:09:56 -07004506 void printType(Type* pType) {
4507 String buffer;
4508 decodeType(buffer, pType);
4509 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004510 }
4511
Jack Palevich2ff5c222009-07-23 15:11:22 -07004512 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004513 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004514 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004515 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004516 } else if (tok == TOK_SHORT) {
4517 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004518 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004519 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004520 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004521 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004522 } else if (tok == TOK_FLOAT) {
4523 pType = mkpFloat;
4524 } else if (tok == TOK_DOUBLE) {
4525 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004526 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004527 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004528 }
4529 next();
Jack Palevich86351982009-06-30 18:09:56 -07004530 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004531 }
4532
Jack Palevich2ff5c222009-07-23 15:11:22 -07004533 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004534 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004535 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004536 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004537 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004538 if (declName) {
4539 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004540 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004541 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004542
Jack Palevich86351982009-06-30 18:09:56 -07004543 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004544 pType->length = pOldType->length;
4545 } else if (nameRequired) {
4546 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004547 }
Jack Palevich3f226492009-07-02 14:46:19 -07004548 // fprintf(stderr, "Parsed a declaration: ");
4549 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004550 if (reportFailure) {
4551 return NULL;
4552 }
Jack Palevich86351982009-06-30 18:09:56 -07004553 return pType;
4554 }
4555
Jack Palevich2ff5c222009-07-23 15:11:22 -07004556 Type* expectDeclaration(Type* pBaseType) {
4557 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004558 if (! pType) {
4559 error("Expected a declaration");
4560 }
4561 return pType;
4562 }
4563
Jack Palevich3f226492009-07-02 14:46:19 -07004564 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004565 Type* acceptCastTypeDeclaration() {
4566 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004567 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004568 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004569 }
Jack Palevich86351982009-06-30 18:09:56 -07004570 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004571 }
4572
Jack Palevich2ff5c222009-07-23 15:11:22 -07004573 Type* expectCastTypeDeclaration() {
4574 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004575 if (! pType) {
4576 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004577 }
Jack Palevich3f226492009-07-02 14:46:19 -07004578 return pType;
4579 }
4580
4581 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004582 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004583 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004584 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004585 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004586 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004587 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004588 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004589 return pType;
4590 }
4591
4592 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004593 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004594 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004595 // direct-dcl :
4596 // name
4597 // (dcl)
4598 // direct-dcl()
4599 // direct-dcl[]
4600 Type* pNewHead = NULL;
4601 if (accept('(')) {
4602 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004603 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004604 skip(')');
4605 } else if ((declName = acceptSymbol()) != 0) {
4606 if (nameAllowed == false && declName) {
4607 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004608 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004609 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004610 } else if (nameRequired && ! declName) {
4611 String temp;
4612 decodeToken(temp, tok, true);
4613 error("Expected name. Got %s", temp.getUnwrapped());
4614 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004615 }
Jack Palevichb6154502009-08-04 14:56:09 -07004616 for(;;) {
4617 if (accept('(')) {
4618 // Function declaration
4619 Type* pTail = acceptArgs(nameAllowed);
4620 pType = createType(TY_FUNC, pType, pTail);
4621 skip(')');
4622 } if (accept('[')) {
4623 if (tok != ']') {
4624 if (tok != TOK_NUM || tokc <= 0) {
4625 error("Expected positive integer constant");
4626 } else {
4627 Type* pDecayType = createPtrType(pType);
4628 pType = createType(TY_ARRAY, pType, pDecayType);
4629 pType->length = tokc;
4630 }
4631 next();
4632 }
4633 skip(']');
4634 } else {
4635 break;
4636 }
Jack Palevich86351982009-06-30 18:09:56 -07004637 }
Jack Palevich3f226492009-07-02 14:46:19 -07004638
4639 if (pNewHead) {
4640 Type* pA = pNewHead;
4641 while (pA->pHead) {
4642 pA = pA->pHead;
4643 }
4644 pA->pHead = pType;
4645 pType = pNewHead;
4646 }
Jack Palevich86351982009-06-30 18:09:56 -07004647 return pType;
4648 }
4649
Jack Palevich2ff5c222009-07-23 15:11:22 -07004650 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004651 Type* pHead = NULL;
4652 Type* pTail = NULL;
4653 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004654 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004655 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004656 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004657 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004658 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004659 if (!pHead) {
4660 pHead = pParam;
4661 pTail = pParam;
4662 } else {
4663 pTail->pTail = pParam;
4664 pTail = pParam;
4665 }
4666 }
4667 }
4668 if (! accept(',')) {
4669 break;
4670 }
4671 }
4672 return pHead;
4673 }
4674
Jack Palevich2ff5c222009-07-23 15:11:22 -07004675 Type* expectPrimitiveType() {
4676 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004677 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004678 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004679 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004680 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004681 }
Jack Palevich86351982009-06-30 18:09:56 -07004682 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004683 }
4684
Jack Palevichb5e33312009-07-30 19:06:34 -07004685 void checkLVal() {
4686 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4687 error("Expected an lval");
4688 }
4689 }
4690
Jack Palevich86351982009-06-30 18:09:56 -07004691 void addGlobalSymbol(Type* pDecl) {
4692 tokenid_t t = pDecl->id;
4693 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004694 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004695 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004696 }
Jack Palevich86351982009-06-30 18:09:56 -07004697 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004698 }
4699
Jack Palevich86351982009-06-30 18:09:56 -07004700 void reportDuplicate(tokenid_t t) {
4701 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004702 }
4703
Jack Palevich86351982009-06-30 18:09:56 -07004704 void addLocalSymbol(Type* pDecl) {
4705 tokenid_t t = pDecl->id;
4706 if (mLocals.isDefinedAtCurrentLevel(t)) {
4707 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004708 }
Jack Palevich86351982009-06-30 18:09:56 -07004709 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004710 }
4711
Jack Palevich95727a02009-07-06 12:07:15 -07004712 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004713 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004714
Jack Palevich95727a02009-07-06 12:07:15 -07004715 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004716 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004717 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004718 if (!pDecl) {
4719 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004720 }
Jack Palevich86351982009-06-30 18:09:56 -07004721 int variableAddress = 0;
4722 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004723 size_t alignment = pGen->stackAlignmentOf(pDecl);
4724 size_t alignmentMask = ~ (alignment - 1);
4725 size_t sizeOf = pGen->sizeOf(pDecl);
4726 loc = (loc + alignment - 1) & alignmentMask;
4727 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4728 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004729 variableAddress = -loc;
4730 VI(pDecl->id)->pAddress = (void*) variableAddress;
4731 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004732 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004733 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004734 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004735 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004736 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004737 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004738 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004739 if (tok == ',')
4740 next();
4741 }
4742 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004743 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004744 }
4745 }
4746
Jack Palevichf1728be2009-06-12 13:53:51 -07004747 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004748 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004749 }
4750
Jack Palevich37c54bd2009-07-14 18:35:36 -07004751 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004752 if (token == EOF ) {
4753 buffer.printf("EOF");
4754 } else if (token == TOK_NUM) {
4755 buffer.printf("numeric constant");
4756 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004757 if (token < 32) {
4758 buffer.printf("'\\x%02x'", token);
4759 } else {
4760 buffer.printf("'%c'", token);
4761 }
Jack Palevich569f1352009-06-29 14:29:08 -07004762 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004763 if (quote) {
4764 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4765 buffer.printf("keyword \"%s\"", nameof(token));
4766 } else {
4767 buffer.printf("symbol \"%s\"", nameof(token));
4768 }
4769 } else {
4770 buffer.printf("%s", nameof(token));
4771 }
Jack Palevich569f1352009-06-29 14:29:08 -07004772 }
4773 }
4774
Jack Palevich40600de2009-07-01 15:32:35 -07004775 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004776 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004777 if (!result) {
4778 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004779 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004780 error("Expected symbol. Got %s", temp.getUnwrapped());
4781 }
4782 return result;
4783 }
4784
Jack Palevich86351982009-06-30 18:09:56 -07004785 tokenid_t acceptSymbol() {
4786 tokenid_t result = 0;
4787 if (tok >= TOK_SYMBOL) {
4788 result = tok;
4789 next();
Jack Palevich86351982009-06-30 18:09:56 -07004790 }
4791 return result;
4792 }
4793
Jack Palevichb7c81e92009-06-04 19:56:13 -07004794 void globalDeclarations() {
4795 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004796 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004797 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004798 break;
4799 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004800 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004801 if (!pDecl) {
4802 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004803 }
Jack Palevich86351982009-06-30 18:09:56 -07004804 if (! isDefined(pDecl->id)) {
4805 addGlobalSymbol(pDecl);
4806 }
4807 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004808 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004809 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004810 }
Jack Palevich86351982009-06-30 18:09:56 -07004811 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004812 // it's a variable declaration
4813 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004814 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004815 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004816 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004817 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004818 }
Jack Palevich86351982009-06-30 18:09:56 -07004819 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004820 if (tok == TOK_NUM) {
4821 if (name) {
4822 * (int*) name->pAddress = tokc;
4823 }
4824 next();
4825 } else {
4826 error("Expected an integer constant");
4827 }
4828 }
Jack Palevich86351982009-06-30 18:09:56 -07004829 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004830 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004831 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004832 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004833 if (!pDecl) {
4834 break;
4835 }
4836 if (! isDefined(pDecl->id)) {
4837 addGlobalSymbol(pDecl);
4838 }
4839 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004840 }
4841 skip(';');
4842 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004843 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004844 if (accept(';')) {
4845 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004846 } else if (tok != '{') {
4847 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004848 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004849 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004850 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004851 /* patch forward references */
4852 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004853 /* put function address */
4854 name->pAddress = (void*) codeBuf.getPC();
4855 }
4856 // Calculate stack offsets for parameters
4857 mLocals.pushLevel();
4858 intptr_t a = 8;
4859 int argCount = 0;
4860 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4861 Type* pArg = pP->pHead;
4862 addLocalSymbol(pArg);
4863 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004864 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004865 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004866 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004867 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004868 argCount++;
4869 }
4870 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004871 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004872 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004873 block(0, true);
4874 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004875 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004876 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004877 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004878 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004879 }
4880 }
4881 }
4882
Jack Palevich9cbd2262009-07-08 16:48:41 -07004883 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4884 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4885 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004886 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004887 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004888 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004889 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004890 char* result = (char*) base;
4891 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004892 return result;
4893 }
4894
Jack Palevich21a15a22009-05-11 14:49:29 -07004895 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004896 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004897 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004898 pGlobalBase = 0;
4899 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004900 if (pGen) {
4901 delete pGen;
4902 pGen = 0;
4903 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004904 if (file) {
4905 delete file;
4906 file = 0;
4907 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004908 }
4909
Jack Palevich8c246a92009-07-14 21:14:10 -07004910 // One-time initialization, when class is constructed.
4911 void init() {
4912 mpSymbolLookupFn = 0;
4913 mpSymbolLookupContext = 0;
4914 }
4915
Jack Palevich21a15a22009-05-11 14:49:29 -07004916 void clear() {
4917 tok = 0;
4918 tokc = 0;
4919 tokl = 0;
4920 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004921 rsym = 0;
4922 loc = 0;
4923 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004924 dptr = 0;
4925 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004926 file = 0;
4927 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004928 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004929 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004930 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004931 mLineNumber = 1;
4932 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004933 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004934
Jack Palevich22305132009-05-13 10:58:45 -07004935 void setArchitecture(const char* architecture) {
4936 delete pGen;
4937 pGen = 0;
4938
4939 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004940#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004941 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004942 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004943 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004944#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004945#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004946 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004947 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004948 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004949#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004950 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004951 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004952 }
4953 }
4954
4955 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004956#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004957 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004958#elif defined(DEFAULT_X86_CODEGEN)
4959 pGen = new X86CodeGenerator();
4960#endif
4961 }
4962 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004963 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004964 } else {
4965 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004966 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004967 }
4968 }
4969
Jack Palevich77ae76e2009-05-10 19:59:24 -07004970public:
Jack Palevich22305132009-05-13 10:58:45 -07004971 struct args {
4972 args() {
4973 architecture = 0;
4974 }
4975 const char* architecture;
4976 };
4977
Jack Paleviche7b59062009-05-19 17:12:17 -07004978 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004979 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004980 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004981 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004982
Jack Paleviche7b59062009-05-19 17:12:17 -07004983 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004984 cleanup();
4985 }
4986
Jack Palevich8c246a92009-07-14 21:14:10 -07004987 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4988 mpSymbolLookupFn = pFn;
4989 mpSymbolLookupContext = pContext;
4990 }
4991
Jack Palevich1cdef202009-05-22 12:06:27 -07004992 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004993 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004994
Jack Palevich2ff5c222009-07-23 15:11:22 -07004995 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004996 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004997 cleanup();
4998 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004999 mTokenTable.setArena(&mGlobalArena);
5000 mGlobals.setArena(&mGlobalArena);
5001 mGlobals.setTokenTable(&mTokenTable);
5002 mLocals.setArena(&mLocalArena);
5003 mLocals.setTokenTable(&mTokenTable);
5004
5005 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005006 codeBuf.init(ALLOC_SIZE);
5007 setArchitecture(NULL);
5008 if (!pGen) {
5009 return -1;
5010 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005011#ifdef PROVIDE_TRACE_CODEGEN
5012 pGen = new TraceCodeGenerator(pGen);
5013#endif
5014 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005015 pGen->init(&codeBuf);
5016 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005017 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5018 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005019 inp();
5020 next();
5021 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005022 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005023 result = pGen->finishCompile();
5024 if (result == 0) {
5025 if (mErrorBuf.len()) {
5026 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005027 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005028 }
Jack Palevichce105a92009-07-16 14:30:33 -07005029 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005030 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005031 }
5032
Jack Palevich86351982009-06-30 18:09:56 -07005033 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005034 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005035 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005036 mkpChar = createType(TY_CHAR, NULL, NULL);
5037 mkpVoid = createType(TY_VOID, NULL, NULL);
5038 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5039 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5040 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5041 mkpIntPtr = createPtrType(mkpInt);
5042 mkpCharPtr = createPtrType(mkpChar);
5043 mkpFloatPtr = createPtrType(mkpFloat);
5044 mkpDoublePtr = createPtrType(mkpDouble);
5045 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005046 }
5047
Jack Palevicha6baa232009-06-12 11:25:59 -07005048 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005049 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005050 }
5051
Jack Palevich569f1352009-06-29 14:29:08 -07005052 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005053 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005054 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005055 }
5056
Jack Palevich569f1352009-06-29 14:29:08 -07005057 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005058 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005059 error("Undefined forward reference: %s",
5060 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005061 }
5062 return true;
5063 }
5064
Jack Palevich21a15a22009-05-11 14:49:29 -07005065 int dump(FILE* out) {
5066 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5067 return 0;
5068 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005069
Jack Palevicha6535612009-05-13 16:24:17 -07005070 int disassemble(FILE* out) {
5071 return pGen->disassemble(out);
5072 }
5073
Jack Palevich1cdef202009-05-22 12:06:27 -07005074 /* Look through the symbol table to find a symbol.
5075 * If found, return its value.
5076 */
5077 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005078 if (mCompileResult == 0) {
5079 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5080 VariableInfo* pVariableInfo = VI(tok);
5081 if (pVariableInfo) {
5082 return pVariableInfo->pAddress;
5083 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005084 }
5085 return NULL;
5086 }
5087
Jack Palevicheedf9d22009-06-04 16:23:40 -07005088 void getPragmas(ACCsizei* actualStringCount,
5089 ACCsizei maxStringCount, ACCchar** strings) {
5090 int stringCount = mPragmaStringCount;
5091 if (actualStringCount) {
5092 *actualStringCount = stringCount;
5093 }
5094 if (stringCount > maxStringCount) {
5095 stringCount = maxStringCount;
5096 }
5097 if (strings) {
5098 char* pPragmas = mPragmas.getUnwrapped();
5099 while (stringCount-- > 0) {
5100 *strings++ = pPragmas;
5101 pPragmas += strlen(pPragmas) + 1;
5102 }
5103 }
5104 }
5105
Jack Palevichac0e95e2009-05-29 13:53:44 -07005106 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005107 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005108 }
5109
Jack Palevich77ae76e2009-05-10 19:59:24 -07005110};
5111
Jack Paleviche7b59062009-05-19 17:12:17 -07005112const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005113 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5114
Jack Paleviche7b59062009-05-19 17:12:17 -07005115const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005116 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5117 5, 5, /* ==, != */
5118 9, 10, /* &&, || */
5119 6, 7, 8, /* & ^ | */
5120 2, 2 /* ~ ! */
5121 };
5122
Jack Palevich8b0624c2009-05-20 12:12:06 -07005123#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005124FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005125#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005126
Jack Palevich8b0624c2009-05-20 12:12:06 -07005127#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005128const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005129 0x1, // ++
5130 0xff, // --
5131 0xc1af0f, // *
5132 0xf9f79991, // /
5133 0xf9f79991, // % (With manual assist to swap results)
5134 0xc801, // +
5135 0xd8f7c829, // -
5136 0xe0d391, // <<
5137 0xf8d391, // >>
5138 0xe, // <=
5139 0xd, // >=
5140 0xc, // <
5141 0xf, // >
5142 0x4, // ==
5143 0x5, // !=
5144 0x0, // &&
5145 0x1, // ||
5146 0xc821, // &
5147 0xc831, // ^
5148 0xc809, // |
5149 0xd0f7, // ~
5150 0x4 // !
5151};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005152#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005153
Jack Palevich1cdef202009-05-22 12:06:27 -07005154struct ACCscript {
5155 ACCscript() {
5156 text = 0;
5157 textLength = 0;
5158 accError = ACC_NO_ERROR;
5159 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005160
Jack Palevich1cdef202009-05-22 12:06:27 -07005161 ~ACCscript() {
5162 delete text;
5163 }
Jack Palevich546b2242009-05-13 15:10:04 -07005164
Jack Palevich8c246a92009-07-14 21:14:10 -07005165 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5166 compiler.registerSymbolCallback(pFn, pContext);
5167 }
5168
Jack Palevich1cdef202009-05-22 12:06:27 -07005169 void setError(ACCenum error) {
5170 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5171 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005172 }
5173 }
5174
Jack Palevich1cdef202009-05-22 12:06:27 -07005175 ACCenum getError() {
5176 ACCenum result = accError;
5177 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005178 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005179 }
5180
Jack Palevich1cdef202009-05-22 12:06:27 -07005181 Compiler compiler;
5182 char* text;
5183 int textLength;
5184 ACCenum accError;
5185};
5186
5187
5188extern "C"
5189ACCscript* accCreateScript() {
5190 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005191}
Jack Palevich1cdef202009-05-22 12:06:27 -07005192
5193extern "C"
5194ACCenum accGetError( ACCscript* script ) {
5195 return script->getError();
5196}
5197
5198extern "C"
5199void accDeleteScript(ACCscript* script) {
5200 delete script;
5201}
5202
5203extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005204void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5205 ACCvoid* pContext) {
5206 script->registerSymbolCallback(pFn, pContext);
5207}
5208
5209extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005210void accScriptSource(ACCscript* script,
5211 ACCsizei count,
5212 const ACCchar ** string,
5213 const ACCint * length) {
5214 int totalLength = 0;
5215 for(int i = 0; i < count; i++) {
5216 int len = -1;
5217 const ACCchar* s = string[i];
5218 if (length) {
5219 len = length[i];
5220 }
5221 if (len < 0) {
5222 len = strlen(s);
5223 }
5224 totalLength += len;
5225 }
5226 delete script->text;
5227 char* text = new char[totalLength + 1];
5228 script->text = text;
5229 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005230 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005231 for(int i = 0; i < count; i++) {
5232 int len = -1;
5233 const ACCchar* s = string[i];
5234 if (length) {
5235 len = length[i];
5236 }
5237 if (len < 0) {
5238 len = strlen(s);
5239 }
Jack Palevich09555c72009-05-27 12:25:55 -07005240 memcpy(dest, s, len);
5241 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005242 }
5243 text[totalLength] = '\0';
5244}
5245
5246extern "C"
5247void accCompileScript(ACCscript* script) {
5248 int result = script->compiler.compile(script->text, script->textLength);
5249 if (result) {
5250 script->setError(ACC_INVALID_OPERATION);
5251 }
5252}
5253
5254extern "C"
5255void accGetScriptiv(ACCscript* script,
5256 ACCenum pname,
5257 ACCint * params) {
5258 switch (pname) {
5259 case ACC_INFO_LOG_LENGTH:
5260 *params = 0;
5261 break;
5262 }
5263}
5264
5265extern "C"
5266void accGetScriptInfoLog(ACCscript* script,
5267 ACCsizei maxLength,
5268 ACCsizei * length,
5269 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005270 char* message = script->compiler.getErrorMessage();
5271 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005272 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005273 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005274 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005275 if (infoLog && maxLength > 0) {
5276 int trimmedLength = maxLength < messageLength ?
5277 maxLength : messageLength;
5278 memcpy(infoLog, message, trimmedLength);
5279 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005280 }
5281}
5282
5283extern "C"
5284void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5285 ACCvoid ** address) {
5286 void* value = script->compiler.lookup(name);
5287 if (value) {
5288 *address = value;
5289 } else {
5290 script->setError(ACC_INVALID_VALUE);
5291 }
5292}
5293
Jack Palevicheedf9d22009-06-04 16:23:40 -07005294extern "C"
5295void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5296 ACCsizei maxStringCount, ACCchar** strings){
5297 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5298}
5299
-b master422972c2009-06-17 19:13:52 -07005300extern "C"
5301void accDisassemble(ACCscript* script) {
5302 script->compiler.disassemble(stderr);
5303}
5304
Jack Palevicheedf9d22009-06-04 16:23:40 -07005305
Jack Palevich1cdef202009-05-22 12:06:27 -07005306} // namespace acc
5307