blob: 1990dd6e06558135ac3f5447a355251aacb8ac92 [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 Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070016#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070017#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070018#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070019#include <stdlib.h>
20#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070021#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070022
Jack Palevich8dc662e2009-06-09 22:53:47 +000023#if defined(__i386__)
24#include <sys/mman.h>
25#endif
26
Jack Palevich546b2242009-05-13 15:10:04 -070027#if defined(__arm__)
28#include <unistd.h>
29#endif
30
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Paleviche7b59062009-05-19 17:12:17 -070042#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070043#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070044#endif
Jack Palevicha6535612009-05-13 16:24:17 -070045
Jack Palevich30321cb2009-08-20 15:34:23 -070046#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
47#define ARM_USE_VFP
48#endif
49
Jack Palevich1cdef202009-05-22 12:06:27 -070050#include <acc/acc.h>
51
Jack Palevich09555c72009-05-27 12:25:55 -070052#define LOG_API(...) do {} while(0)
53// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070054
-b master422972c2009-06-17 19:13:52 -070055#define LOG_STACK(...) do {} while(0)
56// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
57
Jack Palevich9f51a262009-07-29 16:22:26 -070058#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070059// #define PROVIDE_TRACE_CODEGEN
60
Jack Palevich7f5b1a22009-08-17 16:54:56 -070061#define assert(b) assertImpl(b, __LINE__)
62
Jack Palevichbbf8ab52009-05-11 11:54:30 -070063namespace acc {
64
Jack Palevich8df46192009-07-07 14:48:51 -070065// Subset of STL vector.
66template<class E> class Vector {
67 public:
68 Vector() {
69 mpBase = 0;
70 mUsed = 0;
71 mSize = 0;
72 }
73
74 ~Vector() {
75 if (mpBase) {
76 for(size_t i = 0; i < mUsed; i++) {
77 mpBase[mUsed].~E();
78 }
79 free(mpBase);
80 }
81 }
82
83 inline E& operator[](size_t i) {
84 return mpBase[i];
85 }
86
87 inline E& front() {
88 return mpBase[0];
89 }
90
91 inline E& back() {
92 return mpBase[mUsed - 1];
93 }
94
95 void pop_back() {
96 mUsed -= 1;
97 mpBase[mUsed].~E();
98 }
99
100 void push_back(const E& item) {
101 * ensure(1) = item;
102 }
103
104 size_t size() {
105 return mUsed;
106 }
107
108private:
109 E* ensure(int n) {
110 size_t newUsed = mUsed + n;
111 if (newUsed > mSize) {
112 size_t newSize = mSize * 2 + 10;
113 if (newSize < newUsed) {
114 newSize = newUsed;
115 }
116 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
117 mSize = newSize;
118 }
119 E* result = mpBase + mUsed;
120 mUsed = newUsed;
121 return result;
122 }
123
124 E* mpBase;
125 size_t mUsed;
126 size_t mSize;
127};
128
Jack Palevichac0e95e2009-05-29 13:53:44 -0700129class ErrorSink {
130public:
131 void error(const char *fmt, ...) {
132 va_list ap;
133 va_start(ap, fmt);
134 verror(fmt, ap);
135 va_end(ap);
136 }
137
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700138 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700139 virtual void verror(const char* fmt, va_list ap) = 0;
140};
141
142class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700143 typedef int tokenid_t;
144 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700145 TY_INT, // 0
146 TY_CHAR, // 1
147 TY_SHORT, // 2
148 TY_VOID, // 3
149 TY_FLOAT, // 4
150 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700151 TY_POINTER, // 6
152 TY_ARRAY, // 7
153 TY_STRUCT, // 8
154 TY_FUNC, // 9
155 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700156 };
157
158 struct Type {
159 TypeTag tag;
Jack Palevichb6154502009-08-04 14:56:09 -0700160 tokenid_t id; // For function arguments, local vars
161 int length; // length of array
Jack Palevich8df46192009-07-07 14:48:51 -0700162 Type* pHead;
163 Type* pTail;
164 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700165
Jack Palevichba929a42009-07-17 10:20:32 -0700166 enum ExpressionType {
167 ET_RVALUE,
168 ET_LVALUE
169 };
170
171 struct ExpressionValue {
172 ExpressionValue() {
173 et = ET_RVALUE;
174 pType = NULL;
175 }
176 ExpressionType et;
177 Type* pType;
178 };
179
Jack Palevich21a15a22009-05-11 14:49:29 -0700180 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700181 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700182 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700183 ErrorSink* mErrorSink;
184 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700185 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700186
Jack Palevich21a15a22009-05-11 14:49:29 -0700187 void release() {
188 if (pProgramBase != 0) {
189 free(pProgramBase);
190 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700191 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700192 }
193
Jack Palevich0a280a02009-06-11 10:53:51 -0700194 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700195 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700196 bool overflow = newSize > mSize;
197 if (overflow && !mOverflowed) {
198 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700199 if (mErrorSink) {
200 mErrorSink->error("Code too large: %d bytes", newSize);
201 }
202 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700203 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700204 }
205
Jack Palevich21a15a22009-05-11 14:49:29 -0700206 public:
207 CodeBuf() {
208 pProgramBase = 0;
209 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700210 mErrorSink = 0;
211 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700213 }
214
215 ~CodeBuf() {
216 release();
217 }
218
219 void init(int size) {
220 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700221 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700222 pProgramBase = (char*) calloc(1, size);
223 ind = pProgramBase;
224 }
225
Jack Palevichac0e95e2009-05-29 13:53:44 -0700226 void setErrorSink(ErrorSink* pErrorSink) {
227 mErrorSink = pErrorSink;
228 }
229
Jack Palevich546b2242009-05-13 15:10:04 -0700230 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700231 if(check(4)) {
232 return 0;
233 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700234 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700235 * (int*) ind = n;
236 ind += 4;
237 return result;
238 }
239
Jack Palevich21a15a22009-05-11 14:49:29 -0700240 /*
241 * Output a byte. Handles all values, 0..ff.
242 */
243 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700244 if(check(1)) {
245 return;
246 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700247 *ind++ = n;
248 }
249
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 inline void* getBase() {
251 return (void*) pProgramBase;
252 }
253
Jack Palevich8b0624c2009-05-20 12:12:06 -0700254 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700255 return ind - pProgramBase;
256 }
257
Jack Palevich8b0624c2009-05-20 12:12:06 -0700258 intptr_t getPC() {
259 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 }
261 };
262
Jack Palevich1cdef202009-05-22 12:06:27 -0700263 /**
264 * A code generator creates an in-memory program, generating the code on
265 * the fly. There is one code generator implementation for each supported
266 * architecture.
267 *
268 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700269 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700270 * FP - a frame pointer for accessing function arguments and local
271 * variables.
272 * SP - a stack pointer for storing intermediate results while evaluating
273 * expressions. The stack pointer grows downwards.
274 *
275 * The function calling convention is that all arguments are placed on the
276 * stack such that the first argument has the lowest address.
277 * After the call, the result is in R0. The caller is responsible for
278 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700279 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700280 * FP and SP registers are saved.
281 */
282
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 class CodeGenerator {
284 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700285 CodeGenerator() {
286 mErrorSink = 0;
287 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700288 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700289 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700290 virtual ~CodeGenerator() {}
291
Jack Palevich22305132009-05-13 10:58:45 -0700292 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700293 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700294 pCodeBuf->setErrorSink(mErrorSink);
295 }
296
Jack Palevichb67b18f2009-06-11 21:12:23 -0700297 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700298 mErrorSink = pErrorSink;
299 if (pCodeBuf) {
300 pCodeBuf->setErrorSink(mErrorSink);
301 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700302 }
303
Jack Palevich58c30ee2009-07-17 16:35:23 -0700304 /* Give the code generator some utility types so it can
305 * use its own types as needed for the results of some
306 * operations like gcmp.
307 */
308
Jack Palevicha8f427f2009-07-13 18:40:08 -0700309 void setTypes(Type* pInt) {
310 mkpInt = pInt;
311 }
312
Jack Palevich1cdef202009-05-22 12:06:27 -0700313 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700314 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700315 * Save the old value of the FP.
316 * Set the new value of the FP.
317 * Convert from the native platform calling convention to
318 * our stack-based calling convention. This may require
319 * pushing arguments from registers to the stack.
320 * Allocate "N" bytes of stack space. N isn't known yet, so
321 * just emit the instructions for adjusting the stack, and return
322 * the address to patch up. The patching will be done in
323 * functionExit().
324 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700325 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700326 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700327
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 /* Emit a function epilog.
329 * Restore the old SP and FP register values.
330 * Return to the calling function.
331 * argCount - the number of arguments to the function.
332 * localVariableAddress - returned from functionEntry()
333 * localVariableSize - the size in bytes of the local variables.
334 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700335 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700336 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700337
Jack Palevich1cdef202009-05-22 12:06:27 -0700338 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700339 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700340
Jack Palevich1a539db2009-07-08 13:04:41 -0700341 /* Load floating point value from global address. */
342 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 /* Jump to a target, and return the address of the word that
345 * holds the target data, in case it needs to be fixed up later.
346 */
Jack Palevich22305132009-05-13 10:58:45 -0700347 virtual int gjmp(int t) = 0;
348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /* Test R0 and jump to a target if the test succeeds.
350 * l = 0: je, l == 1: jne
351 * Return the address of the word that holds the targed data, in
352 * case it needs to be fixed up later.
353 */
Jack Palevich22305132009-05-13 10:58:45 -0700354 virtual int gtst(bool l, int t) = 0;
355
Jack Palevich9eed7a22009-07-06 17:24:34 -0700356 /* Compare TOS against R0, and store the boolean result in R0.
357 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700358 * op specifies the comparison.
359 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700360 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700361
Jack Palevich9eed7a22009-07-06 17:24:34 -0700362 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700364 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700365 */
Jack Palevich546b2242009-05-13 15:10:04 -0700366 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700367
Jack Palevich9eed7a22009-07-06 17:24:34 -0700368 /* Compare 0 against R0, and store the boolean result in R0.
369 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700371 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700372
373 /* Perform the arithmetic op specified by op. 0 is the
374 * left argument, R0 is the right argument.
375 */
376 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700377
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700378 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700379 */
380 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700381
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700382 /* Turn R0, TOS into R0 TOS R0 */
383
384 virtual void over() = 0;
385
386 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700387 */
388 virtual void popR0() = 0;
389
Jack Palevich9eed7a22009-07-06 17:24:34 -0700390 /* Store R0 to the address stored in TOS.
391 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700393 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700394
Jack Palevich1cdef202009-05-22 12:06:27 -0700395 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700396 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700397 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700398
Jack Palevich1cdef202009-05-22 12:06:27 -0700399 /* Load the absolute address of a variable to R0.
400 * If ea <= LOCAL, then this is a local variable, or an
401 * argument, addressed relative to FP.
402 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700403 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700404 * et is ET_RVALUE for things like string constants, ET_LVALUE for
405 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700407 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700408
Jack Palevich9f51a262009-07-29 16:22:26 -0700409 /* Load the pc-relative address of a forward-referenced variable to R0.
410 * Return the address of the 4-byte constant so that it can be filled
411 * in later.
412 */
413 virtual int leaForward(int ea, Type* pPointerType) = 0;
414
Jack Palevich8df46192009-07-07 14:48:51 -0700415 /**
416 * Convert R0 to the given type.
417 */
Jack Palevichb6154502009-08-04 14:56:09 -0700418
419 void convertR0(Type* pType) {
420 convertR0Imp(pType, false);
421 }
422
423 void castR0(Type* pType) {
424 convertR0Imp(pType, true);
425 }
426
427 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700428
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 /* Emit code to adjust the stack for a function call. Return the
430 * label for the address of the instruction that adjusts the
431 * stack size. This will be passed as argument "a" to
432 * endFunctionCallArguments.
433 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700434 virtual int beginFunctionCallArguments() = 0;
435
Jack Palevich1cdef202009-05-22 12:06:27 -0700436 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700437 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700439 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Patch the function call preamble.
442 * a is the address returned from beginFunctionCallArguments
443 * l is the number of bytes the arguments took on the stack.
444 * Typically you would also emit code to convert the argument
445 * list into whatever the native function calling convention is.
446 * On ARM for example you would pop the first 5 arguments into
447 * R0..R4
448 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700449 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700450
Jack Palevich1cdef202009-05-22 12:06:27 -0700451 /* Emit a call to an unknown function. The argument "symbol" needs to
452 * be stored in the location where the address should go. It forms
453 * a chain. The address will be patched later.
454 * Return the address of the word that has to be patched.
455 */
Jack Palevich8df46192009-07-07 14:48:51 -0700456 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700457
Jack Palevich1cdef202009-05-22 12:06:27 -0700458 /* Call a function pointer. L is the number of bytes the arguments
459 * take on the stack. The address of the function is stored at
460 * location SP + l.
461 */
Jack Palevich8df46192009-07-07 14:48:51 -0700462 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700463
Jack Palevich1cdef202009-05-22 12:06:27 -0700464 /* Adjust SP after returning from a function call. l is the
465 * number of bytes of arguments stored on the stack. isIndirect
466 * is true if this was an indirect call. (In which case the
467 * address of the function is stored at location SP + l.)
468 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700469 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700470
Jack Palevich1cdef202009-05-22 12:06:27 -0700471 /* Print a disassembly of the assembled code to out. Return
472 * non-zero if there is an error.
473 */
Jack Palevicha6535612009-05-13 16:24:17 -0700474 virtual int disassemble(FILE* out) = 0;
475
Jack Palevich1cdef202009-05-22 12:06:27 -0700476 /* Generate a symbol at the current PC. t is the head of a
477 * linked list of addresses to patch.
478 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700479 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700480
Jack Palevich9f51a262009-07-29 16:22:26 -0700481 /* Resolve a forward reference function at the current PC.
482 * t is the head of a
483 * linked list of addresses to patch.
484 * (Like gsym, but using absolute address, not PC relative address.)
485 */
486 virtual void resolveForward(int t) = 0;
487
Jack Palevich1cdef202009-05-22 12:06:27 -0700488 /*
489 * Do any cleanup work required at the end of a compile.
490 * For example, an instruction cache might need to be
491 * invalidated.
492 * Return non-zero if there is an error.
493 */
494 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700495
Jack Palevicha6535612009-05-13 16:24:17 -0700496 /**
497 * Adjust relative branches by this amount.
498 */
499 virtual int jumpOffset() = 0;
500
Jack Palevich9eed7a22009-07-06 17:24:34 -0700501 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700502 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700503 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700504 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505
506 /**
507 * Array element alignment (in bytes) for this type of data.
508 */
509 virtual size_t sizeOf(Type* type) = 0;
510
Jack Palevich9cbd2262009-07-08 16:48:41 -0700511 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700512 * Stack alignment of this type of data
513 */
514 virtual size_t stackAlignmentOf(Type* pType) = 0;
515
516 /**
517 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700518 */
519 virtual size_t stackSizeOf(Type* pType) = 0;
520
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700521 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700522 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700523 }
524
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700525 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700526 return mExpressionStack.back().et;
527 }
528
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700529 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700530 mExpressionStack.back().et = et;
531 }
532
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700533 virtual size_t getExpressionStackDepth() {
534 return mExpressionStack.size();
535 }
536
Jack Palevichb5e33312009-07-30 19:06:34 -0700537 virtual void forceR0RVal() {
538 if (getR0ExpressionType() == ET_LVALUE) {
539 loadR0FromR0();
540 }
541 }
542
Jack Palevich21a15a22009-05-11 14:49:29 -0700543 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700544 /*
545 * Output a byte. Handles all values, 0..ff.
546 */
547 void ob(int n) {
548 pCodeBuf->ob(n);
549 }
550
Jack Palevich8b0624c2009-05-20 12:12:06 -0700551 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700552 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700553 }
554
Jack Palevich8b0624c2009-05-20 12:12:06 -0700555 intptr_t getBase() {
556 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700557 }
558
Jack Palevich8b0624c2009-05-20 12:12:06 -0700559 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700560 return pCodeBuf->getPC();
561 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700562
563 intptr_t getSize() {
564 return pCodeBuf->getSize();
565 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700566
567 void error(const char* fmt,...) {
568 va_list ap;
569 va_start(ap, fmt);
570 mErrorSink->verror(fmt, ap);
571 va_end(ap);
572 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700573
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700574 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700575 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700576 error("code generator assertion failed at line %s:%d.", __FILE__, line);
577 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700578 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700579 }
580 }
Jack Palevich8df46192009-07-07 14:48:51 -0700581
582 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700583 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700584 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700585 mExpressionStack.back().et = ET_RVALUE;
586 }
587
588 void setR0Type(Type* pType, ExpressionType et) {
589 assert(pType != NULL);
590 mExpressionStack.back().pType = pType;
591 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700592 }
593
Jack Palevich8df46192009-07-07 14:48:51 -0700594 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700595 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700596 }
597
598 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700599 if (mExpressionStack.size()) {
600 mExpressionStack.push_back(mExpressionStack.back());
601 } else {
602 mExpressionStack.push_back(ExpressionValue());
603 }
604
Jack Palevich8df46192009-07-07 14:48:51 -0700605 }
606
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700607 void overType() {
608 size_t size = mExpressionStack.size();
609 if (size >= 2) {
610 mExpressionStack.push_back(mExpressionStack.back());
611 mExpressionStack[size-1] = mExpressionStack[size-2];
612 mExpressionStack[size-2] = mExpressionStack[size];
613 }
614 }
615
Jack Palevich8df46192009-07-07 14:48:51 -0700616 void popType() {
617 mExpressionStack.pop_back();
618 }
619
620 bool bitsSame(Type* pA, Type* pB) {
621 return collapseType(pA->tag) == collapseType(pB->tag);
622 }
623
624 TypeTag collapseType(TypeTag tag) {
625 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700626 TY_INT,
627 TY_INT,
628 TY_INT,
629 TY_VOID,
630 TY_FLOAT,
631 TY_DOUBLE,
632 TY_INT,
633 TY_INT,
634 TY_VOID,
635 TY_VOID,
636 TY_VOID
637 };
Jack Palevich8df46192009-07-07 14:48:51 -0700638 return collapsedTag[tag];
639 }
640
Jack Palevich1a539db2009-07-08 13:04:41 -0700641 TypeTag collapseTypeR0() {
642 return collapseType(getR0Type()->tag);
643 }
644
Jack Palevichb6154502009-08-04 14:56:09 -0700645 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700646 return isFloatTag(pType->tag);
647 }
648
Jack Palevichb6154502009-08-04 14:56:09 -0700649 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700650 return tag == TY_FLOAT || tag == TY_DOUBLE;
651 }
652
Jack Palevichb6154502009-08-04 14:56:09 -0700653 static bool isPointerType(Type* pType) {
654 return isPointerTag(pType->tag);
655 }
656
657 static bool isPointerTag(TypeTag tag) {
658 return tag == TY_POINTER || tag == TY_ARRAY;
659 }
660
661 Type* getPointerArithmeticResultType(Type* a, Type* b) {
662 TypeTag aTag = a->tag;
663 TypeTag bTag = b->tag;
664 if (aTag == TY_POINTER) {
665 return a;
666 }
667 if (bTag == TY_POINTER) {
668 return b;
669 }
670 if (aTag == TY_ARRAY) {
671 return a->pTail;
672 }
673 if (bTag == TY_ARRAY) {
674 return b->pTail;
675 }
676 return NULL;
677 }
678
Jack Palevicha8f427f2009-07-13 18:40:08 -0700679 Type* mkpInt;
680
Jack Palevich21a15a22009-05-11 14:49:29 -0700681 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700682 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700683 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700684 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700685 };
686
Jack Paleviche7b59062009-05-19 17:12:17 -0700687#ifdef PROVIDE_ARM_CODEGEN
688
Jack Palevich22305132009-05-13 10:58:45 -0700689 class ARMCodeGenerator : public CodeGenerator {
690 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700691 ARMCodeGenerator() {
692#ifdef ARM_USE_VFP
693 LOGD("Using ARM VFP hardware floating point.");
694#else
695 LOGD("Using ARM soft floating point.");
696#endif
697 }
-b master422972c2009-06-17 19:13:52 -0700698
Jack Palevich22305132009-05-13 10:58:45 -0700699 virtual ~ARMCodeGenerator() {}
700
701 /* returns address to patch with local variable size
702 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700703 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700704 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700705 // sp -> arg4 arg5 ...
706 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700707 int regArgCount = calcRegArgCount(pDecl);
708 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700709 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700710 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700711 }
712 // sp -> arg0 arg1 ...
713 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700714 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700715 // sp, fp -> oldfp, retadr, arg0 arg1 ....
716 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700717 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700718 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700719 // We don't know how many local variables we are going to use,
720 // but we will round the allocation up to a multiple of
721 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700722 }
723
Jack Palevichb7718b92009-07-09 22:00:24 -0700724 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700725 // Round local variable size up to a multiple of stack alignment
726 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
727 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700728 // Patch local variable allocation code:
729 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700730 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700731 }
Jack Palevich69796b62009-05-14 15:42:26 -0700732 *(char*) (localVariableAddress) = localVariableSize;
733
Jack Palevich30321cb2009-08-20 15:34:23 -0700734#ifdef ARM_USE_VFP
735 {
736 Type* pReturnType = pDecl->pHead;
737 switch(pReturnType->tag) {
738 case TY_FLOAT:
739 o4(0xEE170A90); // fmrs r0, s15
740 break;
741 case TY_DOUBLE:
742 o4(0xEC510B17); // fmrrd r0, r1, d7
743 break;
744 default:
745 break;
746 }
747 }
748#endif
749
Jack Palevich69796b62009-05-14 15:42:26 -0700750 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
751 o4(0xE1A0E00B); // mov lr, fp
752 o4(0xE59BB000); // ldr fp, [fp]
753 o4(0xE28ED004); // add sp, lr, #4
754 // sp -> retadr, arg0, ...
755 o4(0xE8BD4000); // ldmfd sp!, {lr}
756 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700757
758 // We store the PC into the lr so we can adjust the sp before
759 // returning. We need to pull off the registers we pushed
760 // earlier. We don't need to actually store them anywhere,
761 // just adjust the stack.
762 int regArgCount = calcRegArgCount(pDecl);
763 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700764 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
765 }
766 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700767 }
768
769 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700770 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700771 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700772 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700773 }
774
Jack Palevich1a539db2009-07-08 13:04:41 -0700775 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700776 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700777 // Global, absolute address
778 o4(0xE59F0000); // ldr r0, .L1
779 o4(0xEA000000); // b .L99
780 o4(address); // .L1: .word ea
781 // .L99:
782
783 switch (pType->tag) {
784 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700785#ifdef ARM_USE_VFP
786 o4(0xEDD07A00); // flds s15, [r0]
787#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700788 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700789#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700790 break;
791 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700792#ifdef ARM_USE_VFP
793 o4(0xED907B00); // fldd d7, [r0]
794#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700795 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700796#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700797 break;
798 default:
799 assert(false);
800 break;
801 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700802 }
803
Jack Palevich22305132009-05-13 10:58:45 -0700804 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700805 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700806 }
807
808 /* l = 0: je, l == 1: jne */
809 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700810 Type* pR0Type = getR0Type();
811 TypeTag tagR0 = pR0Type->tag;
812 switch(tagR0) {
813 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700814#ifdef ARM_USE_VFP
815 o4(0xEEF57A40); // fcmpzs s15
816 o4(0xEEF1FA10); // fmstat
817#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700818 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -0700819 o4(0xE3500000); // cmp r0,#0
820#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700821 break;
822 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700823#ifdef ARM_USE_VFP
824 o4(0xEEB57B40); // fcmpzd d7
825 o4(0xEEF1FA10); // fmstat
826#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700827 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -0700828 o4(0xE3500000); // cmp r0,#0
829#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700830 break;
831 default:
Jack Palevich30321cb2009-08-20 15:34:23 -0700832 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700833 break;
834 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700835 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
836 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700837 }
838
Jack Palevich58c30ee2009-07-17 16:35:23 -0700839 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700840 Type* pR0Type = getR0Type();
841 Type* pTOSType = getTOSType();
842 TypeTag tagR0 = collapseType(pR0Type->tag);
843 TypeTag tagTOS = collapseType(pTOSType->tag);
844 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700845 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700846 o4(0xE1510000); // cmp r1, r1
847 switch(op) {
848 case OP_EQUALS:
849 o4(0x03A00001); // moveq r0,#1
850 o4(0x13A00000); // movne r0,#0
851 break;
852 case OP_NOT_EQUALS:
853 o4(0x03A00000); // moveq r0,#0
854 o4(0x13A00001); // movne r0,#1
855 break;
856 case OP_LESS_EQUAL:
857 o4(0xD3A00001); // movle r0,#1
858 o4(0xC3A00000); // movgt r0,#0
859 break;
860 case OP_GREATER:
861 o4(0xD3A00000); // movle r0,#0
862 o4(0xC3A00001); // movgt r0,#1
863 break;
864 case OP_GREATER_EQUAL:
865 o4(0xA3A00001); // movge r0,#1
866 o4(0xB3A00000); // movlt r0,#0
867 break;
868 case OP_LESS:
869 o4(0xA3A00000); // movge r0,#0
870 o4(0xB3A00001); // movlt r0,#1
871 break;
872 default:
873 error("Unknown comparison op %d", op);
874 break;
875 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700876 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
877 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700878#ifdef ARM_USE_VFP
879 o4(0xEEB46BC7); // fcmped d6, d7
880 o4(0xEEF1FA10); // fmstat
881 switch(op) {
882 case OP_EQUALS:
883 o4(0x03A00001); // moveq r0,#1
884 o4(0x13A00000); // movne r0,#0
885 break;
886 case OP_NOT_EQUALS:
887 o4(0x03A00000); // moveq r0,#0
888 o4(0x13A00001); // movne r0,#1
889 break;
890 case OP_LESS_EQUAL:
891 o4(0xD3A00001); // movle r0,#1
892 o4(0xC3A00000); // movgt r0,#0
893 break;
894 case OP_GREATER:
895 o4(0xD3A00000); // movle r0,#0
896 o4(0xC3A00001); // movgt r0,#1
897 break;
898 case OP_GREATER_EQUAL:
899 o4(0xA3A00001); // movge r0,#1
900 o4(0xB3A00000); // movlt r0,#0
901 break;
902 case OP_LESS:
903 o4(0xA3A00000); // movge r0,#0
904 o4(0xB3A00001); // movlt r0,#1
905 break;
906 default:
907 error("Unknown comparison op %d", op);
908 break;
909 }
910#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700911 switch(op) {
912 case OP_EQUALS:
913 callRuntime((void*) runtime_cmp_eq_dd);
914 break;
915 case OP_NOT_EQUALS:
916 callRuntime((void*) runtime_cmp_ne_dd);
917 break;
918 case OP_LESS_EQUAL:
919 callRuntime((void*) runtime_cmp_le_dd);
920 break;
921 case OP_GREATER:
922 callRuntime((void*) runtime_cmp_gt_dd);
923 break;
924 case OP_GREATER_EQUAL:
925 callRuntime((void*) runtime_cmp_ge_dd);
926 break;
927 case OP_LESS:
928 callRuntime((void*) runtime_cmp_lt_dd);
929 break;
930 default:
931 error("Unknown comparison op %d", op);
932 break;
933 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700934#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700935 } else {
936 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700937#ifdef ARM_USE_VFP
938 o4(0xEEB47AE7); // fcmpes s14, s15
939 o4(0xEEF1FA10); // fmstat
940 switch(op) {
941 case OP_EQUALS:
942 o4(0x03A00001); // moveq r0,#1
943 o4(0x13A00000); // movne r0,#0
944 break;
945 case OP_NOT_EQUALS:
946 o4(0x03A00000); // moveq r0,#0
947 o4(0x13A00001); // movne r0,#1
948 break;
949 case OP_LESS_EQUAL:
950 o4(0xD3A00001); // movle r0,#1
951 o4(0xC3A00000); // movgt r0,#0
952 break;
953 case OP_GREATER:
954 o4(0xD3A00000); // movle r0,#0
955 o4(0xC3A00001); // movgt r0,#1
956 break;
957 case OP_GREATER_EQUAL:
958 o4(0xA3A00001); // movge r0,#1
959 o4(0xB3A00000); // movlt r0,#0
960 break;
961 case OP_LESS:
962 o4(0xA3A00000); // movge r0,#0
963 o4(0xB3A00001); // movlt r0,#1
964 break;
965 default:
966 error("Unknown comparison op %d", op);
967 break;
968 }
969#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700970 switch(op) {
971 case OP_EQUALS:
972 callRuntime((void*) runtime_cmp_eq_ff);
973 break;
974 case OP_NOT_EQUALS:
975 callRuntime((void*) runtime_cmp_ne_ff);
976 break;
977 case OP_LESS_EQUAL:
978 callRuntime((void*) runtime_cmp_le_ff);
979 break;
980 case OP_GREATER:
981 callRuntime((void*) runtime_cmp_gt_ff);
982 break;
983 case OP_GREATER_EQUAL:
984 callRuntime((void*) runtime_cmp_ge_ff);
985 break;
986 case OP_LESS:
987 callRuntime((void*) runtime_cmp_lt_ff);
988 break;
989 default:
990 error("Unknown comparison op %d", op);
991 break;
992 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700993#endif
Jack Palevich8de461d2009-05-14 17:21:45 -0700994 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700995 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700996 }
997
Jack Palevich546b2242009-05-13 15:10:04 -0700998 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700999 Type* pR0Type = getR0Type();
1000 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001001 TypeTag tagR0 = pR0Type->tag;
1002 TypeTag tagTOS = pTOSType->tag;
1003 bool isFloatR0 = isFloatTag(tagR0);
1004 bool isFloatTOS = isFloatTag(tagTOS);
1005 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001006 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001007 bool isPtrR0 = isPointerTag(tagR0);
1008 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001009 if (isPtrR0 || isPtrTOS) {
1010 if (isPtrR0 && isPtrTOS) {
1011 if (op != OP_MINUS) {
1012 error("Unsupported pointer-pointer operation %d.", op);
1013 }
1014 if (! typeEqual(pR0Type, pTOSType)) {
1015 error("Incompatible pointer types for subtraction.");
1016 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001017 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001018 setR0Type(mkpInt);
1019 int size = sizeOf(pR0Type->pHead);
1020 if (size != 1) {
1021 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001022 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001023 // TODO: Optimize for power-of-two.
1024 genOp(OP_DIV);
1025 }
1026 } else {
1027 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1028 error("Unsupported pointer-scalar operation %d", op);
1029 }
Jack Palevichb6154502009-08-04 14:56:09 -07001030 Type* pPtrType = getPointerArithmeticResultType(
1031 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001032 int size = sizeOf(pPtrType->pHead);
1033 if (size != 1) {
1034 // TODO: Optimize for power-of-two.
1035 liReg(size, 2);
1036 if (isPtrR0) {
1037 o4(0x0E0010192); // mul r1,r2,r1
1038 } else {
1039 o4(0x0E0000092); // mul r0,r2,r0
1040 }
1041 }
1042 switch(op) {
1043 case OP_PLUS:
1044 o4(0xE0810000); // add r0,r1,r0
1045 break;
1046 case OP_MINUS:
1047 o4(0xE0410000); // sub r0,r1,r0
1048 break;
1049 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001050 setR0Type(pPtrType);
1051 }
1052 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001053 switch(op) {
1054 case OP_MUL:
1055 o4(0x0E0000091); // mul r0,r1,r0
1056 break;
1057 case OP_DIV:
1058 callRuntime((void*) runtime_DIV);
1059 break;
1060 case OP_MOD:
1061 callRuntime((void*) runtime_MOD);
1062 break;
1063 case OP_PLUS:
1064 o4(0xE0810000); // add r0,r1,r0
1065 break;
1066 case OP_MINUS:
1067 o4(0xE0410000); // sub r0,r1,r0
1068 break;
1069 case OP_SHIFT_LEFT:
1070 o4(0xE1A00011); // lsl r0,r1,r0
1071 break;
1072 case OP_SHIFT_RIGHT:
1073 o4(0xE1A00051); // asr r0,r1,r0
1074 break;
1075 case OP_BIT_AND:
1076 o4(0xE0010000); // and r0,r1,r0
1077 break;
1078 case OP_BIT_XOR:
1079 o4(0xE0210000); // eor r0,r1,r0
1080 break;
1081 case OP_BIT_OR:
1082 o4(0xE1810000); // orr r0,r1,r0
1083 break;
1084 case OP_BIT_NOT:
1085 o4(0xE1E00000); // mvn r0, r0
1086 break;
1087 default:
1088 error("Unimplemented op %d\n", op);
1089 break;
1090 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001091 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001092 } else {
1093 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1094 if (pResultType->tag == TY_DOUBLE) {
1095 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001096
Jack Palevichb7718b92009-07-09 22:00:24 -07001097 switch(op) {
1098 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001099#ifdef ARM_USE_VFP
1100 o4(0xEE267B07); // fmuld d7, d6, d7
1101#else
1102 callRuntime((void*) runtime_op_mul_dd);
1103#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 break;
1105 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001106#ifdef ARM_USE_VFP
1107 o4(0xEE867B07); // fdivd d7, d6, d7
1108#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001109 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001110#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001111 break;
1112 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001113#ifdef ARM_USE_VFP
1114 o4(0xEE367B07); // faddd d7, d6, d7
1115#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001116 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001117#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001118 break;
1119 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001120#ifdef ARM_USE_VFP
1121 o4(0xEE367B47); // fsubd d7, d6, d7
1122#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001123 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001124#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001125 break;
1126 default:
1127 error("Unsupported binary floating operation %d\n", op);
1128 break;
1129 }
1130 } else {
1131 setupFloatArgs();
1132 switch(op) {
1133 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001134#ifdef ARM_USE_VFP
1135 o4(0xEE677A27); // fmuls s15, s14, s15
1136#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001137 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001138#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001139 break;
1140 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001141#ifdef ARM_USE_VFP
1142 o4(0xEEC77A27); // fdivs s15, s14, s15
1143#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001144 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001145#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001146 break;
1147 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001148#ifdef ARM_USE_VFP
1149 o4(0xEE777A27); // fadds s15, s14, s15
1150#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001151 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001152#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001153 break;
1154 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001155#ifdef ARM_USE_VFP
1156 o4(0xEE777A67); // fsubs s15, s14, s15
1157#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001158 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001159#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001160 break;
1161 default:
1162 error("Unsupported binary floating operation %d\n", op);
1163 break;
1164 }
1165 }
1166 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001167 }
Jack Palevich22305132009-05-13 10:58:45 -07001168 }
1169
Jack Palevich58c30ee2009-07-17 16:35:23 -07001170 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001171 if (op != OP_LOGICAL_NOT) {
1172 error("Unknown unary cmp %d", op);
1173 } else {
1174 Type* pR0Type = getR0Type();
1175 TypeTag tag = collapseType(pR0Type->tag);
1176 switch(tag) {
1177 case TY_INT:
1178 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001179 o4(0xE1510000); // cmp r1, r0
1180 o4(0x03A00001); // moveq r0,#1
1181 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001182 break;
1183 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001184#ifdef ARM_USE_VFP
1185 o4(0xEEF57A40); // fcmpzs s15
1186 o4(0xEEF1FA10); // fmstat
1187 o4(0x03A00001); // moveq r0,#1
1188 o4(0x13A00000); // movne r0,#0
1189#else
1190 callRuntime((void*) runtime_is_zero_f);
1191#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001192 break;
1193 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001194#ifdef ARM_USE_VFP
1195 o4(0xEEB57B40); // fcmpzd d7
1196 o4(0xEEF1FA10); // fmstat
1197 o4(0x03A00001); // moveq r0,#1
1198 o4(0x13A00000); // movne r0,#0
1199#else
1200 callRuntime((void*) runtime_is_zero_d);
1201#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001202 break;
1203 default:
1204 error("gUnaryCmp unsupported type");
1205 break;
1206 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001207 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001208 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001209 }
1210
1211 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001212 Type* pR0Type = getR0Type();
1213 TypeTag tag = collapseType(pR0Type->tag);
1214 switch(tag) {
1215 case TY_INT:
1216 switch(op) {
1217 case OP_MINUS:
1218 o4(0xE3A01000); // mov r1, #0
1219 o4(0xE0410000); // sub r0,r1,r0
1220 break;
1221 case OP_BIT_NOT:
1222 o4(0xE1E00000); // mvn r0, r0
1223 break;
1224 default:
1225 error("Unknown unary op %d\n", op);
1226 break;
1227 }
1228 break;
1229 case TY_FLOAT:
1230 case TY_DOUBLE:
1231 switch (op) {
1232 case OP_MINUS:
1233 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001234#ifdef ARM_USE_VFP
1235 o4(0xEEF17A67); // fnegs s15, s15
1236#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001237 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001238#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001239 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001240#ifdef ARM_USE_VFP
1241 o4(0xEEB17B47); // fnegd d7, d7
1242#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001243 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001244#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001245 }
1246 break;
1247 case OP_BIT_NOT:
1248 error("Can't apply '~' operator to a float or double.");
1249 break;
1250 default:
1251 error("Unknown unary op %d\n", op);
1252 break;
1253 }
1254 break;
1255 default:
1256 error("genUnaryOp unsupported type");
1257 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001258 }
Jack Palevich22305132009-05-13 10:58:45 -07001259 }
1260
Jack Palevich1cdef202009-05-22 12:06:27 -07001261 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001262 Type* pR0Type = getR0Type();
1263 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001264
1265#ifdef ARM_USE_VFP
1266 switch (r0ct ) {
1267 case TY_FLOAT:
1268 o4(0xED6D7A01); // fstmfds sp!,{s15}
1269 mStackUse += 4;
1270 break;
1271 case TY_DOUBLE:
1272 o4(0xED2D7B02); // fstmfdd sp!,{d7}
1273 mStackUse += 8;
1274 break;
1275 default:
1276 o4(0xE92D0001); // stmfd sp!,{r0}
1277 mStackUse += 4;
1278 }
1279#else
1280
Jack Palevichb7718b92009-07-09 22:00:24 -07001281 if (r0ct != TY_DOUBLE) {
1282 o4(0xE92D0001); // stmfd sp!,{r0}
1283 mStackUse += 4;
1284 } else {
1285 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1286 mStackUse += 8;
1287 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001288#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001289 pushType();
-b master422972c2009-06-17 19:13:52 -07001290 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001291 }
1292
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001293 virtual void over() {
1294 // We know it's only used for int-ptr ops (++/--)
1295
1296 Type* pR0Type = getR0Type();
1297 TypeTag r0ct = collapseType(pR0Type->tag);
1298
1299 Type* pTOSType = getTOSType();
1300 TypeTag tosct = collapseType(pTOSType->tag);
1301
1302 assert (r0ct == TY_INT && tosct == TY_INT);
1303
1304 o4(0xE8BD0002); // ldmfd sp!,{r1}
1305 o4(0xE92D0001); // stmfd sp!,{r0}
1306 o4(0xE92D0002); // stmfd sp!,{r1}
1307 overType();
1308 mStackUse += 4;
1309 }
1310
Jack Palevich58c30ee2009-07-17 16:35:23 -07001311 virtual void popR0() {
1312 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001313 TypeTag tosct = collapseType(pTOSType->tag);
1314#ifdef ARM_USE_VFP
1315 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
1316 error("Unsupported popR0 float/double");
1317 }
1318#endif
1319 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001320 case TY_INT:
1321 case TY_FLOAT:
1322 o4(0xE8BD0001); // ldmfd sp!,{r0}
1323 mStackUse -= 4;
1324 break;
1325 case TY_DOUBLE:
1326 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1327 mStackUse -= 8;
1328 break;
1329 default:
1330 error("Can't pop this type.");
1331 break;
1332 }
1333 popType();
1334 LOG_STACK("popR0: %d\n", mStackUse);
1335 }
1336
1337 virtual void storeR0ToTOS() {
1338 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001339 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001340 Type* pDestType = pPointerType->pHead;
1341 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001342 o4(0xE8BD0004); // ldmfd sp!,{r2}
1343 popType();
-b master422972c2009-06-17 19:13:52 -07001344 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001345 switch (pDestType->tag) {
1346 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001347 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001348 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001349 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001350 case TY_FLOAT:
1351#ifdef ARM_USE_VFP
1352 o4(0xEDC27A00); // fsts s15, [r2, #0]
1353#else
1354 o4(0xE5820000); // str r0, [r2]
1355#endif
1356 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001357 case TY_SHORT:
1358 o4(0xE1C200B0); // strh r0, [r2]
1359 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001360 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001361 o4(0xE5C20000); // strb r0, [r2]
1362 break;
1363 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001364#ifdef ARM_USE_VFP
1365 o4(0xED827B00); // fstd d7, [r2, #0]
1366#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001367 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001368#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001369 break;
1370 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001371 error("storeR0ToTOS: unimplemented type %d",
1372 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001373 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001374 }
Jack Palevich22305132009-05-13 10:58:45 -07001375 }
1376
Jack Palevich58c30ee2009-07-17 16:35:23 -07001377 virtual void loadR0FromR0() {
1378 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001379 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001380 Type* pNewType = pPointerType->pHead;
1381 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001382 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001383 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001384 case TY_INT:
1385 o4(0xE5900000); // ldr r0, [r0]
1386 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001387 case TY_FLOAT:
1388#ifdef ARM_USE_VFP
1389 o4(0xEDD07A00); // flds s15, [r0, #0]
1390#else
1391 o4(0xE5900000); // ldr r0, [r0]
1392#endif
1393 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001394 case TY_SHORT:
1395 o4(0xE1D000F0); // ldrsh r0, [r0]
1396 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001397 case TY_CHAR:
1398 o4(0xE5D00000); // ldrb r0, [r0]
1399 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001400 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001401#ifdef ARM_USE_VFP
1402 o4(0xED907B00); // fldd d7, [r0, #0]
1403#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001404 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001405#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001406 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001407 case TY_ARRAY:
1408 pNewType = pNewType->pTail;
1409 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001410 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001411 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001412 break;
1413 }
Jack Palevich80e49722009-08-04 15:39:49 -07001414 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001415 }
1416
Jack Palevichb5e33312009-07-30 19:06:34 -07001417 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001418 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001419 // Local, fp relative
1420 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1421 error("Offset out of range: %08x", ea);
1422 }
1423 if (ea < 0) {
1424 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1425 } else {
1426 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1427 }
Jack Palevichbd894902009-05-14 19:35:31 -07001428 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001429 // Global, absolute.
1430 o4(0xE59F0000); // ldr r0, .L1
1431 o4(0xEA000000); // b .L99
1432 o4(ea); // .L1: .word 0
1433 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001434 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001435 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001436 }
1437
Jack Palevich9f51a262009-07-29 16:22:26 -07001438 virtual int leaForward(int ea, Type* pPointerType) {
1439 setR0Type(pPointerType);
1440 int result = ea;
1441 int pc = getPC();
1442 int offset = 0;
1443 if (ea) {
1444 offset = (pc - ea - 8) >> 2;
1445 if ((offset & 0xffff) != offset) {
1446 error("function forward reference out of bounds");
1447 }
1448 } else {
1449 offset = 0;
1450 }
1451 o4(0xE59F0000 | offset); // ldr r0, .L1
1452
1453 if (ea == 0) {
1454 o4(0xEA000000); // b .L99
1455 result = o4(ea); // .L1: .word 0
1456 // .L99:
1457 }
1458 return result;
1459 }
1460
Jack Palevichb6154502009-08-04 14:56:09 -07001461 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001462 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001463 if (isPointerType(pType) && isPointerType(pR0Type)) {
1464 Type* pA = pR0Type;
1465 Type* pB = pType;
1466 // Array decays to pointer
1467 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1468 pA = pA->pTail;
1469 }
1470 if (typeEqual(pA, pB)) {
1471 return; // OK
1472 }
1473 if (pB->pHead->tag == TY_VOID) {
1474 return; // convert to void* is OK.
1475 }
1476 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
1477 && isCast) {
1478 return; // OK
1479 }
1480 error("Incompatible pointer or array types");
1481 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001482 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001483 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001484 TypeTag r0Tag = collapseType(pR0Type->tag);
1485 TypeTag destTag = collapseType(pType->tag);
1486 if (r0Tag == TY_INT) {
1487 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001488#ifdef ARM_USE_VFP
1489 o4(0xEE070A90); // fmsr s15, r0
1490 o4(0xEEF87AE7); // fsitos s15, s15
1491
1492#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001493 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001494#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001495 } else {
1496 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001497#ifdef ARM_USE_VFP
1498 o4(0xEE070A90); // fmsr s15, r0
1499 o4(0xEEB87BE7); // fsitod d7, s15
1500
1501#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001502 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001503#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001504 }
1505 } else if (r0Tag == TY_FLOAT) {
1506 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001507#ifdef ARM_USE_VFP
1508 o4(0xEEFD7AE7); // ftosizs s15, s15
1509 o4(0xEE170A90); // fmrs r0, s15
1510#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001511 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001512#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001513 } else {
1514 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001515#ifdef ARM_USE_VFP
1516 o4(0xEEB77AE7); // fcvtds d7, s15
1517#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001518 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001519#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001520 }
1521 } else {
1522 assert (r0Tag == TY_DOUBLE);
1523 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001524#ifdef ARM_USE_VFP
1525 o4(0xEEFD7BC7); // ftosizd s15, d7
1526 o4(0xEE170A90); // fmrs r0, s15
1527#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001528 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001529#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001530 } else {
1531 assert(destTag == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001532#ifdef ARM_USE_VFP
1533 o4(0xEEF77BC7); // fcvtsd s15, d7
1534#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001535 callRuntime((void*) runtime_double_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001536#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001537 }
1538 }
Jack Palevich8df46192009-07-07 14:48:51 -07001539 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001540 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001541 }
1542
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001543 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001544 return o4(0xE24DDF00); // Placeholder
1545 }
1546
Jack Palevich8148c5b2009-07-16 18:24:47 -07001547 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001548 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001549 Type* pR0Type = getR0Type();
1550 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001551#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001552 switch(r0ct) {
1553 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001554 if (l < 0 || l > 4096-4) {
1555 error("l out of range for stack offset: 0x%08x", l);
1556 }
1557 o4(0xE58D0000 | l); // str r0, [sp, #l]
1558 return 4;
1559 case TY_FLOAT:
1560 if (l < 0 || l > 1020 || (l & 3)) {
1561 error("l out of range for stack offset: 0x%08x", l);
1562 }
1563 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
1564 return 4;
1565 case TY_DOUBLE: {
1566 // Align to 8 byte boundary
1567 int l2 = (l + 7) & ~7;
1568 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1569 error("l out of range for stack offset: 0x%08x", l);
1570 }
1571 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
1572 return (l2 - l) + 8;
1573 }
1574 default:
1575 assert(false);
1576 return 0;
1577 }
1578#else
1579 switch(r0ct) {
1580 case TY_INT:
1581 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001582 if (l < 0 || l > 4096-4) {
1583 error("l out of range for stack offset: 0x%08x", l);
1584 }
1585 o4(0xE58D0000 + l); // str r0, [sp, #l]
1586 return 4;
1587 case TY_DOUBLE: {
1588 // Align to 8 byte boundary
1589 int l2 = (l + 7) & ~7;
1590 if (l2 < 0 || l2 > 4096-8) {
1591 error("l out of range for stack offset: 0x%08x", l);
1592 }
1593 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1594 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1595 return (l2 - l) + 8;
1596 }
1597 default:
1598 assert(false);
1599 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001600 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001601#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001602 }
1603
Jack Palevichb7718b92009-07-09 22:00:24 -07001604 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001605 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001606 // Have to calculate register arg count from actual stack size,
1607 // in order to properly handle ... functions.
1608 int regArgCount = l >> 2;
1609 if (regArgCount > 4) {
1610 regArgCount = 4;
1611 }
1612 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001613 argumentStackUse -= regArgCount * 4;
1614 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1615 }
1616 mStackUse += argumentStackUse;
1617
1618 // Align stack.
1619 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1620 * STACK_ALIGNMENT);
1621 mStackAlignmentAdjustment = 0;
1622 if (missalignment > 0) {
1623 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1624 }
1625 l += mStackAlignmentAdjustment;
1626
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001627 if (l < 0 || l > 0x3FC) {
1628 error("L out of range for stack adjustment: 0x%08x", l);
1629 }
1630 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001631 mStackUse += mStackAlignmentAdjustment;
1632 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1633 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001634 }
1635
Jack Palevich8df46192009-07-07 14:48:51 -07001636 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001637 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001638 // Forward calls are always short (local)
1639 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001640 }
1641
Jack Palevich8df46192009-07-07 14:48:51 -07001642 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001643 assert(pFunc->tag == TY_FUNC);
1644 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001645 int argCount = l >> 2;
1646 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001647 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001648 if (adjustedL < 0 || adjustedL > 4096-4) {
1649 error("l out of range for stack offset: 0x%08x", l);
1650 }
1651 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1652 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001653 Type* pReturnType = pFunc->pHead;
1654 setR0Type(pReturnType);
1655#ifdef ARM_USE_VFP
1656 switch(pReturnType->tag) {
1657 case TY_FLOAT:
1658 o4(0xEE070A90); // fmsr s15, r0
1659 break;
1660 case TY_DOUBLE:
1661 o4(0xEC410B17); // fmdrr d7, r0, r1
1662 break;
1663 default:
1664 break;
1665 }
1666#endif
Jack Palevich22305132009-05-13 10:58:45 -07001667 }
1668
Jack Palevichb7718b92009-07-09 22:00:24 -07001669 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001670 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001671 // Have to calculate register arg count from actual stack size,
1672 // in order to properly handle ... functions.
1673 int regArgCount = l >> 2;
1674 if (regArgCount > 4) {
1675 regArgCount = 4;
1676 }
1677 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001678 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1679 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001680 if (stackUse) {
1681 if (stackUse < 0 || stackUse > 255) {
1682 error("L out of range for stack adjustment: 0x%08x", l);
1683 }
1684 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001685 mStackUse -= stackUse * 4;
1686 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001687 }
Jack Palevich22305132009-05-13 10:58:45 -07001688 }
1689
Jack Palevicha6535612009-05-13 16:24:17 -07001690 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001691 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001692 }
1693
1694 /* output a symbol and patch all calls to it */
1695 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001696 int n;
1697 int base = getBase();
1698 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001699 while (t) {
1700 int data = * (int*) t;
1701 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1702 if (decodedOffset == 0) {
1703 n = 0;
1704 } else {
1705 n = base + decodedOffset; /* next value */
1706 }
1707 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1708 | encodeRelAddress(pc - t - 8);
1709 t = n;
1710 }
1711 }
1712
Jack Palevich9f51a262009-07-29 16:22:26 -07001713 /* output a symbol and patch all calls to it */
1714 virtual void resolveForward(int t) {
1715 if (t) {
1716 int pc = getPC();
1717 *(int *) t = pc;
1718 }
1719 }
1720
Jack Palevich1cdef202009-05-22 12:06:27 -07001721 virtual int finishCompile() {
1722#if defined(__arm__)
1723 const long base = long(getBase());
1724 const long curr = long(getPC());
1725 int err = cacheflush(base, curr, 0);
1726 return err;
1727#else
1728 return 0;
1729#endif
1730 }
1731
Jack Palevicha6535612009-05-13 16:24:17 -07001732 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001733#ifdef ENABLE_ARM_DISASSEMBLY
1734 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001735 disasm_interface_t di;
1736 di.di_readword = disassemble_readword;
1737 di.di_printaddr = disassemble_printaddr;
1738 di.di_printf = disassemble_printf;
1739
1740 int base = getBase();
1741 int pc = getPC();
1742 for(int i = base; i < pc; i += 4) {
1743 fprintf(out, "%08x: %08x ", i, *(int*) i);
1744 ::disasm(&di, i, 0);
1745 }
Jack Palevich09555c72009-05-27 12:25:55 -07001746#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001747 return 0;
1748 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001749
Jack Palevich9eed7a22009-07-06 17:24:34 -07001750 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001751 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001752 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001753 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001754 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001755 case TY_CHAR:
1756 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001757 case TY_SHORT:
1758 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001759 case TY_DOUBLE:
1760 return 8;
1761 default:
1762 return 4;
1763 }
1764 }
1765
1766 /**
1767 * Array element alignment (in bytes) for this type of data.
1768 */
1769 virtual size_t sizeOf(Type* pType){
1770 switch(pType->tag) {
1771 case TY_INT:
1772 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001773 case TY_SHORT:
1774 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001775 case TY_CHAR:
1776 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001777 case TY_FLOAT:
1778 return 4;
1779 case TY_DOUBLE:
1780 return 8;
1781 case TY_POINTER:
1782 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001783 case TY_ARRAY:
1784 return pType->length * sizeOf(pType->pHead);
1785 default:
1786 error("Unsupported type %d", pType->tag);
1787 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001788 }
1789 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001790
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001791 virtual size_t stackAlignmentOf(Type* pType) {
1792 switch(pType->tag) {
1793 case TY_DOUBLE:
1794 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001795 case TY_ARRAY:
1796 return stackAlignmentOf(pType->pHead);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001797 default:
1798 return 4;
1799 }
1800 }
1801
Jack Palevich9cbd2262009-07-08 16:48:41 -07001802 virtual size_t stackSizeOf(Type* pType) {
1803 switch(pType->tag) {
1804 case TY_DOUBLE:
1805 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001806 case TY_ARRAY:
1807 return sizeOf(pType);
1808 case TY_FUNC:
1809 error("stackSizeOf func not supported");
1810 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001811 default:
1812 return 4;
1813 }
1814 }
1815
Jack Palevich22305132009-05-13 10:58:45 -07001816 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001817 static FILE* disasmOut;
1818
1819 static u_int
1820 disassemble_readword(u_int address)
1821 {
1822 return(*((u_int *)address));
1823 }
1824
1825 static void
1826 disassemble_printaddr(u_int address)
1827 {
1828 fprintf(disasmOut, "0x%08x", address);
1829 }
1830
1831 static void
1832 disassemble_printf(const char *fmt, ...) {
1833 va_list ap;
1834 va_start(ap, fmt);
1835 vfprintf(disasmOut, fmt, ap);
1836 va_end(ap);
1837 }
1838
1839 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1840
1841 /** Encode a relative address that might also be
1842 * a label.
1843 */
1844 int encodeAddress(int value) {
1845 int base = getBase();
1846 if (value >= base && value <= getPC() ) {
1847 // This is a label, encode it relative to the base.
1848 value = value - base;
1849 }
1850 return encodeRelAddress(value);
1851 }
1852
1853 int encodeRelAddress(int value) {
1854 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1855 }
Jack Palevich22305132009-05-13 10:58:45 -07001856
Jack Palevichb7718b92009-07-09 22:00:24 -07001857 int calcRegArgCount(Type* pDecl) {
1858 int reg = 0;
1859 Type* pArgs = pDecl->pTail;
1860 while (pArgs && reg < 4) {
1861 Type* pArg = pArgs->pHead;
1862 if ( pArg->tag == TY_DOUBLE) {
1863 int evenReg = (reg + 1) & ~1;
1864 if (evenReg >= 4) {
1865 break;
1866 }
1867 reg = evenReg + 2;
1868 } else {
1869 reg++;
1870 }
1871 pArgs = pArgs->pTail;
1872 }
1873 return reg;
1874 }
1875
Jack Palevich58c30ee2009-07-17 16:35:23 -07001876 void setupIntPtrArgs() {
1877 o4(0xE8BD0002); // ldmfd sp!,{r1}
1878 mStackUse -= 4;
1879 popType();
1880 }
1881
Jack Palevich30321cb2009-08-20 15:34:23 -07001882 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001883 * Make sure both R0 and TOS are floats. (Could be ints)
1884 * We know that at least one of R0 and TOS is already a float
1885 */
1886 void setupFloatArgs() {
1887 Type* pR0Type = getR0Type();
1888 Type* pTOSType = getTOSType();
1889 TypeTag tagR0 = collapseType(pR0Type->tag);
1890 TypeTag tagTOS = collapseType(pTOSType->tag);
1891 if (tagR0 != TY_FLOAT) {
1892 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001893#ifdef ARM_USE_VFP
1894 o4(0xEE070A90); // fmsr s15, r0
1895 o4(0xEEF87AE7); // fsitos s15, s15
1896#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001897 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001898#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001899 }
1900 if (tagTOS != TY_FLOAT) {
1901 assert(tagTOS == TY_INT);
1902 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001903#ifdef ARM_USE_VFP
1904 o4(0xECBD7A01); // fldmfds sp!, {s14}
1905 o4(0xEEB87AC7); // fsitos s14, s14
1906#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001907 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1908 o4(0xE59D0004); // ldr r0, [sp, #4]
1909 callRuntime((void*) runtime_int_to_float);
1910 o4(0xE1A01000); // mov r1, r0
1911 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1912 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001913#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001914 } else {
1915 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001916#ifdef ARM_USE_VFP
1917 o4(0xECBD7A01); // fldmfds sp!, {s14}
1918
1919#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001920 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001921#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001922 }
1923 mStackUse -= 4;
1924 popType();
1925 }
1926
Jack Palevich30321cb2009-08-20 15:34:23 -07001927 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001928 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1929 * We know that at least one of R0 and TOS are already a double.
1930 */
1931
1932 void setupDoubleArgs() {
1933 Type* pR0Type = getR0Type();
1934 Type* pTOSType = getTOSType();
1935 TypeTag tagR0 = collapseType(pR0Type->tag);
1936 TypeTag tagTOS = collapseType(pTOSType->tag);
1937 if (tagR0 != TY_DOUBLE) {
1938 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001939#ifdef ARM_USE_VFP
1940 o4(0xEE070A90); // fmsr s15, r0
1941 o4(0xEEB87BE7); // fsitod d7, s15
1942
1943#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001944 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001945#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001946 } else {
1947 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001948#ifdef ARM_USE_VFP
1949 o4(0xEEB77AE7); // fcvtds d7, s15
1950#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001951 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001952#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001953 }
1954 }
1955 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001956#ifdef ARM_USE_VFP
1957 if (tagTOS == TY_INT) {
1958 o4(0xECFD6A01); // fldmfds sp!,{s13}
1959 o4(0xEEB86BE6); // fsitod d6, s13
1960 } else {
1961 assert(tagTOS == TY_FLOAT);
1962 o4(0xECFD6A01); // fldmfds sp!,{s13}
1963 o4(0xEEB76AE6); // fcvtds d6, s13
1964 }
1965#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001966 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1967 o4(0xE59D0008); // ldr r0, [sp, #8]
1968 if (tagTOS == TY_INT) {
1969 callRuntime((void*) runtime_int_to_double);
1970 } else {
1971 assert(tagTOS == TY_FLOAT);
1972 callRuntime((void*) runtime_float_to_double);
1973 }
1974 o4(0xE1A02000); // mov r2, r0
1975 o4(0xE1A03001); // mov r3, r1
1976 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1977 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001978#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001979 mStackUse -= 4;
1980 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001981#ifdef ARM_USE_VFP
1982 o4(0xECBD6B02); // fldmfdd sp!, {d6}
1983#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001984 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07001985#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001986 mStackUse -= 8;
1987 }
1988 popType();
1989 }
1990
Jack Palevicha8f427f2009-07-13 18:40:08 -07001991 void liReg(int t, int reg) {
1992 assert(reg >= 0 && reg < 16);
1993 int rN = (reg & 0xf) << 12;
1994 if (t >= 0 && t < 255) {
1995 o4((0xE3A00000 + t) | rN); // mov rN, #0
1996 } else if (t >= -256 && t < 0) {
1997 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001998 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001999 } else {
2000 o4(0xE51F0000 | rN); // ldr rN, .L3
2001 o4(0xEA000000); // b .L99
2002 o4(t); // .L3: .word 0
2003 // .L99:
2004 }
2005 }
2006
Jack Palevichb7718b92009-07-09 22:00:24 -07002007 void callRuntime(void* fn) {
2008 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002009 o4(0xEA000000); // b .L99
2010 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002011 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002012 }
2013
Jack Palevichb7718b92009-07-09 22:00:24 -07002014 // Integer math:
2015
2016 static int runtime_DIV(int b, int a) {
2017 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002018 }
2019
Jack Palevichb7718b92009-07-09 22:00:24 -07002020 static int runtime_MOD(int b, int a) {
2021 return a % b;
2022 }
2023
Jack Palevich30321cb2009-08-20 15:34:23 -07002024#ifndef ARM_USE_VFP
2025
Jack Palevichb7718b92009-07-09 22:00:24 -07002026 // Comparison to zero
2027
2028 static int runtime_is_non_zero_f(float a) {
2029 return a != 0;
2030 }
2031
2032 static int runtime_is_non_zero_d(double a) {
2033 return a != 0;
2034 }
2035
2036 // Comparison to zero
2037
2038 static int runtime_is_zero_f(float a) {
2039 return a == 0;
2040 }
2041
2042 static int runtime_is_zero_d(double a) {
2043 return a == 0;
2044 }
2045
2046 // Type conversion
2047
2048 static int runtime_float_to_int(float a) {
2049 return (int) a;
2050 }
2051
2052 static double runtime_float_to_double(float a) {
2053 return (double) a;
2054 }
2055
2056 static int runtime_double_to_int(double a) {
2057 return (int) a;
2058 }
2059
2060 static float runtime_double_to_float(double a) {
2061 return (float) a;
2062 }
2063
2064 static float runtime_int_to_float(int a) {
2065 return (float) a;
2066 }
2067
2068 static double runtime_int_to_double(int a) {
2069 return (double) a;
2070 }
2071
2072 // Comparisons float
2073
2074 static int runtime_cmp_eq_ff(float b, float a) {
2075 return a == b;
2076 }
2077
2078 static int runtime_cmp_ne_ff(float b, float a) {
2079 return a != b;
2080 }
2081
2082 static int runtime_cmp_lt_ff(float b, float a) {
2083 return a < b;
2084 }
2085
2086 static int runtime_cmp_le_ff(float b, float a) {
2087 return a <= b;
2088 }
2089
2090 static int runtime_cmp_ge_ff(float b, float a) {
2091 return a >= b;
2092 }
2093
2094 static int runtime_cmp_gt_ff(float b, float a) {
2095 return a > b;
2096 }
2097
2098 // Comparisons double
2099
2100 static int runtime_cmp_eq_dd(double b, double a) {
2101 return a == b;
2102 }
2103
2104 static int runtime_cmp_ne_dd(double b, double a) {
2105 return a != b;
2106 }
2107
2108 static int runtime_cmp_lt_dd(double b, double a) {
2109 return a < b;
2110 }
2111
2112 static int runtime_cmp_le_dd(double b, double a) {
2113 return a <= b;
2114 }
2115
2116 static int runtime_cmp_ge_dd(double b, double a) {
2117 return a >= b;
2118 }
2119
2120 static int runtime_cmp_gt_dd(double b, double a) {
2121 return a > b;
2122 }
2123
2124 // Math float
2125
2126 static float runtime_op_add_ff(float b, float a) {
2127 return a + b;
2128 }
2129
2130 static float runtime_op_sub_ff(float b, float a) {
2131 return a - b;
2132 }
2133
2134 static float runtime_op_mul_ff(float b, float a) {
2135 return a * b;
2136 }
2137
2138 static float runtime_op_div_ff(float b, float a) {
2139 return a / b;
2140 }
2141
2142 static float runtime_op_neg_f(float a) {
2143 return -a;
2144 }
2145
2146 // Math double
2147
2148 static double runtime_op_add_dd(double b, double a) {
2149 return a + b;
2150 }
2151
2152 static double runtime_op_sub_dd(double b, double a) {
2153 return a - b;
2154 }
2155
2156 static double runtime_op_mul_dd(double b, double a) {
2157 return a * b;
2158 }
2159
2160 static double runtime_op_div_dd(double b, double a) {
2161 return a / b;
2162 }
2163
2164 static double runtime_op_neg_d(double a) {
2165 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002166 }
-b master422972c2009-06-17 19:13:52 -07002167
Jack Palevich30321cb2009-08-20 15:34:23 -07002168#endif
2169
-b master422972c2009-06-17 19:13:52 -07002170 static const int STACK_ALIGNMENT = 8;
2171 int mStackUse;
2172 // This variable holds the amount we adjusted the stack in the most
2173 // recent endFunctionCallArguments call. It's examined by the
2174 // following adjustStackAfterCall call.
2175 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002176 };
2177
Jack Palevich09555c72009-05-27 12:25:55 -07002178#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002179
2180#ifdef PROVIDE_X86_CODEGEN
2181
Jack Palevich21a15a22009-05-11 14:49:29 -07002182 class X86CodeGenerator : public CodeGenerator {
2183 public:
2184 X86CodeGenerator() {}
2185 virtual ~X86CodeGenerator() {}
2186
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002187 /* returns address to patch with local variable size
2188 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002189 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002190 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2191 return oad(0xec81, 0); /* sub $xxx, %esp */
2192 }
2193
Jack Palevichb7718b92009-07-09 22:00:24 -07002194 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002195 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002196 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002197 }
2198
Jack Palevich21a15a22009-05-11 14:49:29 -07002199 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002200 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002201 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002202 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002203 }
2204
Jack Palevich1a539db2009-07-08 13:04:41 -07002205 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002206 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002207 switch (pType->tag) {
2208 case TY_FLOAT:
2209 oad(0x05D9, address); // flds
2210 break;
2211 case TY_DOUBLE:
2212 oad(0x05DD, address); // fldl
2213 break;
2214 default:
2215 assert(false);
2216 break;
2217 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002218 }
2219
Jack Palevich22305132009-05-13 10:58:45 -07002220 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002221 return psym(0xe9, t);
2222 }
2223
2224 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002225 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002226 Type* pR0Type = getR0Type();
2227 TypeTag tagR0 = pR0Type->tag;
2228 bool isFloatR0 = isFloatTag(tagR0);
2229 if (isFloatR0) {
2230 o(0xeed9); // fldz
2231 o(0xe9da); // fucompp
2232 o(0xe0df); // fnstsw %ax
2233 o(0x9e); // sahf
2234 } else {
2235 o(0xc085); // test %eax, %eax
2236 }
2237 // Use two output statements to generate one instruction.
2238 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002239 return psym(0x84 + l, t);
2240 }
2241
Jack Palevich58c30ee2009-07-17 16:35:23 -07002242 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002243 Type* pR0Type = getR0Type();
2244 Type* pTOSType = getTOSType();
2245 TypeTag tagR0 = pR0Type->tag;
2246 TypeTag tagTOS = pTOSType->tag;
2247 bool isFloatR0 = isFloatTag(tagR0);
2248 bool isFloatTOS = isFloatTag(tagTOS);
2249 if (!isFloatR0 && !isFloatTOS) {
2250 int t = decodeOp(op);
2251 o(0x59); /* pop %ecx */
2252 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002253 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002254 o(0x0f); /* setxx %al */
2255 o(t + 0x90);
2256 o(0xc0);
2257 popType();
2258 } else {
2259 setupFloatOperands();
2260 switch (op) {
2261 case OP_EQUALS:
2262 o(0xe9da); // fucompp
2263 o(0xe0df); // fnstsw %ax
2264 o(0x9e); // sahf
2265 o(0xc0940f); // sete %al
2266 o(0xc29b0f); // setnp %dl
2267 o(0xd021); // andl %edx, %eax
2268 break;
2269 case OP_NOT_EQUALS:
2270 o(0xe9da); // fucompp
2271 o(0xe0df); // fnstsw %ax
2272 o(0x9e); // sahf
2273 o(0xc0950f); // setne %al
2274 o(0xc29a0f); // setp %dl
2275 o(0xd009); // orl %edx, %eax
2276 break;
2277 case OP_GREATER_EQUAL:
2278 o(0xe9da); // fucompp
2279 o(0xe0df); // fnstsw %ax
2280 o(0x05c4f6); // testb $5, %ah
2281 o(0xc0940f); // sete %al
2282 break;
2283 case OP_LESS:
2284 o(0xc9d9); // fxch %st(1)
2285 o(0xe9da); // fucompp
2286 o(0xe0df); // fnstsw %ax
2287 o(0x9e); // sahf
2288 o(0xc0970f); // seta %al
2289 break;
2290 case OP_LESS_EQUAL:
2291 o(0xc9d9); // fxch %st(1)
2292 o(0xe9da); // fucompp
2293 o(0xe0df); // fnstsw %ax
2294 o(0x9e); // sahf
2295 o(0xc0930f); // setea %al
2296 break;
2297 case OP_GREATER:
2298 o(0xe9da); // fucompp
2299 o(0xe0df); // fnstsw %ax
2300 o(0x45c4f6); // testb $69, %ah
2301 o(0xc0940f); // sete %al
2302 break;
2303 default:
2304 error("Unknown comparison op");
2305 }
2306 o(0xc0b60f); // movzbl %al, %eax
2307 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002308 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002309 }
2310
Jack Palevich546b2242009-05-13 15:10:04 -07002311 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002312 Type* pR0Type = getR0Type();
2313 Type* pTOSType = getTOSType();
2314 TypeTag tagR0 = pR0Type->tag;
2315 TypeTag tagTOS = pTOSType->tag;
2316 bool isFloatR0 = isFloatTag(tagR0);
2317 bool isFloatTOS = isFloatTag(tagTOS);
2318 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002319 bool isPtrR0 = isPointerTag(tagR0);
2320 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002321 if (isPtrR0 || isPtrTOS) {
2322 if (isPtrR0 && isPtrTOS) {
2323 if (op != OP_MINUS) {
2324 error("Unsupported pointer-pointer operation %d.", op);
2325 }
2326 if (! typeEqual(pR0Type, pTOSType)) {
2327 error("Incompatible pointer types for subtraction.");
2328 }
2329 o(0x59); /* pop %ecx */
2330 o(decodeOp(op));
2331 popType();
2332 setR0Type(mkpInt);
2333 int size = sizeOf(pR0Type->pHead);
2334 if (size != 1) {
2335 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002336 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002337 // TODO: Optimize for power-of-two.
2338 genOp(OP_DIV);
2339 }
2340 } else {
2341 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2342 error("Unsupported pointer-scalar operation %d", op);
2343 }
Jack Palevichb6154502009-08-04 14:56:09 -07002344 Type* pPtrType = getPointerArithmeticResultType(
2345 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002346 o(0x59); /* pop %ecx */
2347 int size = sizeOf(pPtrType->pHead);
2348 if (size != 1) {
2349 // TODO: Optimize for power-of-two.
2350 if (isPtrR0) {
2351 oad(0xC969, size); // imull $size, %ecx
2352 } else {
2353 oad(0xC069, size); // mul $size, %eax
2354 }
2355 }
2356 o(decodeOp(op));
2357 popType();
2358 setR0Type(pPtrType);
2359 }
2360 } else {
2361 o(0x59); /* pop %ecx */
2362 o(decodeOp(op));
2363 if (op == OP_MOD)
2364 o(0x92); /* xchg %edx, %eax */
2365 popType();
2366 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002367 } else {
2368 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2369 setupFloatOperands();
2370 // Both float. x87 R0 == left hand, x87 R1 == right hand
2371 switch (op) {
2372 case OP_MUL:
2373 o(0xc9de); // fmulp
2374 break;
2375 case OP_DIV:
2376 o(0xf1de); // fdivp
2377 break;
2378 case OP_PLUS:
2379 o(0xc1de); // faddp
2380 break;
2381 case OP_MINUS:
2382 o(0xe1de); // fsubp
2383 break;
2384 default:
2385 error("Unsupported binary floating operation.");
2386 break;
2387 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002388 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002389 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002390 }
2391
Jack Palevich58c30ee2009-07-17 16:35:23 -07002392 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002393 if (op != OP_LOGICAL_NOT) {
2394 error("Unknown unary cmp %d", op);
2395 } else {
2396 Type* pR0Type = getR0Type();
2397 TypeTag tag = collapseType(pR0Type->tag);
2398 switch(tag) {
2399 case TY_INT: {
2400 oad(0xb9, 0); /* movl $0, %ecx */
2401 int t = decodeOp(op);
2402 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002403 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002404 o(0x0f); /* setxx %al */
2405 o(t + 0x90);
2406 o(0xc0);
2407 }
2408 break;
2409 case TY_FLOAT:
2410 case TY_DOUBLE:
2411 o(0xeed9); // fldz
2412 o(0xe9da); // fucompp
2413 o(0xe0df); // fnstsw %ax
2414 o(0x9e); // sahf
2415 o(0xc0950f); // setne %al
2416 o(0xc29a0f); // setp %dl
2417 o(0xd009); // orl %edx, %eax
2418 o(0xc0b60f); // movzbl %al, %eax
2419 o(0x01f083); // xorl $1, %eax
2420 break;
2421 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002422 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002423 break;
2424 }
2425 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002426 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002427 }
2428
2429 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002430 Type* pR0Type = getR0Type();
2431 TypeTag tag = collapseType(pR0Type->tag);
2432 switch(tag) {
2433 case TY_INT:
2434 oad(0xb9, 0); /* movl $0, %ecx */
2435 o(decodeOp(op));
2436 break;
2437 case TY_FLOAT:
2438 case TY_DOUBLE:
2439 switch (op) {
2440 case OP_MINUS:
2441 o(0xe0d9); // fchs
2442 break;
2443 case OP_BIT_NOT:
2444 error("Can't apply '~' operator to a float or double.");
2445 break;
2446 default:
2447 error("Unknown unary op %d\n", op);
2448 break;
2449 }
2450 break;
2451 default:
2452 error("genUnaryOp unsupported type");
2453 break;
2454 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002455 }
2456
Jack Palevich1cdef202009-05-22 12:06:27 -07002457 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002458 Type* pR0Type = getR0Type();
2459 TypeTag r0ct = collapseType(pR0Type->tag);
2460 switch(r0ct) {
2461 case TY_INT:
2462 o(0x50); /* push %eax */
2463 break;
2464 case TY_FLOAT:
2465 o(0x50); /* push %eax */
2466 o(0x241cd9); // fstps 0(%esp)
2467 break;
2468 case TY_DOUBLE:
2469 o(0x50); /* push %eax */
2470 o(0x50); /* push %eax */
2471 o(0x241cdd); // fstpl 0(%esp)
2472 break;
2473 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002474 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002475 break;
2476 }
Jack Palevich8df46192009-07-07 14:48:51 -07002477 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002478 }
2479
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002480 virtual void over() {
2481 // We know it's only used for int-ptr ops (++/--)
2482
2483 Type* pR0Type = getR0Type();
2484 TypeTag r0ct = collapseType(pR0Type->tag);
2485
2486 Type* pTOSType = getTOSType();
2487 TypeTag tosct = collapseType(pTOSType->tag);
2488
2489 assert (r0ct == TY_INT && tosct == TY_INT);
2490
2491 o(0x59); /* pop %ecx */
2492 o(0x50); /* push %eax */
2493 o(0x51); /* push %ecx */
2494
2495 overType();
2496 }
2497
Jack Palevich58c30ee2009-07-17 16:35:23 -07002498 virtual void popR0() {
2499 Type* pR0Type = getR0Type();
2500 TypeTag r0ct = collapseType(pR0Type->tag);
2501 switch(r0ct) {
2502 case TY_INT:
2503 o(0x58); /* popl %eax */
2504 break;
2505 case TY_FLOAT:
2506 o(0x2404d9); // flds (%esp)
2507 o(0x58); /* popl %eax */
2508 break;
2509 case TY_DOUBLE:
2510 o(0x2404dd); // fldl (%esp)
2511 o(0x58); /* popl %eax */
2512 o(0x58); /* popl %eax */
2513 break;
2514 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002515 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002516 break;
2517 }
2518 popType();
2519 }
2520
2521 virtual void storeR0ToTOS() {
2522 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002523 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002524 Type* pTargetType = pPointerType->pHead;
2525 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002526 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002527 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002528 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002529 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002530 case TY_INT:
2531 o(0x0189); /* movl %eax/%al, (%ecx) */
2532 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002533 case TY_SHORT:
2534 o(0x018966); /* movw %ax, (%ecx) */
2535 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002536 case TY_CHAR:
2537 o(0x0188); /* movl %eax/%al, (%ecx) */
2538 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002539 case TY_FLOAT:
2540 o(0x19d9); /* fstps (%ecx) */
2541 break;
2542 case TY_DOUBLE:
2543 o(0x19dd); /* fstpl (%ecx) */
2544 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002545 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002546 error("storeR0ToTOS: unsupported type %d",
2547 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002548 break;
2549 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002550 }
2551
Jack Palevich58c30ee2009-07-17 16:35:23 -07002552 virtual void loadR0FromR0() {
2553 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002554 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002555 Type* pNewType = pPointerType->pHead;
2556 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002557 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002558 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002559 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002560 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002561 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002562 case TY_SHORT:
2563 o(0xbf0f); /* movswl (%eax), %eax */
2564 ob(0);
2565 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002566 case TY_CHAR:
2567 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002568 ob(0); /* add zero in code */
2569 break;
2570 case TY_FLOAT:
2571 o2(0x00d9); // flds (%eax)
2572 break;
2573 case TY_DOUBLE:
2574 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002575 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002576 case TY_ARRAY:
2577 pNewType = pNewType->pTail;
2578 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002579 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002580 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002581 break;
2582 }
Jack Palevich80e49722009-08-04 15:39:49 -07002583 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002584 }
2585
Jack Palevichb5e33312009-07-30 19:06:34 -07002586 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002587 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002588 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002589 }
2590
Jack Palevich9f51a262009-07-29 16:22:26 -07002591 virtual int leaForward(int ea, Type* pPointerType) {
2592 oad(0xb8, ea); /* mov $xx, %eax */
2593 setR0Type(pPointerType);
2594 return getPC() - 4;
2595 }
2596
Jack Palevichb6154502009-08-04 14:56:09 -07002597 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002598 Type* pR0Type = getR0Type();
2599 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002600 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002601 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002602 return;
2603 }
Jack Palevichb6154502009-08-04 14:56:09 -07002604 if (isPointerType(pType) && isPointerType(pR0Type)) {
2605 Type* pA = pR0Type;
2606 Type* pB = pType;
2607 // Array decays to pointer
2608 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2609 pA = pA->pTail;
2610 }
2611 if (typeEqual(pA, pB)) {
2612 return; // OK
2613 }
2614 if (pB->pHead->tag == TY_VOID) {
2615 return; // convert to void* is OK.
2616 }
2617 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
2618 && isCast) {
2619 return; // OK
2620 }
2621 error("Incompatible pointer or array types");
2622 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002623 // do nothing special
2624 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2625 // do nothing special, both held in same register on x87.
2626 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002627 TypeTag r0Tag = collapseType(pR0Type->tag);
2628 TypeTag destTag = collapseType(pType->tag);
2629 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2630 // Convert R0 from int to float
2631 o(0x50); // push %eax
2632 o(0x2404DB); // fildl 0(%esp)
2633 o(0x58); // pop %eax
2634 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2635 // Convert R0 from float to int. Complicated because
2636 // need to save and restore the rounding mode.
2637 o(0x50); // push %eax
2638 o(0x50); // push %eax
2639 o(0x02247cD9); // fnstcw 2(%esp)
2640 o(0x2444b70f); // movzwl 2(%esp), %eax
2641 o(0x02);
2642 o(0x0cb4); // movb $12, %ah
2643 o(0x24048966); // movw %ax, 0(%esp)
2644 o(0x242cd9); // fldcw 0(%esp)
2645 o(0x04245cdb); // fistpl 4(%esp)
2646 o(0x02246cd9); // fldcw 2(%esp)
2647 o(0x58); // pop %eax
2648 o(0x58); // pop %eax
2649 } else {
2650 error("Incompatible types old: %d new: %d",
2651 pR0Type->tag, pType->tag);
2652 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002653 }
2654 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002655 }
2656
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002657 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002658 return oad(0xec81, 0); /* sub $xxx, %esp */
2659 }
2660
Jack Palevich8148c5b2009-07-16 18:24:47 -07002661 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2662 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002663 Type* pR0Type = getR0Type();
2664 TypeTag r0ct = collapseType(pR0Type->tag);
2665 switch(r0ct) {
2666 case TY_INT:
2667 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2668 return 4;
2669 case TY_FLOAT:
2670 oad(0x249CD9, l); /* fstps xxx(%esp) */
2671 return 4;
2672 case TY_DOUBLE:
2673 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2674 return 8;
2675 default:
2676 assert(false);
2677 return 0;
2678 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002679 }
2680
Jack Palevichb7718b92009-07-09 22:00:24 -07002681 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002682 * (int*) a = l;
2683 }
2684
Jack Palevich8df46192009-07-07 14:48:51 -07002685 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002686 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002687 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002688 return psym(0xe8, symbol); /* call xxx */
2689 }
2690
Jack Palevich8df46192009-07-07 14:48:51 -07002691 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002692 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002693 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002694 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002695 oad(0x2494ff, l); /* call *xxx(%esp) */
2696 }
2697
Jack Palevichb7718b92009-07-09 22:00:24 -07002698 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002699 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002700 if (isIndirect) {
2701 l += 4;
2702 }
-b master422972c2009-06-17 19:13:52 -07002703 if (l > 0) {
2704 oad(0xc481, l); /* add $xxx, %esp */
2705 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002706 }
2707
Jack Palevicha6535612009-05-13 16:24:17 -07002708 virtual int jumpOffset() {
2709 return 5;
2710 }
2711
2712 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002713 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002714 }
2715
Jack Paleviche7b59062009-05-19 17:12:17 -07002716 /* output a symbol and patch all calls to it */
2717 virtual void gsym(int t) {
2718 int n;
2719 int pc = getPC();
2720 while (t) {
2721 n = *(int *) t; /* next value */
2722 *(int *) t = pc - t - 4;
2723 t = n;
2724 }
2725 }
2726
Jack Palevich9f51a262009-07-29 16:22:26 -07002727 /* output a symbol and patch all calls to it, using absolute address */
2728 virtual void resolveForward(int t) {
2729 int n;
2730 int pc = getPC();
2731 while (t) {
2732 n = *(int *) t; /* next value */
2733 *(int *) t = pc;
2734 t = n;
2735 }
2736 }
2737
Jack Palevich1cdef202009-05-22 12:06:27 -07002738 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002739 size_t pagesize = 4096;
2740 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2741 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2742 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2743 if (err) {
2744 error("mprotect() failed: %d", errno);
2745 }
2746 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002747 }
2748
Jack Palevich9eed7a22009-07-06 17:24:34 -07002749 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002750 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002751 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002752 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002753 switch (pType->tag) {
2754 case TY_CHAR:
2755 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002756 case TY_SHORT:
2757 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002758 case TY_ARRAY:
2759 return alignmentOf(pType->pHead);
2760 case TY_FUNC:
2761 error("alignment of func not supported");
2762 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002763 default:
2764 return 4;
2765 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002766 }
2767
2768 /**
2769 * Array element alignment (in bytes) for this type of data.
2770 */
2771 virtual size_t sizeOf(Type* pType){
2772 switch(pType->tag) {
2773 case TY_INT:
2774 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002775 case TY_SHORT:
2776 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002777 case TY_CHAR:
2778 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002779 case TY_FLOAT:
2780 return 4;
2781 case TY_DOUBLE:
2782 return 8;
2783 case TY_POINTER:
2784 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002785 case TY_ARRAY:
2786 return pType->length * sizeOf(pType->pHead);
2787 default:
2788 error("Unsupported type %d", pType->tag);
2789 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002790 }
2791 }
2792
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002793 virtual size_t stackAlignmentOf(Type* pType){
2794 return 4;
2795 }
2796
Jack Palevich9cbd2262009-07-08 16:48:41 -07002797 virtual size_t stackSizeOf(Type* pType) {
2798 switch(pType->tag) {
2799 case TY_DOUBLE:
2800 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07002801 case TY_ARRAY:
2802 return sizeOf(pType);
2803 case TY_FUNC:
2804 error("stackSizeOf func not supported");
2805 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002806 default:
2807 return 4;
2808 }
2809 }
2810
Jack Palevich21a15a22009-05-11 14:49:29 -07002811 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002812
2813 /** Output 1 to 4 bytes.
2814 *
2815 */
2816 void o(int n) {
2817 /* cannot use unsigned, so we must do a hack */
2818 while (n && n != -1) {
2819 ob(n & 0xff);
2820 n = n >> 8;
2821 }
2822 }
2823
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002824 /* Output exactly 2 bytes
2825 */
2826 void o2(int n) {
2827 ob(n & 0xff);
2828 ob(0xff & (n >> 8));
2829 }
2830
Jack Paleviche7b59062009-05-19 17:12:17 -07002831 /* psym is used to put an instruction with a data field which is a
2832 reference to a symbol. It is in fact the same as oad ! */
2833 int psym(int n, int t) {
2834 return oad(n, t);
2835 }
2836
2837 /* instruction + address */
2838 int oad(int n, int t) {
2839 o(n);
2840 int result = getPC();
2841 o4(t);
2842 return result;
2843 }
2844
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002845 static const int operatorHelper[];
2846
2847 int decodeOp(int op) {
2848 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002849 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002850 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002851 }
2852 return operatorHelper[op];
2853 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002854
Jack Palevich546b2242009-05-13 15:10:04 -07002855 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002856 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002857 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002858 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002859
2860 void setupFloatOperands() {
2861 Type* pR0Type = getR0Type();
2862 Type* pTOSType = getTOSType();
2863 TypeTag tagR0 = pR0Type->tag;
2864 TypeTag tagTOS = pTOSType->tag;
2865 bool isFloatR0 = isFloatTag(tagR0);
2866 bool isFloatTOS = isFloatTag(tagTOS);
2867 if (! isFloatR0) {
2868 // Convert R0 from int to float
2869 o(0x50); // push %eax
2870 o(0x2404DB); // fildl 0(%esp)
2871 o(0x58); // pop %eax
2872 }
2873 if (! isFloatTOS){
2874 o(0x2404DB); // fildl 0(%esp);
2875 o(0x58); // pop %eax
2876 } else {
2877 if (tagTOS == TY_FLOAT) {
2878 o(0x2404d9); // flds (%esp)
2879 o(0x58); // pop %eax
2880 } else {
2881 o(0x2404dd); // fldl (%esp)
2882 o(0x58); // pop %eax
2883 o(0x58); // pop %eax
2884 }
2885 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002886 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002887 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002888 };
2889
Jack Paleviche7b59062009-05-19 17:12:17 -07002890#endif // PROVIDE_X86_CODEGEN
2891
Jack Palevichb67b18f2009-06-11 21:12:23 -07002892#ifdef PROVIDE_TRACE_CODEGEN
2893 class TraceCodeGenerator : public CodeGenerator {
2894 private:
2895 CodeGenerator* mpBase;
2896
2897 public:
2898 TraceCodeGenerator(CodeGenerator* pBase) {
2899 mpBase = pBase;
2900 }
2901
2902 virtual ~TraceCodeGenerator() {
2903 delete mpBase;
2904 }
2905
2906 virtual void init(CodeBuf* pCodeBuf) {
2907 mpBase->init(pCodeBuf);
2908 }
2909
2910 void setErrorSink(ErrorSink* pErrorSink) {
2911 mpBase->setErrorSink(pErrorSink);
2912 }
2913
2914 /* returns address to patch with local variable size
2915 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002916 virtual int functionEntry(Type* pDecl) {
2917 int result = mpBase->functionEntry(pDecl);
2918 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002919 return result;
2920 }
2921
Jack Palevichb7718b92009-07-09 22:00:24 -07002922 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2923 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2924 localVariableAddress, localVariableSize);
2925 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002926 }
2927
2928 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002929 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002930 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002931 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002932 }
2933
Jack Palevich1a539db2009-07-08 13:04:41 -07002934 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002935 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002936 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002937 }
2938
Jack Palevichb67b18f2009-06-11 21:12:23 -07002939 virtual int gjmp(int t) {
2940 int result = mpBase->gjmp(t);
2941 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2942 return result;
2943 }
2944
2945 /* l = 0: je, l == 1: jne */
2946 virtual int gtst(bool l, int t) {
2947 int result = mpBase->gtst(l, t);
2948 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2949 return result;
2950 }
2951
Jack Palevich58c30ee2009-07-17 16:35:23 -07002952 virtual void gcmp(int op) {
2953 fprintf(stderr, "gcmp(%d)\n", op);
2954 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002955 }
2956
2957 virtual void genOp(int op) {
2958 fprintf(stderr, "genOp(%d)\n", op);
2959 mpBase->genOp(op);
2960 }
2961
Jack Palevich9eed7a22009-07-06 17:24:34 -07002962
Jack Palevich58c30ee2009-07-17 16:35:23 -07002963 virtual void gUnaryCmp(int op) {
2964 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2965 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002966 }
2967
2968 virtual void genUnaryOp(int op) {
2969 fprintf(stderr, "genUnaryOp(%d)\n", op);
2970 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002971 }
2972
2973 virtual void pushR0() {
2974 fprintf(stderr, "pushR0()\n");
2975 mpBase->pushR0();
2976 }
2977
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002978 virtual void over() {
2979 fprintf(stderr, "over()\n");
2980 mpBase->over();
2981 }
2982
Jack Palevich58c30ee2009-07-17 16:35:23 -07002983 virtual void popR0() {
2984 fprintf(stderr, "popR0()\n");
2985 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002986 }
2987
Jack Palevich58c30ee2009-07-17 16:35:23 -07002988 virtual void storeR0ToTOS() {
2989 fprintf(stderr, "storeR0ToTOS()\n");
2990 mpBase->storeR0ToTOS();
2991 }
2992
2993 virtual void loadR0FromR0() {
2994 fprintf(stderr, "loadR0FromR0()\n");
2995 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002996 }
2997
Jack Palevichb5e33312009-07-30 19:06:34 -07002998 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2999 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3000 pPointerType->pHead->tag, et);
3001 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003002 }
3003
Jack Palevich9f51a262009-07-29 16:22:26 -07003004 virtual int leaForward(int ea, Type* pPointerType) {
3005 fprintf(stderr, "leaForward(%d)\n", ea);
3006 return mpBase->leaForward(ea, pPointerType);
3007 }
3008
Jack Palevich30321cb2009-08-20 15:34:23 -07003009 virtual void convertR0Imp(Type* pType, bool isCast){
3010 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3011 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003012 }
3013
3014 virtual int beginFunctionCallArguments() {
3015 int result = mpBase->beginFunctionCallArguments();
3016 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3017 return result;
3018 }
3019
Jack Palevich8148c5b2009-07-16 18:24:47 -07003020 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3021 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3022 pArgType->tag);
3023 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003024 }
3025
Jack Palevichb7718b92009-07-09 22:00:24 -07003026 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003027 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003028 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003029 }
3030
Jack Palevich8df46192009-07-07 14:48:51 -07003031 virtual int callForward(int symbol, Type* pFunc) {
3032 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003033 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3034 return result;
3035 }
3036
Jack Palevich8df46192009-07-07 14:48:51 -07003037 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003038 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3039 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003040 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003041 }
3042
Jack Palevichb7718b92009-07-09 22:00:24 -07003043 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3044 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3045 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003046 }
3047
3048 virtual int jumpOffset() {
3049 return mpBase->jumpOffset();
3050 }
3051
3052 virtual int disassemble(FILE* out) {
3053 return mpBase->disassemble(out);
3054 }
3055
3056 /* output a symbol and patch all calls to it */
3057 virtual void gsym(int t) {
3058 fprintf(stderr, "gsym(%d)\n", t);
3059 mpBase->gsym(t);
3060 }
3061
Jack Palevich9f51a262009-07-29 16:22:26 -07003062 virtual void resolveForward(int t) {
3063 mpBase->resolveForward(t);
3064 }
3065
Jack Palevichb67b18f2009-06-11 21:12:23 -07003066 virtual int finishCompile() {
3067 int result = mpBase->finishCompile();
3068 fprintf(stderr, "finishCompile() = %d\n", result);
3069 return result;
3070 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003071
3072 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003073 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003074 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003075 virtual size_t alignmentOf(Type* pType){
3076 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003077 }
3078
3079 /**
3080 * Array element alignment (in bytes) for this type of data.
3081 */
3082 virtual size_t sizeOf(Type* pType){
3083 return mpBase->sizeOf(pType);
3084 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003085
Jack Palevich9cbd2262009-07-08 16:48:41 -07003086
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003087 virtual size_t stackAlignmentOf(Type* pType) {
3088 return mpBase->stackAlignmentOf(pType);
3089 }
3090
3091
Jack Palevich9cbd2262009-07-08 16:48:41 -07003092 virtual size_t stackSizeOf(Type* pType) {
3093 return mpBase->stackSizeOf(pType);
3094 }
3095
Jack Palevich1a539db2009-07-08 13:04:41 -07003096 virtual Type* getR0Type() {
3097 return mpBase->getR0Type();
3098 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003099
3100 virtual ExpressionType getR0ExpressionType() {
3101 return mpBase->getR0ExpressionType();
3102 }
3103
3104 virtual void setR0ExpressionType(ExpressionType et) {
3105 mpBase->setR0ExpressionType(et);
3106 }
3107
3108 virtual size_t getExpressionStackDepth() {
3109 return mpBase->getExpressionStackDepth();
3110 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003111
3112 virtual void forceR0RVal() {
3113 return mpBase->forceR0RVal();
3114 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003115 };
3116
3117#endif // PROVIDE_TRACE_CODEGEN
3118
Jack Palevich569f1352009-06-29 14:29:08 -07003119 class Arena {
3120 public:
3121 // Used to record a given allocation amount.
3122 // Used:
3123 // Mark mark = arena.mark();
3124 // ... lots of arena.allocate()
3125 // arena.free(mark);
3126
3127 struct Mark {
3128 size_t chunk;
3129 size_t offset;
3130 };
3131
3132 Arena() {
3133 mCurrentChunk = 0;
3134 Chunk start(CHUNK_SIZE);
3135 mData.push_back(start);
3136 }
3137
3138 ~Arena() {
3139 for(size_t i = 0; i < mData.size(); i++) {
3140 mData[i].free();
3141 }
3142 }
3143
3144 // Alloc using the standard alignment size safe for any variable
3145 void* alloc(size_t size) {
3146 return alloc(size, 8);
3147 }
3148
3149 Mark mark(){
3150 Mark result;
3151 result.chunk = mCurrentChunk;
3152 result.offset = mData[mCurrentChunk].mOffset;
3153 return result;
3154 }
3155
3156 void freeToMark(const Mark& mark) {
3157 mCurrentChunk = mark.chunk;
3158 mData[mCurrentChunk].mOffset = mark.offset;
3159 }
3160
3161 private:
3162 // Allocate memory aligned to a given size
3163 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3164 // Memory is not zero filled.
3165
3166 void* alloc(size_t size, size_t alignment) {
3167 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3168 if (mCurrentChunk + 1 < mData.size()) {
3169 mCurrentChunk++;
3170 } else {
3171 size_t allocSize = CHUNK_SIZE;
3172 if (allocSize < size + alignment - 1) {
3173 allocSize = size + alignment - 1;
3174 }
3175 Chunk chunk(allocSize);
3176 mData.push_back(chunk);
3177 mCurrentChunk++;
3178 }
3179 }
3180 return mData[mCurrentChunk].allocate(size, alignment);
3181 }
3182
3183 static const size_t CHUNK_SIZE = 128*1024;
3184 // Note: this class does not deallocate its
3185 // memory when it's destroyed. It depends upon
3186 // its parent to deallocate the memory.
3187 struct Chunk {
3188 Chunk() {
3189 mpData = 0;
3190 mSize = 0;
3191 mOffset = 0;
3192 }
3193
3194 Chunk(size_t size) {
3195 mSize = size;
3196 mpData = (char*) malloc(size);
3197 mOffset = 0;
3198 }
3199
3200 ~Chunk() {
3201 // Doesn't deallocate memory.
3202 }
3203
3204 void* allocate(size_t size, size_t alignment) {
3205 size_t alignedOffset = aligned(mOffset, alignment);
3206 void* result = mpData + alignedOffset;
3207 mOffset = alignedOffset + size;
3208 return result;
3209 }
3210
3211 void free() {
3212 if (mpData) {
3213 ::free(mpData);
3214 mpData = 0;
3215 }
3216 }
3217
3218 size_t remainingCapacity(size_t alignment) {
3219 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3220 }
3221
3222 // Assume alignment is a power of two
3223 inline size_t aligned(size_t v, size_t alignment) {
3224 size_t mask = alignment-1;
3225 return (v + mask) & ~mask;
3226 }
3227
3228 char* mpData;
3229 size_t mSize;
3230 size_t mOffset;
3231 };
3232
3233 size_t mCurrentChunk;
3234
3235 Vector<Chunk> mData;
3236 };
3237
Jack Palevich569f1352009-06-29 14:29:08 -07003238 struct VariableInfo;
3239
3240 struct Token {
3241 int hash;
3242 size_t length;
3243 char* pText;
3244 tokenid_t id;
3245
3246 // Current values for the token
3247 char* mpMacroDefinition;
3248 VariableInfo* mpVariableInfo;
3249 };
3250
3251 class TokenTable {
3252 public:
3253 // Don't use 0..0xff, allows characters and operators to be tokens too.
3254
3255 static const int TOKEN_BASE = 0x100;
3256 TokenTable() {
3257 mpMap = hashmapCreate(128, hashFn, equalsFn);
3258 }
3259
3260 ~TokenTable() {
3261 hashmapFree(mpMap);
3262 }
3263
3264 void setArena(Arena* pArena) {
3265 mpArena = pArena;
3266 }
3267
3268 // Returns a token for a given string of characters.
3269 tokenid_t intern(const char* pText, size_t length) {
3270 Token probe;
3271 int hash = hashmapHash((void*) pText, length);
3272 {
3273 Token probe;
3274 probe.hash = hash;
3275 probe.length = length;
3276 probe.pText = (char*) pText;
3277 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3278 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003279 return pValue->id;
3280 }
3281 }
3282
3283 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3284 memset(pToken, 0, sizeof(*pToken));
3285 pToken->hash = hash;
3286 pToken->length = length;
3287 pToken->pText = (char*) mpArena->alloc(length + 1);
3288 memcpy(pToken->pText, pText, length);
3289 pToken->pText[length] = 0;
3290 pToken->id = mTokens.size() + TOKEN_BASE;
3291 mTokens.push_back(pToken);
3292 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003293 return pToken->id;
3294 }
3295
3296 // Return the Token for a given tokenid.
3297 Token& operator[](tokenid_t id) {
3298 return *mTokens[id - TOKEN_BASE];
3299 }
3300
3301 inline size_t size() {
3302 return mTokens.size();
3303 }
3304
3305 private:
3306
3307 static int hashFn(void* pKey) {
3308 Token* pToken = (Token*) pKey;
3309 return pToken->hash;
3310 }
3311
3312 static bool equalsFn(void* keyA, void* keyB) {
3313 Token* pTokenA = (Token*) keyA;
3314 Token* pTokenB = (Token*) keyB;
3315 // Don't need to compare hash values, they should always be equal
3316 return pTokenA->length == pTokenB->length
3317 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3318 }
3319
3320 Hashmap* mpMap;
3321 Vector<Token*> mTokens;
3322 Arena* mpArena;
3323 };
3324
Jack Palevich1cdef202009-05-22 12:06:27 -07003325 class InputStream {
3326 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003327 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003328 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003329 };
3330
3331 class TextInputStream : public InputStream {
3332 public:
3333 TextInputStream(const char* text, size_t textLength)
3334 : pText(text), mTextLength(textLength), mPosition(0) {
3335 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003336
Jack Palevichdc456462009-07-16 16:50:56 -07003337 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003338 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3339 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003340
Jack Palevichdc456462009-07-16 16:50:56 -07003341 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003342 const char* pText;
3343 size_t mTextLength;
3344 size_t mPosition;
3345 };
3346
Jack Palevicheedf9d22009-06-04 16:23:40 -07003347 class String {
3348 public:
3349 String() {
3350 mpBase = 0;
3351 mUsed = 0;
3352 mSize = 0;
3353 }
3354
Jack Palevich303d8ff2009-06-11 19:06:24 -07003355 String(const char* item, int len, bool adopt) {
3356 if (len < 0) {
3357 len = strlen(item);
3358 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003359 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003360 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003361 mUsed = len;
3362 mSize = len + 1;
3363 } else {
3364 mpBase = 0;
3365 mUsed = 0;
3366 mSize = 0;
3367 appendBytes(item, len);
3368 }
3369 }
3370
Jack Palevich303d8ff2009-06-11 19:06:24 -07003371 String(const String& other) {
3372 mpBase = 0;
3373 mUsed = 0;
3374 mSize = 0;
3375 appendBytes(other.getUnwrapped(), other.len());
3376 }
3377
Jack Palevicheedf9d22009-06-04 16:23:40 -07003378 ~String() {
3379 if (mpBase) {
3380 free(mpBase);
3381 }
3382 }
3383
Jack Palevicha6baa232009-06-12 11:25:59 -07003384 String& operator=(const String& other) {
3385 clear();
3386 appendBytes(other.getUnwrapped(), other.len());
3387 return *this;
3388 }
3389
Jack Palevich303d8ff2009-06-11 19:06:24 -07003390 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003391 return mpBase;
3392 }
3393
Jack Palevich303d8ff2009-06-11 19:06:24 -07003394 void clear() {
3395 mUsed = 0;
3396 if (mSize > 0) {
3397 mpBase[0] = 0;
3398 }
3399 }
3400
Jack Palevicheedf9d22009-06-04 16:23:40 -07003401 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003402 appendBytes(s, strlen(s));
3403 }
3404
3405 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003406 memcpy(ensure(n), s, n + 1);
3407 }
3408
3409 void append(char c) {
3410 * ensure(1) = c;
3411 }
3412
Jack Palevich86351982009-06-30 18:09:56 -07003413 void append(String& other) {
3414 appendBytes(other.getUnwrapped(), other.len());
3415 }
3416
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003417 char* orphan() {
3418 char* result = mpBase;
3419 mpBase = 0;
3420 mUsed = 0;
3421 mSize = 0;
3422 return result;
3423 }
3424
Jack Palevicheedf9d22009-06-04 16:23:40 -07003425 void printf(const char* fmt,...) {
3426 va_list ap;
3427 va_start(ap, fmt);
3428 vprintf(fmt, ap);
3429 va_end(ap);
3430 }
3431
3432 void vprintf(const char* fmt, va_list ap) {
3433 char* temp;
3434 int numChars = vasprintf(&temp, fmt, ap);
3435 memcpy(ensure(numChars), temp, numChars+1);
3436 free(temp);
3437 }
3438
Jack Palevich303d8ff2009-06-11 19:06:24 -07003439 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003440 return mUsed;
3441 }
3442
3443 private:
3444 char* ensure(int n) {
3445 size_t newUsed = mUsed + n;
3446 if (newUsed > mSize) {
3447 size_t newSize = mSize * 2 + 10;
3448 if (newSize < newUsed) {
3449 newSize = newUsed;
3450 }
3451 mpBase = (char*) realloc(mpBase, newSize + 1);
3452 mSize = newSize;
3453 }
3454 mpBase[newUsed] = '\0';
3455 char* result = mpBase + mUsed;
3456 mUsed = newUsed;
3457 return result;
3458 }
3459
3460 char* mpBase;
3461 size_t mUsed;
3462 size_t mSize;
3463 };
3464
Jack Palevich569f1352009-06-29 14:29:08 -07003465 void internKeywords() {
3466 // Note: order has to match TOK_ constants
3467 static const char* keywords[] = {
3468 "int",
3469 "char",
3470 "void",
3471 "if",
3472 "else",
3473 "while",
3474 "break",
3475 "return",
3476 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003477 "auto",
3478 "case",
3479 "const",
3480 "continue",
3481 "default",
3482 "do",
3483 "double",
3484 "enum",
3485 "extern",
3486 "float",
3487 "goto",
3488 "long",
3489 "register",
3490 "short",
3491 "signed",
3492 "sizeof",
3493 "static",
3494 "struct",
3495 "switch",
3496 "typedef",
3497 "union",
3498 "unsigned",
3499 "volatile",
3500 "_Bool",
3501 "_Complex",
3502 "_Imaginary",
3503 "inline",
3504 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003505
3506 // predefined tokens that can also be symbols start here:
3507 "pragma",
3508 "define",
3509 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003510 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003511
Jack Palevich569f1352009-06-29 14:29:08 -07003512 for(int i = 0; keywords[i]; i++) {
3513 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003514 }
Jack Palevich569f1352009-06-29 14:29:08 -07003515 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003516
Jack Palevich36d94142009-06-08 15:55:32 -07003517 struct InputState {
3518 InputStream* pStream;
3519 int oldCh;
3520 };
3521
Jack Palevich2db168f2009-06-11 14:29:47 -07003522 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003523 void* pAddress;
3524 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003525 tokenid_t tok;
3526 size_t level;
3527 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003528 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003529 };
3530
Jack Palevich303d8ff2009-06-11 19:06:24 -07003531 class SymbolStack {
3532 public:
3533 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003534 mpArena = 0;
3535 mpTokenTable = 0;
3536 }
3537
3538 void setArena(Arena* pArena) {
3539 mpArena = pArena;
3540 }
3541
3542 void setTokenTable(TokenTable* pTokenTable) {
3543 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003544 }
3545
3546 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003547 Mark mark;
3548 mark.mArenaMark = mpArena->mark();
3549 mark.mSymbolHead = mStack.size();
3550 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003551 }
3552
3553 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003554 // Undo any shadowing that was done:
3555 Mark mark = mLevelStack.back();
3556 mLevelStack.pop_back();
3557 while (mStack.size() > mark.mSymbolHead) {
3558 VariableInfo* pV = mStack.back();
3559 mStack.pop_back();
3560 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003561 }
Jack Palevich569f1352009-06-29 14:29:08 -07003562 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003563 }
3564
Jack Palevich569f1352009-06-29 14:29:08 -07003565 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3566 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3567 return pV && pV->level == level();
3568 }
3569
3570 VariableInfo* add(tokenid_t tok) {
3571 Token& token = (*mpTokenTable)[tok];
3572 VariableInfo* pOldV = token.mpVariableInfo;
3573 VariableInfo* pNewV =
3574 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3575 memset(pNewV, 0, sizeof(VariableInfo));
3576 pNewV->tok = tok;
3577 pNewV->level = level();
3578 pNewV->pOldDefinition = pOldV;
3579 token.mpVariableInfo = pNewV;
3580 mStack.push_back(pNewV);
3581 return pNewV;
3582 }
3583
Jack Palevich86351982009-06-30 18:09:56 -07003584 VariableInfo* add(Type* pType) {
3585 VariableInfo* pVI = add(pType->id);
3586 pVI->pType = pType;
3587 return pVI;
3588 }
3589
Jack Palevich569f1352009-06-29 14:29:08 -07003590 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3591 for (size_t i = 0; i < mStack.size(); i++) {
3592 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003593 break;
3594 }
3595 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003596 }
3597
Jack Palevich303d8ff2009-06-11 19:06:24 -07003598 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003599 inline size_t level() {
3600 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003601 }
3602
Jack Palevich569f1352009-06-29 14:29:08 -07003603 struct Mark {
3604 Arena::Mark mArenaMark;
3605 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003606 };
3607
Jack Palevich569f1352009-06-29 14:29:08 -07003608 Arena* mpArena;
3609 TokenTable* mpTokenTable;
3610 Vector<VariableInfo*> mStack;
3611 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003612 };
Jack Palevich36d94142009-06-08 15:55:32 -07003613
3614 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003615 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003616 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003617 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003618 int tokl; // token operator level
3619 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003620 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003621 intptr_t loc; // local variable index
3622 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003623 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003624 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003625 char* dptr; // Macro state: Points to macro text during macro playback.
3626 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003627 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003628 ACCSymbolLookupFn mpSymbolLookupFn;
3629 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003630
3631 // Arena for the duration of the compile
3632 Arena mGlobalArena;
3633 // Arena for data that's only needed when compiling a single function
3634 Arena mLocalArena;
3635
Jack Palevich2ff5c222009-07-23 15:11:22 -07003636 Arena* mpCurrentArena;
3637
Jack Palevich569f1352009-06-29 14:29:08 -07003638 TokenTable mTokenTable;
3639 SymbolStack mGlobals;
3640 SymbolStack mLocals;
3641
Jack Palevich40600de2009-07-01 15:32:35 -07003642 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003643 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003644 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003645 Type* mkpChar; // char
3646 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003647 Type* mkpFloat;
3648 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003649 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003650 Type* mkpIntPtr;
3651 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003652 Type* mkpFloatPtr;
3653 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003654 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003655
Jack Palevich36d94142009-06-08 15:55:32 -07003656 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003657 int mLineNumber;
3658 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003659
3660 CodeBuf codeBuf;
3661 CodeGenerator* pGen;
3662
Jack Palevicheedf9d22009-06-04 16:23:40 -07003663 String mErrorBuf;
3664
Jack Palevicheedf9d22009-06-04 16:23:40 -07003665 String mPragmas;
3666 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003667 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003668
Jack Palevich21a15a22009-05-11 14:49:29 -07003669 static const int ALLOC_SIZE = 99999;
3670
Jack Palevich303d8ff2009-06-11 19:06:24 -07003671 static const int TOK_DUMMY = 1;
3672 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003673 static const int TOK_NUM_FLOAT = 3;
3674 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003675 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003676
3677 // 3..255 are character and/or operators
3678
Jack Palevich2db168f2009-06-11 14:29:47 -07003679 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003680 // Order has to match string list in "internKeywords".
3681 enum {
3682 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3683 TOK_INT = TOK_KEYWORD,
3684 TOK_CHAR,
3685 TOK_VOID,
3686 TOK_IF,
3687 TOK_ELSE,
3688 TOK_WHILE,
3689 TOK_BREAK,
3690 TOK_RETURN,
3691 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003692 TOK_AUTO,
3693 TOK_CASE,
3694 TOK_CONST,
3695 TOK_CONTINUE,
3696 TOK_DEFAULT,
3697 TOK_DO,
3698 TOK_DOUBLE,
3699 TOK_ENUM,
3700 TOK_EXTERN,
3701 TOK_FLOAT,
3702 TOK_GOTO,
3703 TOK_LONG,
3704 TOK_REGISTER,
3705 TOK_SHORT,
3706 TOK_SIGNED,
3707 TOK_SIZEOF,
3708 TOK_STATIC,
3709 TOK_STRUCT,
3710 TOK_SWITCH,
3711 TOK_TYPEDEF,
3712 TOK_UNION,
3713 TOK_UNSIGNED,
3714 TOK_VOLATILE,
3715 TOK__BOOL,
3716 TOK__COMPLEX,
3717 TOK__IMAGINARY,
3718 TOK_INLINE,
3719 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003720
3721 // Symbols start after keywords
3722
3723 TOK_SYMBOL,
3724 TOK_PRAGMA = TOK_SYMBOL,
3725 TOK_DEFINE,
3726 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003727 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003728
3729 static const int LOCAL = 0x200;
3730
3731 static const int SYM_FORWARD = 0;
3732 static const int SYM_DEFINE = 1;
3733
3734 /* tokens in string heap */
3735 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003736
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003737 static const int OP_INCREMENT = 0;
3738 static const int OP_DECREMENT = 1;
3739 static const int OP_MUL = 2;
3740 static const int OP_DIV = 3;
3741 static const int OP_MOD = 4;
3742 static const int OP_PLUS = 5;
3743 static const int OP_MINUS = 6;
3744 static const int OP_SHIFT_LEFT = 7;
3745 static const int OP_SHIFT_RIGHT = 8;
3746 static const int OP_LESS_EQUAL = 9;
3747 static const int OP_GREATER_EQUAL = 10;
3748 static const int OP_LESS = 11;
3749 static const int OP_GREATER = 12;
3750 static const int OP_EQUALS = 13;
3751 static const int OP_NOT_EQUALS = 14;
3752 static const int OP_LOGICAL_AND = 15;
3753 static const int OP_LOGICAL_OR = 16;
3754 static const int OP_BIT_AND = 17;
3755 static const int OP_BIT_XOR = 18;
3756 static const int OP_BIT_OR = 19;
3757 static const int OP_BIT_NOT = 20;
3758 static const int OP_LOGICAL_NOT = 21;
3759 static const int OP_COUNT = 22;
3760
3761 /* Operators are searched from front, the two-character operators appear
3762 * before the single-character operators with the same first character.
3763 * @ is used to pad out single-character operators.
3764 */
3765 static const char* operatorChars;
3766 static const char operatorLevel[];
3767
Jack Palevich569f1352009-06-29 14:29:08 -07003768 /* Called when we detect an internal problem. Does nothing in production.
3769 *
3770 */
3771 void internalError() {
3772 * (char*) 0 = 0;
3773 }
3774
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003775 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003776 if (!isTrue) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003777 LOGD("assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003778 internalError();
3779 }
Jack Palevich86351982009-06-30 18:09:56 -07003780 }
3781
Jack Palevich40600de2009-07-01 15:32:35 -07003782 bool isSymbol(tokenid_t t) {
3783 return t >= TOK_SYMBOL &&
3784 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3785 }
3786
3787 bool isSymbolOrKeyword(tokenid_t t) {
3788 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003789 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003790 }
3791
Jack Palevich86351982009-06-30 18:09:56 -07003792 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003793 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003794 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3795 if (pV && pV->tok != t) {
3796 internalError();
3797 }
3798 return pV;
3799 }
3800
3801 inline bool isDefined(tokenid_t t) {
3802 return t >= TOK_SYMBOL && VI(t) != 0;
3803 }
3804
Jack Palevich40600de2009-07-01 15:32:35 -07003805 const char* nameof(tokenid_t t) {
3806 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003807 return mTokenTable[t].pText;
3808 }
3809
Jack Palevich21a15a22009-05-11 14:49:29 -07003810 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003811 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003812 }
3813
3814 void inp() {
3815 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003816 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003817 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003818 dptr = 0;
3819 ch = dch;
3820 }
Jack Palevichdc456462009-07-16 16:50:56 -07003821 } else {
3822 if (mbBumpLine) {
3823 mLineNumber++;
3824 mbBumpLine = false;
3825 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003826 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003827 if (ch == '\n') {
3828 mbBumpLine = true;
3829 }
3830 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003831#if 0
3832 printf("ch='%c' 0x%x\n", ch, ch);
3833#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003834 }
3835
3836 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003837 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003838 }
3839
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003840 int decodeHex(int c) {
3841 if (isdigit(c)) {
3842 c -= '0';
3843 } else if (c <= 'F') {
3844 c = c - 'A' + 10;
3845 } else {
3846 c =c - 'a' + 10;
3847 }
3848 return c;
3849 }
3850
Jack Palevichb4758ff2009-06-12 12:49:14 -07003851 /* read a character constant, advances ch to after end of constant */
3852 int getq() {
3853 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003854 if (ch == '\\') {
3855 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003856 if (isoctal(ch)) {
3857 // 1 to 3 octal characters.
3858 val = 0;
3859 for(int i = 0; i < 3; i++) {
3860 if (isoctal(ch)) {
3861 val = (val << 3) + ch - '0';
3862 inp();
3863 }
3864 }
3865 return val;
3866 } else if (ch == 'x' || ch == 'X') {
3867 // N hex chars
3868 inp();
3869 if (! isxdigit(ch)) {
3870 error("'x' character escape requires at least one digit.");
3871 } else {
3872 val = 0;
3873 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003874 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003875 inp();
3876 }
3877 }
3878 } else {
3879 int val = ch;
3880 switch (ch) {
3881 case 'a':
3882 val = '\a';
3883 break;
3884 case 'b':
3885 val = '\b';
3886 break;
3887 case 'f':
3888 val = '\f';
3889 break;
3890 case 'n':
3891 val = '\n';
3892 break;
3893 case 'r':
3894 val = '\r';
3895 break;
3896 case 't':
3897 val = '\t';
3898 break;
3899 case 'v':
3900 val = '\v';
3901 break;
3902 case '\\':
3903 val = '\\';
3904 break;
3905 case '\'':
3906 val = '\'';
3907 break;
3908 case '"':
3909 val = '"';
3910 break;
3911 case '?':
3912 val = '?';
3913 break;
3914 default:
3915 error("Undefined character escape %c", ch);
3916 break;
3917 }
3918 inp();
3919 return val;
3920 }
3921 } else {
3922 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003923 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003924 return val;
3925 }
3926
3927 static bool isoctal(int ch) {
3928 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003929 }
3930
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003931 bool acceptCh(int c) {
3932 bool result = c == ch;
3933 if (result) {
3934 pdef(ch);
3935 inp();
3936 }
3937 return result;
3938 }
3939
3940 bool acceptDigitsCh() {
3941 bool result = false;
3942 while (isdigit(ch)) {
3943 result = true;
3944 pdef(ch);
3945 inp();
3946 }
3947 return result;
3948 }
3949
3950 void parseFloat() {
3951 tok = TOK_NUM_DOUBLE;
3952 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003953 if(mTokenString.len() == 0) {
3954 mTokenString.append('0');
3955 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003956 acceptCh('.');
3957 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003958 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003959 acceptCh('-') || acceptCh('+');
3960 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003961 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003962 if (ch == 'f' || ch == 'F') {
3963 tok = TOK_NUM_FLOAT;
3964 inp();
3965 } else if (ch == 'l' || ch == 'L') {
3966 inp();
3967 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003968 }
3969 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003970 char* pEnd = pText + strlen(pText);
3971 char* pEndPtr = 0;
3972 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003973 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003974 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003975 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003976 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003977 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003978 if (errno || pEndPtr != pEnd) {
3979 error("Can't parse constant: %s", pText);
3980 }
3981 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003982 }
3983
Jack Palevich21a15a22009-05-11 14:49:29 -07003984 void next() {
3985 int l, a;
3986
Jack Palevich546b2242009-05-13 15:10:04 -07003987 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003988 if (ch == '#') {
3989 inp();
3990 next();
3991 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003992 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003993 } else if (tok == TOK_PRAGMA) {
3994 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003995 } else if (tok == TOK_LINE) {
3996 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003997 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003998 error("Unsupported preprocessor directive \"%s\"",
3999 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004000 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004001 }
4002 inp();
4003 }
4004 tokl = 0;
4005 tok = ch;
4006 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004007 if (isdigit(ch) || ch == '.') {
4008 // Start of a numeric constant. Could be integer, float, or
4009 // double, won't know until we look further.
4010 mTokenString.clear();
4011 pdef(ch);
4012 inp();
4013 int base = 10;
4014 if (tok == '0') {
4015 if (ch == 'x' || ch == 'X') {
4016 base = 16;
4017 tok = TOK_NUM;
4018 tokc = 0;
4019 inp();
4020 while ( isxdigit(ch) ) {
4021 tokc = (tokc << 4) + decodeHex(ch);
4022 inp();
4023 }
4024 } else if (isoctal(ch)){
4025 base = 8;
4026 tok = TOK_NUM;
4027 tokc = 0;
4028 while ( isoctal(ch) ) {
4029 tokc = (tokc << 3) + (ch - '0');
4030 inp();
4031 }
4032 }
4033 } else if (isdigit(tok)){
4034 acceptDigitsCh();
4035 }
4036 if (base == 10) {
4037 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4038 parseFloat();
4039 } else {
4040 // It's an integer constant
4041 char* pText = mTokenString.getUnwrapped();
4042 char* pEnd = pText + strlen(pText);
4043 char* pEndPtr = 0;
4044 errno = 0;
4045 tokc = strtol(pText, &pEndPtr, base);
4046 if (errno || pEndPtr != pEnd) {
4047 error("Can't parse constant: %s %d %d", pText, base, errno);
4048 }
4049 tok = TOK_NUM;
4050 }
4051 }
4052 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004053 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004054 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004055 pdef(ch);
4056 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004057 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004058 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004059 if (! mbSuppressMacroExpansion) {
4060 // Is this a macro?
4061 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4062 if (pMacroDefinition) {
4063 // Yes, it is a macro
4064 dptr = pMacroDefinition;
4065 dch = ch;
4066 inp();
4067 next();
4068 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004069 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004070 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004071 inp();
4072 if (tok == '\'') {
4073 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004074 tokc = getq();
4075 if (ch != '\'') {
4076 error("Expected a ' character, got %c", ch);
4077 } else {
4078 inp();
4079 }
Jack Palevich546b2242009-05-13 15:10:04 -07004080 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004081 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004082 while (ch && ch != EOF) {
4083 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004084 inp();
4085 inp();
4086 if (ch == '/')
4087 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004088 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004089 if (ch == EOF) {
4090 error("End of file inside comment.");
4091 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004092 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004093 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004094 } else if ((tok == '/') & (ch == '/')) {
4095 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004096 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004097 inp();
4098 }
4099 inp();
4100 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07004101 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004102 const char* t = operatorChars;
4103 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004104 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004105 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004106 tokl = operatorLevel[opIndex];
4107 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004108 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004109#if 0
4110 printf("%c%c -> tokl=%d tokc=0x%x\n",
4111 l, a, tokl, tokc);
4112#endif
4113 if (a == ch) {
4114 inp();
4115 tok = TOK_DUMMY; /* dummy token for double tokens */
4116 }
Jack Palevich0c017742009-07-31 12:00:39 -07004117 /* check for op=, valid for * / % + - << >> & ^ | */
4118 if (ch == '=' &&
4119 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004120 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004121 inp();
4122 tok = TOK_OP_ASSIGNMENT;
4123 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004124 break;
4125 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004126 opIndex++;
4127 }
4128 if (l == 0) {
4129 tokl = 0;
4130 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004131 }
4132 }
4133 }
4134#if 0
4135 {
Jack Palevich569f1352009-06-29 14:29:08 -07004136 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004137 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004138 fprintf(stderr, "%s\n", buf.getUnwrapped());
4139 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004140#endif
4141 }
4142
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004143 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004144 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004145 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004146 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004147 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004148 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004149 if (ch == '(') {
4150 delete pName;
4151 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004152 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004153 }
4154 while (isspace(ch)) {
4155 inp();
4156 }
Jack Palevich569f1352009-06-29 14:29:08 -07004157 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004158 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004159 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004160 // Check for '//' comments.
4161 if (appendToValue && ch == '/') {
4162 inp();
4163 if (ch == '/') {
4164 appendToValue = false;
4165 } else {
4166 value.append('/');
4167 }
4168 }
4169 if (appendToValue && ch != EOF) {
4170 value.append(ch);
4171 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004172 inp();
4173 }
Jack Palevich569f1352009-06-29 14:29:08 -07004174 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4175 memcpy(pDefn, value.getUnwrapped(), value.len());
4176 pDefn[value.len()] = 0;
4177 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004178 }
4179
Jack Palevicheedf9d22009-06-04 16:23:40 -07004180 void doPragma() {
4181 // # pragma name(val)
4182 int state = 0;
4183 while(ch != EOF && ch != '\n' && state < 10) {
4184 switch(state) {
4185 case 0:
4186 if (isspace(ch)) {
4187 inp();
4188 } else {
4189 state++;
4190 }
4191 break;
4192 case 1:
4193 if (isalnum(ch)) {
4194 mPragmas.append(ch);
4195 inp();
4196 } else if (ch == '(') {
4197 mPragmas.append(0);
4198 inp();
4199 state++;
4200 } else {
4201 state = 11;
4202 }
4203 break;
4204 case 2:
4205 if (isalnum(ch)) {
4206 mPragmas.append(ch);
4207 inp();
4208 } else if (ch == ')') {
4209 mPragmas.append(0);
4210 inp();
4211 state = 10;
4212 } else {
4213 state = 11;
4214 }
4215 break;
4216 }
4217 }
4218 if(state != 10) {
4219 error("Unexpected pragma syntax");
4220 }
4221 mPragmaStringCount += 2;
4222 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004223
Jack Palevichdc456462009-07-16 16:50:56 -07004224 void doLine() {
4225 // # line number { "filename "}
4226 next();
4227 if (tok != TOK_NUM) {
4228 error("Expected a line-number");
4229 } else {
4230 mLineNumber = tokc-1; // The end-of-line will increment it.
4231 }
4232 while(ch != EOF && ch != '\n') {
4233 inp();
4234 }
4235 }
4236
Jack Palevichac0e95e2009-05-29 13:53:44 -07004237 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004238 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004239 mErrorBuf.vprintf(fmt, ap);
4240 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004241 }
4242
Jack Palevich8b0624c2009-05-20 12:12:06 -07004243 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004244 if (tok != c) {
4245 error("'%c' expected", c);
4246 }
4247 next();
4248 }
4249
Jack Palevich86351982009-06-30 18:09:56 -07004250 bool accept(intptr_t c) {
4251 if (tok == c) {
4252 next();
4253 return true;
4254 }
4255 return false;
4256 }
4257
Jack Palevich40600de2009-07-01 15:32:35 -07004258 bool acceptStringLiteral() {
4259 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004260 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004261 // This while loop merges multiple adjacent string constants.
4262 while (tok == '"') {
4263 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004264 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004265 }
4266 if (ch != '"') {
4267 error("Unterminated string constant.");
4268 }
4269 inp();
4270 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004271 }
Jack Palevich40600de2009-07-01 15:32:35 -07004272 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004273 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004274 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004275 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004276
4277 return true;
4278 }
4279 return false;
4280 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004281
Jack Palevichb1544ca2009-07-16 15:09:20 -07004282 void linkGlobal(tokenid_t t, bool isFunction) {
4283 VariableInfo* pVI = VI(t);
4284 void* n = NULL;
4285 if (mpSymbolLookupFn) {
4286 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4287 }
4288 if (pVI->pType == NULL) {
4289 if (isFunction) {
4290 pVI->pType = mkpIntFn;
4291 } else {
4292 pVI->pType = mkpInt;
4293 }
4294 }
4295 pVI->pAddress = n;
4296 }
4297
Jack Palevich29daf572009-07-30 19:38:55 -07004298 void unaryOrAssignment() {
4299 unary();
4300 if (accept('=')) {
4301 checkLVal();
4302 pGen->pushR0();
4303 expr();
4304 pGen->forceR0RVal();
4305 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004306 } else if (tok == TOK_OP_ASSIGNMENT) {
4307 int t = tokc;
4308 next();
4309 checkLVal();
4310 pGen->pushR0();
4311 pGen->forceR0RVal();
4312 pGen->pushR0();
4313 expr();
4314 pGen->forceR0RVal();
4315 pGen->genOp(t);
4316 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004317 }
4318 }
4319
Jack Palevich40600de2009-07-01 15:32:35 -07004320 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004321 */
Jack Palevich29daf572009-07-30 19:38:55 -07004322 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004323 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004324 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004325 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004326 if (acceptStringLiteral()) {
4327 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004328 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004329 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004330 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004331 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004332 t = tok;
4333 next();
4334 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004335 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004336 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004337 // Align to 4-byte boundary
4338 glo = (char*) (((intptr_t) glo + 3) & -4);
4339 * (float*) glo = (float) ad;
4340 pGen->loadFloat((int) glo, mkpFloat);
4341 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004342 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004343 // Align to 8-byte boundary
4344 glo = (char*) (((intptr_t) glo + 7) & -8);
4345 * (double*) glo = ad;
4346 pGen->loadFloat((int) glo, mkpDouble);
4347 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004348 } else if (c == 2) {
4349 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004350 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004351 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004352 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004353 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004354 else if (t == '+') {
4355 // ignore unary plus.
4356 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004357 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004358 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004359 } else if (c == 11) {
4360 // pre increment / pre decrement
4361 unary();
4362 doIncDec(a == OP_INCREMENT, 0);
4363 }
4364 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004365 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004366 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004367 if (pCast) {
4368 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004369 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004370 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004371 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004372 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004373 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004374 skip(')');
4375 }
4376 } else if (t == '*') {
4377 /* This is a pointer dereference.
4378 */
Jack Palevich29daf572009-07-30 19:38:55 -07004379 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004380 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004381 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004382 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004383 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4384 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004385 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004386 } else if (t == EOF ) {
4387 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004388 } else if (t == ';') {
4389 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004390 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004391 // Don't have to do anything special here, the error
4392 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004393 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004394 if (!isDefined(t)) {
4395 mGlobals.add(t);
4396 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004397 }
Jack Palevich8df46192009-07-07 14:48:51 -07004398 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004399 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004400 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004401 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004402 linkGlobal(t, tok == '(');
4403 n = (intptr_t) pVI->pAddress;
4404 if (!n && tok != '(') {
4405 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004406 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004407 }
Jack Palevich29daf572009-07-30 19:38:55 -07004408 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004409 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004410 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004411 linkGlobal(t, false);
4412 n = (intptr_t) pVI->pAddress;
4413 if (!n) {
4414 error("Undeclared variable %s\n", nameof(t));
4415 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004416 }
Jack Palevich5b659092009-07-31 14:55:07 -07004417 }
4418 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004419 Type* pVal;
4420 ExpressionType et;
4421 if (pVI->pType->tag == TY_ARRAY) {
4422 pVal = pVI->pType;
4423 et = ET_RVALUE;
4424 } else {
4425 pVal = createPtrType(pVI->pType);
4426 et = ET_LVALUE;
4427 }
Jack Palevich5b659092009-07-31 14:55:07 -07004428 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004429 int tag = pVal->pHead->tag;
4430 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004431 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004432 }
Jack Palevich5b659092009-07-31 14:55:07 -07004433 pGen->leaR0(n, pVal, et);
4434 } else {
4435 pVI->pForward = (void*) pGen->leaForward(
4436 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004437 }
4438 }
4439 }
4440
Jack Palevich5b659092009-07-31 14:55:07 -07004441 /* Now handle postfix operators */
4442 for(;;) {
4443 if (tokl == 11) {
4444 // post inc / post dec
4445 doIncDec(tokc == OP_INCREMENT, true);
4446 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004447 } else if (accept('[')) {
4448 // Array reference
4449 pGen->forceR0RVal();
4450 pGen->pushR0();
4451 commaExpr();
4452 pGen->forceR0RVal();
4453 pGen->genOp(OP_PLUS);
4454 doPointer();
4455 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004456 } else if (accept('(')) {
4457 /* function call */
4458 Type* pDecl = NULL;
4459 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004460 Type* pFn = pGen->getR0Type();
4461 assert(pFn->tag == TY_POINTER);
4462 assert(pFn->pHead->tag == TY_FUNC);
4463 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004464 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004465 Type* pArgList = pDecl->pTail;
4466 bool varArgs = pArgList == NULL;
4467 /* push args and invert order */
4468 a = pGen->beginFunctionCallArguments();
4469 int l = 0;
4470 int argCount = 0;
4471 while (tok != ')' && tok != EOF) {
4472 if (! varArgs && !pArgList) {
4473 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004474 }
Jack Palevich5b659092009-07-31 14:55:07 -07004475 expr();
4476 pGen->forceR0RVal();
4477 Type* pTargetType;
4478 if (pArgList) {
4479 pTargetType = pArgList->pHead;
4480 pArgList = pArgList->pTail;
4481 } else {
4482 // This is a ... function, just pass arguments in their
4483 // natural type.
4484 pTargetType = pGen->getR0Type();
4485 if (pTargetType->tag == TY_FLOAT) {
4486 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004487 } else if (pTargetType->tag == TY_ARRAY) {
4488 // Pass arrays by pointer.
4489 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004490 }
4491 }
4492 if (pTargetType->tag == TY_VOID) {
4493 error("Can't pass void value for argument %d",
4494 argCount + 1);
4495 } else {
4496 l += pGen->storeR0ToArg(l, pTargetType);
4497 }
4498 if (accept(',')) {
4499 // fine
4500 } else if ( tok != ')') {
4501 error("Expected ',' or ')'");
4502 }
4503 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004504 }
Jack Palevich5b659092009-07-31 14:55:07 -07004505 if (! varArgs && pArgList) {
4506 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004507 }
Jack Palevich5b659092009-07-31 14:55:07 -07004508 pGen->endFunctionCallArguments(pDecl, a, l);
4509 skip(')');
4510 pGen->callIndirect(l, pDecl);
4511 pGen->adjustStackAfterCall(pDecl, l, true);
4512 } else {
4513 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004514 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004515 }
4516 }
4517
Jack Palevichaaac9282009-07-31 14:34:34 -07004518 void doIncDec(int isInc, int isPost) {
4519 // R0 already has the lval
4520 checkLVal();
4521 int lit = isInc ? 1 : -1;
4522 pGen->pushR0();
4523 pGen->loadR0FromR0();
4524 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004525 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4526 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004527 error("++/-- illegal for this type. %d", tag);
4528 }
4529 if (isPost) {
4530 pGen->over();
4531 pGen->pushR0();
4532 pGen->li(lit);
4533 pGen->genOp(OP_PLUS);
4534 pGen->storeR0ToTOS();
4535 pGen->popR0();
4536 } else {
4537 pGen->pushR0();
4538 pGen->li(lit);
4539 pGen->genOp(OP_PLUS);
4540 pGen->over();
4541 pGen->storeR0ToTOS();
4542 pGen->popR0();
4543 }
4544 }
4545
Jack Palevich47cbea92009-07-31 15:25:53 -07004546 void doPointer() {
4547 pGen->forceR0RVal();
4548 Type* pR0Type = pGen->getR0Type();
4549 if (pR0Type->tag != TY_POINTER) {
4550 error("Expected a pointer type.");
4551 } else {
4552 if (pR0Type->pHead->tag != TY_FUNC) {
4553 pGen->setR0ExpressionType(ET_LVALUE);
4554 }
4555 }
4556 }
4557
Jack Palevich40600de2009-07-01 15:32:35 -07004558 /* Recursive descent parser for binary operations.
4559 */
4560 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004561 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004562 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004563 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004564 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004565 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004566 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004567 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004568 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004569 t = tokc;
4570 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004571 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004572 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004573 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004574 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004575 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004576 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004577 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004578 // Check for syntax error.
4579 if (pGen->getR0Type() == NULL) {
4580 // We failed to parse a right-hand argument.
4581 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004582 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004583 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004584 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004585 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004586 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004587 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004588 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004589 }
4590 }
4591 }
4592 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004593 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004594 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004595 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004596 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004597 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004598 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004599 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004600 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004601 }
4602 }
4603 }
4604
Jack Palevich43aaee32009-07-31 14:01:37 -07004605 void commaExpr() {
4606 for(;;) {
4607 expr();
4608 if (!accept(',')) {
4609 break;
4610 }
4611 }
4612 }
4613
Jack Palevich21a15a22009-05-11 14:49:29 -07004614 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004615 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004616 }
4617
4618 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004619 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004620 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004621 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004622 }
4623
Jack Palevicha6baa232009-06-12 11:25:59 -07004624 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004625 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004626
Jack Palevich95727a02009-07-06 12:07:15 -07004627 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004628 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004629 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004630 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004631 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004632 next();
4633 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004634 a = test_expr();
4635 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004636 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004637 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004638 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004639 n = pGen->gjmp(0); /* jmp */
4640 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004641 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004642 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004643 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004644 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004645 }
Jack Palevich546b2242009-05-13 15:10:04 -07004646 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004647 t = tok;
4648 next();
4649 skip('(');
4650 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004651 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004652 a = test_expr();
4653 } else {
4654 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004655 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004656 skip(';');
4657 n = codeBuf.getPC();
4658 a = 0;
4659 if (tok != ';')
4660 a = test_expr();
4661 skip(';');
4662 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004663 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004664 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004665 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004666 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004667 n = t + 4;
4668 }
4669 }
4670 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004671 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004672 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004673 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004674 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004675 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004676 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004677 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004678 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004679 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004680 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004681 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004682 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004683 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004684 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004685 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004686 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004687 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004688 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004689 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004690 if (pReturnType->tag == TY_VOID) {
4691 error("Must not return a value from a void function");
4692 } else {
4693 pGen->convertR0(pReturnType);
4694 }
4695 } else {
4696 if (pReturnType->tag != TY_VOID) {
4697 error("Must specify a value here");
4698 }
Jack Palevich8df46192009-07-07 14:48:51 -07004699 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004700 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004701 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004702 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004703 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004704 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004705 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004706 }
4707 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004708
Jack Palevicha8f427f2009-07-13 18:40:08 -07004709 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004710 if (a == b) {
4711 return true;
4712 }
4713 if (a == NULL || b == NULL) {
4714 return false;
4715 }
4716 TypeTag at = a->tag;
4717 if (at != b->tag) {
4718 return false;
4719 }
4720 if (at == TY_POINTER) {
4721 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004722 } else if (at == TY_ARRAY) {
4723 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004724 } else if (at == TY_FUNC || at == TY_PARAM) {
4725 return typeEqual(a->pHead, b->pHead)
4726 && typeEqual(a->pTail, b->pTail);
4727 }
4728 return true;
4729 }
4730
Jack Palevich2ff5c222009-07-23 15:11:22 -07004731 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004732 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004733 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004734 memset(pType, 0, sizeof(*pType));
4735 pType->tag = tag;
4736 pType->pHead = pHead;
4737 pType->pTail = pTail;
4738 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004739 }
4740
Jack Palevich2ff5c222009-07-23 15:11:22 -07004741 Type* createPtrType(Type* pType) {
4742 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004743 }
4744
4745 /**
4746 * Try to print a type in declaration order
4747 */
Jack Palevich86351982009-06-30 18:09:56 -07004748 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004749 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004750 if (pType == NULL) {
4751 buffer.appendCStr("null");
4752 return;
4753 }
Jack Palevich3f226492009-07-02 14:46:19 -07004754 decodeTypeImp(buffer, pType);
4755 }
4756
4757 void decodeTypeImp(String& buffer, Type* pType) {
4758 decodeTypeImpPrefix(buffer, pType);
4759
Jack Palevich86351982009-06-30 18:09:56 -07004760 String temp;
4761 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004762 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004763 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004764 }
4765
4766 decodeTypeImpPostfix(buffer, pType);
4767 }
4768
4769 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4770 TypeTag tag = pType->tag;
4771
Jack Palevich37c54bd2009-07-14 18:35:36 -07004772 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004773 switch (tag) {
4774 case TY_INT:
4775 buffer.appendCStr("int");
4776 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004777 case TY_SHORT:
4778 buffer.appendCStr("short");
4779 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004780 case TY_CHAR:
4781 buffer.appendCStr("char");
4782 break;
4783 case TY_VOID:
4784 buffer.appendCStr("void");
4785 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004786 case TY_FLOAT:
4787 buffer.appendCStr("float");
4788 break;
4789 case TY_DOUBLE:
4790 buffer.appendCStr("double");
4791 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004792 default:
4793 break;
4794 }
Jack Palevich86351982009-06-30 18:09:56 -07004795 buffer.append(' ');
4796 }
Jack Palevich3f226492009-07-02 14:46:19 -07004797
4798 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004799 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004800 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004801 case TY_SHORT:
4802 break;
Jack Palevich86351982009-06-30 18:09:56 -07004803 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004804 break;
4805 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004806 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004807 case TY_FLOAT:
4808 break;
4809 case TY_DOUBLE:
4810 break;
Jack Palevich86351982009-06-30 18:09:56 -07004811 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004812 decodeTypeImpPrefix(buffer, pType->pHead);
4813 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4814 buffer.append('(');
4815 }
4816 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004817 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004818 case TY_ARRAY:
4819 decodeTypeImpPrefix(buffer, pType->pHead);
4820 break;
Jack Palevich86351982009-06-30 18:09:56 -07004821 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004822 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004823 break;
4824 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004825 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004826 break;
4827 default:
4828 String temp;
4829 temp.printf("Unknown tag %d", pType->tag);
4830 buffer.append(temp);
4831 break;
4832 }
Jack Palevich3f226492009-07-02 14:46:19 -07004833 }
4834
4835 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4836 TypeTag tag = pType->tag;
4837
4838 switch(tag) {
4839 case TY_POINTER:
4840 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4841 buffer.append(')');
4842 }
4843 decodeTypeImpPostfix(buffer, pType->pHead);
4844 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004845 case TY_ARRAY:
4846 {
4847 String temp;
4848 temp.printf("[%d]", pType->length);
4849 buffer.append(temp);
4850 }
4851 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004852 case TY_FUNC:
4853 buffer.append('(');
4854 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4855 decodeTypeImp(buffer, pArg);
4856 if (pArg->pTail) {
4857 buffer.appendCStr(", ");
4858 }
4859 }
4860 buffer.append(')');
4861 break;
4862 default:
4863 break;
Jack Palevich86351982009-06-30 18:09:56 -07004864 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004865 }
4866
Jack Palevich86351982009-06-30 18:09:56 -07004867 void printType(Type* pType) {
4868 String buffer;
4869 decodeType(buffer, pType);
4870 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004871 }
4872
Jack Palevich2ff5c222009-07-23 15:11:22 -07004873 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004874 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004875 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004876 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004877 } else if (tok == TOK_SHORT) {
4878 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004879 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004880 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004881 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004882 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004883 } else if (tok == TOK_FLOAT) {
4884 pType = mkpFloat;
4885 } else if (tok == TOK_DOUBLE) {
4886 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004887 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004888 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004889 }
4890 next();
Jack Palevich86351982009-06-30 18:09:56 -07004891 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004892 }
4893
Jack Palevich2ff5c222009-07-23 15:11:22 -07004894 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004895 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004896 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004897 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004898 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004899 if (declName) {
4900 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004901 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004902 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004903
Jack Palevich86351982009-06-30 18:09:56 -07004904 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004905 pType->length = pOldType->length;
4906 } else if (nameRequired) {
4907 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004908 }
Jack Palevich3f226492009-07-02 14:46:19 -07004909 // fprintf(stderr, "Parsed a declaration: ");
4910 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004911 if (reportFailure) {
4912 return NULL;
4913 }
Jack Palevich86351982009-06-30 18:09:56 -07004914 return pType;
4915 }
4916
Jack Palevich2ff5c222009-07-23 15:11:22 -07004917 Type* expectDeclaration(Type* pBaseType) {
4918 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004919 if (! pType) {
4920 error("Expected a declaration");
4921 }
4922 return pType;
4923 }
4924
Jack Palevich3f226492009-07-02 14:46:19 -07004925 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004926 Type* acceptCastTypeDeclaration() {
4927 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004928 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004929 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004930 }
Jack Palevich86351982009-06-30 18:09:56 -07004931 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004932 }
4933
Jack Palevich2ff5c222009-07-23 15:11:22 -07004934 Type* expectCastTypeDeclaration() {
4935 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004936 if (! pType) {
4937 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004938 }
Jack Palevich3f226492009-07-02 14:46:19 -07004939 return pType;
4940 }
4941
4942 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004943 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004944 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004945 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004946 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004947 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004948 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004949 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004950 return pType;
4951 }
4952
4953 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004954 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004955 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004956 // direct-dcl :
4957 // name
4958 // (dcl)
4959 // direct-dcl()
4960 // direct-dcl[]
4961 Type* pNewHead = NULL;
4962 if (accept('(')) {
4963 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004964 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004965 skip(')');
4966 } else if ((declName = acceptSymbol()) != 0) {
4967 if (nameAllowed == false && declName) {
4968 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004969 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004970 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004971 } else if (nameRequired && ! declName) {
4972 String temp;
4973 decodeToken(temp, tok, true);
4974 error("Expected name. Got %s", temp.getUnwrapped());
4975 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004976 }
Jack Palevichb6154502009-08-04 14:56:09 -07004977 for(;;) {
4978 if (accept('(')) {
4979 // Function declaration
4980 Type* pTail = acceptArgs(nameAllowed);
4981 pType = createType(TY_FUNC, pType, pTail);
4982 skip(')');
4983 } if (accept('[')) {
4984 if (tok != ']') {
4985 if (tok != TOK_NUM || tokc <= 0) {
4986 error("Expected positive integer constant");
4987 } else {
4988 Type* pDecayType = createPtrType(pType);
4989 pType = createType(TY_ARRAY, pType, pDecayType);
4990 pType->length = tokc;
4991 }
4992 next();
4993 }
4994 skip(']');
4995 } else {
4996 break;
4997 }
Jack Palevich86351982009-06-30 18:09:56 -07004998 }
Jack Palevich3f226492009-07-02 14:46:19 -07004999
5000 if (pNewHead) {
5001 Type* pA = pNewHead;
5002 while (pA->pHead) {
5003 pA = pA->pHead;
5004 }
5005 pA->pHead = pType;
5006 pType = pNewHead;
5007 }
Jack Palevich86351982009-06-30 18:09:56 -07005008 return pType;
5009 }
5010
Jack Palevich2ff5c222009-07-23 15:11:22 -07005011 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005012 Type* pHead = NULL;
5013 Type* pTail = NULL;
5014 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005015 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005016 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005017 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005018 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005019 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005020 if (!pHead) {
5021 pHead = pParam;
5022 pTail = pParam;
5023 } else {
5024 pTail->pTail = pParam;
5025 pTail = pParam;
5026 }
5027 }
5028 }
5029 if (! accept(',')) {
5030 break;
5031 }
5032 }
5033 return pHead;
5034 }
5035
Jack Palevich2ff5c222009-07-23 15:11:22 -07005036 Type* expectPrimitiveType() {
5037 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005038 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005039 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005040 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005041 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005042 }
Jack Palevich86351982009-06-30 18:09:56 -07005043 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005044 }
5045
Jack Palevichb5e33312009-07-30 19:06:34 -07005046 void checkLVal() {
5047 if (pGen->getR0ExpressionType() != ET_LVALUE) {
5048 error("Expected an lval");
5049 }
5050 }
5051
Jack Palevich86351982009-06-30 18:09:56 -07005052 void addGlobalSymbol(Type* pDecl) {
5053 tokenid_t t = pDecl->id;
5054 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005055 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005056 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005057 }
Jack Palevich86351982009-06-30 18:09:56 -07005058 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005059 }
5060
Jack Palevich86351982009-06-30 18:09:56 -07005061 void reportDuplicate(tokenid_t t) {
5062 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005063 }
5064
Jack Palevich86351982009-06-30 18:09:56 -07005065 void addLocalSymbol(Type* pDecl) {
5066 tokenid_t t = pDecl->id;
5067 if (mLocals.isDefinedAtCurrentLevel(t)) {
5068 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005069 }
Jack Palevich86351982009-06-30 18:09:56 -07005070 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005071 }
5072
Jack Palevich95727a02009-07-06 12:07:15 -07005073 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005074 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005075
Jack Palevich95727a02009-07-06 12:07:15 -07005076 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005077 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005078 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005079 if (!pDecl) {
5080 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005081 }
Jack Palevich86351982009-06-30 18:09:56 -07005082 int variableAddress = 0;
5083 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005084 size_t alignment = pGen->stackAlignmentOf(pDecl);
5085 size_t alignmentMask = ~ (alignment - 1);
5086 size_t sizeOf = pGen->sizeOf(pDecl);
5087 loc = (loc + alignment - 1) & alignmentMask;
5088 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5089 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005090 variableAddress = -loc;
5091 VI(pDecl->id)->pAddress = (void*) variableAddress;
5092 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005093 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005094 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005095 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005096 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005097 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005098 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005099 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005100 if (tok == ',')
5101 next();
5102 }
5103 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005104 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005105 }
5106 }
5107
Jack Palevichf1728be2009-06-12 13:53:51 -07005108 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005109 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005110 }
5111
Jack Palevich37c54bd2009-07-14 18:35:36 -07005112 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005113 if (token == EOF ) {
5114 buffer.printf("EOF");
5115 } else if (token == TOK_NUM) {
5116 buffer.printf("numeric constant");
5117 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005118 if (token < 32) {
5119 buffer.printf("'\\x%02x'", token);
5120 } else {
5121 buffer.printf("'%c'", token);
5122 }
Jack Palevich569f1352009-06-29 14:29:08 -07005123 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005124 if (quote) {
5125 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5126 buffer.printf("keyword \"%s\"", nameof(token));
5127 } else {
5128 buffer.printf("symbol \"%s\"", nameof(token));
5129 }
5130 } else {
5131 buffer.printf("%s", nameof(token));
5132 }
Jack Palevich569f1352009-06-29 14:29:08 -07005133 }
5134 }
5135
Jack Palevich40600de2009-07-01 15:32:35 -07005136 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005137 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005138 if (!result) {
5139 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005140 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005141 error("Expected symbol. Got %s", temp.getUnwrapped());
5142 }
5143 return result;
5144 }
5145
Jack Palevich86351982009-06-30 18:09:56 -07005146 tokenid_t acceptSymbol() {
5147 tokenid_t result = 0;
5148 if (tok >= TOK_SYMBOL) {
5149 result = tok;
5150 next();
Jack Palevich86351982009-06-30 18:09:56 -07005151 }
5152 return result;
5153 }
5154
Jack Palevichb7c81e92009-06-04 19:56:13 -07005155 void globalDeclarations() {
5156 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005157 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005158 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005159 break;
5160 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005161 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005162 if (!pDecl) {
5163 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005164 }
Jack Palevich86351982009-06-30 18:09:56 -07005165 if (! isDefined(pDecl->id)) {
5166 addGlobalSymbol(pDecl);
5167 }
5168 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005169 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005170 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005171 }
Jack Palevich86351982009-06-30 18:09:56 -07005172 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005173 // it's a variable declaration
5174 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005175 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005176 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005177 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005178 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005179 }
Jack Palevich86351982009-06-30 18:09:56 -07005180 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005181 if (tok == TOK_NUM) {
5182 if (name) {
5183 * (int*) name->pAddress = tokc;
5184 }
5185 next();
5186 } else {
5187 error("Expected an integer constant");
5188 }
5189 }
Jack Palevich86351982009-06-30 18:09:56 -07005190 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005191 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005192 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005193 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005194 if (!pDecl) {
5195 break;
5196 }
5197 if (! isDefined(pDecl->id)) {
5198 addGlobalSymbol(pDecl);
5199 }
5200 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005201 }
5202 skip(';');
5203 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005204 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005205 if (accept(';')) {
5206 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005207 } else if (tok != '{') {
5208 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005209 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005210 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07005211 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005212 /* patch forward references */
5213 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005214 /* put function address */
5215 name->pAddress = (void*) codeBuf.getPC();
5216 }
5217 // Calculate stack offsets for parameters
5218 mLocals.pushLevel();
5219 intptr_t a = 8;
5220 int argCount = 0;
5221 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5222 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005223 if (pArg->id) {
5224 addLocalSymbol(pArg);
5225 }
Jack Palevich95727a02009-07-06 12:07:15 -07005226 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005227 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07005228 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005229 if (pArg->id) {
5230 VI(pArg->id)->pAddress = (void*) a;
5231 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005232 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07005233 argCount++;
5234 }
5235 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005236 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005237 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005238 block(0, true);
5239 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005240 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005241 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005242 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07005243 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005244 }
5245 }
5246 }
5247
Jack Palevich9cbd2262009-07-08 16:48:41 -07005248 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5249 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5250 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005251 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005252 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07005253 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005254 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005255 char* result = (char*) base;
5256 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005257 return result;
5258 }
5259
Jack Palevich21a15a22009-05-11 14:49:29 -07005260 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005261 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005262 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005263 pGlobalBase = 0;
5264 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005265 if (pGen) {
5266 delete pGen;
5267 pGen = 0;
5268 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005269 if (file) {
5270 delete file;
5271 file = 0;
5272 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005273 }
5274
Jack Palevich8c246a92009-07-14 21:14:10 -07005275 // One-time initialization, when class is constructed.
5276 void init() {
5277 mpSymbolLookupFn = 0;
5278 mpSymbolLookupContext = 0;
5279 }
5280
Jack Palevich21a15a22009-05-11 14:49:29 -07005281 void clear() {
5282 tok = 0;
5283 tokc = 0;
5284 tokl = 0;
5285 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005286 rsym = 0;
5287 loc = 0;
5288 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005289 dptr = 0;
5290 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005291 file = 0;
5292 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005293 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005294 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005295 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005296 mLineNumber = 1;
5297 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005298 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005299 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005300
Jack Palevich22305132009-05-13 10:58:45 -07005301 void setArchitecture(const char* architecture) {
5302 delete pGen;
5303 pGen = 0;
5304
5305 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005306#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005307 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005308 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005309 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005310#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005311#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005312 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005313 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005314 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005315#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005316 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005317 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005318 }
5319 }
5320
5321 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005322#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005323 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005324#elif defined(DEFAULT_X86_CODEGEN)
5325 pGen = new X86CodeGenerator();
5326#endif
5327 }
5328 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005329 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005330 } else {
5331 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005332 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005333 }
5334 }
5335
Jack Palevich77ae76e2009-05-10 19:59:24 -07005336public:
Jack Palevich22305132009-05-13 10:58:45 -07005337 struct args {
5338 args() {
5339 architecture = 0;
5340 }
5341 const char* architecture;
5342 };
5343
Jack Paleviche7b59062009-05-19 17:12:17 -07005344 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005345 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005346 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005347 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005348
Jack Paleviche7b59062009-05-19 17:12:17 -07005349 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005350 cleanup();
5351 }
5352
Jack Palevich8c246a92009-07-14 21:14:10 -07005353 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5354 mpSymbolLookupFn = pFn;
5355 mpSymbolLookupContext = pContext;
5356 }
5357
Jack Palevich1cdef202009-05-22 12:06:27 -07005358 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005359 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005360
Jack Palevich2ff5c222009-07-23 15:11:22 -07005361 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005362 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005363 cleanup();
5364 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005365 mTokenTable.setArena(&mGlobalArena);
5366 mGlobals.setArena(&mGlobalArena);
5367 mGlobals.setTokenTable(&mTokenTable);
5368 mLocals.setArena(&mLocalArena);
5369 mLocals.setTokenTable(&mTokenTable);
5370
5371 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005372 codeBuf.init(ALLOC_SIZE);
5373 setArchitecture(NULL);
5374 if (!pGen) {
5375 return -1;
5376 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005377#ifdef PROVIDE_TRACE_CODEGEN
5378 pGen = new TraceCodeGenerator(pGen);
5379#endif
5380 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005381 pGen->init(&codeBuf);
5382 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005383 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5384 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005385 inp();
5386 next();
5387 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005388 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005389 result = pGen->finishCompile();
5390 if (result == 0) {
5391 if (mErrorBuf.len()) {
5392 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005393 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005394 }
Jack Palevichce105a92009-07-16 14:30:33 -07005395 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005396 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005397 }
5398
Jack Palevich86351982009-06-30 18:09:56 -07005399 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005400 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005401 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005402 mkpChar = createType(TY_CHAR, NULL, NULL);
5403 mkpVoid = createType(TY_VOID, NULL, NULL);
5404 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5405 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5406 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5407 mkpIntPtr = createPtrType(mkpInt);
5408 mkpCharPtr = createPtrType(mkpChar);
5409 mkpFloatPtr = createPtrType(mkpFloat);
5410 mkpDoublePtr = createPtrType(mkpDouble);
5411 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005412 }
5413
Jack Palevicha6baa232009-06-12 11:25:59 -07005414 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005415 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005416 }
5417
Jack Palevich569f1352009-06-29 14:29:08 -07005418 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005419 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005420 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005421 }
5422
Jack Palevich569f1352009-06-29 14:29:08 -07005423 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005424 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005425 error("Undefined forward reference: %s",
5426 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005427 }
5428 return true;
5429 }
5430
Jack Palevich21a15a22009-05-11 14:49:29 -07005431 int dump(FILE* out) {
5432 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5433 return 0;
5434 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005435
Jack Palevicha6535612009-05-13 16:24:17 -07005436 int disassemble(FILE* out) {
5437 return pGen->disassemble(out);
5438 }
5439
Jack Palevich1cdef202009-05-22 12:06:27 -07005440 /* Look through the symbol table to find a symbol.
5441 * If found, return its value.
5442 */
5443 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005444 if (mCompileResult == 0) {
5445 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5446 VariableInfo* pVariableInfo = VI(tok);
5447 if (pVariableInfo) {
5448 return pVariableInfo->pAddress;
5449 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005450 }
5451 return NULL;
5452 }
5453
Jack Palevicheedf9d22009-06-04 16:23:40 -07005454 void getPragmas(ACCsizei* actualStringCount,
5455 ACCsizei maxStringCount, ACCchar** strings) {
5456 int stringCount = mPragmaStringCount;
5457 if (actualStringCount) {
5458 *actualStringCount = stringCount;
5459 }
5460 if (stringCount > maxStringCount) {
5461 stringCount = maxStringCount;
5462 }
5463 if (strings) {
5464 char* pPragmas = mPragmas.getUnwrapped();
5465 while (stringCount-- > 0) {
5466 *strings++ = pPragmas;
5467 pPragmas += strlen(pPragmas) + 1;
5468 }
5469 }
5470 }
5471
Jack Palevichac0e95e2009-05-29 13:53:44 -07005472 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005473 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005474 }
5475
Jack Palevich77ae76e2009-05-10 19:59:24 -07005476};
5477
Jack Paleviche7b59062009-05-19 17:12:17 -07005478const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005479 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5480
Jack Paleviche7b59062009-05-19 17:12:17 -07005481const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005482 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5483 5, 5, /* ==, != */
5484 9, 10, /* &&, || */
5485 6, 7, 8, /* & ^ | */
5486 2, 2 /* ~ ! */
5487 };
5488
Jack Palevich8b0624c2009-05-20 12:12:06 -07005489#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005490FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005491#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005492
Jack Palevich8b0624c2009-05-20 12:12:06 -07005493#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005494const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005495 0x1, // ++
5496 0xff, // --
5497 0xc1af0f, // *
5498 0xf9f79991, // /
5499 0xf9f79991, // % (With manual assist to swap results)
5500 0xc801, // +
5501 0xd8f7c829, // -
5502 0xe0d391, // <<
5503 0xf8d391, // >>
5504 0xe, // <=
5505 0xd, // >=
5506 0xc, // <
5507 0xf, // >
5508 0x4, // ==
5509 0x5, // !=
5510 0x0, // &&
5511 0x1, // ||
5512 0xc821, // &
5513 0xc831, // ^
5514 0xc809, // |
5515 0xd0f7, // ~
5516 0x4 // !
5517};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005518#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005519
Jack Palevich1cdef202009-05-22 12:06:27 -07005520struct ACCscript {
5521 ACCscript() {
5522 text = 0;
5523 textLength = 0;
5524 accError = ACC_NO_ERROR;
5525 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005526
Jack Palevich1cdef202009-05-22 12:06:27 -07005527 ~ACCscript() {
5528 delete text;
5529 }
Jack Palevich546b2242009-05-13 15:10:04 -07005530
Jack Palevich8c246a92009-07-14 21:14:10 -07005531 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5532 compiler.registerSymbolCallback(pFn, pContext);
5533 }
5534
Jack Palevich1cdef202009-05-22 12:06:27 -07005535 void setError(ACCenum error) {
5536 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5537 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005538 }
5539 }
5540
Jack Palevich1cdef202009-05-22 12:06:27 -07005541 ACCenum getError() {
5542 ACCenum result = accError;
5543 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005544 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005545 }
5546
Jack Palevich1cdef202009-05-22 12:06:27 -07005547 Compiler compiler;
5548 char* text;
5549 int textLength;
5550 ACCenum accError;
5551};
5552
5553
5554extern "C"
5555ACCscript* accCreateScript() {
5556 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005557}
Jack Palevich1cdef202009-05-22 12:06:27 -07005558
5559extern "C"
5560ACCenum accGetError( ACCscript* script ) {
5561 return script->getError();
5562}
5563
5564extern "C"
5565void accDeleteScript(ACCscript* script) {
5566 delete script;
5567}
5568
5569extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005570void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5571 ACCvoid* pContext) {
5572 script->registerSymbolCallback(pFn, pContext);
5573}
5574
5575extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005576void accScriptSource(ACCscript* script,
5577 ACCsizei count,
5578 const ACCchar ** string,
5579 const ACCint * length) {
5580 int totalLength = 0;
5581 for(int i = 0; i < count; i++) {
5582 int len = -1;
5583 const ACCchar* s = string[i];
5584 if (length) {
5585 len = length[i];
5586 }
5587 if (len < 0) {
5588 len = strlen(s);
5589 }
5590 totalLength += len;
5591 }
5592 delete script->text;
5593 char* text = new char[totalLength + 1];
5594 script->text = text;
5595 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005596 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005597 for(int i = 0; i < count; i++) {
5598 int len = -1;
5599 const ACCchar* s = string[i];
5600 if (length) {
5601 len = length[i];
5602 }
5603 if (len < 0) {
5604 len = strlen(s);
5605 }
Jack Palevich09555c72009-05-27 12:25:55 -07005606 memcpy(dest, s, len);
5607 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005608 }
5609 text[totalLength] = '\0';
5610}
5611
5612extern "C"
5613void accCompileScript(ACCscript* script) {
5614 int result = script->compiler.compile(script->text, script->textLength);
5615 if (result) {
5616 script->setError(ACC_INVALID_OPERATION);
5617 }
5618}
5619
5620extern "C"
5621void accGetScriptiv(ACCscript* script,
5622 ACCenum pname,
5623 ACCint * params) {
5624 switch (pname) {
5625 case ACC_INFO_LOG_LENGTH:
5626 *params = 0;
5627 break;
5628 }
5629}
5630
5631extern "C"
5632void accGetScriptInfoLog(ACCscript* script,
5633 ACCsizei maxLength,
5634 ACCsizei * length,
5635 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005636 char* message = script->compiler.getErrorMessage();
5637 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005638 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005639 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005640 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005641 if (infoLog && maxLength > 0) {
5642 int trimmedLength = maxLength < messageLength ?
5643 maxLength : messageLength;
5644 memcpy(infoLog, message, trimmedLength);
5645 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005646 }
5647}
5648
5649extern "C"
5650void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5651 ACCvoid ** address) {
5652 void* value = script->compiler.lookup(name);
5653 if (value) {
5654 *address = value;
5655 } else {
5656 script->setError(ACC_INVALID_VALUE);
5657 }
5658}
5659
Jack Palevicheedf9d22009-06-04 16:23:40 -07005660extern "C"
5661void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5662 ACCsizei maxStringCount, ACCchar** strings){
5663 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5664}
5665
-b master422972c2009-06-17 19:13:52 -07005666extern "C"
5667void accDisassemble(ACCscript* script) {
5668 script->compiler.disassemble(stderr);
5669}
5670
Jack Palevicheedf9d22009-06-04 16:23:40 -07005671
Jack Palevich1cdef202009-05-22 12:06:27 -07005672} // namespace acc
5673