blob: c52b992203e18121bf28d10220da67284be22aaa [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 Palevich9221bcc2009-08-26 16:15:07 -0700160 tokenid_t id; // For function arguments, global vars, local vars, struct elements
161 tokenid_t structTag; // For structs the name of the struct
162 int length; // length of array, offset of struct element. -1 means struct is forward defined
163 int alignment; // for structs only
164 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700165 Type* pTail;
166 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700167
Jack Palevichba929a42009-07-17 10:20:32 -0700168 enum ExpressionType {
169 ET_RVALUE,
170 ET_LVALUE
171 };
172
173 struct ExpressionValue {
174 ExpressionValue() {
175 et = ET_RVALUE;
176 pType = NULL;
177 }
178 ExpressionType et;
179 Type* pType;
180 };
181
Jack Palevich21a15a22009-05-11 14:49:29 -0700182 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700183 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700184 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 ErrorSink* mErrorSink;
186 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700187 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700188
Jack Palevich21a15a22009-05-11 14:49:29 -0700189 void release() {
190 if (pProgramBase != 0) {
191 free(pProgramBase);
192 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700193 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700194 }
195
Jack Palevich0a280a02009-06-11 10:53:51 -0700196 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700197 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700198 bool overflow = newSize > mSize;
199 if (overflow && !mOverflowed) {
200 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700201 if (mErrorSink) {
202 mErrorSink->error("Code too large: %d bytes", newSize);
203 }
204 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700205 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700206 }
207
Jack Palevich21a15a22009-05-11 14:49:29 -0700208 public:
209 CodeBuf() {
210 pProgramBase = 0;
211 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700212 mErrorSink = 0;
213 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700214 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700215 }
216
217 ~CodeBuf() {
218 release();
219 }
220
221 void init(int size) {
222 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700223 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700224 pProgramBase = (char*) calloc(1, size);
225 ind = pProgramBase;
226 }
227
Jack Palevichac0e95e2009-05-29 13:53:44 -0700228 void setErrorSink(ErrorSink* pErrorSink) {
229 mErrorSink = pErrorSink;
230 }
231
Jack Palevich546b2242009-05-13 15:10:04 -0700232 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700233 if(check(4)) {
234 return 0;
235 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700236 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700237 * (int*) ind = n;
238 ind += 4;
239 return result;
240 }
241
Jack Palevich21a15a22009-05-11 14:49:29 -0700242 /*
243 * Output a byte. Handles all values, 0..ff.
244 */
245 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700246 if(check(1)) {
247 return;
248 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700249 *ind++ = n;
250 }
251
Jack Palevich21a15a22009-05-11 14:49:29 -0700252 inline void* getBase() {
253 return (void*) pProgramBase;
254 }
255
Jack Palevich8b0624c2009-05-20 12:12:06 -0700256 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700257 return ind - pProgramBase;
258 }
259
Jack Palevich8b0624c2009-05-20 12:12:06 -0700260 intptr_t getPC() {
261 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700262 }
263 };
264
Jack Palevich1cdef202009-05-22 12:06:27 -0700265 /**
266 * A code generator creates an in-memory program, generating the code on
267 * the fly. There is one code generator implementation for each supported
268 * architecture.
269 *
270 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700271 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700272 * FP - a frame pointer for accessing function arguments and local
273 * variables.
274 * SP - a stack pointer for storing intermediate results while evaluating
275 * expressions. The stack pointer grows downwards.
276 *
277 * The function calling convention is that all arguments are placed on the
278 * stack such that the first argument has the lowest address.
279 * After the call, the result is in R0. The caller is responsible for
280 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700281 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700282 * FP and SP registers are saved.
283 */
284
Jack Palevich21a15a22009-05-11 14:49:29 -0700285 class CodeGenerator {
286 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700287 CodeGenerator() {
288 mErrorSink = 0;
289 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700290 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700291 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700292 virtual ~CodeGenerator() {}
293
Jack Palevich22305132009-05-13 10:58:45 -0700294 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700295 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700296 pCodeBuf->setErrorSink(mErrorSink);
297 }
298
Jack Palevichb67b18f2009-06-11 21:12:23 -0700299 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700300 mErrorSink = pErrorSink;
301 if (pCodeBuf) {
302 pCodeBuf->setErrorSink(mErrorSink);
303 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700304 }
305
Jack Palevich58c30ee2009-07-17 16:35:23 -0700306 /* Give the code generator some utility types so it can
307 * use its own types as needed for the results of some
308 * operations like gcmp.
309 */
310
Jack Palevicha8f427f2009-07-13 18:40:08 -0700311 void setTypes(Type* pInt) {
312 mkpInt = pInt;
313 }
314
Jack Palevich1cdef202009-05-22 12:06:27 -0700315 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700316 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 * Save the old value of the FP.
318 * Set the new value of the FP.
319 * Convert from the native platform calling convention to
320 * our stack-based calling convention. This may require
321 * pushing arguments from registers to the stack.
322 * Allocate "N" bytes of stack space. N isn't known yet, so
323 * just emit the instructions for adjusting the stack, and return
324 * the address to patch up. The patching will be done in
325 * functionExit().
326 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700327 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700328 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700329
Jack Palevich1cdef202009-05-22 12:06:27 -0700330 /* Emit a function epilog.
331 * Restore the old SP and FP register values.
332 * Return to the calling function.
333 * argCount - the number of arguments to the function.
334 * localVariableAddress - returned from functionEntry()
335 * localVariableSize - the size in bytes of the local variables.
336 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700337 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700338 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700339
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700341 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700342
Jack Palevich1a539db2009-07-08 13:04:41 -0700343 /* Load floating point value from global address. */
344 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700345
Jack Palevich9221bcc2009-08-26 16:15:07 -0700346 /* Add the struct offset in bytes to R0, change the type to pType */
347 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /* Jump to a target, and return the address of the word that
350 * holds the target data, in case it needs to be fixed up later.
351 */
Jack Palevich22305132009-05-13 10:58:45 -0700352 virtual int gjmp(int t) = 0;
353
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 /* Test R0 and jump to a target if the test succeeds.
355 * l = 0: je, l == 1: jne
356 * Return the address of the word that holds the targed data, in
357 * case it needs to be fixed up later.
358 */
Jack Palevich22305132009-05-13 10:58:45 -0700359 virtual int gtst(bool l, int t) = 0;
360
Jack Palevich9eed7a22009-07-06 17:24:34 -0700361 /* Compare TOS against R0, and store the boolean result in R0.
362 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 * op specifies the comparison.
364 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700365 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700366
Jack Palevich9eed7a22009-07-06 17:24:34 -0700367 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700368 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700369 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 */
Jack Palevich546b2242009-05-13 15:10:04 -0700371 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700372
Jack Palevich9eed7a22009-07-06 17:24:34 -0700373 /* Compare 0 against R0, and store the boolean result in R0.
374 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700375 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700376 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700377
378 /* Perform the arithmetic op specified by op. 0 is the
379 * left argument, R0 is the right argument.
380 */
381 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700382
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700383 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700384 */
385 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700386
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700387 /* Turn R0, TOS into R0 TOS R0 */
388
389 virtual void over() = 0;
390
391 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700392 */
393 virtual void popR0() = 0;
394
Jack Palevich9eed7a22009-07-06 17:24:34 -0700395 /* Store R0 to the address stored in TOS.
396 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700397 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700398 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700399
Jack Palevich1cdef202009-05-22 12:06:27 -0700400 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700401 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700402 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700403
Jack Palevich1cdef202009-05-22 12:06:27 -0700404 /* Load the absolute address of a variable to R0.
405 * If ea <= LOCAL, then this is a local variable, or an
406 * argument, addressed relative to FP.
407 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700408 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700409 * et is ET_RVALUE for things like string constants, ET_LVALUE for
410 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700411 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700412 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700413
Jack Palevich9f51a262009-07-29 16:22:26 -0700414 /* Load the pc-relative address of a forward-referenced variable to R0.
415 * Return the address of the 4-byte constant so that it can be filled
416 * in later.
417 */
418 virtual int leaForward(int ea, Type* pPointerType) = 0;
419
Jack Palevich8df46192009-07-07 14:48:51 -0700420 /**
421 * Convert R0 to the given type.
422 */
Jack Palevichb6154502009-08-04 14:56:09 -0700423
424 void convertR0(Type* pType) {
425 convertR0Imp(pType, false);
426 }
427
428 void castR0(Type* pType) {
429 convertR0Imp(pType, true);
430 }
431
432 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Emit code to adjust the stack for a function call. Return the
435 * label for the address of the instruction that adjusts the
436 * stack size. This will be passed as argument "a" to
437 * endFunctionCallArguments.
438 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700439 virtual int beginFunctionCallArguments() = 0;
440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700442 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700444 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700445
Jack Palevich1cdef202009-05-22 12:06:27 -0700446 /* Patch the function call preamble.
447 * a is the address returned from beginFunctionCallArguments
448 * l is the number of bytes the arguments took on the stack.
449 * Typically you would also emit code to convert the argument
450 * list into whatever the native function calling convention is.
451 * On ARM for example you would pop the first 5 arguments into
452 * R0..R4
453 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700454 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700455
Jack Palevich1cdef202009-05-22 12:06:27 -0700456 /* Emit a call to an unknown function. The argument "symbol" needs to
457 * be stored in the location where the address should go. It forms
458 * a chain. The address will be patched later.
459 * Return the address of the word that has to be patched.
460 */
Jack Palevich8df46192009-07-07 14:48:51 -0700461 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700462
Jack Palevich1cdef202009-05-22 12:06:27 -0700463 /* Call a function pointer. L is the number of bytes the arguments
464 * take on the stack. The address of the function is stored at
465 * location SP + l.
466 */
Jack Palevich8df46192009-07-07 14:48:51 -0700467 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700468
Jack Palevich1cdef202009-05-22 12:06:27 -0700469 /* Adjust SP after returning from a function call. l is the
470 * number of bytes of arguments stored on the stack. isIndirect
471 * is true if this was an indirect call. (In which case the
472 * address of the function is stored at location SP + l.)
473 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700474 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700475
Jack Palevich1cdef202009-05-22 12:06:27 -0700476 /* Print a disassembly of the assembled code to out. Return
477 * non-zero if there is an error.
478 */
Jack Palevicha6535612009-05-13 16:24:17 -0700479 virtual int disassemble(FILE* out) = 0;
480
Jack Palevich1cdef202009-05-22 12:06:27 -0700481 /* Generate a symbol at the current PC. t is the head of a
482 * linked list of addresses to patch.
483 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700484 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700485
Jack Palevich9f51a262009-07-29 16:22:26 -0700486 /* Resolve a forward reference function at the current PC.
487 * t is the head of a
488 * linked list of addresses to patch.
489 * (Like gsym, but using absolute address, not PC relative address.)
490 */
491 virtual void resolveForward(int t) = 0;
492
Jack Palevich1cdef202009-05-22 12:06:27 -0700493 /*
494 * Do any cleanup work required at the end of a compile.
495 * For example, an instruction cache might need to be
496 * invalidated.
497 * Return non-zero if there is an error.
498 */
499 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700500
Jack Palevicha6535612009-05-13 16:24:17 -0700501 /**
502 * Adjust relative branches by this amount.
503 */
504 virtual int jumpOffset() = 0;
505
Jack Palevich9eed7a22009-07-06 17:24:34 -0700506 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700507 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700508 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700509 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700510
511 /**
512 * Array element alignment (in bytes) for this type of data.
513 */
514 virtual size_t sizeOf(Type* type) = 0;
515
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700516 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700517 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700518 }
519
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700520 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700521 return mExpressionStack.back().et;
522 }
523
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700524 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700525 mExpressionStack.back().et = et;
526 }
527
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700528 virtual size_t getExpressionStackDepth() {
529 return mExpressionStack.size();
530 }
531
Jack Palevichb5e33312009-07-30 19:06:34 -0700532 virtual void forceR0RVal() {
533 if (getR0ExpressionType() == ET_LVALUE) {
534 loadR0FromR0();
535 }
536 }
537
Jack Palevich21a15a22009-05-11 14:49:29 -0700538 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700539 /*
540 * Output a byte. Handles all values, 0..ff.
541 */
542 void ob(int n) {
543 pCodeBuf->ob(n);
544 }
545
Jack Palevich8b0624c2009-05-20 12:12:06 -0700546 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700547 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700548 }
549
Jack Palevich8b0624c2009-05-20 12:12:06 -0700550 intptr_t getBase() {
551 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700552 }
553
Jack Palevich8b0624c2009-05-20 12:12:06 -0700554 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700555 return pCodeBuf->getPC();
556 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700557
558 intptr_t getSize() {
559 return pCodeBuf->getSize();
560 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700561
562 void error(const char* fmt,...) {
563 va_list ap;
564 va_start(ap, fmt);
565 mErrorSink->verror(fmt, ap);
566 va_end(ap);
567 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700568
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700569 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700570 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700571 error("code generator assertion failed at line %s:%d.", __FILE__, line);
572 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700573 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700574 }
575 }
Jack Palevich8df46192009-07-07 14:48:51 -0700576
577 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700578 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700579 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700580 mExpressionStack.back().et = ET_RVALUE;
581 }
582
583 void setR0Type(Type* pType, ExpressionType et) {
584 assert(pType != NULL);
585 mExpressionStack.back().pType = pType;
586 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700587 }
588
Jack Palevich8df46192009-07-07 14:48:51 -0700589 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700590 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700591 }
592
593 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700594 if (mExpressionStack.size()) {
595 mExpressionStack.push_back(mExpressionStack.back());
596 } else {
597 mExpressionStack.push_back(ExpressionValue());
598 }
599
Jack Palevich8df46192009-07-07 14:48:51 -0700600 }
601
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700602 void overType() {
603 size_t size = mExpressionStack.size();
604 if (size >= 2) {
605 mExpressionStack.push_back(mExpressionStack.back());
606 mExpressionStack[size-1] = mExpressionStack[size-2];
607 mExpressionStack[size-2] = mExpressionStack[size];
608 }
609 }
610
Jack Palevich8df46192009-07-07 14:48:51 -0700611 void popType() {
612 mExpressionStack.pop_back();
613 }
614
615 bool bitsSame(Type* pA, Type* pB) {
616 return collapseType(pA->tag) == collapseType(pB->tag);
617 }
618
619 TypeTag collapseType(TypeTag tag) {
620 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700621 TY_INT,
622 TY_INT,
623 TY_INT,
624 TY_VOID,
625 TY_FLOAT,
626 TY_DOUBLE,
627 TY_INT,
628 TY_INT,
629 TY_VOID,
630 TY_VOID,
631 TY_VOID
632 };
Jack Palevich8df46192009-07-07 14:48:51 -0700633 return collapsedTag[tag];
634 }
635
Jack Palevich1a539db2009-07-08 13:04:41 -0700636 TypeTag collapseTypeR0() {
637 return collapseType(getR0Type()->tag);
638 }
639
Jack Palevichb6154502009-08-04 14:56:09 -0700640 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700641 return isFloatTag(pType->tag);
642 }
643
Jack Palevichb6154502009-08-04 14:56:09 -0700644 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700645 return tag == TY_FLOAT || tag == TY_DOUBLE;
646 }
647
Jack Palevichb6154502009-08-04 14:56:09 -0700648 static bool isPointerType(Type* pType) {
649 return isPointerTag(pType->tag);
650 }
651
652 static bool isPointerTag(TypeTag tag) {
653 return tag == TY_POINTER || tag == TY_ARRAY;
654 }
655
656 Type* getPointerArithmeticResultType(Type* a, Type* b) {
657 TypeTag aTag = a->tag;
658 TypeTag bTag = b->tag;
659 if (aTag == TY_POINTER) {
660 return a;
661 }
662 if (bTag == TY_POINTER) {
663 return b;
664 }
665 if (aTag == TY_ARRAY) {
666 return a->pTail;
667 }
668 if (bTag == TY_ARRAY) {
669 return b->pTail;
670 }
671 return NULL;
672 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700673 Type* mkpInt;
674
Jack Palevich21a15a22009-05-11 14:49:29 -0700675 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700676 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700677 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700678 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700679 };
680
Jack Paleviche7b59062009-05-19 17:12:17 -0700681#ifdef PROVIDE_ARM_CODEGEN
682
Jack Palevich22305132009-05-13 10:58:45 -0700683 class ARMCodeGenerator : public CodeGenerator {
684 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700685 ARMCodeGenerator() {
686#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700687 LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700688#else
Jack Palevichc0f25332009-08-25 12:23:43 -0700689 LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700690#endif
691 }
-b master422972c2009-06-17 19:13:52 -0700692
Jack Palevich22305132009-05-13 10:58:45 -0700693 virtual ~ARMCodeGenerator() {}
694
695 /* returns address to patch with local variable size
696 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700697 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700698 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700699 // sp -> arg4 arg5 ...
700 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700701 int regArgCount = calcRegArgCount(pDecl);
702 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700703 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700704 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700705 }
706 // sp -> arg0 arg1 ...
707 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700708 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700709 // sp, fp -> oldfp, retadr, arg0 arg1 ....
710 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700711 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700712 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700713 // We don't know how many local variables we are going to use,
714 // but we will round the allocation up to a multiple of
715 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700716 }
717
Jack Palevichb7718b92009-07-09 22:00:24 -0700718 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700719 // Round local variable size up to a multiple of stack alignment
720 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
721 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700722 // Patch local variable allocation code:
723 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700724 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700725 }
Jack Palevich69796b62009-05-14 15:42:26 -0700726 *(char*) (localVariableAddress) = localVariableSize;
727
Jack Palevich30321cb2009-08-20 15:34:23 -0700728#ifdef ARM_USE_VFP
729 {
Jack Palevichc0f25332009-08-25 12:23:43 -0700730 Type* pReturnType = pDecl->pHead;
731 switch(pReturnType->tag) {
732 case TY_FLOAT:
733 o4(0xEE170A90); // fmrs r0, s15
734 break;
735 case TY_DOUBLE:
736 o4(0xEC510B17); // fmrrd r0, r1, d7
737 break;
738 default:
739 break;
740 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700741 }
742#endif
743
Jack Palevich69796b62009-05-14 15:42:26 -0700744 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
745 o4(0xE1A0E00B); // mov lr, fp
746 o4(0xE59BB000); // ldr fp, [fp]
747 o4(0xE28ED004); // add sp, lr, #4
748 // sp -> retadr, arg0, ...
749 o4(0xE8BD4000); // ldmfd sp!, {lr}
750 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700751
752 // We store the PC into the lr so we can adjust the sp before
753 // returning. We need to pull off the registers we pushed
754 // earlier. We don't need to actually store them anywhere,
755 // just adjust the stack.
756 int regArgCount = calcRegArgCount(pDecl);
757 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700758 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
759 }
760 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700761 }
762
763 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700764 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700765 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700766 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700767 }
768
Jack Palevich1a539db2009-07-08 13:04:41 -0700769 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700770 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700771 // Global, absolute address
772 o4(0xE59F0000); // ldr r0, .L1
773 o4(0xEA000000); // b .L99
774 o4(address); // .L1: .word ea
775 // .L99:
776
777 switch (pType->tag) {
778 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700779#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700780 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700781#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700782 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700783#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700784 break;
785 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700786#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700787 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700788#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700789 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700790#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700791 break;
792 default:
793 assert(false);
794 break;
795 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700796 }
797
Jack Palevich9221bcc2009-08-26 16:15:07 -0700798
799 virtual void addStructOffsetR0(int offset, Type* pType) {
800 if (offset) {
801 size_t immediate = 0;
802 if (encode12BitImmediate(offset, &immediate)) {
803 o4(0xE2800000 | immediate); // add r0, r0, #offset
804 } else {
805 error("structure offset out of range: %d", offset);
806 }
807 }
808 setR0Type(pType, ET_LVALUE);
809 }
810
Jack Palevich22305132009-05-13 10:58:45 -0700811 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700812 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700813 }
814
815 /* l = 0: je, l == 1: jne */
816 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700817 Type* pR0Type = getR0Type();
818 TypeTag tagR0 = pR0Type->tag;
819 switch(tagR0) {
820 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700821#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700822 o4(0xEEF57A40); // fcmpzs s15
823 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700824#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700825 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -0700826 o4(0xE3500000); // cmp r0,#0
827#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700828 break;
829 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700830#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700831 o4(0xEEB57B40); // fcmpzd d7
832 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700833#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700834 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -0700835 o4(0xE3500000); // cmp r0,#0
836#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700837 break;
838 default:
Jack Palevich30321cb2009-08-20 15:34:23 -0700839 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700840 break;
841 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700842 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
843 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700844 }
845
Jack Palevich58c30ee2009-07-17 16:35:23 -0700846 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700847 Type* pR0Type = getR0Type();
848 Type* pTOSType = getTOSType();
849 TypeTag tagR0 = collapseType(pR0Type->tag);
850 TypeTag tagTOS = collapseType(pTOSType->tag);
851 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700852 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700853 o4(0xE1510000); // cmp r1, r1
854 switch(op) {
855 case OP_EQUALS:
856 o4(0x03A00001); // moveq r0,#1
857 o4(0x13A00000); // movne r0,#0
858 break;
859 case OP_NOT_EQUALS:
860 o4(0x03A00000); // moveq r0,#0
861 o4(0x13A00001); // movne r0,#1
862 break;
863 case OP_LESS_EQUAL:
864 o4(0xD3A00001); // movle r0,#1
865 o4(0xC3A00000); // movgt r0,#0
866 break;
867 case OP_GREATER:
868 o4(0xD3A00000); // movle r0,#0
869 o4(0xC3A00001); // movgt r0,#1
870 break;
871 case OP_GREATER_EQUAL:
872 o4(0xA3A00001); // movge r0,#1
873 o4(0xB3A00000); // movlt r0,#0
874 break;
875 case OP_LESS:
876 o4(0xA3A00000); // movge r0,#0
877 o4(0xB3A00001); // movlt r0,#1
878 break;
879 default:
880 error("Unknown comparison op %d", op);
881 break;
882 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700883 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
884 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700885#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700886 o4(0xEEB46BC7); // fcmped d6, d7
887 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700888 switch(op) {
889 case OP_EQUALS:
890 o4(0x03A00001); // moveq r0,#1
891 o4(0x13A00000); // movne r0,#0
892 break;
893 case OP_NOT_EQUALS:
894 o4(0x03A00000); // moveq r0,#0
895 o4(0x13A00001); // movne r0,#1
896 break;
897 case OP_LESS_EQUAL:
898 o4(0xD3A00001); // movle r0,#1
899 o4(0xC3A00000); // movgt r0,#0
900 break;
901 case OP_GREATER:
902 o4(0xD3A00000); // movle r0,#0
903 o4(0xC3A00001); // movgt r0,#1
904 break;
905 case OP_GREATER_EQUAL:
906 o4(0xA3A00001); // movge r0,#1
907 o4(0xB3A00000); // movlt r0,#0
908 break;
909 case OP_LESS:
910 o4(0xA3A00000); // movge r0,#0
911 o4(0xB3A00001); // movlt r0,#1
912 break;
913 default:
914 error("Unknown comparison op %d", op);
915 break;
916 }
917#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700918 switch(op) {
919 case OP_EQUALS:
920 callRuntime((void*) runtime_cmp_eq_dd);
921 break;
922 case OP_NOT_EQUALS:
923 callRuntime((void*) runtime_cmp_ne_dd);
924 break;
925 case OP_LESS_EQUAL:
926 callRuntime((void*) runtime_cmp_le_dd);
927 break;
928 case OP_GREATER:
929 callRuntime((void*) runtime_cmp_gt_dd);
930 break;
931 case OP_GREATER_EQUAL:
932 callRuntime((void*) runtime_cmp_ge_dd);
933 break;
934 case OP_LESS:
935 callRuntime((void*) runtime_cmp_lt_dd);
936 break;
937 default:
938 error("Unknown comparison op %d", op);
939 break;
940 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700941#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700942 } else {
943 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700944#ifdef ARM_USE_VFP
945 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -0700946 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700947 switch(op) {
948 case OP_EQUALS:
949 o4(0x03A00001); // moveq r0,#1
950 o4(0x13A00000); // movne r0,#0
951 break;
952 case OP_NOT_EQUALS:
953 o4(0x03A00000); // moveq r0,#0
954 o4(0x13A00001); // movne r0,#1
955 break;
956 case OP_LESS_EQUAL:
957 o4(0xD3A00001); // movle r0,#1
958 o4(0xC3A00000); // movgt r0,#0
959 break;
960 case OP_GREATER:
961 o4(0xD3A00000); // movle r0,#0
962 o4(0xC3A00001); // movgt r0,#1
963 break;
964 case OP_GREATER_EQUAL:
965 o4(0xA3A00001); // movge r0,#1
966 o4(0xB3A00000); // movlt r0,#0
967 break;
968 case OP_LESS:
969 o4(0xA3A00000); // movge r0,#0
970 o4(0xB3A00001); // movlt r0,#1
971 break;
972 default:
973 error("Unknown comparison op %d", op);
974 break;
975 }
976#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700977 switch(op) {
978 case OP_EQUALS:
979 callRuntime((void*) runtime_cmp_eq_ff);
980 break;
981 case OP_NOT_EQUALS:
982 callRuntime((void*) runtime_cmp_ne_ff);
983 break;
984 case OP_LESS_EQUAL:
985 callRuntime((void*) runtime_cmp_le_ff);
986 break;
987 case OP_GREATER:
988 callRuntime((void*) runtime_cmp_gt_ff);
989 break;
990 case OP_GREATER_EQUAL:
991 callRuntime((void*) runtime_cmp_ge_ff);
992 break;
993 case OP_LESS:
994 callRuntime((void*) runtime_cmp_lt_ff);
995 break;
996 default:
997 error("Unknown comparison op %d", op);
998 break;
999 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001000#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001001 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001002 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001003 }
1004
Jack Palevich546b2242009-05-13 15:10:04 -07001005 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001006 Type* pR0Type = getR0Type();
1007 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001008 TypeTag tagR0 = pR0Type->tag;
1009 TypeTag tagTOS = pTOSType->tag;
1010 bool isFloatR0 = isFloatTag(tagR0);
1011 bool isFloatTOS = isFloatTag(tagTOS);
1012 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001013 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001014 bool isPtrR0 = isPointerTag(tagR0);
1015 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001016 if (isPtrR0 || isPtrTOS) {
1017 if (isPtrR0 && isPtrTOS) {
1018 if (op != OP_MINUS) {
1019 error("Unsupported pointer-pointer operation %d.", op);
1020 }
1021 if (! typeEqual(pR0Type, pTOSType)) {
1022 error("Incompatible pointer types for subtraction.");
1023 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001024 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001025 setR0Type(mkpInt);
1026 int size = sizeOf(pR0Type->pHead);
1027 if (size != 1) {
1028 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001029 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001030 // TODO: Optimize for power-of-two.
1031 genOp(OP_DIV);
1032 }
1033 } else {
1034 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1035 error("Unsupported pointer-scalar operation %d", op);
1036 }
Jack Palevichb6154502009-08-04 14:56:09 -07001037 Type* pPtrType = getPointerArithmeticResultType(
1038 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001039 int size = sizeOf(pPtrType->pHead);
1040 if (size != 1) {
1041 // TODO: Optimize for power-of-two.
1042 liReg(size, 2);
1043 if (isPtrR0) {
1044 o4(0x0E0010192); // mul r1,r2,r1
1045 } else {
1046 o4(0x0E0000092); // mul r0,r2,r0
1047 }
1048 }
1049 switch(op) {
1050 case OP_PLUS:
1051 o4(0xE0810000); // add r0,r1,r0
1052 break;
1053 case OP_MINUS:
1054 o4(0xE0410000); // sub r0,r1,r0
1055 break;
1056 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001057 setR0Type(pPtrType);
1058 }
1059 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001060 switch(op) {
1061 case OP_MUL:
1062 o4(0x0E0000091); // mul r0,r1,r0
1063 break;
1064 case OP_DIV:
1065 callRuntime((void*) runtime_DIV);
1066 break;
1067 case OP_MOD:
1068 callRuntime((void*) runtime_MOD);
1069 break;
1070 case OP_PLUS:
1071 o4(0xE0810000); // add r0,r1,r0
1072 break;
1073 case OP_MINUS:
1074 o4(0xE0410000); // sub r0,r1,r0
1075 break;
1076 case OP_SHIFT_LEFT:
1077 o4(0xE1A00011); // lsl r0,r1,r0
1078 break;
1079 case OP_SHIFT_RIGHT:
1080 o4(0xE1A00051); // asr r0,r1,r0
1081 break;
1082 case OP_BIT_AND:
1083 o4(0xE0010000); // and r0,r1,r0
1084 break;
1085 case OP_BIT_XOR:
1086 o4(0xE0210000); // eor r0,r1,r0
1087 break;
1088 case OP_BIT_OR:
1089 o4(0xE1810000); // orr r0,r1,r0
1090 break;
1091 case OP_BIT_NOT:
1092 o4(0xE1E00000); // mvn r0, r0
1093 break;
1094 default:
1095 error("Unimplemented op %d\n", op);
1096 break;
1097 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001098 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001099 } else {
1100 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1101 if (pResultType->tag == TY_DOUBLE) {
1102 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001103
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 switch(op) {
1105 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001106#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001107 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001108#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001109 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001110#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001111 break;
1112 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001113#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001114 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001115#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001116 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001117#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001118 break;
1119 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001120#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001121 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001122#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001123 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001124#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001125 break;
1126 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001127#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001128 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001129#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001130 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001131#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001132 break;
1133 default:
1134 error("Unsupported binary floating operation %d\n", op);
1135 break;
1136 }
1137 } else {
1138 setupFloatArgs();
1139 switch(op) {
1140 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001141#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001142 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001143#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001144 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001145#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001146 break;
1147 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001148#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001149 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001150#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001151 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001152#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001153 break;
1154 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001155#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001156 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001157#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001158 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001159#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001160 break;
1161 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001162#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001163 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001164#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001165 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001166#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001167 break;
1168 default:
1169 error("Unsupported binary floating operation %d\n", op);
1170 break;
1171 }
1172 }
1173 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001174 }
Jack Palevich22305132009-05-13 10:58:45 -07001175 }
1176
Jack Palevich58c30ee2009-07-17 16:35:23 -07001177 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001178 if (op != OP_LOGICAL_NOT) {
1179 error("Unknown unary cmp %d", op);
1180 } else {
1181 Type* pR0Type = getR0Type();
1182 TypeTag tag = collapseType(pR0Type->tag);
1183 switch(tag) {
1184 case TY_INT:
1185 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001186 o4(0xE1510000); // cmp r1, r0
1187 o4(0x03A00001); // moveq r0,#1
1188 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001189 break;
1190 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001191#ifdef ARM_USE_VFP
1192 o4(0xEEF57A40); // fcmpzs s15
1193 o4(0xEEF1FA10); // fmstat
1194 o4(0x03A00001); // moveq r0,#1
1195 o4(0x13A00000); // movne r0,#0
1196#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001197 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001198#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001199 break;
1200 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001201#ifdef ARM_USE_VFP
1202 o4(0xEEB57B40); // fcmpzd d7
1203 o4(0xEEF1FA10); // fmstat
1204 o4(0x03A00001); // moveq r0,#1
1205 o4(0x13A00000); // movne r0,#0
1206#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001207 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001208#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001209 break;
1210 default:
1211 error("gUnaryCmp unsupported type");
1212 break;
1213 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001214 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001215 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001216 }
1217
1218 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001219 Type* pR0Type = getR0Type();
1220 TypeTag tag = collapseType(pR0Type->tag);
1221 switch(tag) {
1222 case TY_INT:
1223 switch(op) {
1224 case OP_MINUS:
1225 o4(0xE3A01000); // mov r1, #0
1226 o4(0xE0410000); // sub r0,r1,r0
1227 break;
1228 case OP_BIT_NOT:
1229 o4(0xE1E00000); // mvn r0, r0
1230 break;
1231 default:
1232 error("Unknown unary op %d\n", op);
1233 break;
1234 }
1235 break;
1236 case TY_FLOAT:
1237 case TY_DOUBLE:
1238 switch (op) {
1239 case OP_MINUS:
1240 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001241#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001242 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001243#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001244 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001245#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001246 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001247#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001248 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001249#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001250 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001251#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001252 }
1253 break;
1254 case OP_BIT_NOT:
1255 error("Can't apply '~' operator to a float or double.");
1256 break;
1257 default:
1258 error("Unknown unary op %d\n", op);
1259 break;
1260 }
1261 break;
1262 default:
1263 error("genUnaryOp unsupported type");
1264 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001265 }
Jack Palevich22305132009-05-13 10:58:45 -07001266 }
1267
Jack Palevich1cdef202009-05-22 12:06:27 -07001268 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001269 Type* pR0Type = getR0Type();
1270 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001271
1272#ifdef ARM_USE_VFP
1273 switch (r0ct ) {
1274 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001275 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001276 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001277 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001278 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001279 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001280 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001281 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001282 default:
1283 o4(0xE92D0001); // stmfd sp!,{r0}
1284 mStackUse += 4;
1285 }
1286#else
1287
Jack Palevichb7718b92009-07-09 22:00:24 -07001288 if (r0ct != TY_DOUBLE) {
1289 o4(0xE92D0001); // stmfd sp!,{r0}
1290 mStackUse += 4;
1291 } else {
1292 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1293 mStackUse += 8;
1294 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001295#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001296 pushType();
-b master422972c2009-06-17 19:13:52 -07001297 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001298 }
1299
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001300 virtual void over() {
1301 // We know it's only used for int-ptr ops (++/--)
1302
1303 Type* pR0Type = getR0Type();
1304 TypeTag r0ct = collapseType(pR0Type->tag);
1305
1306 Type* pTOSType = getTOSType();
1307 TypeTag tosct = collapseType(pTOSType->tag);
1308
1309 assert (r0ct == TY_INT && tosct == TY_INT);
1310
1311 o4(0xE8BD0002); // ldmfd sp!,{r1}
1312 o4(0xE92D0001); // stmfd sp!,{r0}
1313 o4(0xE92D0002); // stmfd sp!,{r1}
1314 overType();
1315 mStackUse += 4;
1316 }
1317
Jack Palevich58c30ee2009-07-17 16:35:23 -07001318 virtual void popR0() {
1319 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001320 TypeTag tosct = collapseType(pTOSType->tag);
1321#ifdef ARM_USE_VFP
1322 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001323 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001324 }
1325#endif
1326 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001327 case TY_INT:
1328 case TY_FLOAT:
1329 o4(0xE8BD0001); // ldmfd sp!,{r0}
1330 mStackUse -= 4;
1331 break;
1332 case TY_DOUBLE:
1333 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1334 mStackUse -= 8;
1335 break;
1336 default:
1337 error("Can't pop this type.");
1338 break;
1339 }
1340 popType();
1341 LOG_STACK("popR0: %d\n", mStackUse);
1342 }
1343
1344 virtual void storeR0ToTOS() {
1345 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001346 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001347 Type* pDestType = pPointerType->pHead;
1348 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001349 o4(0xE8BD0004); // ldmfd sp!,{r2}
1350 popType();
-b master422972c2009-06-17 19:13:52 -07001351 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001352 switch (pDestType->tag) {
1353 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001354 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001355 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001356 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001357 case TY_FLOAT:
1358#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001359 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001360#else
1361 o4(0xE5820000); // str r0, [r2]
1362#endif
1363 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001364 case TY_SHORT:
1365 o4(0xE1C200B0); // strh r0, [r2]
1366 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001367 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001368 o4(0xE5C20000); // strb r0, [r2]
1369 break;
1370 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001371#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001372 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001373#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001374 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001375#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001376 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001377 case TY_STRUCT:
1378 {
1379 int size = sizeOf(pDestType);
1380 if (size > 0) {
1381 liReg(size, 1);
1382 callRuntime((void*) runtime_structCopy);
1383 }
1384 }
1385 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001386 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001387 error("storeR0ToTOS: unimplemented type %d",
1388 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001389 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001390 }
Jack Palevich22305132009-05-13 10:58:45 -07001391 }
1392
Jack Palevich58c30ee2009-07-17 16:35:23 -07001393 virtual void loadR0FromR0() {
1394 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001395 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001396 Type* pNewType = pPointerType->pHead;
1397 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001398 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001399 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001400 case TY_INT:
1401 o4(0xE5900000); // ldr r0, [r0]
1402 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001403 case TY_FLOAT:
1404#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001405 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001406#else
1407 o4(0xE5900000); // ldr r0, [r0]
1408#endif
1409 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001410 case TY_SHORT:
1411 o4(0xE1D000F0); // ldrsh r0, [r0]
1412 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001413 case TY_CHAR:
1414 o4(0xE5D00000); // ldrb r0, [r0]
1415 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001416 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001417#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001418 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001419#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001420 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001421#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001422 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001423 case TY_ARRAY:
1424 pNewType = pNewType->pTail;
1425 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001426 case TY_STRUCT:
1427 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001428 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001429 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001430 break;
1431 }
Jack Palevich80e49722009-08-04 15:39:49 -07001432 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001433 }
1434
Jack Palevichb5e33312009-07-30 19:06:34 -07001435 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001436 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001437 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001438
1439 size_t immediate = 0;
1440 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001441 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001442 inRange = encode12BitImmediate(-ea, &immediate);
1443 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001444 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001445 inRange = encode12BitImmediate(ea, &immediate);
1446 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1447 }
1448 if (! inRange) {
1449 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001450 }
Jack Palevichbd894902009-05-14 19:35:31 -07001451 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001452 // Global, absolute.
1453 o4(0xE59F0000); // ldr r0, .L1
1454 o4(0xEA000000); // b .L99
1455 o4(ea); // .L1: .word 0
1456 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001457 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001458 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001459 }
1460
Jack Palevich9f51a262009-07-29 16:22:26 -07001461 virtual int leaForward(int ea, Type* pPointerType) {
1462 setR0Type(pPointerType);
1463 int result = ea;
1464 int pc = getPC();
1465 int offset = 0;
1466 if (ea) {
1467 offset = (pc - ea - 8) >> 2;
1468 if ((offset & 0xffff) != offset) {
1469 error("function forward reference out of bounds");
1470 }
1471 } else {
1472 offset = 0;
1473 }
1474 o4(0xE59F0000 | offset); // ldr r0, .L1
1475
1476 if (ea == 0) {
1477 o4(0xEA000000); // b .L99
1478 result = o4(ea); // .L1: .word 0
1479 // .L99:
1480 }
1481 return result;
1482 }
1483
Jack Palevichb6154502009-08-04 14:56:09 -07001484 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001485 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001486 if (isPointerType(pType) && isPointerType(pR0Type)) {
1487 Type* pA = pR0Type;
1488 Type* pB = pType;
1489 // Array decays to pointer
1490 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1491 pA = pA->pTail;
1492 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001493 if (! (typeEqual(pA, pB)
1494 || pB->pHead->tag == TY_VOID
1495 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1496 )) {
1497 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001498 }
Jack Palevichb6154502009-08-04 14:56:09 -07001499 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001500 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001501 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001502 TypeTag r0Tag = collapseType(pR0Type->tag);
1503 TypeTag destTag = collapseType(pType->tag);
1504 if (r0Tag == TY_INT) {
1505 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001506#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001507 o4(0xEE070A90); // fmsr s15, r0
1508 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001509
1510#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001511 callRuntime((void*) runtime_int_to_float);
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
Jack Palevichc0f25332009-08-25 12:23:43 -07001516 o4(0xEE070A90); // fmsr s15, r0
1517 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001518
1519#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001520 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001521#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001522 }
1523 } else if (r0Tag == TY_FLOAT) {
1524 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001525#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001526 o4(0xEEFD7AE7); // ftosizs s15, s15
1527 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001528#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001529 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001530#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001531 } else {
1532 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001533#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001534 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001535#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001536 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001537#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001538 }
1539 } else {
1540 assert (r0Tag == TY_DOUBLE);
1541 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001542#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001543 o4(0xEEFD7BC7); // ftosizd s15, d7
1544 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001545#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001546 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001547#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001548 } else {
1549 assert(destTag == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001550#ifdef ARM_USE_VFP
1551 o4(0xEEF77BC7); // fcvtsd s15, d7
1552#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001553 callRuntime((void*) runtime_double_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001554#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001555 }
1556 }
Jack Palevich8df46192009-07-07 14:48:51 -07001557 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001558 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001559 }
1560
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001561 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001562 return o4(0xE24DDF00); // Placeholder
1563 }
1564
Jack Palevich8148c5b2009-07-16 18:24:47 -07001565 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001566 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001567 Type* pR0Type = getR0Type();
1568 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001569#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001570 switch(r0ct) {
1571 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001572 if (l < 0 || l > 4096-4) {
1573 error("l out of range for stack offset: 0x%08x", l);
1574 }
1575 o4(0xE58D0000 | l); // str r0, [sp, #l]
1576 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001577 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001578 if (l < 0 || l > 1020 || (l & 3)) {
1579 error("l out of range for stack offset: 0x%08x", l);
1580 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001581 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001582 return 4;
1583 case TY_DOUBLE: {
1584 // Align to 8 byte boundary
1585 int l2 = (l + 7) & ~7;
1586 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1587 error("l out of range for stack offset: 0x%08x", l);
1588 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001589 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001590 return (l2 - l) + 8;
1591 }
1592 default:
1593 assert(false);
1594 return 0;
1595 }
1596#else
1597 switch(r0ct) {
1598 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001599 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001600 if (l < 0 || l > 4096-4) {
1601 error("l out of range for stack offset: 0x%08x", l);
1602 }
1603 o4(0xE58D0000 + l); // str r0, [sp, #l]
1604 return 4;
1605 case TY_DOUBLE: {
1606 // Align to 8 byte boundary
1607 int l2 = (l + 7) & ~7;
1608 if (l2 < 0 || l2 > 4096-8) {
1609 error("l out of range for stack offset: 0x%08x", l);
1610 }
1611 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1612 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1613 return (l2 - l) + 8;
1614 }
1615 default:
1616 assert(false);
1617 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001618 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001619#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001620 }
1621
Jack Palevichb7718b92009-07-09 22:00:24 -07001622 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001623 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001624 // Have to calculate register arg count from actual stack size,
1625 // in order to properly handle ... functions.
1626 int regArgCount = l >> 2;
1627 if (regArgCount > 4) {
1628 regArgCount = 4;
1629 }
1630 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001631 argumentStackUse -= regArgCount * 4;
1632 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1633 }
1634 mStackUse += argumentStackUse;
1635
1636 // Align stack.
1637 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1638 * STACK_ALIGNMENT);
1639 mStackAlignmentAdjustment = 0;
1640 if (missalignment > 0) {
1641 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1642 }
1643 l += mStackAlignmentAdjustment;
1644
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001645 if (l < 0 || l > 0x3FC) {
1646 error("L out of range for stack adjustment: 0x%08x", l);
1647 }
1648 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001649 mStackUse += mStackAlignmentAdjustment;
1650 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1651 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001652 }
1653
Jack Palevich8df46192009-07-07 14:48:51 -07001654 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001655 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001656 // Forward calls are always short (local)
1657 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001658 }
1659
Jack Palevich8df46192009-07-07 14:48:51 -07001660 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001661 assert(pFunc->tag == TY_FUNC);
1662 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001663 int argCount = l >> 2;
1664 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001665 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001666 if (adjustedL < 0 || adjustedL > 4096-4) {
1667 error("l out of range for stack offset: 0x%08x", l);
1668 }
1669 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1670 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001671 Type* pReturnType = pFunc->pHead;
1672 setR0Type(pReturnType);
1673#ifdef ARM_USE_VFP
1674 switch(pReturnType->tag) {
1675 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001676 o4(0xEE070A90); // fmsr s15, r0
1677 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001678 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001679 o4(0xEC410B17); // fmdrr d7, r0, r1
1680 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001681 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001682 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001683 }
1684#endif
Jack Palevich22305132009-05-13 10:58:45 -07001685 }
1686
Jack Palevichb7718b92009-07-09 22:00:24 -07001687 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001688 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001689 // Have to calculate register arg count from actual stack size,
1690 // in order to properly handle ... functions.
1691 int regArgCount = l >> 2;
1692 if (regArgCount > 4) {
1693 regArgCount = 4;
1694 }
1695 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001696 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1697 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001698 if (stackUse) {
1699 if (stackUse < 0 || stackUse > 255) {
1700 error("L out of range for stack adjustment: 0x%08x", l);
1701 }
1702 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001703 mStackUse -= stackUse * 4;
1704 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001705 }
Jack Palevich22305132009-05-13 10:58:45 -07001706 }
1707
Jack Palevicha6535612009-05-13 16:24:17 -07001708 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001709 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001710 }
1711
1712 /* output a symbol and patch all calls to it */
1713 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001714 int n;
1715 int base = getBase();
1716 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001717 while (t) {
1718 int data = * (int*) t;
1719 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1720 if (decodedOffset == 0) {
1721 n = 0;
1722 } else {
1723 n = base + decodedOffset; /* next value */
1724 }
1725 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1726 | encodeRelAddress(pc - t - 8);
1727 t = n;
1728 }
1729 }
1730
Jack Palevich9f51a262009-07-29 16:22:26 -07001731 /* output a symbol and patch all calls to it */
1732 virtual void resolveForward(int t) {
1733 if (t) {
1734 int pc = getPC();
1735 *(int *) t = pc;
1736 }
1737 }
1738
Jack Palevich1cdef202009-05-22 12:06:27 -07001739 virtual int finishCompile() {
1740#if defined(__arm__)
1741 const long base = long(getBase());
1742 const long curr = long(getPC());
1743 int err = cacheflush(base, curr, 0);
1744 return err;
1745#else
1746 return 0;
1747#endif
1748 }
1749
Jack Palevicha6535612009-05-13 16:24:17 -07001750 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001751#ifdef ENABLE_ARM_DISASSEMBLY
1752 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001753 disasm_interface_t di;
1754 di.di_readword = disassemble_readword;
1755 di.di_printaddr = disassemble_printaddr;
1756 di.di_printf = disassemble_printf;
1757
1758 int base = getBase();
1759 int pc = getPC();
1760 for(int i = base; i < pc; i += 4) {
1761 fprintf(out, "%08x: %08x ", i, *(int*) i);
1762 ::disasm(&di, i, 0);
1763 }
Jack Palevich09555c72009-05-27 12:25:55 -07001764#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001765 return 0;
1766 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001767
Jack Palevich9eed7a22009-07-06 17:24:34 -07001768 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001769 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001770 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001771 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001772 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001773 case TY_CHAR:
1774 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001775 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07001776 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001777 case TY_DOUBLE:
1778 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001779 case TY_ARRAY:
1780 return alignmentOf(pType->pHead);
1781 case TY_STRUCT:
1782 return pType->pHead->alignment & 0x7fffffff;
1783 case TY_FUNC:
1784 error("alignment of func not supported");
1785 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001786 default:
1787 return 4;
1788 }
1789 }
1790
1791 /**
1792 * Array element alignment (in bytes) for this type of data.
1793 */
1794 virtual size_t sizeOf(Type* pType){
1795 switch(pType->tag) {
1796 case TY_INT:
1797 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001798 case TY_SHORT:
1799 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001800 case TY_CHAR:
1801 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001802 case TY_FLOAT:
1803 return 4;
1804 case TY_DOUBLE:
1805 return 8;
1806 case TY_POINTER:
1807 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001808 case TY_ARRAY:
1809 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07001810 case TY_STRUCT:
1811 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07001812 default:
1813 error("Unsupported type %d", pType->tag);
1814 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001815 }
1816 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001817
Jack Palevich22305132009-05-13 10:58:45 -07001818 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001819 static FILE* disasmOut;
1820
1821 static u_int
1822 disassemble_readword(u_int address)
1823 {
1824 return(*((u_int *)address));
1825 }
1826
1827 static void
1828 disassemble_printaddr(u_int address)
1829 {
1830 fprintf(disasmOut, "0x%08x", address);
1831 }
1832
1833 static void
1834 disassemble_printf(const char *fmt, ...) {
1835 va_list ap;
1836 va_start(ap, fmt);
1837 vfprintf(disasmOut, fmt, ap);
1838 va_end(ap);
1839 }
1840
1841 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1842
1843 /** Encode a relative address that might also be
1844 * a label.
1845 */
1846 int encodeAddress(int value) {
1847 int base = getBase();
1848 if (value >= base && value <= getPC() ) {
1849 // This is a label, encode it relative to the base.
1850 value = value - base;
1851 }
1852 return encodeRelAddress(value);
1853 }
1854
1855 int encodeRelAddress(int value) {
1856 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1857 }
Jack Palevich22305132009-05-13 10:58:45 -07001858
Jack Palevichb7718b92009-07-09 22:00:24 -07001859 int calcRegArgCount(Type* pDecl) {
1860 int reg = 0;
1861 Type* pArgs = pDecl->pTail;
1862 while (pArgs && reg < 4) {
1863 Type* pArg = pArgs->pHead;
1864 if ( pArg->tag == TY_DOUBLE) {
1865 int evenReg = (reg + 1) & ~1;
1866 if (evenReg >= 4) {
1867 break;
1868 }
1869 reg = evenReg + 2;
1870 } else {
1871 reg++;
1872 }
1873 pArgs = pArgs->pTail;
1874 }
1875 return reg;
1876 }
1877
Jack Palevich58c30ee2009-07-17 16:35:23 -07001878 void setupIntPtrArgs() {
1879 o4(0xE8BD0002); // ldmfd sp!,{r1}
1880 mStackUse -= 4;
1881 popType();
1882 }
1883
Jack Palevich30321cb2009-08-20 15:34:23 -07001884 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001885 * Make sure both R0 and TOS are floats. (Could be ints)
1886 * We know that at least one of R0 and TOS is already a float
1887 */
1888 void setupFloatArgs() {
1889 Type* pR0Type = getR0Type();
1890 Type* pTOSType = getTOSType();
1891 TypeTag tagR0 = collapseType(pR0Type->tag);
1892 TypeTag tagTOS = collapseType(pTOSType->tag);
1893 if (tagR0 != TY_FLOAT) {
1894 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001895#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001896 o4(0xEE070A90); // fmsr s15, r0
1897 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001898#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001899 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001900#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001901 }
1902 if (tagTOS != TY_FLOAT) {
1903 assert(tagTOS == TY_INT);
1904 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001905#ifdef ARM_USE_VFP
1906 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07001907 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07001908#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001909 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1910 o4(0xE59D0004); // ldr r0, [sp, #4]
1911 callRuntime((void*) runtime_int_to_float);
1912 o4(0xE1A01000); // mov r1, r0
1913 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1914 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001915#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001916 } else {
1917 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001918#ifdef ARM_USE_VFP
1919 o4(0xECBD7A01); // fldmfds sp!, {s14}
1920
1921#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001922 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001923#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001924 }
1925 mStackUse -= 4;
1926 popType();
1927 }
1928
Jack Palevich30321cb2009-08-20 15:34:23 -07001929 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001930 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1931 * We know that at least one of R0 and TOS are already a double.
1932 */
1933
1934 void setupDoubleArgs() {
1935 Type* pR0Type = getR0Type();
1936 Type* pTOSType = getTOSType();
1937 TypeTag tagR0 = collapseType(pR0Type->tag);
1938 TypeTag tagTOS = collapseType(pTOSType->tag);
1939 if (tagR0 != TY_DOUBLE) {
1940 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001941#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001942 o4(0xEE070A90); // fmsr s15, r0
1943 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001944
1945#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001946 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001947#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001948 } else {
1949 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001950#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001951 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001952#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001953 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001954#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001955 }
1956 }
1957 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001958#ifdef ARM_USE_VFP
1959 if (tagTOS == TY_INT) {
1960 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001961 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001962 } else {
1963 assert(tagTOS == TY_FLOAT);
1964 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001965 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001966 }
1967#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001968 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1969 o4(0xE59D0008); // ldr r0, [sp, #8]
1970 if (tagTOS == TY_INT) {
1971 callRuntime((void*) runtime_int_to_double);
1972 } else {
1973 assert(tagTOS == TY_FLOAT);
1974 callRuntime((void*) runtime_float_to_double);
1975 }
1976 o4(0xE1A02000); // mov r2, r0
1977 o4(0xE1A03001); // mov r3, r1
1978 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1979 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001980#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001981 mStackUse -= 4;
1982 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001983#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001984 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07001985#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001986 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07001987#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001988 mStackUse -= 8;
1989 }
1990 popType();
1991 }
1992
Jack Palevicha8f427f2009-07-13 18:40:08 -07001993 void liReg(int t, int reg) {
1994 assert(reg >= 0 && reg < 16);
1995 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001996 size_t encodedImmediate;
1997 if (encode12BitImmediate(t, &encodedImmediate)) {
1998 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
1999 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002000 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002001 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002002 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002003 o4(0xE51F0000 | rN); // ldr rN, .L3
2004 o4(0xEA000000); // b .L99
2005 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002006 // .L99:
2007 }
2008 }
2009
Jack Palevich9221bcc2009-08-26 16:15:07 -07002010 bool encode12BitImmediate(size_t immediate, size_t* pResult) {
2011 for(size_t i = 0; i < 16; i++) {
2012 size_t rotate = i * 2;
2013 size_t mask = rotateRight(0xff, rotate);
2014 if ((immediate | mask) == mask) {
2015 size_t bits8 = rotateLeft(immediate, rotate);
2016 assert(bits8 <= 0xff);
2017 *pResult = (i << 8) | bits8;
2018 return true;
2019 }
2020 }
2021 return false;
2022 }
2023
2024 size_t rotateRight(size_t n, size_t rotate) {
2025 return (n >> rotate) | (n << (32 - rotate));
2026 }
2027
2028 size_t rotateLeft(size_t n, size_t rotate) {
2029 return (n << rotate) | (n >> (32 - rotate));
2030 }
2031
Jack Palevichb7718b92009-07-09 22:00:24 -07002032 void callRuntime(void* fn) {
2033 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002034 o4(0xEA000000); // b .L99
2035 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002036 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002037 }
2038
Jack Palevichb7718b92009-07-09 22:00:24 -07002039 // Integer math:
2040
2041 static int runtime_DIV(int b, int a) {
2042 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002043 }
2044
Jack Palevichb7718b92009-07-09 22:00:24 -07002045 static int runtime_MOD(int b, int a) {
2046 return a % b;
2047 }
2048
Jack Palevich9221bcc2009-08-26 16:15:07 -07002049 static void runtime_structCopy(void* src, size_t size, void* dest) {
2050 memcpy(dest, src, size);
2051 }
2052
Jack Palevich30321cb2009-08-20 15:34:23 -07002053#ifndef ARM_USE_VFP
2054
Jack Palevichb7718b92009-07-09 22:00:24 -07002055 // Comparison to zero
2056
2057 static int runtime_is_non_zero_f(float a) {
2058 return a != 0;
2059 }
2060
2061 static int runtime_is_non_zero_d(double a) {
2062 return a != 0;
2063 }
2064
2065 // Comparison to zero
2066
2067 static int runtime_is_zero_f(float a) {
2068 return a == 0;
2069 }
2070
2071 static int runtime_is_zero_d(double a) {
2072 return a == 0;
2073 }
2074
2075 // Type conversion
2076
2077 static int runtime_float_to_int(float a) {
2078 return (int) a;
2079 }
2080
2081 static double runtime_float_to_double(float a) {
2082 return (double) a;
2083 }
2084
2085 static int runtime_double_to_int(double a) {
2086 return (int) a;
2087 }
2088
2089 static float runtime_double_to_float(double a) {
2090 return (float) a;
2091 }
2092
2093 static float runtime_int_to_float(int a) {
2094 return (float) a;
2095 }
2096
2097 static double runtime_int_to_double(int a) {
2098 return (double) a;
2099 }
2100
2101 // Comparisons float
2102
2103 static int runtime_cmp_eq_ff(float b, float a) {
2104 return a == b;
2105 }
2106
2107 static int runtime_cmp_ne_ff(float b, float a) {
2108 return a != b;
2109 }
2110
2111 static int runtime_cmp_lt_ff(float b, float a) {
2112 return a < b;
2113 }
2114
2115 static int runtime_cmp_le_ff(float b, float a) {
2116 return a <= b;
2117 }
2118
2119 static int runtime_cmp_ge_ff(float b, float a) {
2120 return a >= b;
2121 }
2122
2123 static int runtime_cmp_gt_ff(float b, float a) {
2124 return a > b;
2125 }
2126
2127 // Comparisons double
2128
2129 static int runtime_cmp_eq_dd(double b, double a) {
2130 return a == b;
2131 }
2132
2133 static int runtime_cmp_ne_dd(double b, double a) {
2134 return a != b;
2135 }
2136
2137 static int runtime_cmp_lt_dd(double b, double a) {
2138 return a < b;
2139 }
2140
2141 static int runtime_cmp_le_dd(double b, double a) {
2142 return a <= b;
2143 }
2144
2145 static int runtime_cmp_ge_dd(double b, double a) {
2146 return a >= b;
2147 }
2148
2149 static int runtime_cmp_gt_dd(double b, double a) {
2150 return a > b;
2151 }
2152
2153 // Math float
2154
2155 static float runtime_op_add_ff(float b, float a) {
2156 return a + b;
2157 }
2158
2159 static float runtime_op_sub_ff(float b, float a) {
2160 return a - b;
2161 }
2162
2163 static float runtime_op_mul_ff(float b, float a) {
2164 return a * b;
2165 }
2166
2167 static float runtime_op_div_ff(float b, float a) {
2168 return a / b;
2169 }
2170
2171 static float runtime_op_neg_f(float a) {
2172 return -a;
2173 }
2174
2175 // Math double
2176
2177 static double runtime_op_add_dd(double b, double a) {
2178 return a + b;
2179 }
2180
2181 static double runtime_op_sub_dd(double b, double a) {
2182 return a - b;
2183 }
2184
2185 static double runtime_op_mul_dd(double b, double a) {
2186 return a * b;
2187 }
2188
2189 static double runtime_op_div_dd(double b, double a) {
2190 return a / b;
2191 }
2192
2193 static double runtime_op_neg_d(double a) {
2194 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002195 }
-b master422972c2009-06-17 19:13:52 -07002196
Jack Palevich30321cb2009-08-20 15:34:23 -07002197#endif
2198
-b master422972c2009-06-17 19:13:52 -07002199 static const int STACK_ALIGNMENT = 8;
2200 int mStackUse;
2201 // This variable holds the amount we adjusted the stack in the most
2202 // recent endFunctionCallArguments call. It's examined by the
2203 // following adjustStackAfterCall call.
2204 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002205 };
2206
Jack Palevich09555c72009-05-27 12:25:55 -07002207#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002208
2209#ifdef PROVIDE_X86_CODEGEN
2210
Jack Palevich21a15a22009-05-11 14:49:29 -07002211 class X86CodeGenerator : public CodeGenerator {
2212 public:
2213 X86CodeGenerator() {}
2214 virtual ~X86CodeGenerator() {}
2215
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002216 /* returns address to patch with local variable size
2217 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002218 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002219 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2220 return oad(0xec81, 0); /* sub $xxx, %esp */
2221 }
2222
Jack Palevichb7718b92009-07-09 22:00:24 -07002223 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002224 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002225 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002226 }
2227
Jack Palevich21a15a22009-05-11 14:49:29 -07002228 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002229 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002230 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002231 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002232 }
2233
Jack Palevich1a539db2009-07-08 13:04:41 -07002234 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002235 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002236 switch (pType->tag) {
2237 case TY_FLOAT:
2238 oad(0x05D9, address); // flds
2239 break;
2240 case TY_DOUBLE:
2241 oad(0x05DD, address); // fldl
2242 break;
2243 default:
2244 assert(false);
2245 break;
2246 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002247 }
2248
Jack Palevich9221bcc2009-08-26 16:15:07 -07002249 virtual void addStructOffsetR0(int offset, Type* pType) {
2250 if (offset) {
2251 oad(0x05, offset); // addl offset, %eax
2252 }
2253 setR0Type(pType, ET_LVALUE);
2254 }
2255
Jack Palevich22305132009-05-13 10:58:45 -07002256 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002257 return psym(0xe9, t);
2258 }
2259
2260 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002261 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002262 Type* pR0Type = getR0Type();
2263 TypeTag tagR0 = pR0Type->tag;
2264 bool isFloatR0 = isFloatTag(tagR0);
2265 if (isFloatR0) {
2266 o(0xeed9); // fldz
2267 o(0xe9da); // fucompp
2268 o(0xe0df); // fnstsw %ax
2269 o(0x9e); // sahf
2270 } else {
2271 o(0xc085); // test %eax, %eax
2272 }
2273 // Use two output statements to generate one instruction.
2274 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002275 return psym(0x84 + l, t);
2276 }
2277
Jack Palevich58c30ee2009-07-17 16:35:23 -07002278 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002279 Type* pR0Type = getR0Type();
2280 Type* pTOSType = getTOSType();
2281 TypeTag tagR0 = pR0Type->tag;
2282 TypeTag tagTOS = pTOSType->tag;
2283 bool isFloatR0 = isFloatTag(tagR0);
2284 bool isFloatTOS = isFloatTag(tagTOS);
2285 if (!isFloatR0 && !isFloatTOS) {
2286 int t = decodeOp(op);
2287 o(0x59); /* pop %ecx */
2288 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002289 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002290 o(0x0f); /* setxx %al */
2291 o(t + 0x90);
2292 o(0xc0);
2293 popType();
2294 } else {
2295 setupFloatOperands();
2296 switch (op) {
2297 case OP_EQUALS:
2298 o(0xe9da); // fucompp
2299 o(0xe0df); // fnstsw %ax
2300 o(0x9e); // sahf
2301 o(0xc0940f); // sete %al
2302 o(0xc29b0f); // setnp %dl
2303 o(0xd021); // andl %edx, %eax
2304 break;
2305 case OP_NOT_EQUALS:
2306 o(0xe9da); // fucompp
2307 o(0xe0df); // fnstsw %ax
2308 o(0x9e); // sahf
2309 o(0xc0950f); // setne %al
2310 o(0xc29a0f); // setp %dl
2311 o(0xd009); // orl %edx, %eax
2312 break;
2313 case OP_GREATER_EQUAL:
2314 o(0xe9da); // fucompp
2315 o(0xe0df); // fnstsw %ax
2316 o(0x05c4f6); // testb $5, %ah
2317 o(0xc0940f); // sete %al
2318 break;
2319 case OP_LESS:
2320 o(0xc9d9); // fxch %st(1)
2321 o(0xe9da); // fucompp
2322 o(0xe0df); // fnstsw %ax
2323 o(0x9e); // sahf
2324 o(0xc0970f); // seta %al
2325 break;
2326 case OP_LESS_EQUAL:
2327 o(0xc9d9); // fxch %st(1)
2328 o(0xe9da); // fucompp
2329 o(0xe0df); // fnstsw %ax
2330 o(0x9e); // sahf
2331 o(0xc0930f); // setea %al
2332 break;
2333 case OP_GREATER:
2334 o(0xe9da); // fucompp
2335 o(0xe0df); // fnstsw %ax
2336 o(0x45c4f6); // testb $69, %ah
2337 o(0xc0940f); // sete %al
2338 break;
2339 default:
2340 error("Unknown comparison op");
2341 }
2342 o(0xc0b60f); // movzbl %al, %eax
2343 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002344 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002345 }
2346
Jack Palevich546b2242009-05-13 15:10:04 -07002347 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002348 Type* pR0Type = getR0Type();
2349 Type* pTOSType = getTOSType();
2350 TypeTag tagR0 = pR0Type->tag;
2351 TypeTag tagTOS = pTOSType->tag;
2352 bool isFloatR0 = isFloatTag(tagR0);
2353 bool isFloatTOS = isFloatTag(tagTOS);
2354 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002355 bool isPtrR0 = isPointerTag(tagR0);
2356 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002357 if (isPtrR0 || isPtrTOS) {
2358 if (isPtrR0 && isPtrTOS) {
2359 if (op != OP_MINUS) {
2360 error("Unsupported pointer-pointer operation %d.", op);
2361 }
2362 if (! typeEqual(pR0Type, pTOSType)) {
2363 error("Incompatible pointer types for subtraction.");
2364 }
2365 o(0x59); /* pop %ecx */
2366 o(decodeOp(op));
2367 popType();
2368 setR0Type(mkpInt);
2369 int size = sizeOf(pR0Type->pHead);
2370 if (size != 1) {
2371 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002372 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002373 // TODO: Optimize for power-of-two.
2374 genOp(OP_DIV);
2375 }
2376 } else {
2377 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2378 error("Unsupported pointer-scalar operation %d", op);
2379 }
Jack Palevichb6154502009-08-04 14:56:09 -07002380 Type* pPtrType = getPointerArithmeticResultType(
2381 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002382 o(0x59); /* pop %ecx */
2383 int size = sizeOf(pPtrType->pHead);
2384 if (size != 1) {
2385 // TODO: Optimize for power-of-two.
2386 if (isPtrR0) {
2387 oad(0xC969, size); // imull $size, %ecx
2388 } else {
2389 oad(0xC069, size); // mul $size, %eax
2390 }
2391 }
2392 o(decodeOp(op));
2393 popType();
2394 setR0Type(pPtrType);
2395 }
2396 } else {
2397 o(0x59); /* pop %ecx */
2398 o(decodeOp(op));
2399 if (op == OP_MOD)
2400 o(0x92); /* xchg %edx, %eax */
2401 popType();
2402 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002403 } else {
2404 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2405 setupFloatOperands();
2406 // Both float. x87 R0 == left hand, x87 R1 == right hand
2407 switch (op) {
2408 case OP_MUL:
2409 o(0xc9de); // fmulp
2410 break;
2411 case OP_DIV:
2412 o(0xf1de); // fdivp
2413 break;
2414 case OP_PLUS:
2415 o(0xc1de); // faddp
2416 break;
2417 case OP_MINUS:
2418 o(0xe1de); // fsubp
2419 break;
2420 default:
2421 error("Unsupported binary floating operation.");
2422 break;
2423 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002424 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002425 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002426 }
2427
Jack Palevich58c30ee2009-07-17 16:35:23 -07002428 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002429 if (op != OP_LOGICAL_NOT) {
2430 error("Unknown unary cmp %d", op);
2431 } else {
2432 Type* pR0Type = getR0Type();
2433 TypeTag tag = collapseType(pR0Type->tag);
2434 switch(tag) {
2435 case TY_INT: {
2436 oad(0xb9, 0); /* movl $0, %ecx */
2437 int t = decodeOp(op);
2438 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002439 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002440 o(0x0f); /* setxx %al */
2441 o(t + 0x90);
2442 o(0xc0);
2443 }
2444 break;
2445 case TY_FLOAT:
2446 case TY_DOUBLE:
2447 o(0xeed9); // fldz
2448 o(0xe9da); // fucompp
2449 o(0xe0df); // fnstsw %ax
2450 o(0x9e); // sahf
2451 o(0xc0950f); // setne %al
2452 o(0xc29a0f); // setp %dl
2453 o(0xd009); // orl %edx, %eax
2454 o(0xc0b60f); // movzbl %al, %eax
2455 o(0x01f083); // xorl $1, %eax
2456 break;
2457 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002458 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002459 break;
2460 }
2461 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002462 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002463 }
2464
2465 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002466 Type* pR0Type = getR0Type();
2467 TypeTag tag = collapseType(pR0Type->tag);
2468 switch(tag) {
2469 case TY_INT:
2470 oad(0xb9, 0); /* movl $0, %ecx */
2471 o(decodeOp(op));
2472 break;
2473 case TY_FLOAT:
2474 case TY_DOUBLE:
2475 switch (op) {
2476 case OP_MINUS:
2477 o(0xe0d9); // fchs
2478 break;
2479 case OP_BIT_NOT:
2480 error("Can't apply '~' operator to a float or double.");
2481 break;
2482 default:
2483 error("Unknown unary op %d\n", op);
2484 break;
2485 }
2486 break;
2487 default:
2488 error("genUnaryOp unsupported type");
2489 break;
2490 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002491 }
2492
Jack Palevich1cdef202009-05-22 12:06:27 -07002493 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002494 Type* pR0Type = getR0Type();
2495 TypeTag r0ct = collapseType(pR0Type->tag);
2496 switch(r0ct) {
2497 case TY_INT:
2498 o(0x50); /* push %eax */
2499 break;
2500 case TY_FLOAT:
2501 o(0x50); /* push %eax */
2502 o(0x241cd9); // fstps 0(%esp)
2503 break;
2504 case TY_DOUBLE:
2505 o(0x50); /* push %eax */
2506 o(0x50); /* push %eax */
2507 o(0x241cdd); // fstpl 0(%esp)
2508 break;
2509 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002510 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002511 break;
2512 }
Jack Palevich8df46192009-07-07 14:48:51 -07002513 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002514 }
2515
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002516 virtual void over() {
2517 // We know it's only used for int-ptr ops (++/--)
2518
2519 Type* pR0Type = getR0Type();
2520 TypeTag r0ct = collapseType(pR0Type->tag);
2521
2522 Type* pTOSType = getTOSType();
2523 TypeTag tosct = collapseType(pTOSType->tag);
2524
2525 assert (r0ct == TY_INT && tosct == TY_INT);
2526
2527 o(0x59); /* pop %ecx */
2528 o(0x50); /* push %eax */
2529 o(0x51); /* push %ecx */
2530
2531 overType();
2532 }
2533
Jack Palevich58c30ee2009-07-17 16:35:23 -07002534 virtual void popR0() {
2535 Type* pR0Type = getR0Type();
2536 TypeTag r0ct = collapseType(pR0Type->tag);
2537 switch(r0ct) {
2538 case TY_INT:
2539 o(0x58); /* popl %eax */
2540 break;
2541 case TY_FLOAT:
2542 o(0x2404d9); // flds (%esp)
2543 o(0x58); /* popl %eax */
2544 break;
2545 case TY_DOUBLE:
2546 o(0x2404dd); // fldl (%esp)
2547 o(0x58); /* popl %eax */
2548 o(0x58); /* popl %eax */
2549 break;
2550 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002551 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002552 break;
2553 }
2554 popType();
2555 }
2556
2557 virtual void storeR0ToTOS() {
2558 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002559 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002560 Type* pTargetType = pPointerType->pHead;
2561 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002562 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002563 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002564 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002565 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002566 case TY_INT:
2567 o(0x0189); /* movl %eax/%al, (%ecx) */
2568 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002569 case TY_SHORT:
2570 o(0x018966); /* movw %ax, (%ecx) */
2571 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002572 case TY_CHAR:
2573 o(0x0188); /* movl %eax/%al, (%ecx) */
2574 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002575 case TY_FLOAT:
2576 o(0x19d9); /* fstps (%ecx) */
2577 break;
2578 case TY_DOUBLE:
2579 o(0x19dd); /* fstpl (%ecx) */
2580 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002581 case TY_STRUCT:
2582 {
2583 // TODO: use alignment information to use movsw/movsl instead of movsb
2584 int size = sizeOf(pTargetType);
2585 if (size > 0) {
2586 o(0x9c); // pushf
2587 o(0x57); // pushl %edi
2588 o(0x56); // pushl %esi
2589 o(0xcf89); // movl %ecx, %edi
2590 o(0xc689); // movl %eax, %esi
2591 oad(0xb9, size); // mov #size, %ecx
2592 o(0xfc); // cld
2593 o(0xf3); // rep
2594 o(0xa4); // movsb
2595 o(0x5e); // popl %esi
2596 o(0x5f); // popl %edi
2597 o(0x9d); // popf
2598 }
2599 }
2600 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002601 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002602 error("storeR0ToTOS: unsupported type %d",
2603 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002604 break;
2605 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002606 }
2607
Jack Palevich58c30ee2009-07-17 16:35:23 -07002608 virtual void loadR0FromR0() {
2609 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002610 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002611 Type* pNewType = pPointerType->pHead;
2612 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002613 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002614 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002615 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002616 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002617 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002618 case TY_SHORT:
2619 o(0xbf0f); /* movswl (%eax), %eax */
2620 ob(0);
2621 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002622 case TY_CHAR:
2623 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002624 ob(0); /* add zero in code */
2625 break;
2626 case TY_FLOAT:
2627 o2(0x00d9); // flds (%eax)
2628 break;
2629 case TY_DOUBLE:
2630 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002631 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002632 case TY_ARRAY:
2633 pNewType = pNewType->pTail;
2634 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002635 case TY_STRUCT:
2636 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002637 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002638 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002639 break;
2640 }
Jack Palevich80e49722009-08-04 15:39:49 -07002641 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002642 }
2643
Jack Palevichb5e33312009-07-30 19:06:34 -07002644 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002645 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002646 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002647 }
2648
Jack Palevich9f51a262009-07-29 16:22:26 -07002649 virtual int leaForward(int ea, Type* pPointerType) {
2650 oad(0xb8, ea); /* mov $xx, %eax */
2651 setR0Type(pPointerType);
2652 return getPC() - 4;
2653 }
2654
Jack Palevichb6154502009-08-04 14:56:09 -07002655 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002656 Type* pR0Type = getR0Type();
2657 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002658 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002659 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002660 return;
2661 }
Jack Palevichb6154502009-08-04 14:56:09 -07002662 if (isPointerType(pType) && isPointerType(pR0Type)) {
2663 Type* pA = pR0Type;
2664 Type* pB = pType;
2665 // Array decays to pointer
2666 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2667 pA = pA->pTail;
2668 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002669 if (! (typeEqual(pA, pB)
2670 || pB->pHead->tag == TY_VOID
2671 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2672 )) {
2673 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002674 }
Jack Palevichb6154502009-08-04 14:56:09 -07002675 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002676 // do nothing special
2677 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2678 // do nothing special, both held in same register on x87.
2679 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002680 TypeTag r0Tag = collapseType(pR0Type->tag);
2681 TypeTag destTag = collapseType(pType->tag);
2682 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2683 // Convert R0 from int to float
2684 o(0x50); // push %eax
2685 o(0x2404DB); // fildl 0(%esp)
2686 o(0x58); // pop %eax
2687 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2688 // Convert R0 from float to int. Complicated because
2689 // need to save and restore the rounding mode.
2690 o(0x50); // push %eax
2691 o(0x50); // push %eax
2692 o(0x02247cD9); // fnstcw 2(%esp)
2693 o(0x2444b70f); // movzwl 2(%esp), %eax
2694 o(0x02);
2695 o(0x0cb4); // movb $12, %ah
2696 o(0x24048966); // movw %ax, 0(%esp)
2697 o(0x242cd9); // fldcw 0(%esp)
2698 o(0x04245cdb); // fistpl 4(%esp)
2699 o(0x02246cd9); // fldcw 2(%esp)
2700 o(0x58); // pop %eax
2701 o(0x58); // pop %eax
2702 } else {
2703 error("Incompatible types old: %d new: %d",
2704 pR0Type->tag, pType->tag);
2705 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002706 }
2707 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002708 }
2709
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002710 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002711 return oad(0xec81, 0); /* sub $xxx, %esp */
2712 }
2713
Jack Palevich8148c5b2009-07-16 18:24:47 -07002714 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2715 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002716 Type* pR0Type = getR0Type();
2717 TypeTag r0ct = collapseType(pR0Type->tag);
2718 switch(r0ct) {
2719 case TY_INT:
2720 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2721 return 4;
2722 case TY_FLOAT:
2723 oad(0x249CD9, l); /* fstps xxx(%esp) */
2724 return 4;
2725 case TY_DOUBLE:
2726 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2727 return 8;
2728 default:
2729 assert(false);
2730 return 0;
2731 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002732 }
2733
Jack Palevichb7718b92009-07-09 22:00:24 -07002734 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002735 * (int*) a = l;
2736 }
2737
Jack Palevich8df46192009-07-07 14:48:51 -07002738 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002739 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002740 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002741 return psym(0xe8, symbol); /* call xxx */
2742 }
2743
Jack Palevich8df46192009-07-07 14:48:51 -07002744 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002745 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002746 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002747 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002748 oad(0x2494ff, l); /* call *xxx(%esp) */
2749 }
2750
Jack Palevichb7718b92009-07-09 22:00:24 -07002751 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002752 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002753 if (isIndirect) {
2754 l += 4;
2755 }
-b master422972c2009-06-17 19:13:52 -07002756 if (l > 0) {
2757 oad(0xc481, l); /* add $xxx, %esp */
2758 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002759 }
2760
Jack Palevicha6535612009-05-13 16:24:17 -07002761 virtual int jumpOffset() {
2762 return 5;
2763 }
2764
2765 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002766 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002767 }
2768
Jack Paleviche7b59062009-05-19 17:12:17 -07002769 /* output a symbol and patch all calls to it */
2770 virtual void gsym(int t) {
2771 int n;
2772 int pc = getPC();
2773 while (t) {
2774 n = *(int *) t; /* next value */
2775 *(int *) t = pc - t - 4;
2776 t = n;
2777 }
2778 }
2779
Jack Palevich9f51a262009-07-29 16:22:26 -07002780 /* output a symbol and patch all calls to it, using absolute address */
2781 virtual void resolveForward(int t) {
2782 int n;
2783 int pc = getPC();
2784 while (t) {
2785 n = *(int *) t; /* next value */
2786 *(int *) t = pc;
2787 t = n;
2788 }
2789 }
2790
Jack Palevich1cdef202009-05-22 12:06:27 -07002791 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002792 size_t pagesize = 4096;
2793 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2794 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2795 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2796 if (err) {
2797 error("mprotect() failed: %d", errno);
2798 }
2799 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002800 }
2801
Jack Palevich9eed7a22009-07-06 17:24:34 -07002802 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002803 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002804 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002805 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002806 switch (pType->tag) {
2807 case TY_CHAR:
2808 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002809 case TY_SHORT:
2810 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002811 case TY_ARRAY:
2812 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002813 case TY_STRUCT:
2814 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07002815 case TY_FUNC:
2816 error("alignment of func not supported");
2817 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002818 default:
2819 return 4;
2820 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002821 }
2822
2823 /**
2824 * Array element alignment (in bytes) for this type of data.
2825 */
2826 virtual size_t sizeOf(Type* pType){
2827 switch(pType->tag) {
2828 case TY_INT:
2829 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002830 case TY_SHORT:
2831 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002832 case TY_CHAR:
2833 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002834 case TY_FLOAT:
2835 return 4;
2836 case TY_DOUBLE:
2837 return 8;
2838 case TY_POINTER:
2839 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002840 case TY_ARRAY:
2841 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002842 case TY_STRUCT:
2843 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002844 default:
2845 error("Unsupported type %d", pType->tag);
2846 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002847 }
2848 }
2849
Jack Palevich21a15a22009-05-11 14:49:29 -07002850 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002851
2852 /** Output 1 to 4 bytes.
2853 *
2854 */
2855 void o(int n) {
2856 /* cannot use unsigned, so we must do a hack */
2857 while (n && n != -1) {
2858 ob(n & 0xff);
2859 n = n >> 8;
2860 }
2861 }
2862
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002863 /* Output exactly 2 bytes
2864 */
2865 void o2(int n) {
2866 ob(n & 0xff);
2867 ob(0xff & (n >> 8));
2868 }
2869
Jack Paleviche7b59062009-05-19 17:12:17 -07002870 /* psym is used to put an instruction with a data field which is a
2871 reference to a symbol. It is in fact the same as oad ! */
2872 int psym(int n, int t) {
2873 return oad(n, t);
2874 }
2875
2876 /* instruction + address */
2877 int oad(int n, int t) {
2878 o(n);
2879 int result = getPC();
2880 o4(t);
2881 return result;
2882 }
2883
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002884 static const int operatorHelper[];
2885
2886 int decodeOp(int op) {
2887 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002888 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002889 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002890 }
2891 return operatorHelper[op];
2892 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002893
Jack Palevich546b2242009-05-13 15:10:04 -07002894 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002895 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002896 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002897 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002898
2899 void setupFloatOperands() {
2900 Type* pR0Type = getR0Type();
2901 Type* pTOSType = getTOSType();
2902 TypeTag tagR0 = pR0Type->tag;
2903 TypeTag tagTOS = pTOSType->tag;
2904 bool isFloatR0 = isFloatTag(tagR0);
2905 bool isFloatTOS = isFloatTag(tagTOS);
2906 if (! isFloatR0) {
2907 // Convert R0 from int to float
2908 o(0x50); // push %eax
2909 o(0x2404DB); // fildl 0(%esp)
2910 o(0x58); // pop %eax
2911 }
2912 if (! isFloatTOS){
2913 o(0x2404DB); // fildl 0(%esp);
2914 o(0x58); // pop %eax
2915 } else {
2916 if (tagTOS == TY_FLOAT) {
2917 o(0x2404d9); // flds (%esp)
2918 o(0x58); // pop %eax
2919 } else {
2920 o(0x2404dd); // fldl (%esp)
2921 o(0x58); // pop %eax
2922 o(0x58); // pop %eax
2923 }
2924 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002925 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002926 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002927 };
2928
Jack Paleviche7b59062009-05-19 17:12:17 -07002929#endif // PROVIDE_X86_CODEGEN
2930
Jack Palevichb67b18f2009-06-11 21:12:23 -07002931#ifdef PROVIDE_TRACE_CODEGEN
2932 class TraceCodeGenerator : public CodeGenerator {
2933 private:
2934 CodeGenerator* mpBase;
2935
2936 public:
2937 TraceCodeGenerator(CodeGenerator* pBase) {
2938 mpBase = pBase;
2939 }
2940
2941 virtual ~TraceCodeGenerator() {
2942 delete mpBase;
2943 }
2944
2945 virtual void init(CodeBuf* pCodeBuf) {
2946 mpBase->init(pCodeBuf);
2947 }
2948
2949 void setErrorSink(ErrorSink* pErrorSink) {
2950 mpBase->setErrorSink(pErrorSink);
2951 }
2952
2953 /* returns address to patch with local variable size
2954 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002955 virtual int functionEntry(Type* pDecl) {
2956 int result = mpBase->functionEntry(pDecl);
2957 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002958 return result;
2959 }
2960
Jack Palevichb7718b92009-07-09 22:00:24 -07002961 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2962 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2963 localVariableAddress, localVariableSize);
2964 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002965 }
2966
2967 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002968 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002969 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002970 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002971 }
2972
Jack Palevich1a539db2009-07-08 13:04:41 -07002973 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002974 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002975 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002976 }
2977
Jack Palevich9221bcc2009-08-26 16:15:07 -07002978 virtual void addStructOffsetR0(int offset, Type* pType) {
2979 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
2980 mpBase->addStructOffsetR0(offset, pType);
2981 }
2982
Jack Palevichb67b18f2009-06-11 21:12:23 -07002983 virtual int gjmp(int t) {
2984 int result = mpBase->gjmp(t);
2985 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2986 return result;
2987 }
2988
2989 /* l = 0: je, l == 1: jne */
2990 virtual int gtst(bool l, int t) {
2991 int result = mpBase->gtst(l, t);
2992 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2993 return result;
2994 }
2995
Jack Palevich58c30ee2009-07-17 16:35:23 -07002996 virtual void gcmp(int op) {
2997 fprintf(stderr, "gcmp(%d)\n", op);
2998 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002999 }
3000
3001 virtual void genOp(int op) {
3002 fprintf(stderr, "genOp(%d)\n", op);
3003 mpBase->genOp(op);
3004 }
3005
Jack Palevich9eed7a22009-07-06 17:24:34 -07003006
Jack Palevich58c30ee2009-07-17 16:35:23 -07003007 virtual void gUnaryCmp(int op) {
3008 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3009 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003010 }
3011
3012 virtual void genUnaryOp(int op) {
3013 fprintf(stderr, "genUnaryOp(%d)\n", op);
3014 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003015 }
3016
3017 virtual void pushR0() {
3018 fprintf(stderr, "pushR0()\n");
3019 mpBase->pushR0();
3020 }
3021
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003022 virtual void over() {
3023 fprintf(stderr, "over()\n");
3024 mpBase->over();
3025 }
3026
Jack Palevich58c30ee2009-07-17 16:35:23 -07003027 virtual void popR0() {
3028 fprintf(stderr, "popR0()\n");
3029 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003030 }
3031
Jack Palevich58c30ee2009-07-17 16:35:23 -07003032 virtual void storeR0ToTOS() {
3033 fprintf(stderr, "storeR0ToTOS()\n");
3034 mpBase->storeR0ToTOS();
3035 }
3036
3037 virtual void loadR0FromR0() {
3038 fprintf(stderr, "loadR0FromR0()\n");
3039 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003040 }
3041
Jack Palevichb5e33312009-07-30 19:06:34 -07003042 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3043 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3044 pPointerType->pHead->tag, et);
3045 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003046 }
3047
Jack Palevich9f51a262009-07-29 16:22:26 -07003048 virtual int leaForward(int ea, Type* pPointerType) {
3049 fprintf(stderr, "leaForward(%d)\n", ea);
3050 return mpBase->leaForward(ea, pPointerType);
3051 }
3052
Jack Palevich30321cb2009-08-20 15:34:23 -07003053 virtual void convertR0Imp(Type* pType, bool isCast){
3054 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3055 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003056 }
3057
3058 virtual int beginFunctionCallArguments() {
3059 int result = mpBase->beginFunctionCallArguments();
3060 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3061 return result;
3062 }
3063
Jack Palevich8148c5b2009-07-16 18:24:47 -07003064 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3065 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3066 pArgType->tag);
3067 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003068 }
3069
Jack Palevichb7718b92009-07-09 22:00:24 -07003070 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003071 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003072 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003073 }
3074
Jack Palevich8df46192009-07-07 14:48:51 -07003075 virtual int callForward(int symbol, Type* pFunc) {
3076 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003077 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3078 return result;
3079 }
3080
Jack Palevich8df46192009-07-07 14:48:51 -07003081 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003082 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3083 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003084 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003085 }
3086
Jack Palevichb7718b92009-07-09 22:00:24 -07003087 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3088 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3089 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003090 }
3091
3092 virtual int jumpOffset() {
3093 return mpBase->jumpOffset();
3094 }
3095
3096 virtual int disassemble(FILE* out) {
3097 return mpBase->disassemble(out);
3098 }
3099
3100 /* output a symbol and patch all calls to it */
3101 virtual void gsym(int t) {
3102 fprintf(stderr, "gsym(%d)\n", t);
3103 mpBase->gsym(t);
3104 }
3105
Jack Palevich9f51a262009-07-29 16:22:26 -07003106 virtual void resolveForward(int t) {
3107 mpBase->resolveForward(t);
3108 }
3109
Jack Palevichb67b18f2009-06-11 21:12:23 -07003110 virtual int finishCompile() {
3111 int result = mpBase->finishCompile();
3112 fprintf(stderr, "finishCompile() = %d\n", result);
3113 return result;
3114 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003115
3116 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003117 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003118 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003119 virtual size_t alignmentOf(Type* pType){
3120 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003121 }
3122
3123 /**
3124 * Array element alignment (in bytes) for this type of data.
3125 */
3126 virtual size_t sizeOf(Type* pType){
3127 return mpBase->sizeOf(pType);
3128 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003129
3130 virtual Type* getR0Type() {
3131 return mpBase->getR0Type();
3132 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003133
3134 virtual ExpressionType getR0ExpressionType() {
3135 return mpBase->getR0ExpressionType();
3136 }
3137
3138 virtual void setR0ExpressionType(ExpressionType et) {
3139 mpBase->setR0ExpressionType(et);
3140 }
3141
3142 virtual size_t getExpressionStackDepth() {
3143 return mpBase->getExpressionStackDepth();
3144 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003145
3146 virtual void forceR0RVal() {
3147 return mpBase->forceR0RVal();
3148 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003149 };
3150
3151#endif // PROVIDE_TRACE_CODEGEN
3152
Jack Palevich569f1352009-06-29 14:29:08 -07003153 class Arena {
3154 public:
3155 // Used to record a given allocation amount.
3156 // Used:
3157 // Mark mark = arena.mark();
3158 // ... lots of arena.allocate()
3159 // arena.free(mark);
3160
3161 struct Mark {
3162 size_t chunk;
3163 size_t offset;
3164 };
3165
3166 Arena() {
3167 mCurrentChunk = 0;
3168 Chunk start(CHUNK_SIZE);
3169 mData.push_back(start);
3170 }
3171
3172 ~Arena() {
3173 for(size_t i = 0; i < mData.size(); i++) {
3174 mData[i].free();
3175 }
3176 }
3177
3178 // Alloc using the standard alignment size safe for any variable
3179 void* alloc(size_t size) {
3180 return alloc(size, 8);
3181 }
3182
3183 Mark mark(){
3184 Mark result;
3185 result.chunk = mCurrentChunk;
3186 result.offset = mData[mCurrentChunk].mOffset;
3187 return result;
3188 }
3189
3190 void freeToMark(const Mark& mark) {
3191 mCurrentChunk = mark.chunk;
3192 mData[mCurrentChunk].mOffset = mark.offset;
3193 }
3194
3195 private:
3196 // Allocate memory aligned to a given size
3197 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3198 // Memory is not zero filled.
3199
3200 void* alloc(size_t size, size_t alignment) {
3201 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3202 if (mCurrentChunk + 1 < mData.size()) {
3203 mCurrentChunk++;
3204 } else {
3205 size_t allocSize = CHUNK_SIZE;
3206 if (allocSize < size + alignment - 1) {
3207 allocSize = size + alignment - 1;
3208 }
3209 Chunk chunk(allocSize);
3210 mData.push_back(chunk);
3211 mCurrentChunk++;
3212 }
3213 }
3214 return mData[mCurrentChunk].allocate(size, alignment);
3215 }
3216
3217 static const size_t CHUNK_SIZE = 128*1024;
3218 // Note: this class does not deallocate its
3219 // memory when it's destroyed. It depends upon
3220 // its parent to deallocate the memory.
3221 struct Chunk {
3222 Chunk() {
3223 mpData = 0;
3224 mSize = 0;
3225 mOffset = 0;
3226 }
3227
3228 Chunk(size_t size) {
3229 mSize = size;
3230 mpData = (char*) malloc(size);
3231 mOffset = 0;
3232 }
3233
3234 ~Chunk() {
3235 // Doesn't deallocate memory.
3236 }
3237
3238 void* allocate(size_t size, size_t alignment) {
3239 size_t alignedOffset = aligned(mOffset, alignment);
3240 void* result = mpData + alignedOffset;
3241 mOffset = alignedOffset + size;
3242 return result;
3243 }
3244
3245 void free() {
3246 if (mpData) {
3247 ::free(mpData);
3248 mpData = 0;
3249 }
3250 }
3251
3252 size_t remainingCapacity(size_t alignment) {
3253 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3254 }
3255
3256 // Assume alignment is a power of two
3257 inline size_t aligned(size_t v, size_t alignment) {
3258 size_t mask = alignment-1;
3259 return (v + mask) & ~mask;
3260 }
3261
3262 char* mpData;
3263 size_t mSize;
3264 size_t mOffset;
3265 };
3266
3267 size_t mCurrentChunk;
3268
3269 Vector<Chunk> mData;
3270 };
3271
Jack Palevich569f1352009-06-29 14:29:08 -07003272 struct VariableInfo;
3273
3274 struct Token {
3275 int hash;
3276 size_t length;
3277 char* pText;
3278 tokenid_t id;
3279
3280 // Current values for the token
3281 char* mpMacroDefinition;
3282 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003283 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003284 };
3285
3286 class TokenTable {
3287 public:
3288 // Don't use 0..0xff, allows characters and operators to be tokens too.
3289
3290 static const int TOKEN_BASE = 0x100;
3291 TokenTable() {
3292 mpMap = hashmapCreate(128, hashFn, equalsFn);
3293 }
3294
3295 ~TokenTable() {
3296 hashmapFree(mpMap);
3297 }
3298
3299 void setArena(Arena* pArena) {
3300 mpArena = pArena;
3301 }
3302
3303 // Returns a token for a given string of characters.
3304 tokenid_t intern(const char* pText, size_t length) {
3305 Token probe;
3306 int hash = hashmapHash((void*) pText, length);
3307 {
3308 Token probe;
3309 probe.hash = hash;
3310 probe.length = length;
3311 probe.pText = (char*) pText;
3312 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3313 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003314 return pValue->id;
3315 }
3316 }
3317
3318 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3319 memset(pToken, 0, sizeof(*pToken));
3320 pToken->hash = hash;
3321 pToken->length = length;
3322 pToken->pText = (char*) mpArena->alloc(length + 1);
3323 memcpy(pToken->pText, pText, length);
3324 pToken->pText[length] = 0;
3325 pToken->id = mTokens.size() + TOKEN_BASE;
3326 mTokens.push_back(pToken);
3327 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003328 return pToken->id;
3329 }
3330
3331 // Return the Token for a given tokenid.
3332 Token& operator[](tokenid_t id) {
3333 return *mTokens[id - TOKEN_BASE];
3334 }
3335
3336 inline size_t size() {
3337 return mTokens.size();
3338 }
3339
3340 private:
3341
3342 static int hashFn(void* pKey) {
3343 Token* pToken = (Token*) pKey;
3344 return pToken->hash;
3345 }
3346
3347 static bool equalsFn(void* keyA, void* keyB) {
3348 Token* pTokenA = (Token*) keyA;
3349 Token* pTokenB = (Token*) keyB;
3350 // Don't need to compare hash values, they should always be equal
3351 return pTokenA->length == pTokenB->length
3352 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3353 }
3354
3355 Hashmap* mpMap;
3356 Vector<Token*> mTokens;
3357 Arena* mpArena;
3358 };
3359
Jack Palevich1cdef202009-05-22 12:06:27 -07003360 class InputStream {
3361 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003362 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003363 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003364 };
3365
3366 class TextInputStream : public InputStream {
3367 public:
3368 TextInputStream(const char* text, size_t textLength)
3369 : pText(text), mTextLength(textLength), mPosition(0) {
3370 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003371
Jack Palevichdc456462009-07-16 16:50:56 -07003372 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003373 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3374 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003375
Jack Palevichdc456462009-07-16 16:50:56 -07003376 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003377 const char* pText;
3378 size_t mTextLength;
3379 size_t mPosition;
3380 };
3381
Jack Palevicheedf9d22009-06-04 16:23:40 -07003382 class String {
3383 public:
3384 String() {
3385 mpBase = 0;
3386 mUsed = 0;
3387 mSize = 0;
3388 }
3389
Jack Palevich303d8ff2009-06-11 19:06:24 -07003390 String(const char* item, int len, bool adopt) {
3391 if (len < 0) {
3392 len = strlen(item);
3393 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003394 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003395 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003396 mUsed = len;
3397 mSize = len + 1;
3398 } else {
3399 mpBase = 0;
3400 mUsed = 0;
3401 mSize = 0;
3402 appendBytes(item, len);
3403 }
3404 }
3405
Jack Palevich303d8ff2009-06-11 19:06:24 -07003406 String(const String& other) {
3407 mpBase = 0;
3408 mUsed = 0;
3409 mSize = 0;
3410 appendBytes(other.getUnwrapped(), other.len());
3411 }
3412
Jack Palevicheedf9d22009-06-04 16:23:40 -07003413 ~String() {
3414 if (mpBase) {
3415 free(mpBase);
3416 }
3417 }
3418
Jack Palevicha6baa232009-06-12 11:25:59 -07003419 String& operator=(const String& other) {
3420 clear();
3421 appendBytes(other.getUnwrapped(), other.len());
3422 return *this;
3423 }
3424
Jack Palevich303d8ff2009-06-11 19:06:24 -07003425 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003426 return mpBase;
3427 }
3428
Jack Palevich303d8ff2009-06-11 19:06:24 -07003429 void clear() {
3430 mUsed = 0;
3431 if (mSize > 0) {
3432 mpBase[0] = 0;
3433 }
3434 }
3435
Jack Palevicheedf9d22009-06-04 16:23:40 -07003436 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003437 appendBytes(s, strlen(s));
3438 }
3439
3440 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003441 memcpy(ensure(n), s, n + 1);
3442 }
3443
3444 void append(char c) {
3445 * ensure(1) = c;
3446 }
3447
Jack Palevich86351982009-06-30 18:09:56 -07003448 void append(String& other) {
3449 appendBytes(other.getUnwrapped(), other.len());
3450 }
3451
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003452 char* orphan() {
3453 char* result = mpBase;
3454 mpBase = 0;
3455 mUsed = 0;
3456 mSize = 0;
3457 return result;
3458 }
3459
Jack Palevicheedf9d22009-06-04 16:23:40 -07003460 void printf(const char* fmt,...) {
3461 va_list ap;
3462 va_start(ap, fmt);
3463 vprintf(fmt, ap);
3464 va_end(ap);
3465 }
3466
3467 void vprintf(const char* fmt, va_list ap) {
3468 char* temp;
3469 int numChars = vasprintf(&temp, fmt, ap);
3470 memcpy(ensure(numChars), temp, numChars+1);
3471 free(temp);
3472 }
3473
Jack Palevich303d8ff2009-06-11 19:06:24 -07003474 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003475 return mUsed;
3476 }
3477
3478 private:
3479 char* ensure(int n) {
3480 size_t newUsed = mUsed + n;
3481 if (newUsed > mSize) {
3482 size_t newSize = mSize * 2 + 10;
3483 if (newSize < newUsed) {
3484 newSize = newUsed;
3485 }
3486 mpBase = (char*) realloc(mpBase, newSize + 1);
3487 mSize = newSize;
3488 }
3489 mpBase[newUsed] = '\0';
3490 char* result = mpBase + mUsed;
3491 mUsed = newUsed;
3492 return result;
3493 }
3494
3495 char* mpBase;
3496 size_t mUsed;
3497 size_t mSize;
3498 };
3499
Jack Palevich569f1352009-06-29 14:29:08 -07003500 void internKeywords() {
3501 // Note: order has to match TOK_ constants
3502 static const char* keywords[] = {
3503 "int",
3504 "char",
3505 "void",
3506 "if",
3507 "else",
3508 "while",
3509 "break",
3510 "return",
3511 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003512 "auto",
3513 "case",
3514 "const",
3515 "continue",
3516 "default",
3517 "do",
3518 "double",
3519 "enum",
3520 "extern",
3521 "float",
3522 "goto",
3523 "long",
3524 "register",
3525 "short",
3526 "signed",
3527 "sizeof",
3528 "static",
3529 "struct",
3530 "switch",
3531 "typedef",
3532 "union",
3533 "unsigned",
3534 "volatile",
3535 "_Bool",
3536 "_Complex",
3537 "_Imaginary",
3538 "inline",
3539 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003540
3541 // predefined tokens that can also be symbols start here:
3542 "pragma",
3543 "define",
3544 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003545 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003546
Jack Palevich569f1352009-06-29 14:29:08 -07003547 for(int i = 0; keywords[i]; i++) {
3548 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003549 }
Jack Palevich569f1352009-06-29 14:29:08 -07003550 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003551
Jack Palevich36d94142009-06-08 15:55:32 -07003552 struct InputState {
3553 InputStream* pStream;
3554 int oldCh;
3555 };
3556
Jack Palevich2db168f2009-06-11 14:29:47 -07003557 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003558 void* pAddress;
3559 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003560 tokenid_t tok;
3561 size_t level;
3562 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003563 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003564 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003565 };
3566
Jack Palevich303d8ff2009-06-11 19:06:24 -07003567 class SymbolStack {
3568 public:
3569 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003570 mpArena = 0;
3571 mpTokenTable = 0;
3572 }
3573
3574 void setArena(Arena* pArena) {
3575 mpArena = pArena;
3576 }
3577
3578 void setTokenTable(TokenTable* pTokenTable) {
3579 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003580 }
3581
3582 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003583 Mark mark;
3584 mark.mArenaMark = mpArena->mark();
3585 mark.mSymbolHead = mStack.size();
3586 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003587 }
3588
3589 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003590 // Undo any shadowing that was done:
3591 Mark mark = mLevelStack.back();
3592 mLevelStack.pop_back();
3593 while (mStack.size() > mark.mSymbolHead) {
3594 VariableInfo* pV = mStack.back();
3595 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003596 if (pV->isStructTag) {
3597 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3598 } else {
3599 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3600 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003601 }
Jack Palevich569f1352009-06-29 14:29:08 -07003602 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003603 }
3604
Jack Palevich569f1352009-06-29 14:29:08 -07003605 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3606 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3607 return pV && pV->level == level();
3608 }
3609
Jack Palevich9221bcc2009-08-26 16:15:07 -07003610 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3611 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3612 return pV && pV->level == level();
3613 }
3614
Jack Palevich569f1352009-06-29 14:29:08 -07003615 VariableInfo* add(tokenid_t tok) {
3616 Token& token = (*mpTokenTable)[tok];
3617 VariableInfo* pOldV = token.mpVariableInfo;
3618 VariableInfo* pNewV =
3619 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3620 memset(pNewV, 0, sizeof(VariableInfo));
3621 pNewV->tok = tok;
3622 pNewV->level = level();
3623 pNewV->pOldDefinition = pOldV;
3624 token.mpVariableInfo = pNewV;
3625 mStack.push_back(pNewV);
3626 return pNewV;
3627 }
3628
Jack Palevich9221bcc2009-08-26 16:15:07 -07003629 VariableInfo* addStructTag(tokenid_t tok) {
3630 Token& token = (*mpTokenTable)[tok];
3631 VariableInfo* pOldS = token.mpStructInfo;
3632 VariableInfo* pNewS =
3633 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3634 memset(pNewS, 0, sizeof(VariableInfo));
3635 pNewS->tok = tok;
3636 pNewS->level = level();
3637 pNewS->isStructTag = true;
3638 pNewS->pOldDefinition = pOldS;
3639 token.mpStructInfo = pNewS;
3640 mStack.push_back(pNewS);
3641 return pNewS;
3642 }
3643
Jack Palevich86351982009-06-30 18:09:56 -07003644 VariableInfo* add(Type* pType) {
3645 VariableInfo* pVI = add(pType->id);
3646 pVI->pType = pType;
3647 return pVI;
3648 }
3649
Jack Palevich569f1352009-06-29 14:29:08 -07003650 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3651 for (size_t i = 0; i < mStack.size(); i++) {
3652 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003653 break;
3654 }
3655 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003656 }
3657
Jack Palevich303d8ff2009-06-11 19:06:24 -07003658 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003659 inline size_t level() {
3660 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003661 }
3662
Jack Palevich569f1352009-06-29 14:29:08 -07003663 struct Mark {
3664 Arena::Mark mArenaMark;
3665 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003666 };
3667
Jack Palevich569f1352009-06-29 14:29:08 -07003668 Arena* mpArena;
3669 TokenTable* mpTokenTable;
3670 Vector<VariableInfo*> mStack;
3671 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003672 };
Jack Palevich36d94142009-06-08 15:55:32 -07003673
3674 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003675 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003676 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003677 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003678 int tokl; // token operator level
3679 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003680 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003681 intptr_t loc; // local variable index
3682 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003683 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003684 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003685 char* dptr; // Macro state: Points to macro text during macro playback.
3686 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003687 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003688 ACCSymbolLookupFn mpSymbolLookupFn;
3689 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003690
3691 // Arena for the duration of the compile
3692 Arena mGlobalArena;
3693 // Arena for data that's only needed when compiling a single function
3694 Arena mLocalArena;
3695
Jack Palevich2ff5c222009-07-23 15:11:22 -07003696 Arena* mpCurrentArena;
3697
Jack Palevich569f1352009-06-29 14:29:08 -07003698 TokenTable mTokenTable;
3699 SymbolStack mGlobals;
3700 SymbolStack mLocals;
3701
Jack Palevich9221bcc2009-08-26 16:15:07 -07003702 SymbolStack* mpCurrentSymbolStack;
3703
Jack Palevich40600de2009-07-01 15:32:35 -07003704 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003705 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003706 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003707 Type* mkpChar; // char
3708 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003709 Type* mkpFloat;
3710 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003711 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003712 Type* mkpIntPtr;
3713 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003714 Type* mkpFloatPtr;
3715 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003716 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003717
Jack Palevich36d94142009-06-08 15:55:32 -07003718 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003719 int mLineNumber;
3720 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003721
3722 CodeBuf codeBuf;
3723 CodeGenerator* pGen;
3724
Jack Palevicheedf9d22009-06-04 16:23:40 -07003725 String mErrorBuf;
3726
Jack Palevicheedf9d22009-06-04 16:23:40 -07003727 String mPragmas;
3728 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003729 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003730
Jack Palevich21a15a22009-05-11 14:49:29 -07003731 static const int ALLOC_SIZE = 99999;
3732
Jack Palevich303d8ff2009-06-11 19:06:24 -07003733 static const int TOK_DUMMY = 1;
3734 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003735 static const int TOK_NUM_FLOAT = 3;
3736 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003737 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003738 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003739
3740 // 3..255 are character and/or operators
3741
Jack Palevich2db168f2009-06-11 14:29:47 -07003742 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003743 // Order has to match string list in "internKeywords".
3744 enum {
3745 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3746 TOK_INT = TOK_KEYWORD,
3747 TOK_CHAR,
3748 TOK_VOID,
3749 TOK_IF,
3750 TOK_ELSE,
3751 TOK_WHILE,
3752 TOK_BREAK,
3753 TOK_RETURN,
3754 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003755 TOK_AUTO,
3756 TOK_CASE,
3757 TOK_CONST,
3758 TOK_CONTINUE,
3759 TOK_DEFAULT,
3760 TOK_DO,
3761 TOK_DOUBLE,
3762 TOK_ENUM,
3763 TOK_EXTERN,
3764 TOK_FLOAT,
3765 TOK_GOTO,
3766 TOK_LONG,
3767 TOK_REGISTER,
3768 TOK_SHORT,
3769 TOK_SIGNED,
3770 TOK_SIZEOF,
3771 TOK_STATIC,
3772 TOK_STRUCT,
3773 TOK_SWITCH,
3774 TOK_TYPEDEF,
3775 TOK_UNION,
3776 TOK_UNSIGNED,
3777 TOK_VOLATILE,
3778 TOK__BOOL,
3779 TOK__COMPLEX,
3780 TOK__IMAGINARY,
3781 TOK_INLINE,
3782 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003783
3784 // Symbols start after keywords
3785
3786 TOK_SYMBOL,
3787 TOK_PRAGMA = TOK_SYMBOL,
3788 TOK_DEFINE,
3789 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003790 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003791
3792 static const int LOCAL = 0x200;
3793
3794 static const int SYM_FORWARD = 0;
3795 static const int SYM_DEFINE = 1;
3796
3797 /* tokens in string heap */
3798 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003799
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003800 static const int OP_INCREMENT = 0;
3801 static const int OP_DECREMENT = 1;
3802 static const int OP_MUL = 2;
3803 static const int OP_DIV = 3;
3804 static const int OP_MOD = 4;
3805 static const int OP_PLUS = 5;
3806 static const int OP_MINUS = 6;
3807 static const int OP_SHIFT_LEFT = 7;
3808 static const int OP_SHIFT_RIGHT = 8;
3809 static const int OP_LESS_EQUAL = 9;
3810 static const int OP_GREATER_EQUAL = 10;
3811 static const int OP_LESS = 11;
3812 static const int OP_GREATER = 12;
3813 static const int OP_EQUALS = 13;
3814 static const int OP_NOT_EQUALS = 14;
3815 static const int OP_LOGICAL_AND = 15;
3816 static const int OP_LOGICAL_OR = 16;
3817 static const int OP_BIT_AND = 17;
3818 static const int OP_BIT_XOR = 18;
3819 static const int OP_BIT_OR = 19;
3820 static const int OP_BIT_NOT = 20;
3821 static const int OP_LOGICAL_NOT = 21;
3822 static const int OP_COUNT = 22;
3823
3824 /* Operators are searched from front, the two-character operators appear
3825 * before the single-character operators with the same first character.
3826 * @ is used to pad out single-character operators.
3827 */
3828 static const char* operatorChars;
3829 static const char operatorLevel[];
3830
Jack Palevich569f1352009-06-29 14:29:08 -07003831 /* Called when we detect an internal problem. Does nothing in production.
3832 *
3833 */
3834 void internalError() {
3835 * (char*) 0 = 0;
3836 }
3837
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003838 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003839 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07003840 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003841 internalError();
3842 }
Jack Palevich86351982009-06-30 18:09:56 -07003843 }
3844
Jack Palevich40600de2009-07-01 15:32:35 -07003845 bool isSymbol(tokenid_t t) {
3846 return t >= TOK_SYMBOL &&
3847 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3848 }
3849
3850 bool isSymbolOrKeyword(tokenid_t t) {
3851 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003852 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003853 }
3854
Jack Palevich86351982009-06-30 18:09:56 -07003855 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003856 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003857 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3858 if (pV && pV->tok != t) {
3859 internalError();
3860 }
3861 return pV;
3862 }
3863
3864 inline bool isDefined(tokenid_t t) {
3865 return t >= TOK_SYMBOL && VI(t) != 0;
3866 }
3867
Jack Palevich40600de2009-07-01 15:32:35 -07003868 const char* nameof(tokenid_t t) {
3869 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003870 return mTokenTable[t].pText;
3871 }
3872
Jack Palevich21a15a22009-05-11 14:49:29 -07003873 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003874 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003875 }
3876
3877 void inp() {
3878 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003879 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003880 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003881 dptr = 0;
3882 ch = dch;
3883 }
Jack Palevichdc456462009-07-16 16:50:56 -07003884 } else {
3885 if (mbBumpLine) {
3886 mLineNumber++;
3887 mbBumpLine = false;
3888 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003889 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003890 if (ch == '\n') {
3891 mbBumpLine = true;
3892 }
3893 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003894#if 0
3895 printf("ch='%c' 0x%x\n", ch, ch);
3896#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003897 }
3898
3899 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003900 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003901 }
3902
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003903 int decodeHex(int c) {
3904 if (isdigit(c)) {
3905 c -= '0';
3906 } else if (c <= 'F') {
3907 c = c - 'A' + 10;
3908 } else {
3909 c =c - 'a' + 10;
3910 }
3911 return c;
3912 }
3913
Jack Palevichb4758ff2009-06-12 12:49:14 -07003914 /* read a character constant, advances ch to after end of constant */
3915 int getq() {
3916 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003917 if (ch == '\\') {
3918 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003919 if (isoctal(ch)) {
3920 // 1 to 3 octal characters.
3921 val = 0;
3922 for(int i = 0; i < 3; i++) {
3923 if (isoctal(ch)) {
3924 val = (val << 3) + ch - '0';
3925 inp();
3926 }
3927 }
3928 return val;
3929 } else if (ch == 'x' || ch == 'X') {
3930 // N hex chars
3931 inp();
3932 if (! isxdigit(ch)) {
3933 error("'x' character escape requires at least one digit.");
3934 } else {
3935 val = 0;
3936 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003937 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003938 inp();
3939 }
3940 }
3941 } else {
3942 int val = ch;
3943 switch (ch) {
3944 case 'a':
3945 val = '\a';
3946 break;
3947 case 'b':
3948 val = '\b';
3949 break;
3950 case 'f':
3951 val = '\f';
3952 break;
3953 case 'n':
3954 val = '\n';
3955 break;
3956 case 'r':
3957 val = '\r';
3958 break;
3959 case 't':
3960 val = '\t';
3961 break;
3962 case 'v':
3963 val = '\v';
3964 break;
3965 case '\\':
3966 val = '\\';
3967 break;
3968 case '\'':
3969 val = '\'';
3970 break;
3971 case '"':
3972 val = '"';
3973 break;
3974 case '?':
3975 val = '?';
3976 break;
3977 default:
3978 error("Undefined character escape %c", ch);
3979 break;
3980 }
3981 inp();
3982 return val;
3983 }
3984 } else {
3985 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003986 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003987 return val;
3988 }
3989
3990 static bool isoctal(int ch) {
3991 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003992 }
3993
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003994 bool acceptCh(int c) {
3995 bool result = c == ch;
3996 if (result) {
3997 pdef(ch);
3998 inp();
3999 }
4000 return result;
4001 }
4002
4003 bool acceptDigitsCh() {
4004 bool result = false;
4005 while (isdigit(ch)) {
4006 result = true;
4007 pdef(ch);
4008 inp();
4009 }
4010 return result;
4011 }
4012
4013 void parseFloat() {
4014 tok = TOK_NUM_DOUBLE;
4015 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004016 if(mTokenString.len() == 0) {
4017 mTokenString.append('0');
4018 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004019 acceptCh('.');
4020 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004021 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004022 acceptCh('-') || acceptCh('+');
4023 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004024 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004025 if (ch == 'f' || ch == 'F') {
4026 tok = TOK_NUM_FLOAT;
4027 inp();
4028 } else if (ch == 'l' || ch == 'L') {
4029 inp();
4030 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004031 }
4032 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004033 char* pEnd = pText + strlen(pText);
4034 char* pEndPtr = 0;
4035 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004036 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004037 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004038 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004039 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004040 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004041 if (errno || pEndPtr != pEnd) {
4042 error("Can't parse constant: %s", pText);
4043 }
4044 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004045 }
4046
Jack Palevich21a15a22009-05-11 14:49:29 -07004047 void next() {
4048 int l, a;
4049
Jack Palevich546b2242009-05-13 15:10:04 -07004050 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004051 if (ch == '#') {
4052 inp();
4053 next();
4054 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004055 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004056 } else if (tok == TOK_PRAGMA) {
4057 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004058 } else if (tok == TOK_LINE) {
4059 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004060 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004061 error("Unsupported preprocessor directive \"%s\"",
4062 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004063 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004064 }
4065 inp();
4066 }
4067 tokl = 0;
4068 tok = ch;
4069 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004070 if (isdigit(ch) || ch == '.') {
4071 // Start of a numeric constant. Could be integer, float, or
4072 // double, won't know until we look further.
4073 mTokenString.clear();
4074 pdef(ch);
4075 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004076 if (tok == '.' && !isdigit(ch)) {
4077 goto done;
4078 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004079 int base = 10;
4080 if (tok == '0') {
4081 if (ch == 'x' || ch == 'X') {
4082 base = 16;
4083 tok = TOK_NUM;
4084 tokc = 0;
4085 inp();
4086 while ( isxdigit(ch) ) {
4087 tokc = (tokc << 4) + decodeHex(ch);
4088 inp();
4089 }
4090 } else if (isoctal(ch)){
4091 base = 8;
4092 tok = TOK_NUM;
4093 tokc = 0;
4094 while ( isoctal(ch) ) {
4095 tokc = (tokc << 3) + (ch - '0');
4096 inp();
4097 }
4098 }
4099 } else if (isdigit(tok)){
4100 acceptDigitsCh();
4101 }
4102 if (base == 10) {
4103 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4104 parseFloat();
4105 } else {
4106 // It's an integer constant
4107 char* pText = mTokenString.getUnwrapped();
4108 char* pEnd = pText + strlen(pText);
4109 char* pEndPtr = 0;
4110 errno = 0;
4111 tokc = strtol(pText, &pEndPtr, base);
4112 if (errno || pEndPtr != pEnd) {
4113 error("Can't parse constant: %s %d %d", pText, base, errno);
4114 }
4115 tok = TOK_NUM;
4116 }
4117 }
4118 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004119 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004120 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004121 pdef(ch);
4122 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004123 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004124 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004125 if (! mbSuppressMacroExpansion) {
4126 // Is this a macro?
4127 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4128 if (pMacroDefinition) {
4129 // Yes, it is a macro
4130 dptr = pMacroDefinition;
4131 dch = ch;
4132 inp();
4133 next();
4134 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004135 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004136 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004137 inp();
4138 if (tok == '\'') {
4139 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004140 tokc = getq();
4141 if (ch != '\'') {
4142 error("Expected a ' character, got %c", ch);
4143 } else {
4144 inp();
4145 }
Jack Palevich546b2242009-05-13 15:10:04 -07004146 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004147 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004148 while (ch && ch != EOF) {
4149 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004150 inp();
4151 inp();
4152 if (ch == '/')
4153 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004154 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004155 if (ch == EOF) {
4156 error("End of file inside comment.");
4157 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004158 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004159 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004160 } else if ((tok == '/') & (ch == '/')) {
4161 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004162 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004163 inp();
4164 }
4165 inp();
4166 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004167 } else if ((tok == '-') & (ch == '>')) {
4168 inp();
4169 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004170 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004171 const char* t = operatorChars;
4172 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004173 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004174 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004175 tokl = operatorLevel[opIndex];
4176 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004177 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004178#if 0
4179 printf("%c%c -> tokl=%d tokc=0x%x\n",
4180 l, a, tokl, tokc);
4181#endif
4182 if (a == ch) {
4183 inp();
4184 tok = TOK_DUMMY; /* dummy token for double tokens */
4185 }
Jack Palevich0c017742009-07-31 12:00:39 -07004186 /* check for op=, valid for * / % + - << >> & ^ | */
4187 if (ch == '=' &&
4188 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004189 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004190 inp();
4191 tok = TOK_OP_ASSIGNMENT;
4192 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004193 break;
4194 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004195 opIndex++;
4196 }
4197 if (l == 0) {
4198 tokl = 0;
4199 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004200 }
4201 }
4202 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004203
4204 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004205#if 0
4206 {
Jack Palevich569f1352009-06-29 14:29:08 -07004207 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004208 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004209 fprintf(stderr, "%s\n", buf.getUnwrapped());
4210 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004211#endif
4212 }
4213
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004214 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004215 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004216 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004217 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004218 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004219 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004220 if (ch == '(') {
4221 delete pName;
4222 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004223 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004224 }
4225 while (isspace(ch)) {
4226 inp();
4227 }
Jack Palevich569f1352009-06-29 14:29:08 -07004228 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004229 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004230 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004231 // Check for '//' comments.
4232 if (appendToValue && ch == '/') {
4233 inp();
4234 if (ch == '/') {
4235 appendToValue = false;
4236 } else {
4237 value.append('/');
4238 }
4239 }
4240 if (appendToValue && ch != EOF) {
4241 value.append(ch);
4242 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004243 inp();
4244 }
Jack Palevich569f1352009-06-29 14:29:08 -07004245 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4246 memcpy(pDefn, value.getUnwrapped(), value.len());
4247 pDefn[value.len()] = 0;
4248 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004249 }
4250
Jack Palevicheedf9d22009-06-04 16:23:40 -07004251 void doPragma() {
4252 // # pragma name(val)
4253 int state = 0;
4254 while(ch != EOF && ch != '\n' && state < 10) {
4255 switch(state) {
4256 case 0:
4257 if (isspace(ch)) {
4258 inp();
4259 } else {
4260 state++;
4261 }
4262 break;
4263 case 1:
4264 if (isalnum(ch)) {
4265 mPragmas.append(ch);
4266 inp();
4267 } else if (ch == '(') {
4268 mPragmas.append(0);
4269 inp();
4270 state++;
4271 } else {
4272 state = 11;
4273 }
4274 break;
4275 case 2:
4276 if (isalnum(ch)) {
4277 mPragmas.append(ch);
4278 inp();
4279 } else if (ch == ')') {
4280 mPragmas.append(0);
4281 inp();
4282 state = 10;
4283 } else {
4284 state = 11;
4285 }
4286 break;
4287 }
4288 }
4289 if(state != 10) {
4290 error("Unexpected pragma syntax");
4291 }
4292 mPragmaStringCount += 2;
4293 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004294
Jack Palevichdc456462009-07-16 16:50:56 -07004295 void doLine() {
4296 // # line number { "filename "}
4297 next();
4298 if (tok != TOK_NUM) {
4299 error("Expected a line-number");
4300 } else {
4301 mLineNumber = tokc-1; // The end-of-line will increment it.
4302 }
4303 while(ch != EOF && ch != '\n') {
4304 inp();
4305 }
4306 }
4307
Jack Palevichac0e95e2009-05-29 13:53:44 -07004308 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004309 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004310 mErrorBuf.vprintf(fmt, ap);
4311 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004312 }
4313
Jack Palevich8b0624c2009-05-20 12:12:06 -07004314 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004315 if (tok != c) {
4316 error("'%c' expected", c);
4317 }
4318 next();
4319 }
4320
Jack Palevich86351982009-06-30 18:09:56 -07004321 bool accept(intptr_t c) {
4322 if (tok == c) {
4323 next();
4324 return true;
4325 }
4326 return false;
4327 }
4328
Jack Palevich40600de2009-07-01 15:32:35 -07004329 bool acceptStringLiteral() {
4330 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004331 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004332 // This while loop merges multiple adjacent string constants.
4333 while (tok == '"') {
4334 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004335 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004336 }
4337 if (ch != '"') {
4338 error("Unterminated string constant.");
4339 }
4340 inp();
4341 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004342 }
Jack Palevich40600de2009-07-01 15:32:35 -07004343 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004344 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004345 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004346 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004347
4348 return true;
4349 }
4350 return false;
4351 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004352
Jack Palevichb1544ca2009-07-16 15:09:20 -07004353 void linkGlobal(tokenid_t t, bool isFunction) {
4354 VariableInfo* pVI = VI(t);
4355 void* n = NULL;
4356 if (mpSymbolLookupFn) {
4357 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4358 }
4359 if (pVI->pType == NULL) {
4360 if (isFunction) {
4361 pVI->pType = mkpIntFn;
4362 } else {
4363 pVI->pType = mkpInt;
4364 }
4365 }
4366 pVI->pAddress = n;
4367 }
4368
Jack Palevich29daf572009-07-30 19:38:55 -07004369 void unaryOrAssignment() {
4370 unary();
4371 if (accept('=')) {
4372 checkLVal();
4373 pGen->pushR0();
4374 expr();
4375 pGen->forceR0RVal();
4376 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004377 } else if (tok == TOK_OP_ASSIGNMENT) {
4378 int t = tokc;
4379 next();
4380 checkLVal();
4381 pGen->pushR0();
4382 pGen->forceR0RVal();
4383 pGen->pushR0();
4384 expr();
4385 pGen->forceR0RVal();
4386 pGen->genOp(t);
4387 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004388 }
4389 }
4390
Jack Palevich40600de2009-07-01 15:32:35 -07004391 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004392 */
Jack Palevich29daf572009-07-30 19:38:55 -07004393 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004394 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004395 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004396 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004397 if (acceptStringLiteral()) {
4398 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004399 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004400 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004401 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004402 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004403 t = tok;
4404 next();
4405 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004406 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004407 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004408 // Align to 4-byte boundary
4409 glo = (char*) (((intptr_t) glo + 3) & -4);
4410 * (float*) glo = (float) ad;
4411 pGen->loadFloat((int) glo, mkpFloat);
4412 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004413 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004414 // Align to 8-byte boundary
4415 glo = (char*) (((intptr_t) glo + 7) & -8);
4416 * (double*) glo = ad;
4417 pGen->loadFloat((int) glo, mkpDouble);
4418 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004419 } else if (c == 2) {
4420 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004421 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004422 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004423 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004424 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004425 else if (t == '+') {
4426 // ignore unary plus.
4427 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004428 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004429 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004430 } else if (c == 11) {
4431 // pre increment / pre decrement
4432 unary();
4433 doIncDec(a == OP_INCREMENT, 0);
4434 }
4435 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004436 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004437 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004438 if (pCast) {
4439 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004440 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004441 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004442 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004443 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004444 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004445 skip(')');
4446 }
4447 } else if (t == '*') {
4448 /* This is a pointer dereference.
4449 */
Jack Palevich29daf572009-07-30 19:38:55 -07004450 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004451 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004452 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004453 unary();
4454 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004455 } else if (t == EOF ) {
4456 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004457 } else if (t == ';') {
4458 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004459 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004460 // Don't have to do anything special here, the error
4461 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004462 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004463 if (!isDefined(t)) {
4464 mGlobals.add(t);
4465 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004466 }
Jack Palevich8df46192009-07-07 14:48:51 -07004467 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004468 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004469 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004470 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004471 linkGlobal(t, tok == '(');
4472 n = (intptr_t) pVI->pAddress;
4473 if (!n && tok != '(') {
4474 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004475 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004476 }
Jack Palevich29daf572009-07-30 19:38:55 -07004477 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004478 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004479 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004480 linkGlobal(t, false);
4481 n = (intptr_t) pVI->pAddress;
4482 if (!n) {
4483 error("Undeclared variable %s\n", nameof(t));
4484 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004485 }
Jack Palevich5b659092009-07-31 14:55:07 -07004486 }
4487 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004488 Type* pVal;
4489 ExpressionType et;
4490 if (pVI->pType->tag == TY_ARRAY) {
4491 pVal = pVI->pType;
4492 et = ET_RVALUE;
4493 } else {
4494 pVal = createPtrType(pVI->pType);
4495 et = ET_LVALUE;
4496 }
Jack Palevich5b659092009-07-31 14:55:07 -07004497 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004498 int tag = pVal->pHead->tag;
4499 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004500 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004501 }
Jack Palevich5b659092009-07-31 14:55:07 -07004502 pGen->leaR0(n, pVal, et);
4503 } else {
4504 pVI->pForward = (void*) pGen->leaForward(
4505 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004506 }
4507 }
4508 }
4509
Jack Palevich5b659092009-07-31 14:55:07 -07004510 /* Now handle postfix operators */
4511 for(;;) {
4512 if (tokl == 11) {
4513 // post inc / post dec
4514 doIncDec(tokc == OP_INCREMENT, true);
4515 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004516 } else if (accept('[')) {
4517 // Array reference
4518 pGen->forceR0RVal();
4519 pGen->pushR0();
4520 commaExpr();
4521 pGen->forceR0RVal();
4522 pGen->genOp(OP_PLUS);
4523 doPointer();
4524 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004525 } else if (accept('.')) {
4526 // struct element
4527 pGen->forceR0RVal();
4528 Type* pStruct = pGen->getR0Type();
4529 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004530 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004531 } else {
4532 error("expected a struct value to the left of '.'");
4533 }
4534 } else if (accept(TOK_OP_ARROW)) {
4535 pGen->forceR0RVal();
4536 Type* pPtr = pGen->getR0Type();
4537 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4538 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004539 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004540 } else {
4541 error("Expected a pointer to a struct to the left of '->'");
4542 }
Jack Palevich5b659092009-07-31 14:55:07 -07004543 } else if (accept('(')) {
4544 /* function call */
4545 Type* pDecl = NULL;
4546 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004547 Type* pFn = pGen->getR0Type();
4548 assert(pFn->tag == TY_POINTER);
4549 assert(pFn->pHead->tag == TY_FUNC);
4550 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004551 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004552 Type* pArgList = pDecl->pTail;
4553 bool varArgs = pArgList == NULL;
4554 /* push args and invert order */
4555 a = pGen->beginFunctionCallArguments();
4556 int l = 0;
4557 int argCount = 0;
4558 while (tok != ')' && tok != EOF) {
4559 if (! varArgs && !pArgList) {
4560 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004561 }
Jack Palevich5b659092009-07-31 14:55:07 -07004562 expr();
4563 pGen->forceR0RVal();
4564 Type* pTargetType;
4565 if (pArgList) {
4566 pTargetType = pArgList->pHead;
4567 pArgList = pArgList->pTail;
4568 } else {
4569 // This is a ... function, just pass arguments in their
4570 // natural type.
4571 pTargetType = pGen->getR0Type();
4572 if (pTargetType->tag == TY_FLOAT) {
4573 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004574 } else if (pTargetType->tag == TY_ARRAY) {
4575 // Pass arrays by pointer.
4576 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004577 }
4578 }
4579 if (pTargetType->tag == TY_VOID) {
4580 error("Can't pass void value for argument %d",
4581 argCount + 1);
4582 } else {
4583 l += pGen->storeR0ToArg(l, pTargetType);
4584 }
4585 if (accept(',')) {
4586 // fine
4587 } else if ( tok != ')') {
4588 error("Expected ',' or ')'");
4589 }
4590 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004591 }
Jack Palevich5b659092009-07-31 14:55:07 -07004592 if (! varArgs && pArgList) {
4593 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004594 }
Jack Palevich5b659092009-07-31 14:55:07 -07004595 pGen->endFunctionCallArguments(pDecl, a, l);
4596 skip(')');
4597 pGen->callIndirect(l, pDecl);
4598 pGen->adjustStackAfterCall(pDecl, l, true);
4599 } else {
4600 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004601 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004602 }
4603 }
4604
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004605 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004606 Type* pStructElement = lookupStructMember(pStruct, tok);
4607 if (pStructElement) {
4608 next();
4609 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4610 } else {
4611 String buf;
4612 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004613 error("Expected a struct member to the right of '%s', got %s",
4614 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004615 }
4616 }
4617
Jack Palevichaaac9282009-07-31 14:34:34 -07004618 void doIncDec(int isInc, int isPost) {
4619 // R0 already has the lval
4620 checkLVal();
4621 int lit = isInc ? 1 : -1;
4622 pGen->pushR0();
4623 pGen->loadR0FromR0();
4624 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004625 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4626 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004627 error("++/-- illegal for this type. %d", tag);
4628 }
4629 if (isPost) {
4630 pGen->over();
4631 pGen->pushR0();
4632 pGen->li(lit);
4633 pGen->genOp(OP_PLUS);
4634 pGen->storeR0ToTOS();
4635 pGen->popR0();
4636 } else {
4637 pGen->pushR0();
4638 pGen->li(lit);
4639 pGen->genOp(OP_PLUS);
4640 pGen->over();
4641 pGen->storeR0ToTOS();
4642 pGen->popR0();
4643 }
4644 }
4645
Jack Palevich47cbea92009-07-31 15:25:53 -07004646 void doPointer() {
4647 pGen->forceR0RVal();
4648 Type* pR0Type = pGen->getR0Type();
4649 if (pR0Type->tag != TY_POINTER) {
4650 error("Expected a pointer type.");
4651 } else {
4652 if (pR0Type->pHead->tag != TY_FUNC) {
4653 pGen->setR0ExpressionType(ET_LVALUE);
4654 }
4655 }
4656 }
4657
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004658 void doAddressOf() {
4659 Type* pR0 = pGen->getR0Type();
4660 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4661 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4662 error("Expected an lvalue");
4663 }
4664 Type* pR0Type = pGen->getR0Type();
4665 pGen->setR0ExpressionType(ET_RVALUE);
4666 }
4667
Jack Palevich40600de2009-07-01 15:32:35 -07004668 /* Recursive descent parser for binary operations.
4669 */
4670 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004671 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004672 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004673 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004674 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004675 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004676 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004677 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004678 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004679 t = tokc;
4680 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004681 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004682 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004683 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004684 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004685 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004686 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004687 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004688 // Check for syntax error.
4689 if (pGen->getR0Type() == NULL) {
4690 // We failed to parse a right-hand argument.
4691 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004692 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004693 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004694 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004695 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004696 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004697 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004698 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004699 }
4700 }
4701 }
4702 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004703 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004704 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004705 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004706 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004707 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004708 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004709 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004710 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004711 }
4712 }
4713 }
4714
Jack Palevich43aaee32009-07-31 14:01:37 -07004715 void commaExpr() {
4716 for(;;) {
4717 expr();
4718 if (!accept(',')) {
4719 break;
4720 }
4721 }
4722 }
4723
Jack Palevich21a15a22009-05-11 14:49:29 -07004724 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004725 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004726 }
4727
4728 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004729 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004730 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004731 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004732 }
4733
Jack Palevicha6baa232009-06-12 11:25:59 -07004734 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004735 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004736
Jack Palevich95727a02009-07-06 12:07:15 -07004737 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004738 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004739 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004740 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004741 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004742 next();
4743 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004744 a = test_expr();
4745 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004746 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004747 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004748 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004749 n = pGen->gjmp(0); /* jmp */
4750 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004751 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004752 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004753 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004754 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004755 }
Jack Palevich546b2242009-05-13 15:10:04 -07004756 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004757 t = tok;
4758 next();
4759 skip('(');
4760 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004761 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004762 a = test_expr();
4763 } else {
4764 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004765 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004766 skip(';');
4767 n = codeBuf.getPC();
4768 a = 0;
4769 if (tok != ';')
4770 a = test_expr();
4771 skip(';');
4772 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004773 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004774 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004775 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004776 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004777 n = t + 4;
4778 }
4779 }
4780 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004781 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004782 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004783 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004784 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004785 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004786 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004787 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004788 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004789 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004790 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004791 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004792 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004793 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004794 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004795 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004796 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004797 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004798 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004799 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004800 if (pReturnType->tag == TY_VOID) {
4801 error("Must not return a value from a void function");
4802 } else {
4803 pGen->convertR0(pReturnType);
4804 }
4805 } else {
4806 if (pReturnType->tag != TY_VOID) {
4807 error("Must specify a value here");
4808 }
Jack Palevich8df46192009-07-07 14:48:51 -07004809 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004810 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004811 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004812 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004813 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004814 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004815 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004816 }
4817 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004818
Jack Palevicha8f427f2009-07-13 18:40:08 -07004819 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004820 if (a == b) {
4821 return true;
4822 }
4823 if (a == NULL || b == NULL) {
4824 return false;
4825 }
4826 TypeTag at = a->tag;
4827 if (at != b->tag) {
4828 return false;
4829 }
4830 if (at == TY_POINTER) {
4831 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004832 } else if (at == TY_ARRAY) {
4833 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004834 } else if (at == TY_FUNC || at == TY_PARAM) {
4835 return typeEqual(a->pHead, b->pHead)
4836 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004837 } else if (at == TY_STRUCT) {
4838 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004839 }
4840 return true;
4841 }
4842
Jack Palevich2ff5c222009-07-23 15:11:22 -07004843 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004844 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004845 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004846 memset(pType, 0, sizeof(*pType));
4847 pType->tag = tag;
4848 pType->pHead = pHead;
4849 pType->pTail = pTail;
4850 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004851 }
4852
Jack Palevich2ff5c222009-07-23 15:11:22 -07004853 Type* createPtrType(Type* pType) {
4854 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004855 }
4856
4857 /**
4858 * Try to print a type in declaration order
4859 */
Jack Palevich86351982009-06-30 18:09:56 -07004860 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004861 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004862 if (pType == NULL) {
4863 buffer.appendCStr("null");
4864 return;
4865 }
Jack Palevich3f226492009-07-02 14:46:19 -07004866 decodeTypeImp(buffer, pType);
4867 }
4868
4869 void decodeTypeImp(String& buffer, Type* pType) {
4870 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004871 decodeId(buffer, pType->id);
4872 decodeTypeImpPostfix(buffer, pType);
4873 }
Jack Palevich3f226492009-07-02 14:46:19 -07004874
Jack Palevich9221bcc2009-08-26 16:15:07 -07004875 void decodeId(String& buffer, tokenid_t id) {
4876 if (id) {
4877 String temp;
4878 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004879 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004880 }
Jack Palevich3f226492009-07-02 14:46:19 -07004881 }
4882
4883 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4884 TypeTag tag = pType->tag;
4885
Jack Palevich9221bcc2009-08-26 16:15:07 -07004886 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004887 switch (tag) {
4888 case TY_INT:
4889 buffer.appendCStr("int");
4890 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004891 case TY_SHORT:
4892 buffer.appendCStr("short");
4893 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004894 case TY_CHAR:
4895 buffer.appendCStr("char");
4896 break;
4897 case TY_VOID:
4898 buffer.appendCStr("void");
4899 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004900 case TY_FLOAT:
4901 buffer.appendCStr("float");
4902 break;
4903 case TY_DOUBLE:
4904 buffer.appendCStr("double");
4905 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004906 case TY_STRUCT:
4907 {
4908 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4909 buffer.appendCStr(isStruct ? "struct" : "union");
4910 if (pType->pHead && pType->pHead->structTag) {
4911 buffer.append(' ');
4912 decodeId(buffer, pType->pHead->structTag);
4913 }
4914 }
4915 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004916 default:
4917 break;
4918 }
Jack Palevich86351982009-06-30 18:09:56 -07004919 buffer.append(' ');
4920 }
Jack Palevich3f226492009-07-02 14:46:19 -07004921
4922 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004923 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004924 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004925 case TY_SHORT:
4926 break;
Jack Palevich86351982009-06-30 18:09:56 -07004927 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004928 break;
4929 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004930 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004931 case TY_FLOAT:
4932 break;
4933 case TY_DOUBLE:
4934 break;
Jack Palevich86351982009-06-30 18:09:56 -07004935 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004936 decodeTypeImpPrefix(buffer, pType->pHead);
4937 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4938 buffer.append('(');
4939 }
4940 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004941 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004942 case TY_ARRAY:
4943 decodeTypeImpPrefix(buffer, pType->pHead);
4944 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004945 case TY_STRUCT:
4946 break;
Jack Palevich86351982009-06-30 18:09:56 -07004947 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004948 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004949 break;
4950 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004951 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004952 break;
4953 default:
4954 String temp;
4955 temp.printf("Unknown tag %d", pType->tag);
4956 buffer.append(temp);
4957 break;
4958 }
Jack Palevich3f226492009-07-02 14:46:19 -07004959 }
4960
4961 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4962 TypeTag tag = pType->tag;
4963
4964 switch(tag) {
4965 case TY_POINTER:
4966 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4967 buffer.append(')');
4968 }
4969 decodeTypeImpPostfix(buffer, pType->pHead);
4970 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004971 case TY_ARRAY:
4972 {
4973 String temp;
4974 temp.printf("[%d]", pType->length);
4975 buffer.append(temp);
4976 }
4977 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004978 case TY_STRUCT:
4979 if (pType->pHead->length >= 0) {
4980 buffer.appendCStr(" {");
4981 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4982 decodeTypeImp(buffer, pArg->pHead);
4983 buffer.appendCStr(";");
4984 }
4985 buffer.append('}');
4986 }
4987 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004988 case TY_FUNC:
4989 buffer.append('(');
4990 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4991 decodeTypeImp(buffer, pArg);
4992 if (pArg->pTail) {
4993 buffer.appendCStr(", ");
4994 }
4995 }
4996 buffer.append(')');
4997 break;
4998 default:
4999 break;
Jack Palevich86351982009-06-30 18:09:56 -07005000 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005001 }
5002
Jack Palevich86351982009-06-30 18:09:56 -07005003 void printType(Type* pType) {
5004 String buffer;
5005 decodeType(buffer, pType);
5006 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005007 }
5008
Jack Palevich2ff5c222009-07-23 15:11:22 -07005009 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005010 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005011 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005012 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005013 } else if (tok == TOK_SHORT) {
5014 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005015 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005016 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005017 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005018 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005019 } else if (tok == TOK_FLOAT) {
5020 pType = mkpFloat;
5021 } else if (tok == TOK_DOUBLE) {
5022 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005023 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5024 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005025 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005026 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005027 }
5028 next();
Jack Palevich86351982009-06-30 18:09:56 -07005029 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005030 }
5031
Jack Palevich9221bcc2009-08-26 16:15:07 -07005032 Type* acceptStruct() {
5033 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5034 bool isStruct = tok == TOK_STRUCT;
5035 next();
5036 tokenid_t structTag = acceptSymbol();
5037 bool isDeclaration = accept('{');
5038 bool fail = false;
5039
5040 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5041 if (structTag) {
5042 Token* pToken = &mTokenTable[structTag];
5043 VariableInfo* pStructInfo = pToken->mpStructInfo;
5044 bool needToDeclare = !pStructInfo;
5045 if (pStructInfo) {
5046 if (isDeclaration) {
5047 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5048 if (pStructInfo->pType->pHead->length == -1) {
5049 // we're filling in a forward declaration.
5050 needToDeclare = false;
5051 } else {
5052 error("A struct with the same name is already defined at this level.");
5053 fail = true;
5054 }
5055 } else {
5056 needToDeclare = true;
5057 }
5058 }
5059 if (!fail) {
5060 assert(pStructInfo->isStructTag);
5061 pStructType->pHead = pStructInfo->pType;
5062 pStructType->pTail = pStructType->pHead->pTail;
5063 }
5064 }
5065
5066 if (needToDeclare) {
5067 // This is a new struct name
5068 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5069 pStructType = createType(TY_STRUCT, NULL, NULL);
5070 pStructType->structTag = structTag;
5071 pStructType->pHead = pStructType;
5072 if (! isDeclaration) {
5073 // A forward declaration
5074 pStructType->length = -1;
5075 }
5076 pToken->mpStructInfo->pType = pStructType;
5077 }
5078 } else {
5079 // An anonymous struct
5080 pStructType->pHead = pStructType;
5081 }
5082
5083 if (isDeclaration) {
5084 size_t offset = 0;
5085 size_t structSize = 0;
5086 size_t structAlignment = 0;
5087 Type** pParamHolder = & pStructType->pHead->pTail;
5088 while (tok != '}' && tok != EOF) {
5089 Type* pPrimitiveType = expectPrimitiveType();
5090 if (pPrimitiveType) {
5091 while (tok != ';' && tok != EOF) {
5092 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5093 if (!pItem) {
5094 break;
5095 }
5096 if (lookupStructMember(pStructType, pItem->id)) {
5097 String buf;
5098 decodeToken(buf, pItem->id, false);
5099 error("Duplicate struct member %s", buf.getUnwrapped());
5100 }
5101 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5102 size_t alignment = pGen->alignmentOf(pItem);
5103 if (alignment > structAlignment) {
5104 structAlignment = alignment;
5105 }
5106 size_t alignmentMask = alignment - 1;
5107 offset = (offset + alignmentMask) & ~alignmentMask;
5108 pStructElement->length = offset;
5109 size_t size = pGen->sizeOf(pItem);
5110 if (isStruct) {
5111 offset += size;
5112 structSize = offset;
5113 } else {
5114 if (size >= structSize) {
5115 structSize = size;
5116 }
5117 }
5118 *pParamHolder = pStructElement;
5119 pParamHolder = &pStructElement->pTail;
5120 accept(',');
5121 }
5122 skip(';');
5123 } else {
5124 // Some sort of syntax error, skip token and keep trying
5125 next();
5126 }
5127 }
5128 if (!fail) {
5129 pStructType->pHead->length = structSize;
5130 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5131 }
5132 skip('}');
5133 }
5134 if (fail) {
5135 pStructType = NULL;
5136 }
5137 return pStructType;
5138 }
5139
5140 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5141 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5142 if (pStructElement->pHead->id == memberId) {
5143 return pStructElement;
5144 }
5145 }
5146 return NULL;
5147 }
5148
Jack Palevich2ff5c222009-07-23 15:11:22 -07005149 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005150 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005151 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005152 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005153 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005154 if (declName) {
5155 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005156 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005157 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005158 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005159 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005160 } else if (nameRequired) {
5161 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005162 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005163#if 0
5164 fprintf(stderr, "Parsed a declaration: ");
5165 printType(pType);
5166#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005167 if (reportFailure) {
5168 return NULL;
5169 }
Jack Palevich86351982009-06-30 18:09:56 -07005170 return pType;
5171 }
5172
Jack Palevich2ff5c222009-07-23 15:11:22 -07005173 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005174 bool nameRequired = pBaseType->tag != TY_STRUCT;
5175 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005176 if (! pType) {
5177 error("Expected a declaration");
5178 }
5179 return pType;
5180 }
5181
Jack Palevich3f226492009-07-02 14:46:19 -07005182 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005183 Type* acceptCastTypeDeclaration() {
5184 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005185 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005186 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005187 }
Jack Palevich86351982009-06-30 18:09:56 -07005188 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005189 }
5190
Jack Palevich2ff5c222009-07-23 15:11:22 -07005191 Type* expectCastTypeDeclaration() {
5192 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005193 if (! pType) {
5194 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005195 }
Jack Palevich3f226492009-07-02 14:46:19 -07005196 return pType;
5197 }
5198
5199 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005200 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005201 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005202 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005203 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005204 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005205 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005206 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005207 return pType;
5208 }
5209
5210 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005211 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005212 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005213 // direct-dcl :
5214 // name
5215 // (dcl)
5216 // direct-dcl()
5217 // direct-dcl[]
5218 Type* pNewHead = NULL;
5219 if (accept('(')) {
5220 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005221 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005222 skip(')');
5223 } else if ((declName = acceptSymbol()) != 0) {
5224 if (nameAllowed == false && declName) {
5225 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005226 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005227 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005228 } else if (nameRequired && ! declName) {
5229 String temp;
5230 decodeToken(temp, tok, true);
5231 error("Expected name. Got %s", temp.getUnwrapped());
5232 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005233 }
Jack Palevichb6154502009-08-04 14:56:09 -07005234 for(;;) {
5235 if (accept('(')) {
5236 // Function declaration
5237 Type* pTail = acceptArgs(nameAllowed);
5238 pType = createType(TY_FUNC, pType, pTail);
5239 skip(')');
5240 } if (accept('[')) {
5241 if (tok != ']') {
5242 if (tok != TOK_NUM || tokc <= 0) {
5243 error("Expected positive integer constant");
5244 } else {
5245 Type* pDecayType = createPtrType(pType);
5246 pType = createType(TY_ARRAY, pType, pDecayType);
5247 pType->length = tokc;
5248 }
5249 next();
5250 }
5251 skip(']');
5252 } else {
5253 break;
5254 }
Jack Palevich86351982009-06-30 18:09:56 -07005255 }
Jack Palevich3f226492009-07-02 14:46:19 -07005256
5257 if (pNewHead) {
5258 Type* pA = pNewHead;
5259 while (pA->pHead) {
5260 pA = pA->pHead;
5261 }
5262 pA->pHead = pType;
5263 pType = pNewHead;
5264 }
Jack Palevich86351982009-06-30 18:09:56 -07005265 return pType;
5266 }
5267
Jack Palevich2ff5c222009-07-23 15:11:22 -07005268 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005269 Type* pHead = NULL;
5270 Type* pTail = NULL;
5271 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005272 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005273 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005274 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005275 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005276 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005277 if (!pHead) {
5278 pHead = pParam;
5279 pTail = pParam;
5280 } else {
5281 pTail->pTail = pParam;
5282 pTail = pParam;
5283 }
5284 }
5285 }
5286 if (! accept(',')) {
5287 break;
5288 }
5289 }
5290 return pHead;
5291 }
5292
Jack Palevich2ff5c222009-07-23 15:11:22 -07005293 Type* expectPrimitiveType() {
5294 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005295 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005296 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005297 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005298 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005299 }
Jack Palevich86351982009-06-30 18:09:56 -07005300 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005301 }
5302
Jack Palevichb5e33312009-07-30 19:06:34 -07005303 void checkLVal() {
5304 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005305 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005306 }
5307 }
5308
Jack Palevich86351982009-06-30 18:09:56 -07005309 void addGlobalSymbol(Type* pDecl) {
5310 tokenid_t t = pDecl->id;
5311 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005312 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005313 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005314 }
Jack Palevich86351982009-06-30 18:09:56 -07005315 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005316 }
5317
Jack Palevich86351982009-06-30 18:09:56 -07005318 void reportDuplicate(tokenid_t t) {
5319 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005320 }
5321
Jack Palevich86351982009-06-30 18:09:56 -07005322 void addLocalSymbol(Type* pDecl) {
5323 tokenid_t t = pDecl->id;
5324 if (mLocals.isDefinedAtCurrentLevel(t)) {
5325 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005326 }
Jack Palevich86351982009-06-30 18:09:56 -07005327 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005328 }
5329
Jack Palevich95727a02009-07-06 12:07:15 -07005330 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005331 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005332
Jack Palevich95727a02009-07-06 12:07:15 -07005333 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005334 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005335 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005336 if (!pDecl) {
5337 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005338 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005339 if (!pDecl->id) {
5340 break;
5341 }
Jack Palevich86351982009-06-30 18:09:56 -07005342 int variableAddress = 0;
5343 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005344 size_t alignment = pGen->alignmentOf(pDecl);
5345 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005346 size_t alignmentMask = ~ (alignment - 1);
5347 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005348 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005349 loc = (loc + alignment - 1) & alignmentMask;
5350 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5351 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005352 variableAddress = -loc;
5353 VI(pDecl->id)->pAddress = (void*) variableAddress;
5354 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005355 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005356 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005357 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005358 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005359 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005360 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005361 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005362 if (tok == ',')
5363 next();
5364 }
5365 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005366 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005367 }
5368 }
5369
Jack Palevichf1728be2009-06-12 13:53:51 -07005370 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005371 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005372 }
5373
Jack Palevich37c54bd2009-07-14 18:35:36 -07005374 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005375 if (token == EOF ) {
5376 buffer.printf("EOF");
5377 } else if (token == TOK_NUM) {
5378 buffer.printf("numeric constant");
5379 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005380 if (token < 32) {
5381 buffer.printf("'\\x%02x'", token);
5382 } else {
5383 buffer.printf("'%c'", token);
5384 }
Jack Palevich569f1352009-06-29 14:29:08 -07005385 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005386 if (quote) {
5387 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5388 buffer.printf("keyword \"%s\"", nameof(token));
5389 } else {
5390 buffer.printf("symbol \"%s\"", nameof(token));
5391 }
5392 } else {
5393 buffer.printf("%s", nameof(token));
5394 }
Jack Palevich569f1352009-06-29 14:29:08 -07005395 }
5396 }
5397
Jack Palevich9221bcc2009-08-26 16:15:07 -07005398 void printToken(tokenid_t token) {
5399 String buffer;
5400 decodeToken(buffer, token, true);
5401 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5402 }
5403
Jack Palevich40600de2009-07-01 15:32:35 -07005404 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005405 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005406 if (!result) {
5407 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005408 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005409 error("Expected symbol. Got %s", temp.getUnwrapped());
5410 }
5411 return result;
5412 }
5413
Jack Palevich86351982009-06-30 18:09:56 -07005414 tokenid_t acceptSymbol() {
5415 tokenid_t result = 0;
5416 if (tok >= TOK_SYMBOL) {
5417 result = tok;
5418 next();
Jack Palevich86351982009-06-30 18:09:56 -07005419 }
5420 return result;
5421 }
5422
Jack Palevichb7c81e92009-06-04 19:56:13 -07005423 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005424 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005425 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005426 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005427 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005428 break;
5429 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005430 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005431 if (!pDecl) {
5432 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005433 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005434 if (!pDecl->id) {
5435 skip(';');
5436 continue;
5437 }
5438
Jack Palevich86351982009-06-30 18:09:56 -07005439 if (! isDefined(pDecl->id)) {
5440 addGlobalSymbol(pDecl);
5441 }
5442 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005443 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005444 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005445 }
Jack Palevich86351982009-06-30 18:09:56 -07005446 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005447 // it's a variable declaration
5448 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005449 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005450 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005451 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005452 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005453 }
Jack Palevich86351982009-06-30 18:09:56 -07005454 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005455 if (tok == TOK_NUM) {
5456 if (name) {
5457 * (int*) name->pAddress = tokc;
5458 }
5459 next();
5460 } else {
5461 error("Expected an integer constant");
5462 }
5463 }
Jack Palevich86351982009-06-30 18:09:56 -07005464 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005465 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005466 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005467 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005468 if (!pDecl) {
5469 break;
5470 }
5471 if (! isDefined(pDecl->id)) {
5472 addGlobalSymbol(pDecl);
5473 }
5474 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005475 }
5476 skip(';');
5477 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005478 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005479 if (accept(';')) {
5480 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005481 } else if (tok != '{') {
5482 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005483 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005484 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005485 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005486 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005487 /* patch forward references */
5488 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005489 /* put function address */
5490 name->pAddress = (void*) codeBuf.getPC();
5491 }
5492 // Calculate stack offsets for parameters
5493 mLocals.pushLevel();
5494 intptr_t a = 8;
5495 int argCount = 0;
5496 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5497 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005498 if (pArg->id) {
5499 addLocalSymbol(pArg);
5500 }
Jack Palevich95727a02009-07-06 12:07:15 -07005501 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005502 Type* pPassingType = passingType(pArg);
5503 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005504 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005505 if (pArg->id) {
5506 VI(pArg->id)->pAddress = (void*) a;
5507 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005508 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005509 argCount++;
5510 }
5511 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005512 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005513 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005514 block(0, true);
5515 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005516 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005517 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005518 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005519 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005520 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005521 }
5522 }
5523 }
5524
Jack Palevich9221bcc2009-08-26 16:15:07 -07005525 Type* passingType(Type* pType) {
5526 switch (pType->tag) {
5527 case TY_CHAR:
5528 case TY_SHORT:
5529 return mkpInt;
5530 default:
5531 return pType;
5532 }
5533 }
5534
Jack Palevich9cbd2262009-07-08 16:48:41 -07005535 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5536 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5537 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005538 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005539 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005540 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005541 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005542 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005543 char* result = (char*) base;
5544 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005545 return result;
5546 }
5547
Jack Palevich21a15a22009-05-11 14:49:29 -07005548 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005549 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005550 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005551 pGlobalBase = 0;
5552 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005553 if (pGen) {
5554 delete pGen;
5555 pGen = 0;
5556 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005557 if (file) {
5558 delete file;
5559 file = 0;
5560 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005561 }
5562
Jack Palevich8c246a92009-07-14 21:14:10 -07005563 // One-time initialization, when class is constructed.
5564 void init() {
5565 mpSymbolLookupFn = 0;
5566 mpSymbolLookupContext = 0;
5567 }
5568
Jack Palevich21a15a22009-05-11 14:49:29 -07005569 void clear() {
5570 tok = 0;
5571 tokc = 0;
5572 tokl = 0;
5573 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005574 rsym = 0;
5575 loc = 0;
5576 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005577 dptr = 0;
5578 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005579 file = 0;
5580 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005581 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005582 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005583 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005584 mLineNumber = 1;
5585 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005586 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005587 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005588
Jack Palevich22305132009-05-13 10:58:45 -07005589 void setArchitecture(const char* architecture) {
5590 delete pGen;
5591 pGen = 0;
5592
5593 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005594#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005595 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005596 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005597 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005598#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005599#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005600 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005601 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005602 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005603#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005604 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005605 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005606 }
5607 }
5608
5609 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005610#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005611 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005612#elif defined(DEFAULT_X86_CODEGEN)
5613 pGen = new X86CodeGenerator();
5614#endif
5615 }
5616 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005617 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005618 } else {
5619 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005620 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005621 }
5622 }
5623
Jack Palevich77ae76e2009-05-10 19:59:24 -07005624public:
Jack Palevich22305132009-05-13 10:58:45 -07005625 struct args {
5626 args() {
5627 architecture = 0;
5628 }
5629 const char* architecture;
5630 };
5631
Jack Paleviche7b59062009-05-19 17:12:17 -07005632 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005633 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005634 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005635 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005636
Jack Paleviche7b59062009-05-19 17:12:17 -07005637 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005638 cleanup();
5639 }
5640
Jack Palevich8c246a92009-07-14 21:14:10 -07005641 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5642 mpSymbolLookupFn = pFn;
5643 mpSymbolLookupContext = pContext;
5644 }
5645
Jack Palevich1cdef202009-05-22 12:06:27 -07005646 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005647 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005648
Jack Palevich2ff5c222009-07-23 15:11:22 -07005649 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005650 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005651 cleanup();
5652 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005653 mTokenTable.setArena(&mGlobalArena);
5654 mGlobals.setArena(&mGlobalArena);
5655 mGlobals.setTokenTable(&mTokenTable);
5656 mLocals.setArena(&mLocalArena);
5657 mLocals.setTokenTable(&mTokenTable);
5658
5659 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005660 codeBuf.init(ALLOC_SIZE);
5661 setArchitecture(NULL);
5662 if (!pGen) {
5663 return -1;
5664 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005665#ifdef PROVIDE_TRACE_CODEGEN
5666 pGen = new TraceCodeGenerator(pGen);
5667#endif
5668 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005669 pGen->init(&codeBuf);
5670 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005671 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5672 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005673 inp();
5674 next();
5675 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005676 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005677 result = pGen->finishCompile();
5678 if (result == 0) {
5679 if (mErrorBuf.len()) {
5680 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005681 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005682 }
Jack Palevichce105a92009-07-16 14:30:33 -07005683 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005684 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005685 }
5686
Jack Palevich86351982009-06-30 18:09:56 -07005687 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005688 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005689 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005690 mkpChar = createType(TY_CHAR, NULL, NULL);
5691 mkpVoid = createType(TY_VOID, NULL, NULL);
5692 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5693 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5694 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5695 mkpIntPtr = createPtrType(mkpInt);
5696 mkpCharPtr = createPtrType(mkpChar);
5697 mkpFloatPtr = createPtrType(mkpFloat);
5698 mkpDoublePtr = createPtrType(mkpDouble);
5699 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005700 }
5701
Jack Palevicha6baa232009-06-12 11:25:59 -07005702 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005703 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005704 }
5705
Jack Palevich569f1352009-06-29 14:29:08 -07005706 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005707 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005708 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005709 }
5710
Jack Palevich569f1352009-06-29 14:29:08 -07005711 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005712 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005713 error("Undefined forward reference: %s",
5714 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005715 }
5716 return true;
5717 }
5718
Jack Palevich21a15a22009-05-11 14:49:29 -07005719 int dump(FILE* out) {
5720 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5721 return 0;
5722 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005723
Jack Palevicha6535612009-05-13 16:24:17 -07005724 int disassemble(FILE* out) {
5725 return pGen->disassemble(out);
5726 }
5727
Jack Palevich1cdef202009-05-22 12:06:27 -07005728 /* Look through the symbol table to find a symbol.
5729 * If found, return its value.
5730 */
5731 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005732 if (mCompileResult == 0) {
5733 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5734 VariableInfo* pVariableInfo = VI(tok);
5735 if (pVariableInfo) {
5736 return pVariableInfo->pAddress;
5737 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005738 }
5739 return NULL;
5740 }
5741
Jack Palevicheedf9d22009-06-04 16:23:40 -07005742 void getPragmas(ACCsizei* actualStringCount,
5743 ACCsizei maxStringCount, ACCchar** strings) {
5744 int stringCount = mPragmaStringCount;
5745 if (actualStringCount) {
5746 *actualStringCount = stringCount;
5747 }
5748 if (stringCount > maxStringCount) {
5749 stringCount = maxStringCount;
5750 }
5751 if (strings) {
5752 char* pPragmas = mPragmas.getUnwrapped();
5753 while (stringCount-- > 0) {
5754 *strings++ = pPragmas;
5755 pPragmas += strlen(pPragmas) + 1;
5756 }
5757 }
5758 }
5759
Jack Palevichac0e95e2009-05-29 13:53:44 -07005760 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005761 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005762 }
5763
Jack Palevich77ae76e2009-05-10 19:59:24 -07005764};
5765
Jack Paleviche7b59062009-05-19 17:12:17 -07005766const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005767 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5768
Jack Paleviche7b59062009-05-19 17:12:17 -07005769const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005770 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5771 5, 5, /* ==, != */
5772 9, 10, /* &&, || */
5773 6, 7, 8, /* & ^ | */
5774 2, 2 /* ~ ! */
5775 };
5776
Jack Palevich8b0624c2009-05-20 12:12:06 -07005777#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005778FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005779#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005780
Jack Palevich8b0624c2009-05-20 12:12:06 -07005781#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005782const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005783 0x1, // ++
5784 0xff, // --
5785 0xc1af0f, // *
5786 0xf9f79991, // /
5787 0xf9f79991, // % (With manual assist to swap results)
5788 0xc801, // +
5789 0xd8f7c829, // -
5790 0xe0d391, // <<
5791 0xf8d391, // >>
5792 0xe, // <=
5793 0xd, // >=
5794 0xc, // <
5795 0xf, // >
5796 0x4, // ==
5797 0x5, // !=
5798 0x0, // &&
5799 0x1, // ||
5800 0xc821, // &
5801 0xc831, // ^
5802 0xc809, // |
5803 0xd0f7, // ~
5804 0x4 // !
5805};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005806#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005807
Jack Palevich1cdef202009-05-22 12:06:27 -07005808struct ACCscript {
5809 ACCscript() {
5810 text = 0;
5811 textLength = 0;
5812 accError = ACC_NO_ERROR;
5813 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005814
Jack Palevich1cdef202009-05-22 12:06:27 -07005815 ~ACCscript() {
5816 delete text;
5817 }
Jack Palevich546b2242009-05-13 15:10:04 -07005818
Jack Palevich8c246a92009-07-14 21:14:10 -07005819 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5820 compiler.registerSymbolCallback(pFn, pContext);
5821 }
5822
Jack Palevich1cdef202009-05-22 12:06:27 -07005823 void setError(ACCenum error) {
5824 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5825 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005826 }
5827 }
5828
Jack Palevich1cdef202009-05-22 12:06:27 -07005829 ACCenum getError() {
5830 ACCenum result = accError;
5831 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005832 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005833 }
5834
Jack Palevich1cdef202009-05-22 12:06:27 -07005835 Compiler compiler;
5836 char* text;
5837 int textLength;
5838 ACCenum accError;
5839};
5840
5841
5842extern "C"
5843ACCscript* accCreateScript() {
5844 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005845}
Jack Palevich1cdef202009-05-22 12:06:27 -07005846
5847extern "C"
5848ACCenum accGetError( ACCscript* script ) {
5849 return script->getError();
5850}
5851
5852extern "C"
5853void accDeleteScript(ACCscript* script) {
5854 delete script;
5855}
5856
5857extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005858void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5859 ACCvoid* pContext) {
5860 script->registerSymbolCallback(pFn, pContext);
5861}
5862
5863extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005864void accScriptSource(ACCscript* script,
5865 ACCsizei count,
5866 const ACCchar ** string,
5867 const ACCint * length) {
5868 int totalLength = 0;
5869 for(int i = 0; i < count; i++) {
5870 int len = -1;
5871 const ACCchar* s = string[i];
5872 if (length) {
5873 len = length[i];
5874 }
5875 if (len < 0) {
5876 len = strlen(s);
5877 }
5878 totalLength += len;
5879 }
5880 delete script->text;
5881 char* text = new char[totalLength + 1];
5882 script->text = text;
5883 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005884 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005885 for(int i = 0; i < count; i++) {
5886 int len = -1;
5887 const ACCchar* s = string[i];
5888 if (length) {
5889 len = length[i];
5890 }
5891 if (len < 0) {
5892 len = strlen(s);
5893 }
Jack Palevich09555c72009-05-27 12:25:55 -07005894 memcpy(dest, s, len);
5895 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005896 }
5897 text[totalLength] = '\0';
5898}
5899
5900extern "C"
5901void accCompileScript(ACCscript* script) {
5902 int result = script->compiler.compile(script->text, script->textLength);
5903 if (result) {
5904 script->setError(ACC_INVALID_OPERATION);
5905 }
5906}
5907
5908extern "C"
5909void accGetScriptiv(ACCscript* script,
5910 ACCenum pname,
5911 ACCint * params) {
5912 switch (pname) {
5913 case ACC_INFO_LOG_LENGTH:
5914 *params = 0;
5915 break;
5916 }
5917}
5918
5919extern "C"
5920void accGetScriptInfoLog(ACCscript* script,
5921 ACCsizei maxLength,
5922 ACCsizei * length,
5923 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005924 char* message = script->compiler.getErrorMessage();
5925 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005926 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005927 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005928 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005929 if (infoLog && maxLength > 0) {
5930 int trimmedLength = maxLength < messageLength ?
5931 maxLength : messageLength;
5932 memcpy(infoLog, message, trimmedLength);
5933 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005934 }
5935}
5936
5937extern "C"
5938void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5939 ACCvoid ** address) {
5940 void* value = script->compiler.lookup(name);
5941 if (value) {
5942 *address = value;
5943 } else {
5944 script->setError(ACC_INVALID_VALUE);
5945 }
5946}
5947
Jack Palevicheedf9d22009-06-04 16:23:40 -07005948extern "C"
5949void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5950 ACCsizei maxStringCount, ACCchar** strings){
5951 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5952}
5953
-b master422972c2009-06-17 19:13:52 -07005954extern "C"
5955void accDisassemble(ACCscript* script) {
5956 script->compiler.disassemble(stderr);
5957}
5958
Jack Palevicheedf9d22009-06-04 16:23:40 -07005959
Jack Palevich1cdef202009-05-22 12:06:27 -07005960} // namespace acc
5961