blob: 535361c9b517c9a08c35f2716fe76ccb9423cd25 [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 Palevich8df46192009-07-07 14:48:51 -07004453 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004454 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4455 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004456 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004457 } else if (t == EOF ) {
4458 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004459 } else if (t == ';') {
4460 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004461 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004462 // Don't have to do anything special here, the error
4463 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004464 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004465 if (!isDefined(t)) {
4466 mGlobals.add(t);
4467 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004468 }
Jack Palevich8df46192009-07-07 14:48:51 -07004469 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004470 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004471 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004472 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004473 linkGlobal(t, tok == '(');
4474 n = (intptr_t) pVI->pAddress;
4475 if (!n && tok != '(') {
4476 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004477 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004478 }
Jack Palevich29daf572009-07-30 19:38:55 -07004479 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004480 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004481 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004482 linkGlobal(t, false);
4483 n = (intptr_t) pVI->pAddress;
4484 if (!n) {
4485 error("Undeclared variable %s\n", nameof(t));
4486 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004487 }
Jack Palevich5b659092009-07-31 14:55:07 -07004488 }
4489 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004490 Type* pVal;
4491 ExpressionType et;
4492 if (pVI->pType->tag == TY_ARRAY) {
4493 pVal = pVI->pType;
4494 et = ET_RVALUE;
4495 } else {
4496 pVal = createPtrType(pVI->pType);
4497 et = ET_LVALUE;
4498 }
Jack Palevich5b659092009-07-31 14:55:07 -07004499 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004500 int tag = pVal->pHead->tag;
4501 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004502 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004503 }
Jack Palevich5b659092009-07-31 14:55:07 -07004504 pGen->leaR0(n, pVal, et);
4505 } else {
4506 pVI->pForward = (void*) pGen->leaForward(
4507 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004508 }
4509 }
4510 }
4511
Jack Palevich5b659092009-07-31 14:55:07 -07004512 /* Now handle postfix operators */
4513 for(;;) {
4514 if (tokl == 11) {
4515 // post inc / post dec
4516 doIncDec(tokc == OP_INCREMENT, true);
4517 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004518 } else if (accept('[')) {
4519 // Array reference
4520 pGen->forceR0RVal();
4521 pGen->pushR0();
4522 commaExpr();
4523 pGen->forceR0RVal();
4524 pGen->genOp(OP_PLUS);
4525 doPointer();
4526 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004527 } else if (accept('.')) {
4528 // struct element
4529 pGen->forceR0RVal();
4530 Type* pStruct = pGen->getR0Type();
4531 if (pStruct->tag == TY_STRUCT) {
4532 doStructMember(pStruct);
4533 } else {
4534 error("expected a struct value to the left of '.'");
4535 }
4536 } else if (accept(TOK_OP_ARROW)) {
4537 pGen->forceR0RVal();
4538 Type* pPtr = pGen->getR0Type();
4539 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4540 pGen->loadR0FromR0();
4541 doStructMember(pPtr->pHead);
4542 } else {
4543 error("Expected a pointer to a struct to the left of '->'");
4544 }
Jack Palevich5b659092009-07-31 14:55:07 -07004545 } else if (accept('(')) {
4546 /* function call */
4547 Type* pDecl = NULL;
4548 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004549 Type* pFn = pGen->getR0Type();
4550 assert(pFn->tag == TY_POINTER);
4551 assert(pFn->pHead->tag == TY_FUNC);
4552 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004553 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004554 Type* pArgList = pDecl->pTail;
4555 bool varArgs = pArgList == NULL;
4556 /* push args and invert order */
4557 a = pGen->beginFunctionCallArguments();
4558 int l = 0;
4559 int argCount = 0;
4560 while (tok != ')' && tok != EOF) {
4561 if (! varArgs && !pArgList) {
4562 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004563 }
Jack Palevich5b659092009-07-31 14:55:07 -07004564 expr();
4565 pGen->forceR0RVal();
4566 Type* pTargetType;
4567 if (pArgList) {
4568 pTargetType = pArgList->pHead;
4569 pArgList = pArgList->pTail;
4570 } else {
4571 // This is a ... function, just pass arguments in their
4572 // natural type.
4573 pTargetType = pGen->getR0Type();
4574 if (pTargetType->tag == TY_FLOAT) {
4575 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004576 } else if (pTargetType->tag == TY_ARRAY) {
4577 // Pass arrays by pointer.
4578 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004579 }
4580 }
4581 if (pTargetType->tag == TY_VOID) {
4582 error("Can't pass void value for argument %d",
4583 argCount + 1);
4584 } else {
4585 l += pGen->storeR0ToArg(l, pTargetType);
4586 }
4587 if (accept(',')) {
4588 // fine
4589 } else if ( tok != ')') {
4590 error("Expected ',' or ')'");
4591 }
4592 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004593 }
Jack Palevich5b659092009-07-31 14:55:07 -07004594 if (! varArgs && pArgList) {
4595 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004596 }
Jack Palevich5b659092009-07-31 14:55:07 -07004597 pGen->endFunctionCallArguments(pDecl, a, l);
4598 skip(')');
4599 pGen->callIndirect(l, pDecl);
4600 pGen->adjustStackAfterCall(pDecl, l, true);
4601 } else {
4602 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004603 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004604 }
4605 }
4606
Jack Palevich9221bcc2009-08-26 16:15:07 -07004607 void doStructMember(Type* pStruct) {
4608 Type* pStructElement = lookupStructMember(pStruct, tok);
4609 if (pStructElement) {
4610 next();
4611 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4612 } else {
4613 String buf;
4614 decodeToken(buf, tok, true);
4615 error("Expected a struct member to the right of '.', got %s", buf.getUnwrapped());
4616 }
4617 }
4618
Jack Palevichaaac9282009-07-31 14:34:34 -07004619 void doIncDec(int isInc, int isPost) {
4620 // R0 already has the lval
4621 checkLVal();
4622 int lit = isInc ? 1 : -1;
4623 pGen->pushR0();
4624 pGen->loadR0FromR0();
4625 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004626 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4627 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004628 error("++/-- illegal for this type. %d", tag);
4629 }
4630 if (isPost) {
4631 pGen->over();
4632 pGen->pushR0();
4633 pGen->li(lit);
4634 pGen->genOp(OP_PLUS);
4635 pGen->storeR0ToTOS();
4636 pGen->popR0();
4637 } else {
4638 pGen->pushR0();
4639 pGen->li(lit);
4640 pGen->genOp(OP_PLUS);
4641 pGen->over();
4642 pGen->storeR0ToTOS();
4643 pGen->popR0();
4644 }
4645 }
4646
Jack Palevich47cbea92009-07-31 15:25:53 -07004647 void doPointer() {
4648 pGen->forceR0RVal();
4649 Type* pR0Type = pGen->getR0Type();
4650 if (pR0Type->tag != TY_POINTER) {
4651 error("Expected a pointer type.");
4652 } else {
4653 if (pR0Type->pHead->tag != TY_FUNC) {
4654 pGen->setR0ExpressionType(ET_LVALUE);
4655 }
4656 }
4657 }
4658
Jack Palevich40600de2009-07-01 15:32:35 -07004659 /* Recursive descent parser for binary operations.
4660 */
4661 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004662 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004663 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004664 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004665 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004666 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004667 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004668 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004669 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004670 t = tokc;
4671 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004672 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004673 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004674 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004675 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004676 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004677 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004678 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004679 // Check for syntax error.
4680 if (pGen->getR0Type() == NULL) {
4681 // We failed to parse a right-hand argument.
4682 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004683 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004684 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004685 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004686 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004687 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004689 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004690 }
4691 }
4692 }
4693 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004694 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004695 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004696 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004697 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004698 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004699 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004700 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004701 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004702 }
4703 }
4704 }
4705
Jack Palevich43aaee32009-07-31 14:01:37 -07004706 void commaExpr() {
4707 for(;;) {
4708 expr();
4709 if (!accept(',')) {
4710 break;
4711 }
4712 }
4713 }
4714
Jack Palevich21a15a22009-05-11 14:49:29 -07004715 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004716 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004717 }
4718
4719 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004720 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004721 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004722 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004723 }
4724
Jack Palevicha6baa232009-06-12 11:25:59 -07004725 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004726 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004727
Jack Palevich95727a02009-07-06 12:07:15 -07004728 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004729 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004730 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004731 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004732 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004733 next();
4734 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004735 a = test_expr();
4736 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004737 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004738 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004739 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004740 n = pGen->gjmp(0); /* jmp */
4741 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004742 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004743 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004744 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004745 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004746 }
Jack Palevich546b2242009-05-13 15:10:04 -07004747 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004748 t = tok;
4749 next();
4750 skip('(');
4751 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004752 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004753 a = test_expr();
4754 } else {
4755 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004756 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004757 skip(';');
4758 n = codeBuf.getPC();
4759 a = 0;
4760 if (tok != ';')
4761 a = test_expr();
4762 skip(';');
4763 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004764 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004765 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004766 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004767 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004768 n = t + 4;
4769 }
4770 }
4771 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004772 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004773 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004774 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004775 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004776 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004777 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004778 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004779 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004780 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004781 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004782 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004783 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004784 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004785 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004786 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004787 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004788 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004789 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004790 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004791 if (pReturnType->tag == TY_VOID) {
4792 error("Must not return a value from a void function");
4793 } else {
4794 pGen->convertR0(pReturnType);
4795 }
4796 } else {
4797 if (pReturnType->tag != TY_VOID) {
4798 error("Must specify a value here");
4799 }
Jack Palevich8df46192009-07-07 14:48:51 -07004800 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004801 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004802 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004803 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004804 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004805 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004806 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004807 }
4808 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004809
Jack Palevicha8f427f2009-07-13 18:40:08 -07004810 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004811 if (a == b) {
4812 return true;
4813 }
4814 if (a == NULL || b == NULL) {
4815 return false;
4816 }
4817 TypeTag at = a->tag;
4818 if (at != b->tag) {
4819 return false;
4820 }
4821 if (at == TY_POINTER) {
4822 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004823 } else if (at == TY_ARRAY) {
4824 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004825 } else if (at == TY_FUNC || at == TY_PARAM) {
4826 return typeEqual(a->pHead, b->pHead)
4827 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004828 } else if (at == TY_STRUCT) {
4829 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004830 }
4831 return true;
4832 }
4833
Jack Palevich2ff5c222009-07-23 15:11:22 -07004834 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004835 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004836 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004837 memset(pType, 0, sizeof(*pType));
4838 pType->tag = tag;
4839 pType->pHead = pHead;
4840 pType->pTail = pTail;
4841 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004842 }
4843
Jack Palevich2ff5c222009-07-23 15:11:22 -07004844 Type* createPtrType(Type* pType) {
4845 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004846 }
4847
4848 /**
4849 * Try to print a type in declaration order
4850 */
Jack Palevich86351982009-06-30 18:09:56 -07004851 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004852 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004853 if (pType == NULL) {
4854 buffer.appendCStr("null");
4855 return;
4856 }
Jack Palevich3f226492009-07-02 14:46:19 -07004857 decodeTypeImp(buffer, pType);
4858 }
4859
4860 void decodeTypeImp(String& buffer, Type* pType) {
4861 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004862 decodeId(buffer, pType->id);
4863 decodeTypeImpPostfix(buffer, pType);
4864 }
Jack Palevich3f226492009-07-02 14:46:19 -07004865
Jack Palevich9221bcc2009-08-26 16:15:07 -07004866 void decodeId(String& buffer, tokenid_t id) {
4867 if (id) {
4868 String temp;
4869 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004870 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004871 }
Jack Palevich3f226492009-07-02 14:46:19 -07004872 }
4873
4874 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4875 TypeTag tag = pType->tag;
4876
Jack Palevich9221bcc2009-08-26 16:15:07 -07004877 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004878 switch (tag) {
4879 case TY_INT:
4880 buffer.appendCStr("int");
4881 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004882 case TY_SHORT:
4883 buffer.appendCStr("short");
4884 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004885 case TY_CHAR:
4886 buffer.appendCStr("char");
4887 break;
4888 case TY_VOID:
4889 buffer.appendCStr("void");
4890 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004891 case TY_FLOAT:
4892 buffer.appendCStr("float");
4893 break;
4894 case TY_DOUBLE:
4895 buffer.appendCStr("double");
4896 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004897 case TY_STRUCT:
4898 {
4899 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4900 buffer.appendCStr(isStruct ? "struct" : "union");
4901 if (pType->pHead && pType->pHead->structTag) {
4902 buffer.append(' ');
4903 decodeId(buffer, pType->pHead->structTag);
4904 }
4905 }
4906 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004907 default:
4908 break;
4909 }
Jack Palevich86351982009-06-30 18:09:56 -07004910 buffer.append(' ');
4911 }
Jack Palevich3f226492009-07-02 14:46:19 -07004912
4913 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004914 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004915 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004916 case TY_SHORT:
4917 break;
Jack Palevich86351982009-06-30 18:09:56 -07004918 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004919 break;
4920 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004921 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004922 case TY_FLOAT:
4923 break;
4924 case TY_DOUBLE:
4925 break;
Jack Palevich86351982009-06-30 18:09:56 -07004926 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004927 decodeTypeImpPrefix(buffer, pType->pHead);
4928 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4929 buffer.append('(');
4930 }
4931 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004932 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004933 case TY_ARRAY:
4934 decodeTypeImpPrefix(buffer, pType->pHead);
4935 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004936 case TY_STRUCT:
4937 break;
Jack Palevich86351982009-06-30 18:09:56 -07004938 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004939 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004940 break;
4941 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004942 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004943 break;
4944 default:
4945 String temp;
4946 temp.printf("Unknown tag %d", pType->tag);
4947 buffer.append(temp);
4948 break;
4949 }
Jack Palevich3f226492009-07-02 14:46:19 -07004950 }
4951
4952 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4953 TypeTag tag = pType->tag;
4954
4955 switch(tag) {
4956 case TY_POINTER:
4957 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4958 buffer.append(')');
4959 }
4960 decodeTypeImpPostfix(buffer, pType->pHead);
4961 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004962 case TY_ARRAY:
4963 {
4964 String temp;
4965 temp.printf("[%d]", pType->length);
4966 buffer.append(temp);
4967 }
4968 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004969 case TY_STRUCT:
4970 if (pType->pHead->length >= 0) {
4971 buffer.appendCStr(" {");
4972 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4973 decodeTypeImp(buffer, pArg->pHead);
4974 buffer.appendCStr(";");
4975 }
4976 buffer.append('}');
4977 }
4978 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004979 case TY_FUNC:
4980 buffer.append('(');
4981 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4982 decodeTypeImp(buffer, pArg);
4983 if (pArg->pTail) {
4984 buffer.appendCStr(", ");
4985 }
4986 }
4987 buffer.append(')');
4988 break;
4989 default:
4990 break;
Jack Palevich86351982009-06-30 18:09:56 -07004991 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004992 }
4993
Jack Palevich86351982009-06-30 18:09:56 -07004994 void printType(Type* pType) {
4995 String buffer;
4996 decodeType(buffer, pType);
4997 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004998 }
4999
Jack Palevich2ff5c222009-07-23 15:11:22 -07005000 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005001 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005002 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005003 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005004 } else if (tok == TOK_SHORT) {
5005 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005006 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005007 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005008 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005009 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005010 } else if (tok == TOK_FLOAT) {
5011 pType = mkpFloat;
5012 } else if (tok == TOK_DOUBLE) {
5013 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005014 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5015 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005016 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005017 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005018 }
5019 next();
Jack Palevich86351982009-06-30 18:09:56 -07005020 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005021 }
5022
Jack Palevich9221bcc2009-08-26 16:15:07 -07005023 Type* acceptStruct() {
5024 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5025 bool isStruct = tok == TOK_STRUCT;
5026 next();
5027 tokenid_t structTag = acceptSymbol();
5028 bool isDeclaration = accept('{');
5029 bool fail = false;
5030
5031 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5032 if (structTag) {
5033 Token* pToken = &mTokenTable[structTag];
5034 VariableInfo* pStructInfo = pToken->mpStructInfo;
5035 bool needToDeclare = !pStructInfo;
5036 if (pStructInfo) {
5037 if (isDeclaration) {
5038 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5039 if (pStructInfo->pType->pHead->length == -1) {
5040 // we're filling in a forward declaration.
5041 needToDeclare = false;
5042 } else {
5043 error("A struct with the same name is already defined at this level.");
5044 fail = true;
5045 }
5046 } else {
5047 needToDeclare = true;
5048 }
5049 }
5050 if (!fail) {
5051 assert(pStructInfo->isStructTag);
5052 pStructType->pHead = pStructInfo->pType;
5053 pStructType->pTail = pStructType->pHead->pTail;
5054 }
5055 }
5056
5057 if (needToDeclare) {
5058 // This is a new struct name
5059 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5060 pStructType = createType(TY_STRUCT, NULL, NULL);
5061 pStructType->structTag = structTag;
5062 pStructType->pHead = pStructType;
5063 if (! isDeclaration) {
5064 // A forward declaration
5065 pStructType->length = -1;
5066 }
5067 pToken->mpStructInfo->pType = pStructType;
5068 }
5069 } else {
5070 // An anonymous struct
5071 pStructType->pHead = pStructType;
5072 }
5073
5074 if (isDeclaration) {
5075 size_t offset = 0;
5076 size_t structSize = 0;
5077 size_t structAlignment = 0;
5078 Type** pParamHolder = & pStructType->pHead->pTail;
5079 while (tok != '}' && tok != EOF) {
5080 Type* pPrimitiveType = expectPrimitiveType();
5081 if (pPrimitiveType) {
5082 while (tok != ';' && tok != EOF) {
5083 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5084 if (!pItem) {
5085 break;
5086 }
5087 if (lookupStructMember(pStructType, pItem->id)) {
5088 String buf;
5089 decodeToken(buf, pItem->id, false);
5090 error("Duplicate struct member %s", buf.getUnwrapped());
5091 }
5092 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5093 size_t alignment = pGen->alignmentOf(pItem);
5094 if (alignment > structAlignment) {
5095 structAlignment = alignment;
5096 }
5097 size_t alignmentMask = alignment - 1;
5098 offset = (offset + alignmentMask) & ~alignmentMask;
5099 pStructElement->length = offset;
5100 size_t size = pGen->sizeOf(pItem);
5101 if (isStruct) {
5102 offset += size;
5103 structSize = offset;
5104 } else {
5105 if (size >= structSize) {
5106 structSize = size;
5107 }
5108 }
5109 *pParamHolder = pStructElement;
5110 pParamHolder = &pStructElement->pTail;
5111 accept(',');
5112 }
5113 skip(';');
5114 } else {
5115 // Some sort of syntax error, skip token and keep trying
5116 next();
5117 }
5118 }
5119 if (!fail) {
5120 pStructType->pHead->length = structSize;
5121 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5122 }
5123 skip('}');
5124 }
5125 if (fail) {
5126 pStructType = NULL;
5127 }
5128 return pStructType;
5129 }
5130
5131 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5132 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5133 if (pStructElement->pHead->id == memberId) {
5134 return pStructElement;
5135 }
5136 }
5137 return NULL;
5138 }
5139
Jack Palevich2ff5c222009-07-23 15:11:22 -07005140 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005141 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005142 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005143 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005144 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005145 if (declName) {
5146 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005147 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005148 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005149 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005150 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005151 } else if (nameRequired) {
5152 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005153 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005154#if 0
5155 fprintf(stderr, "Parsed a declaration: ");
5156 printType(pType);
5157#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005158 if (reportFailure) {
5159 return NULL;
5160 }
Jack Palevich86351982009-06-30 18:09:56 -07005161 return pType;
5162 }
5163
Jack Palevich2ff5c222009-07-23 15:11:22 -07005164 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005165 bool nameRequired = pBaseType->tag != TY_STRUCT;
5166 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005167 if (! pType) {
5168 error("Expected a declaration");
5169 }
5170 return pType;
5171 }
5172
Jack Palevich3f226492009-07-02 14:46:19 -07005173 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005174 Type* acceptCastTypeDeclaration() {
5175 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005176 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005177 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005178 }
Jack Palevich86351982009-06-30 18:09:56 -07005179 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005180 }
5181
Jack Palevich2ff5c222009-07-23 15:11:22 -07005182 Type* expectCastTypeDeclaration() {
5183 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005184 if (! pType) {
5185 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005186 }
Jack Palevich3f226492009-07-02 14:46:19 -07005187 return pType;
5188 }
5189
5190 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005191 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005192 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005193 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005194 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005195 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005196 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005197 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005198 return pType;
5199 }
5200
5201 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005202 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005203 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005204 // direct-dcl :
5205 // name
5206 // (dcl)
5207 // direct-dcl()
5208 // direct-dcl[]
5209 Type* pNewHead = NULL;
5210 if (accept('(')) {
5211 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005212 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005213 skip(')');
5214 } else if ((declName = acceptSymbol()) != 0) {
5215 if (nameAllowed == false && declName) {
5216 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005217 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005218 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005219 } else if (nameRequired && ! declName) {
5220 String temp;
5221 decodeToken(temp, tok, true);
5222 error("Expected name. Got %s", temp.getUnwrapped());
5223 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005224 }
Jack Palevichb6154502009-08-04 14:56:09 -07005225 for(;;) {
5226 if (accept('(')) {
5227 // Function declaration
5228 Type* pTail = acceptArgs(nameAllowed);
5229 pType = createType(TY_FUNC, pType, pTail);
5230 skip(')');
5231 } if (accept('[')) {
5232 if (tok != ']') {
5233 if (tok != TOK_NUM || tokc <= 0) {
5234 error("Expected positive integer constant");
5235 } else {
5236 Type* pDecayType = createPtrType(pType);
5237 pType = createType(TY_ARRAY, pType, pDecayType);
5238 pType->length = tokc;
5239 }
5240 next();
5241 }
5242 skip(']');
5243 } else {
5244 break;
5245 }
Jack Palevich86351982009-06-30 18:09:56 -07005246 }
Jack Palevich3f226492009-07-02 14:46:19 -07005247
5248 if (pNewHead) {
5249 Type* pA = pNewHead;
5250 while (pA->pHead) {
5251 pA = pA->pHead;
5252 }
5253 pA->pHead = pType;
5254 pType = pNewHead;
5255 }
Jack Palevich86351982009-06-30 18:09:56 -07005256 return pType;
5257 }
5258
Jack Palevich2ff5c222009-07-23 15:11:22 -07005259 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005260 Type* pHead = NULL;
5261 Type* pTail = NULL;
5262 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005263 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005264 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005265 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005266 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005267 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005268 if (!pHead) {
5269 pHead = pParam;
5270 pTail = pParam;
5271 } else {
5272 pTail->pTail = pParam;
5273 pTail = pParam;
5274 }
5275 }
5276 }
5277 if (! accept(',')) {
5278 break;
5279 }
5280 }
5281 return pHead;
5282 }
5283
Jack Palevich2ff5c222009-07-23 15:11:22 -07005284 Type* expectPrimitiveType() {
5285 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005286 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005287 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005288 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005289 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005290 }
Jack Palevich86351982009-06-30 18:09:56 -07005291 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005292 }
5293
Jack Palevichb5e33312009-07-30 19:06:34 -07005294 void checkLVal() {
5295 if (pGen->getR0ExpressionType() != ET_LVALUE) {
5296 error("Expected an lval");
5297 }
5298 }
5299
Jack Palevich86351982009-06-30 18:09:56 -07005300 void addGlobalSymbol(Type* pDecl) {
5301 tokenid_t t = pDecl->id;
5302 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005303 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005304 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005305 }
Jack Palevich86351982009-06-30 18:09:56 -07005306 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005307 }
5308
Jack Palevich86351982009-06-30 18:09:56 -07005309 void reportDuplicate(tokenid_t t) {
5310 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005311 }
5312
Jack Palevich86351982009-06-30 18:09:56 -07005313 void addLocalSymbol(Type* pDecl) {
5314 tokenid_t t = pDecl->id;
5315 if (mLocals.isDefinedAtCurrentLevel(t)) {
5316 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005317 }
Jack Palevich86351982009-06-30 18:09:56 -07005318 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005319 }
5320
Jack Palevich95727a02009-07-06 12:07:15 -07005321 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005322 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005323
Jack Palevich95727a02009-07-06 12:07:15 -07005324 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005325 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005326 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005327 if (!pDecl) {
5328 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005329 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005330 if (!pDecl->id) {
5331 break;
5332 }
Jack Palevich86351982009-06-30 18:09:56 -07005333 int variableAddress = 0;
5334 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005335 size_t alignment = pGen->alignmentOf(pDecl);
5336 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005337 size_t alignmentMask = ~ (alignment - 1);
5338 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005339 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005340 loc = (loc + alignment - 1) & alignmentMask;
5341 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5342 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005343 variableAddress = -loc;
5344 VI(pDecl->id)->pAddress = (void*) variableAddress;
5345 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005346 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005347 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005348 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005349 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005350 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005351 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005352 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005353 if (tok == ',')
5354 next();
5355 }
5356 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005357 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005358 }
5359 }
5360
Jack Palevichf1728be2009-06-12 13:53:51 -07005361 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005362 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005363 }
5364
Jack Palevich37c54bd2009-07-14 18:35:36 -07005365 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005366 if (token == EOF ) {
5367 buffer.printf("EOF");
5368 } else if (token == TOK_NUM) {
5369 buffer.printf("numeric constant");
5370 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005371 if (token < 32) {
5372 buffer.printf("'\\x%02x'", token);
5373 } else {
5374 buffer.printf("'%c'", token);
5375 }
Jack Palevich569f1352009-06-29 14:29:08 -07005376 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005377 if (quote) {
5378 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5379 buffer.printf("keyword \"%s\"", nameof(token));
5380 } else {
5381 buffer.printf("symbol \"%s\"", nameof(token));
5382 }
5383 } else {
5384 buffer.printf("%s", nameof(token));
5385 }
Jack Palevich569f1352009-06-29 14:29:08 -07005386 }
5387 }
5388
Jack Palevich9221bcc2009-08-26 16:15:07 -07005389 void printToken(tokenid_t token) {
5390 String buffer;
5391 decodeToken(buffer, token, true);
5392 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5393 }
5394
Jack Palevich40600de2009-07-01 15:32:35 -07005395 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005396 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005397 if (!result) {
5398 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005399 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005400 error("Expected symbol. Got %s", temp.getUnwrapped());
5401 }
5402 return result;
5403 }
5404
Jack Palevich86351982009-06-30 18:09:56 -07005405 tokenid_t acceptSymbol() {
5406 tokenid_t result = 0;
5407 if (tok >= TOK_SYMBOL) {
5408 result = tok;
5409 next();
Jack Palevich86351982009-06-30 18:09:56 -07005410 }
5411 return result;
5412 }
5413
Jack Palevichb7c81e92009-06-04 19:56:13 -07005414 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005415 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005416 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005417 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005418 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005419 break;
5420 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005421 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005422 if (!pDecl) {
5423 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005424 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005425 if (!pDecl->id) {
5426 skip(';');
5427 continue;
5428 }
5429
Jack Palevich86351982009-06-30 18:09:56 -07005430 if (! isDefined(pDecl->id)) {
5431 addGlobalSymbol(pDecl);
5432 }
5433 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005434 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005435 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005436 }
Jack Palevich86351982009-06-30 18:09:56 -07005437 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005438 // it's a variable declaration
5439 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005440 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005441 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005442 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005443 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005444 }
Jack Palevich86351982009-06-30 18:09:56 -07005445 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005446 if (tok == TOK_NUM) {
5447 if (name) {
5448 * (int*) name->pAddress = tokc;
5449 }
5450 next();
5451 } else {
5452 error("Expected an integer constant");
5453 }
5454 }
Jack Palevich86351982009-06-30 18:09:56 -07005455 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005456 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005457 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005458 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005459 if (!pDecl) {
5460 break;
5461 }
5462 if (! isDefined(pDecl->id)) {
5463 addGlobalSymbol(pDecl);
5464 }
5465 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005466 }
5467 skip(';');
5468 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005469 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005470 if (accept(';')) {
5471 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005472 } else if (tok != '{') {
5473 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005474 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005475 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005476 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005477 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005478 /* patch forward references */
5479 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005480 /* put function address */
5481 name->pAddress = (void*) codeBuf.getPC();
5482 }
5483 // Calculate stack offsets for parameters
5484 mLocals.pushLevel();
5485 intptr_t a = 8;
5486 int argCount = 0;
5487 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5488 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005489 if (pArg->id) {
5490 addLocalSymbol(pArg);
5491 }
Jack Palevich95727a02009-07-06 12:07:15 -07005492 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005493 Type* pPassingType = passingType(pArg);
5494 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005495 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005496 if (pArg->id) {
5497 VI(pArg->id)->pAddress = (void*) a;
5498 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005499 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005500 argCount++;
5501 }
5502 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005503 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005504 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005505 block(0, true);
5506 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005507 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005508 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005509 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005510 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005511 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005512 }
5513 }
5514 }
5515
Jack Palevich9221bcc2009-08-26 16:15:07 -07005516 Type* passingType(Type* pType) {
5517 switch (pType->tag) {
5518 case TY_CHAR:
5519 case TY_SHORT:
5520 return mkpInt;
5521 default:
5522 return pType;
5523 }
5524 }
5525
Jack Palevich9cbd2262009-07-08 16:48:41 -07005526 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5527 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5528 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005529 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005530 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005531 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005532 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005533 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005534 char* result = (char*) base;
5535 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005536 return result;
5537 }
5538
Jack Palevich21a15a22009-05-11 14:49:29 -07005539 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005540 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005541 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005542 pGlobalBase = 0;
5543 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005544 if (pGen) {
5545 delete pGen;
5546 pGen = 0;
5547 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005548 if (file) {
5549 delete file;
5550 file = 0;
5551 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005552 }
5553
Jack Palevich8c246a92009-07-14 21:14:10 -07005554 // One-time initialization, when class is constructed.
5555 void init() {
5556 mpSymbolLookupFn = 0;
5557 mpSymbolLookupContext = 0;
5558 }
5559
Jack Palevich21a15a22009-05-11 14:49:29 -07005560 void clear() {
5561 tok = 0;
5562 tokc = 0;
5563 tokl = 0;
5564 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005565 rsym = 0;
5566 loc = 0;
5567 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005568 dptr = 0;
5569 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005570 file = 0;
5571 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005572 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005573 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005574 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005575 mLineNumber = 1;
5576 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005577 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005578 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005579
Jack Palevich22305132009-05-13 10:58:45 -07005580 void setArchitecture(const char* architecture) {
5581 delete pGen;
5582 pGen = 0;
5583
5584 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005585#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005586 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005587 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005588 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005589#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005590#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005591 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005592 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005593 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005594#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005595 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005596 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005597 }
5598 }
5599
5600 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005601#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005602 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005603#elif defined(DEFAULT_X86_CODEGEN)
5604 pGen = new X86CodeGenerator();
5605#endif
5606 }
5607 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005608 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005609 } else {
5610 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005611 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005612 }
5613 }
5614
Jack Palevich77ae76e2009-05-10 19:59:24 -07005615public:
Jack Palevich22305132009-05-13 10:58:45 -07005616 struct args {
5617 args() {
5618 architecture = 0;
5619 }
5620 const char* architecture;
5621 };
5622
Jack Paleviche7b59062009-05-19 17:12:17 -07005623 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005624 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005625 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005626 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005627
Jack Paleviche7b59062009-05-19 17:12:17 -07005628 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005629 cleanup();
5630 }
5631
Jack Palevich8c246a92009-07-14 21:14:10 -07005632 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5633 mpSymbolLookupFn = pFn;
5634 mpSymbolLookupContext = pContext;
5635 }
5636
Jack Palevich1cdef202009-05-22 12:06:27 -07005637 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005638 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005639
Jack Palevich2ff5c222009-07-23 15:11:22 -07005640 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005641 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005642 cleanup();
5643 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005644 mTokenTable.setArena(&mGlobalArena);
5645 mGlobals.setArena(&mGlobalArena);
5646 mGlobals.setTokenTable(&mTokenTable);
5647 mLocals.setArena(&mLocalArena);
5648 mLocals.setTokenTable(&mTokenTable);
5649
5650 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005651 codeBuf.init(ALLOC_SIZE);
5652 setArchitecture(NULL);
5653 if (!pGen) {
5654 return -1;
5655 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005656#ifdef PROVIDE_TRACE_CODEGEN
5657 pGen = new TraceCodeGenerator(pGen);
5658#endif
5659 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005660 pGen->init(&codeBuf);
5661 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005662 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5663 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005664 inp();
5665 next();
5666 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005667 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005668 result = pGen->finishCompile();
5669 if (result == 0) {
5670 if (mErrorBuf.len()) {
5671 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005672 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005673 }
Jack Palevichce105a92009-07-16 14:30:33 -07005674 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005675 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005676 }
5677
Jack Palevich86351982009-06-30 18:09:56 -07005678 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005679 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005680 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005681 mkpChar = createType(TY_CHAR, NULL, NULL);
5682 mkpVoid = createType(TY_VOID, NULL, NULL);
5683 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5684 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5685 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5686 mkpIntPtr = createPtrType(mkpInt);
5687 mkpCharPtr = createPtrType(mkpChar);
5688 mkpFloatPtr = createPtrType(mkpFloat);
5689 mkpDoublePtr = createPtrType(mkpDouble);
5690 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005691 }
5692
Jack Palevicha6baa232009-06-12 11:25:59 -07005693 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005694 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005695 }
5696
Jack Palevich569f1352009-06-29 14:29:08 -07005697 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005698 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005699 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005700 }
5701
Jack Palevich569f1352009-06-29 14:29:08 -07005702 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005703 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005704 error("Undefined forward reference: %s",
5705 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005706 }
5707 return true;
5708 }
5709
Jack Palevich21a15a22009-05-11 14:49:29 -07005710 int dump(FILE* out) {
5711 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5712 return 0;
5713 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005714
Jack Palevicha6535612009-05-13 16:24:17 -07005715 int disassemble(FILE* out) {
5716 return pGen->disassemble(out);
5717 }
5718
Jack Palevich1cdef202009-05-22 12:06:27 -07005719 /* Look through the symbol table to find a symbol.
5720 * If found, return its value.
5721 */
5722 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005723 if (mCompileResult == 0) {
5724 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5725 VariableInfo* pVariableInfo = VI(tok);
5726 if (pVariableInfo) {
5727 return pVariableInfo->pAddress;
5728 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005729 }
5730 return NULL;
5731 }
5732
Jack Palevicheedf9d22009-06-04 16:23:40 -07005733 void getPragmas(ACCsizei* actualStringCount,
5734 ACCsizei maxStringCount, ACCchar** strings) {
5735 int stringCount = mPragmaStringCount;
5736 if (actualStringCount) {
5737 *actualStringCount = stringCount;
5738 }
5739 if (stringCount > maxStringCount) {
5740 stringCount = maxStringCount;
5741 }
5742 if (strings) {
5743 char* pPragmas = mPragmas.getUnwrapped();
5744 while (stringCount-- > 0) {
5745 *strings++ = pPragmas;
5746 pPragmas += strlen(pPragmas) + 1;
5747 }
5748 }
5749 }
5750
Jack Palevichac0e95e2009-05-29 13:53:44 -07005751 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005752 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005753 }
5754
Jack Palevich77ae76e2009-05-10 19:59:24 -07005755};
5756
Jack Paleviche7b59062009-05-19 17:12:17 -07005757const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005758 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5759
Jack Paleviche7b59062009-05-19 17:12:17 -07005760const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005761 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5762 5, 5, /* ==, != */
5763 9, 10, /* &&, || */
5764 6, 7, 8, /* & ^ | */
5765 2, 2 /* ~ ! */
5766 };
5767
Jack Palevich8b0624c2009-05-20 12:12:06 -07005768#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005769FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005770#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005771
Jack Palevich8b0624c2009-05-20 12:12:06 -07005772#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005773const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005774 0x1, // ++
5775 0xff, // --
5776 0xc1af0f, // *
5777 0xf9f79991, // /
5778 0xf9f79991, // % (With manual assist to swap results)
5779 0xc801, // +
5780 0xd8f7c829, // -
5781 0xe0d391, // <<
5782 0xf8d391, // >>
5783 0xe, // <=
5784 0xd, // >=
5785 0xc, // <
5786 0xf, // >
5787 0x4, // ==
5788 0x5, // !=
5789 0x0, // &&
5790 0x1, // ||
5791 0xc821, // &
5792 0xc831, // ^
5793 0xc809, // |
5794 0xd0f7, // ~
5795 0x4 // !
5796};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005797#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005798
Jack Palevich1cdef202009-05-22 12:06:27 -07005799struct ACCscript {
5800 ACCscript() {
5801 text = 0;
5802 textLength = 0;
5803 accError = ACC_NO_ERROR;
5804 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005805
Jack Palevich1cdef202009-05-22 12:06:27 -07005806 ~ACCscript() {
5807 delete text;
5808 }
Jack Palevich546b2242009-05-13 15:10:04 -07005809
Jack Palevich8c246a92009-07-14 21:14:10 -07005810 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5811 compiler.registerSymbolCallback(pFn, pContext);
5812 }
5813
Jack Palevich1cdef202009-05-22 12:06:27 -07005814 void setError(ACCenum error) {
5815 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5816 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005817 }
5818 }
5819
Jack Palevich1cdef202009-05-22 12:06:27 -07005820 ACCenum getError() {
5821 ACCenum result = accError;
5822 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005823 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005824 }
5825
Jack Palevich1cdef202009-05-22 12:06:27 -07005826 Compiler compiler;
5827 char* text;
5828 int textLength;
5829 ACCenum accError;
5830};
5831
5832
5833extern "C"
5834ACCscript* accCreateScript() {
5835 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005836}
Jack Palevich1cdef202009-05-22 12:06:27 -07005837
5838extern "C"
5839ACCenum accGetError( ACCscript* script ) {
5840 return script->getError();
5841}
5842
5843extern "C"
5844void accDeleteScript(ACCscript* script) {
5845 delete script;
5846}
5847
5848extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005849void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5850 ACCvoid* pContext) {
5851 script->registerSymbolCallback(pFn, pContext);
5852}
5853
5854extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005855void accScriptSource(ACCscript* script,
5856 ACCsizei count,
5857 const ACCchar ** string,
5858 const ACCint * length) {
5859 int totalLength = 0;
5860 for(int i = 0; i < count; i++) {
5861 int len = -1;
5862 const ACCchar* s = string[i];
5863 if (length) {
5864 len = length[i];
5865 }
5866 if (len < 0) {
5867 len = strlen(s);
5868 }
5869 totalLength += len;
5870 }
5871 delete script->text;
5872 char* text = new char[totalLength + 1];
5873 script->text = text;
5874 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005875 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005876 for(int i = 0; i < count; i++) {
5877 int len = -1;
5878 const ACCchar* s = string[i];
5879 if (length) {
5880 len = length[i];
5881 }
5882 if (len < 0) {
5883 len = strlen(s);
5884 }
Jack Palevich09555c72009-05-27 12:25:55 -07005885 memcpy(dest, s, len);
5886 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005887 }
5888 text[totalLength] = '\0';
5889}
5890
5891extern "C"
5892void accCompileScript(ACCscript* script) {
5893 int result = script->compiler.compile(script->text, script->textLength);
5894 if (result) {
5895 script->setError(ACC_INVALID_OPERATION);
5896 }
5897}
5898
5899extern "C"
5900void accGetScriptiv(ACCscript* script,
5901 ACCenum pname,
5902 ACCint * params) {
5903 switch (pname) {
5904 case ACC_INFO_LOG_LENGTH:
5905 *params = 0;
5906 break;
5907 }
5908}
5909
5910extern "C"
5911void accGetScriptInfoLog(ACCscript* script,
5912 ACCsizei maxLength,
5913 ACCsizei * length,
5914 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005915 char* message = script->compiler.getErrorMessage();
5916 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005917 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005918 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005919 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005920 if (infoLog && maxLength > 0) {
5921 int trimmedLength = maxLength < messageLength ?
5922 maxLength : messageLength;
5923 memcpy(infoLog, message, trimmedLength);
5924 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005925 }
5926}
5927
5928extern "C"
5929void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5930 ACCvoid ** address) {
5931 void* value = script->compiler.lookup(name);
5932 if (value) {
5933 *address = value;
5934 } else {
5935 script->setError(ACC_INVALID_VALUE);
5936 }
5937}
5938
Jack Palevicheedf9d22009-06-04 16:23:40 -07005939extern "C"
5940void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5941 ACCsizei maxStringCount, ACCchar** strings){
5942 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5943}
5944
-b master422972c2009-06-17 19:13:52 -07005945extern "C"
5946void accDisassemble(ACCscript* script) {
5947 script->compiler.disassemble(stderr);
5948}
5949
Jack Palevicheedf9d22009-06-04 16:23:40 -07005950
Jack Palevich1cdef202009-05-22 12:06:27 -07005951} // namespace acc
5952