blob: 7e6dde6a48576371dab5a8876193a3e066ce8805 [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) {
4530 doStructMember(pStruct);
4531 } 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();
4539 doStructMember(pPtr->pHead);
4540 } 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 Palevich9221bcc2009-08-26 16:15:07 -07004605 void doStructMember(Type* pStruct) {
4606 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);
4613 error("Expected a struct member to the right of '.', got %s", buf.getUnwrapped());
4614 }
4615 }
4616
Jack Palevichaaac9282009-07-31 14:34:34 -07004617 void doIncDec(int isInc, int isPost) {
4618 // R0 already has the lval
4619 checkLVal();
4620 int lit = isInc ? 1 : -1;
4621 pGen->pushR0();
4622 pGen->loadR0FromR0();
4623 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004624 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4625 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004626 error("++/-- illegal for this type. %d", tag);
4627 }
4628 if (isPost) {
4629 pGen->over();
4630 pGen->pushR0();
4631 pGen->li(lit);
4632 pGen->genOp(OP_PLUS);
4633 pGen->storeR0ToTOS();
4634 pGen->popR0();
4635 } else {
4636 pGen->pushR0();
4637 pGen->li(lit);
4638 pGen->genOp(OP_PLUS);
4639 pGen->over();
4640 pGen->storeR0ToTOS();
4641 pGen->popR0();
4642 }
4643 }
4644
Jack Palevich47cbea92009-07-31 15:25:53 -07004645 void doPointer() {
4646 pGen->forceR0RVal();
4647 Type* pR0Type = pGen->getR0Type();
4648 if (pR0Type->tag != TY_POINTER) {
4649 error("Expected a pointer type.");
4650 } else {
4651 if (pR0Type->pHead->tag != TY_FUNC) {
4652 pGen->setR0ExpressionType(ET_LVALUE);
4653 }
4654 }
4655 }
4656
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004657 void doAddressOf() {
4658 Type* pR0 = pGen->getR0Type();
4659 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4660 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4661 error("Expected an lvalue");
4662 }
4663 Type* pR0Type = pGen->getR0Type();
4664 pGen->setR0ExpressionType(ET_RVALUE);
4665 }
4666
Jack Palevich40600de2009-07-01 15:32:35 -07004667 /* Recursive descent parser for binary operations.
4668 */
4669 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004670 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004671 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004672 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004673 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004674 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004675 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004676 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004677 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004678 t = tokc;
4679 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004680 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004681 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004682 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004683 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004684 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004685 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004686 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004687 // Check for syntax error.
4688 if (pGen->getR0Type() == NULL) {
4689 // We failed to parse a right-hand argument.
4690 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004691 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004692 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004693 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004694 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004695 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004696 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004697 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004698 }
4699 }
4700 }
4701 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004702 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004703 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004704 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004705 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004706 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004707 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004708 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004709 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004710 }
4711 }
4712 }
4713
Jack Palevich43aaee32009-07-31 14:01:37 -07004714 void commaExpr() {
4715 for(;;) {
4716 expr();
4717 if (!accept(',')) {
4718 break;
4719 }
4720 }
4721 }
4722
Jack Palevich21a15a22009-05-11 14:49:29 -07004723 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004724 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004725 }
4726
4727 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004728 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004729 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004730 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004731 }
4732
Jack Palevicha6baa232009-06-12 11:25:59 -07004733 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004734 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004735
Jack Palevich95727a02009-07-06 12:07:15 -07004736 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004737 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004738 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004739 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004740 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004741 next();
4742 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004743 a = test_expr();
4744 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004745 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004746 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004747 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004748 n = pGen->gjmp(0); /* jmp */
4749 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004750 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004751 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004752 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004753 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004754 }
Jack Palevich546b2242009-05-13 15:10:04 -07004755 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004756 t = tok;
4757 next();
4758 skip('(');
4759 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004760 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004761 a = test_expr();
4762 } else {
4763 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004764 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004765 skip(';');
4766 n = codeBuf.getPC();
4767 a = 0;
4768 if (tok != ';')
4769 a = test_expr();
4770 skip(';');
4771 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004772 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004773 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004774 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004775 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004776 n = t + 4;
4777 }
4778 }
4779 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004780 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004781 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004782 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004783 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004784 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004785 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004786 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004787 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004788 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004789 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004790 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004791 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004792 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004793 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004794 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004795 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004796 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004797 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004798 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004799 if (pReturnType->tag == TY_VOID) {
4800 error("Must not return a value from a void function");
4801 } else {
4802 pGen->convertR0(pReturnType);
4803 }
4804 } else {
4805 if (pReturnType->tag != TY_VOID) {
4806 error("Must specify a value here");
4807 }
Jack Palevich8df46192009-07-07 14:48:51 -07004808 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004809 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004810 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004811 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004812 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004813 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004814 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004815 }
4816 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004817
Jack Palevicha8f427f2009-07-13 18:40:08 -07004818 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004819 if (a == b) {
4820 return true;
4821 }
4822 if (a == NULL || b == NULL) {
4823 return false;
4824 }
4825 TypeTag at = a->tag;
4826 if (at != b->tag) {
4827 return false;
4828 }
4829 if (at == TY_POINTER) {
4830 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004831 } else if (at == TY_ARRAY) {
4832 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004833 } else if (at == TY_FUNC || at == TY_PARAM) {
4834 return typeEqual(a->pHead, b->pHead)
4835 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004836 } else if (at == TY_STRUCT) {
4837 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004838 }
4839 return true;
4840 }
4841
Jack Palevich2ff5c222009-07-23 15:11:22 -07004842 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004843 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004844 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004845 memset(pType, 0, sizeof(*pType));
4846 pType->tag = tag;
4847 pType->pHead = pHead;
4848 pType->pTail = pTail;
4849 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004850 }
4851
Jack Palevich2ff5c222009-07-23 15:11:22 -07004852 Type* createPtrType(Type* pType) {
4853 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004854 }
4855
4856 /**
4857 * Try to print a type in declaration order
4858 */
Jack Palevich86351982009-06-30 18:09:56 -07004859 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004860 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004861 if (pType == NULL) {
4862 buffer.appendCStr("null");
4863 return;
4864 }
Jack Palevich3f226492009-07-02 14:46:19 -07004865 decodeTypeImp(buffer, pType);
4866 }
4867
4868 void decodeTypeImp(String& buffer, Type* pType) {
4869 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004870 decodeId(buffer, pType->id);
4871 decodeTypeImpPostfix(buffer, pType);
4872 }
Jack Palevich3f226492009-07-02 14:46:19 -07004873
Jack Palevich9221bcc2009-08-26 16:15:07 -07004874 void decodeId(String& buffer, tokenid_t id) {
4875 if (id) {
4876 String temp;
4877 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004878 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004879 }
Jack Palevich3f226492009-07-02 14:46:19 -07004880 }
4881
4882 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4883 TypeTag tag = pType->tag;
4884
Jack Palevich9221bcc2009-08-26 16:15:07 -07004885 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004886 switch (tag) {
4887 case TY_INT:
4888 buffer.appendCStr("int");
4889 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004890 case TY_SHORT:
4891 buffer.appendCStr("short");
4892 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004893 case TY_CHAR:
4894 buffer.appendCStr("char");
4895 break;
4896 case TY_VOID:
4897 buffer.appendCStr("void");
4898 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004899 case TY_FLOAT:
4900 buffer.appendCStr("float");
4901 break;
4902 case TY_DOUBLE:
4903 buffer.appendCStr("double");
4904 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004905 case TY_STRUCT:
4906 {
4907 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4908 buffer.appendCStr(isStruct ? "struct" : "union");
4909 if (pType->pHead && pType->pHead->structTag) {
4910 buffer.append(' ');
4911 decodeId(buffer, pType->pHead->structTag);
4912 }
4913 }
4914 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004915 default:
4916 break;
4917 }
Jack Palevich86351982009-06-30 18:09:56 -07004918 buffer.append(' ');
4919 }
Jack Palevich3f226492009-07-02 14:46:19 -07004920
4921 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004922 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004923 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004924 case TY_SHORT:
4925 break;
Jack Palevich86351982009-06-30 18:09:56 -07004926 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004927 break;
4928 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004929 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004930 case TY_FLOAT:
4931 break;
4932 case TY_DOUBLE:
4933 break;
Jack Palevich86351982009-06-30 18:09:56 -07004934 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004935 decodeTypeImpPrefix(buffer, pType->pHead);
4936 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4937 buffer.append('(');
4938 }
4939 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004940 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004941 case TY_ARRAY:
4942 decodeTypeImpPrefix(buffer, pType->pHead);
4943 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004944 case TY_STRUCT:
4945 break;
Jack Palevich86351982009-06-30 18:09:56 -07004946 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004947 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004948 break;
4949 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004950 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004951 break;
4952 default:
4953 String temp;
4954 temp.printf("Unknown tag %d", pType->tag);
4955 buffer.append(temp);
4956 break;
4957 }
Jack Palevich3f226492009-07-02 14:46:19 -07004958 }
4959
4960 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4961 TypeTag tag = pType->tag;
4962
4963 switch(tag) {
4964 case TY_POINTER:
4965 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4966 buffer.append(')');
4967 }
4968 decodeTypeImpPostfix(buffer, pType->pHead);
4969 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004970 case TY_ARRAY:
4971 {
4972 String temp;
4973 temp.printf("[%d]", pType->length);
4974 buffer.append(temp);
4975 }
4976 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004977 case TY_STRUCT:
4978 if (pType->pHead->length >= 0) {
4979 buffer.appendCStr(" {");
4980 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4981 decodeTypeImp(buffer, pArg->pHead);
4982 buffer.appendCStr(";");
4983 }
4984 buffer.append('}');
4985 }
4986 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004987 case TY_FUNC:
4988 buffer.append('(');
4989 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4990 decodeTypeImp(buffer, pArg);
4991 if (pArg->pTail) {
4992 buffer.appendCStr(", ");
4993 }
4994 }
4995 buffer.append(')');
4996 break;
4997 default:
4998 break;
Jack Palevich86351982009-06-30 18:09:56 -07004999 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005000 }
5001
Jack Palevich86351982009-06-30 18:09:56 -07005002 void printType(Type* pType) {
5003 String buffer;
5004 decodeType(buffer, pType);
5005 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005006 }
5007
Jack Palevich2ff5c222009-07-23 15:11:22 -07005008 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005009 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005010 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005011 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005012 } else if (tok == TOK_SHORT) {
5013 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005014 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005015 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005016 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005017 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005018 } else if (tok == TOK_FLOAT) {
5019 pType = mkpFloat;
5020 } else if (tok == TOK_DOUBLE) {
5021 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005022 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5023 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005024 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005025 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005026 }
5027 next();
Jack Palevich86351982009-06-30 18:09:56 -07005028 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005029 }
5030
Jack Palevich9221bcc2009-08-26 16:15:07 -07005031 Type* acceptStruct() {
5032 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5033 bool isStruct = tok == TOK_STRUCT;
5034 next();
5035 tokenid_t structTag = acceptSymbol();
5036 bool isDeclaration = accept('{');
5037 bool fail = false;
5038
5039 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5040 if (structTag) {
5041 Token* pToken = &mTokenTable[structTag];
5042 VariableInfo* pStructInfo = pToken->mpStructInfo;
5043 bool needToDeclare = !pStructInfo;
5044 if (pStructInfo) {
5045 if (isDeclaration) {
5046 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5047 if (pStructInfo->pType->pHead->length == -1) {
5048 // we're filling in a forward declaration.
5049 needToDeclare = false;
5050 } else {
5051 error("A struct with the same name is already defined at this level.");
5052 fail = true;
5053 }
5054 } else {
5055 needToDeclare = true;
5056 }
5057 }
5058 if (!fail) {
5059 assert(pStructInfo->isStructTag);
5060 pStructType->pHead = pStructInfo->pType;
5061 pStructType->pTail = pStructType->pHead->pTail;
5062 }
5063 }
5064
5065 if (needToDeclare) {
5066 // This is a new struct name
5067 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5068 pStructType = createType(TY_STRUCT, NULL, NULL);
5069 pStructType->structTag = structTag;
5070 pStructType->pHead = pStructType;
5071 if (! isDeclaration) {
5072 // A forward declaration
5073 pStructType->length = -1;
5074 }
5075 pToken->mpStructInfo->pType = pStructType;
5076 }
5077 } else {
5078 // An anonymous struct
5079 pStructType->pHead = pStructType;
5080 }
5081
5082 if (isDeclaration) {
5083 size_t offset = 0;
5084 size_t structSize = 0;
5085 size_t structAlignment = 0;
5086 Type** pParamHolder = & pStructType->pHead->pTail;
5087 while (tok != '}' && tok != EOF) {
5088 Type* pPrimitiveType = expectPrimitiveType();
5089 if (pPrimitiveType) {
5090 while (tok != ';' && tok != EOF) {
5091 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5092 if (!pItem) {
5093 break;
5094 }
5095 if (lookupStructMember(pStructType, pItem->id)) {
5096 String buf;
5097 decodeToken(buf, pItem->id, false);
5098 error("Duplicate struct member %s", buf.getUnwrapped());
5099 }
5100 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5101 size_t alignment = pGen->alignmentOf(pItem);
5102 if (alignment > structAlignment) {
5103 structAlignment = alignment;
5104 }
5105 size_t alignmentMask = alignment - 1;
5106 offset = (offset + alignmentMask) & ~alignmentMask;
5107 pStructElement->length = offset;
5108 size_t size = pGen->sizeOf(pItem);
5109 if (isStruct) {
5110 offset += size;
5111 structSize = offset;
5112 } else {
5113 if (size >= structSize) {
5114 structSize = size;
5115 }
5116 }
5117 *pParamHolder = pStructElement;
5118 pParamHolder = &pStructElement->pTail;
5119 accept(',');
5120 }
5121 skip(';');
5122 } else {
5123 // Some sort of syntax error, skip token and keep trying
5124 next();
5125 }
5126 }
5127 if (!fail) {
5128 pStructType->pHead->length = structSize;
5129 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5130 }
5131 skip('}');
5132 }
5133 if (fail) {
5134 pStructType = NULL;
5135 }
5136 return pStructType;
5137 }
5138
5139 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5140 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5141 if (pStructElement->pHead->id == memberId) {
5142 return pStructElement;
5143 }
5144 }
5145 return NULL;
5146 }
5147
Jack Palevich2ff5c222009-07-23 15:11:22 -07005148 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005149 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005150 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005151 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005152 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005153 if (declName) {
5154 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005155 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005156 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005157 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005158 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005159 } else if (nameRequired) {
5160 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005161 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005162#if 0
5163 fprintf(stderr, "Parsed a declaration: ");
5164 printType(pType);
5165#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005166 if (reportFailure) {
5167 return NULL;
5168 }
Jack Palevich86351982009-06-30 18:09:56 -07005169 return pType;
5170 }
5171
Jack Palevich2ff5c222009-07-23 15:11:22 -07005172 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005173 bool nameRequired = pBaseType->tag != TY_STRUCT;
5174 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005175 if (! pType) {
5176 error("Expected a declaration");
5177 }
5178 return pType;
5179 }
5180
Jack Palevich3f226492009-07-02 14:46:19 -07005181 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005182 Type* acceptCastTypeDeclaration() {
5183 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005184 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005185 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005186 }
Jack Palevich86351982009-06-30 18:09:56 -07005187 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005188 }
5189
Jack Palevich2ff5c222009-07-23 15:11:22 -07005190 Type* expectCastTypeDeclaration() {
5191 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005192 if (! pType) {
5193 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005194 }
Jack Palevich3f226492009-07-02 14:46:19 -07005195 return pType;
5196 }
5197
5198 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005199 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005200 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005201 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005202 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005203 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005204 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005205 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005206 return pType;
5207 }
5208
5209 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005210 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005211 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005212 // direct-dcl :
5213 // name
5214 // (dcl)
5215 // direct-dcl()
5216 // direct-dcl[]
5217 Type* pNewHead = NULL;
5218 if (accept('(')) {
5219 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005220 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005221 skip(')');
5222 } else if ((declName = acceptSymbol()) != 0) {
5223 if (nameAllowed == false && declName) {
5224 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005225 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005226 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005227 } else if (nameRequired && ! declName) {
5228 String temp;
5229 decodeToken(temp, tok, true);
5230 error("Expected name. Got %s", temp.getUnwrapped());
5231 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005232 }
Jack Palevichb6154502009-08-04 14:56:09 -07005233 for(;;) {
5234 if (accept('(')) {
5235 // Function declaration
5236 Type* pTail = acceptArgs(nameAllowed);
5237 pType = createType(TY_FUNC, pType, pTail);
5238 skip(')');
5239 } if (accept('[')) {
5240 if (tok != ']') {
5241 if (tok != TOK_NUM || tokc <= 0) {
5242 error("Expected positive integer constant");
5243 } else {
5244 Type* pDecayType = createPtrType(pType);
5245 pType = createType(TY_ARRAY, pType, pDecayType);
5246 pType->length = tokc;
5247 }
5248 next();
5249 }
5250 skip(']');
5251 } else {
5252 break;
5253 }
Jack Palevich86351982009-06-30 18:09:56 -07005254 }
Jack Palevich3f226492009-07-02 14:46:19 -07005255
5256 if (pNewHead) {
5257 Type* pA = pNewHead;
5258 while (pA->pHead) {
5259 pA = pA->pHead;
5260 }
5261 pA->pHead = pType;
5262 pType = pNewHead;
5263 }
Jack Palevich86351982009-06-30 18:09:56 -07005264 return pType;
5265 }
5266
Jack Palevich2ff5c222009-07-23 15:11:22 -07005267 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005268 Type* pHead = NULL;
5269 Type* pTail = NULL;
5270 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005271 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005272 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005273 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005274 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005275 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005276 if (!pHead) {
5277 pHead = pParam;
5278 pTail = pParam;
5279 } else {
5280 pTail->pTail = pParam;
5281 pTail = pParam;
5282 }
5283 }
5284 }
5285 if (! accept(',')) {
5286 break;
5287 }
5288 }
5289 return pHead;
5290 }
5291
Jack Palevich2ff5c222009-07-23 15:11:22 -07005292 Type* expectPrimitiveType() {
5293 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005294 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005295 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005296 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005297 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005298 }
Jack Palevich86351982009-06-30 18:09:56 -07005299 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005300 }
5301
Jack Palevichb5e33312009-07-30 19:06:34 -07005302 void checkLVal() {
5303 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005304 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005305 }
5306 }
5307
Jack Palevich86351982009-06-30 18:09:56 -07005308 void addGlobalSymbol(Type* pDecl) {
5309 tokenid_t t = pDecl->id;
5310 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005311 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005312 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005313 }
Jack Palevich86351982009-06-30 18:09:56 -07005314 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005315 }
5316
Jack Palevich86351982009-06-30 18:09:56 -07005317 void reportDuplicate(tokenid_t t) {
5318 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005319 }
5320
Jack Palevich86351982009-06-30 18:09:56 -07005321 void addLocalSymbol(Type* pDecl) {
5322 tokenid_t t = pDecl->id;
5323 if (mLocals.isDefinedAtCurrentLevel(t)) {
5324 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005325 }
Jack Palevich86351982009-06-30 18:09:56 -07005326 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005327 }
5328
Jack Palevich95727a02009-07-06 12:07:15 -07005329 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005330 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005331
Jack Palevich95727a02009-07-06 12:07:15 -07005332 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005333 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005334 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005335 if (!pDecl) {
5336 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005337 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005338 if (!pDecl->id) {
5339 break;
5340 }
Jack Palevich86351982009-06-30 18:09:56 -07005341 int variableAddress = 0;
5342 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005343 size_t alignment = pGen->alignmentOf(pDecl);
5344 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005345 size_t alignmentMask = ~ (alignment - 1);
5346 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005347 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005348 loc = (loc + alignment - 1) & alignmentMask;
5349 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5350 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005351 variableAddress = -loc;
5352 VI(pDecl->id)->pAddress = (void*) variableAddress;
5353 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005354 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005355 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005356 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005357 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005358 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005359 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005360 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005361 if (tok == ',')
5362 next();
5363 }
5364 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005365 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005366 }
5367 }
5368
Jack Palevichf1728be2009-06-12 13:53:51 -07005369 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005370 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005371 }
5372
Jack Palevich37c54bd2009-07-14 18:35:36 -07005373 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005374 if (token == EOF ) {
5375 buffer.printf("EOF");
5376 } else if (token == TOK_NUM) {
5377 buffer.printf("numeric constant");
5378 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005379 if (token < 32) {
5380 buffer.printf("'\\x%02x'", token);
5381 } else {
5382 buffer.printf("'%c'", token);
5383 }
Jack Palevich569f1352009-06-29 14:29:08 -07005384 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005385 if (quote) {
5386 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5387 buffer.printf("keyword \"%s\"", nameof(token));
5388 } else {
5389 buffer.printf("symbol \"%s\"", nameof(token));
5390 }
5391 } else {
5392 buffer.printf("%s", nameof(token));
5393 }
Jack Palevich569f1352009-06-29 14:29:08 -07005394 }
5395 }
5396
Jack Palevich9221bcc2009-08-26 16:15:07 -07005397 void printToken(tokenid_t token) {
5398 String buffer;
5399 decodeToken(buffer, token, true);
5400 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5401 }
5402
Jack Palevich40600de2009-07-01 15:32:35 -07005403 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005404 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005405 if (!result) {
5406 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005407 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005408 error("Expected symbol. Got %s", temp.getUnwrapped());
5409 }
5410 return result;
5411 }
5412
Jack Palevich86351982009-06-30 18:09:56 -07005413 tokenid_t acceptSymbol() {
5414 tokenid_t result = 0;
5415 if (tok >= TOK_SYMBOL) {
5416 result = tok;
5417 next();
Jack Palevich86351982009-06-30 18:09:56 -07005418 }
5419 return result;
5420 }
5421
Jack Palevichb7c81e92009-06-04 19:56:13 -07005422 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005423 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005424 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005425 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005426 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005427 break;
5428 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005429 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005430 if (!pDecl) {
5431 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005432 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005433 if (!pDecl->id) {
5434 skip(';');
5435 continue;
5436 }
5437
Jack Palevich86351982009-06-30 18:09:56 -07005438 if (! isDefined(pDecl->id)) {
5439 addGlobalSymbol(pDecl);
5440 }
5441 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005442 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005443 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005444 }
Jack Palevich86351982009-06-30 18:09:56 -07005445 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005446 // it's a variable declaration
5447 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005448 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005449 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005450 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005451 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005452 }
Jack Palevich86351982009-06-30 18:09:56 -07005453 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005454 if (tok == TOK_NUM) {
5455 if (name) {
5456 * (int*) name->pAddress = tokc;
5457 }
5458 next();
5459 } else {
5460 error("Expected an integer constant");
5461 }
5462 }
Jack Palevich86351982009-06-30 18:09:56 -07005463 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005464 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005465 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005466 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005467 if (!pDecl) {
5468 break;
5469 }
5470 if (! isDefined(pDecl->id)) {
5471 addGlobalSymbol(pDecl);
5472 }
5473 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005474 }
5475 skip(';');
5476 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005477 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005478 if (accept(';')) {
5479 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005480 } else if (tok != '{') {
5481 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005482 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005483 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005484 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005485 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005486 /* patch forward references */
5487 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005488 /* put function address */
5489 name->pAddress = (void*) codeBuf.getPC();
5490 }
5491 // Calculate stack offsets for parameters
5492 mLocals.pushLevel();
5493 intptr_t a = 8;
5494 int argCount = 0;
5495 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5496 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005497 if (pArg->id) {
5498 addLocalSymbol(pArg);
5499 }
Jack Palevich95727a02009-07-06 12:07:15 -07005500 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005501 Type* pPassingType = passingType(pArg);
5502 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005503 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005504 if (pArg->id) {
5505 VI(pArg->id)->pAddress = (void*) a;
5506 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005507 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005508 argCount++;
5509 }
5510 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005511 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005512 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005513 block(0, true);
5514 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005515 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005516 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005517 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005518 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005519 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005520 }
5521 }
5522 }
5523
Jack Palevich9221bcc2009-08-26 16:15:07 -07005524 Type* passingType(Type* pType) {
5525 switch (pType->tag) {
5526 case TY_CHAR:
5527 case TY_SHORT:
5528 return mkpInt;
5529 default:
5530 return pType;
5531 }
5532 }
5533
Jack Palevich9cbd2262009-07-08 16:48:41 -07005534 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5535 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5536 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005537 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005538 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005539 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005540 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005541 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005542 char* result = (char*) base;
5543 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005544 return result;
5545 }
5546
Jack Palevich21a15a22009-05-11 14:49:29 -07005547 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005548 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005549 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005550 pGlobalBase = 0;
5551 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005552 if (pGen) {
5553 delete pGen;
5554 pGen = 0;
5555 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005556 if (file) {
5557 delete file;
5558 file = 0;
5559 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005560 }
5561
Jack Palevich8c246a92009-07-14 21:14:10 -07005562 // One-time initialization, when class is constructed.
5563 void init() {
5564 mpSymbolLookupFn = 0;
5565 mpSymbolLookupContext = 0;
5566 }
5567
Jack Palevich21a15a22009-05-11 14:49:29 -07005568 void clear() {
5569 tok = 0;
5570 tokc = 0;
5571 tokl = 0;
5572 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005573 rsym = 0;
5574 loc = 0;
5575 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005576 dptr = 0;
5577 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005578 file = 0;
5579 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005580 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005581 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005582 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005583 mLineNumber = 1;
5584 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005585 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005586 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005587
Jack Palevich22305132009-05-13 10:58:45 -07005588 void setArchitecture(const char* architecture) {
5589 delete pGen;
5590 pGen = 0;
5591
5592 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005593#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005594 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005595 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005596 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005597#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005598#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005599 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005600 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005601 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005602#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005603 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005604 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005605 }
5606 }
5607
5608 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005609#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005610 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005611#elif defined(DEFAULT_X86_CODEGEN)
5612 pGen = new X86CodeGenerator();
5613#endif
5614 }
5615 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005616 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005617 } else {
5618 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005619 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005620 }
5621 }
5622
Jack Palevich77ae76e2009-05-10 19:59:24 -07005623public:
Jack Palevich22305132009-05-13 10:58:45 -07005624 struct args {
5625 args() {
5626 architecture = 0;
5627 }
5628 const char* architecture;
5629 };
5630
Jack Paleviche7b59062009-05-19 17:12:17 -07005631 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005632 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005633 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005634 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005635
Jack Paleviche7b59062009-05-19 17:12:17 -07005636 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005637 cleanup();
5638 }
5639
Jack Palevich8c246a92009-07-14 21:14:10 -07005640 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5641 mpSymbolLookupFn = pFn;
5642 mpSymbolLookupContext = pContext;
5643 }
5644
Jack Palevich1cdef202009-05-22 12:06:27 -07005645 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005646 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005647
Jack Palevich2ff5c222009-07-23 15:11:22 -07005648 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005649 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005650 cleanup();
5651 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005652 mTokenTable.setArena(&mGlobalArena);
5653 mGlobals.setArena(&mGlobalArena);
5654 mGlobals.setTokenTable(&mTokenTable);
5655 mLocals.setArena(&mLocalArena);
5656 mLocals.setTokenTable(&mTokenTable);
5657
5658 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005659 codeBuf.init(ALLOC_SIZE);
5660 setArchitecture(NULL);
5661 if (!pGen) {
5662 return -1;
5663 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005664#ifdef PROVIDE_TRACE_CODEGEN
5665 pGen = new TraceCodeGenerator(pGen);
5666#endif
5667 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005668 pGen->init(&codeBuf);
5669 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005670 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5671 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005672 inp();
5673 next();
5674 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005675 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005676 result = pGen->finishCompile();
5677 if (result == 0) {
5678 if (mErrorBuf.len()) {
5679 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005680 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005681 }
Jack Palevichce105a92009-07-16 14:30:33 -07005682 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005683 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005684 }
5685
Jack Palevich86351982009-06-30 18:09:56 -07005686 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005687 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005688 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005689 mkpChar = createType(TY_CHAR, NULL, NULL);
5690 mkpVoid = createType(TY_VOID, NULL, NULL);
5691 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5692 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5693 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5694 mkpIntPtr = createPtrType(mkpInt);
5695 mkpCharPtr = createPtrType(mkpChar);
5696 mkpFloatPtr = createPtrType(mkpFloat);
5697 mkpDoublePtr = createPtrType(mkpDouble);
5698 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005699 }
5700
Jack Palevicha6baa232009-06-12 11:25:59 -07005701 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005702 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005703 }
5704
Jack Palevich569f1352009-06-29 14:29:08 -07005705 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005706 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005707 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005708 }
5709
Jack Palevich569f1352009-06-29 14:29:08 -07005710 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005711 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005712 error("Undefined forward reference: %s",
5713 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005714 }
5715 return true;
5716 }
5717
Jack Palevich21a15a22009-05-11 14:49:29 -07005718 int dump(FILE* out) {
5719 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5720 return 0;
5721 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005722
Jack Palevicha6535612009-05-13 16:24:17 -07005723 int disassemble(FILE* out) {
5724 return pGen->disassemble(out);
5725 }
5726
Jack Palevich1cdef202009-05-22 12:06:27 -07005727 /* Look through the symbol table to find a symbol.
5728 * If found, return its value.
5729 */
5730 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005731 if (mCompileResult == 0) {
5732 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5733 VariableInfo* pVariableInfo = VI(tok);
5734 if (pVariableInfo) {
5735 return pVariableInfo->pAddress;
5736 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005737 }
5738 return NULL;
5739 }
5740
Jack Palevicheedf9d22009-06-04 16:23:40 -07005741 void getPragmas(ACCsizei* actualStringCount,
5742 ACCsizei maxStringCount, ACCchar** strings) {
5743 int stringCount = mPragmaStringCount;
5744 if (actualStringCount) {
5745 *actualStringCount = stringCount;
5746 }
5747 if (stringCount > maxStringCount) {
5748 stringCount = maxStringCount;
5749 }
5750 if (strings) {
5751 char* pPragmas = mPragmas.getUnwrapped();
5752 while (stringCount-- > 0) {
5753 *strings++ = pPragmas;
5754 pPragmas += strlen(pPragmas) + 1;
5755 }
5756 }
5757 }
5758
Jack Palevichac0e95e2009-05-29 13:53:44 -07005759 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005760 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005761 }
5762
Jack Palevich77ae76e2009-05-10 19:59:24 -07005763};
5764
Jack Paleviche7b59062009-05-19 17:12:17 -07005765const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005766 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5767
Jack Paleviche7b59062009-05-19 17:12:17 -07005768const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005769 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5770 5, 5, /* ==, != */
5771 9, 10, /* &&, || */
5772 6, 7, 8, /* & ^ | */
5773 2, 2 /* ~ ! */
5774 };
5775
Jack Palevich8b0624c2009-05-20 12:12:06 -07005776#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005777FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005778#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005779
Jack Palevich8b0624c2009-05-20 12:12:06 -07005780#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005781const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005782 0x1, // ++
5783 0xff, // --
5784 0xc1af0f, // *
5785 0xf9f79991, // /
5786 0xf9f79991, // % (With manual assist to swap results)
5787 0xc801, // +
5788 0xd8f7c829, // -
5789 0xe0d391, // <<
5790 0xf8d391, // >>
5791 0xe, // <=
5792 0xd, // >=
5793 0xc, // <
5794 0xf, // >
5795 0x4, // ==
5796 0x5, // !=
5797 0x0, // &&
5798 0x1, // ||
5799 0xc821, // &
5800 0xc831, // ^
5801 0xc809, // |
5802 0xd0f7, // ~
5803 0x4 // !
5804};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005805#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005806
Jack Palevich1cdef202009-05-22 12:06:27 -07005807struct ACCscript {
5808 ACCscript() {
5809 text = 0;
5810 textLength = 0;
5811 accError = ACC_NO_ERROR;
5812 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005813
Jack Palevich1cdef202009-05-22 12:06:27 -07005814 ~ACCscript() {
5815 delete text;
5816 }
Jack Palevich546b2242009-05-13 15:10:04 -07005817
Jack Palevich8c246a92009-07-14 21:14:10 -07005818 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5819 compiler.registerSymbolCallback(pFn, pContext);
5820 }
5821
Jack Palevich1cdef202009-05-22 12:06:27 -07005822 void setError(ACCenum error) {
5823 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5824 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005825 }
5826 }
5827
Jack Palevich1cdef202009-05-22 12:06:27 -07005828 ACCenum getError() {
5829 ACCenum result = accError;
5830 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005831 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005832 }
5833
Jack Palevich1cdef202009-05-22 12:06:27 -07005834 Compiler compiler;
5835 char* text;
5836 int textLength;
5837 ACCenum accError;
5838};
5839
5840
5841extern "C"
5842ACCscript* accCreateScript() {
5843 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005844}
Jack Palevich1cdef202009-05-22 12:06:27 -07005845
5846extern "C"
5847ACCenum accGetError( ACCscript* script ) {
5848 return script->getError();
5849}
5850
5851extern "C"
5852void accDeleteScript(ACCscript* script) {
5853 delete script;
5854}
5855
5856extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005857void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5858 ACCvoid* pContext) {
5859 script->registerSymbolCallback(pFn, pContext);
5860}
5861
5862extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005863void accScriptSource(ACCscript* script,
5864 ACCsizei count,
5865 const ACCchar ** string,
5866 const ACCint * length) {
5867 int totalLength = 0;
5868 for(int i = 0; i < count; i++) {
5869 int len = -1;
5870 const ACCchar* s = string[i];
5871 if (length) {
5872 len = length[i];
5873 }
5874 if (len < 0) {
5875 len = strlen(s);
5876 }
5877 totalLength += len;
5878 }
5879 delete script->text;
5880 char* text = new char[totalLength + 1];
5881 script->text = text;
5882 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005883 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005884 for(int i = 0; i < count; i++) {
5885 int len = -1;
5886 const ACCchar* s = string[i];
5887 if (length) {
5888 len = length[i];
5889 }
5890 if (len < 0) {
5891 len = strlen(s);
5892 }
Jack Palevich09555c72009-05-27 12:25:55 -07005893 memcpy(dest, s, len);
5894 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005895 }
5896 text[totalLength] = '\0';
5897}
5898
5899extern "C"
5900void accCompileScript(ACCscript* script) {
5901 int result = script->compiler.compile(script->text, script->textLength);
5902 if (result) {
5903 script->setError(ACC_INVALID_OPERATION);
5904 }
5905}
5906
5907extern "C"
5908void accGetScriptiv(ACCscript* script,
5909 ACCenum pname,
5910 ACCint * params) {
5911 switch (pname) {
5912 case ACC_INFO_LOG_LENGTH:
5913 *params = 0;
5914 break;
5915 }
5916}
5917
5918extern "C"
5919void accGetScriptInfoLog(ACCscript* script,
5920 ACCsizei maxLength,
5921 ACCsizei * length,
5922 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005923 char* message = script->compiler.getErrorMessage();
5924 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005925 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005926 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005927 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005928 if (infoLog && maxLength > 0) {
5929 int trimmedLength = maxLength < messageLength ?
5930 maxLength : messageLength;
5931 memcpy(infoLog, message, trimmedLength);
5932 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005933 }
5934}
5935
5936extern "C"
5937void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5938 ACCvoid ** address) {
5939 void* value = script->compiler.lookup(name);
5940 if (value) {
5941 *address = value;
5942 } else {
5943 script->setError(ACC_INVALID_VALUE);
5944 }
5945}
5946
Jack Palevicheedf9d22009-06-04 16:23:40 -07005947extern "C"
5948void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5949 ACCsizei maxStringCount, ACCchar** strings){
5950 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5951}
5952
-b master422972c2009-06-17 19:13:52 -07005953extern "C"
5954void accDisassemble(ACCscript* script) {
5955 script->compiler.disassemble(stderr);
5956}
5957
Jack Palevicheedf9d22009-06-04 16:23:40 -07005958
Jack Palevich1cdef202009-05-22 12:06:27 -07005959} // namespace acc
5960