blob: a4222e65eb2474527ffd9a7c3945934f4c804af0 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070016#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070017#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070018#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070019#include <stdlib.h>
20#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070021#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070022
Jack Palevich8dc662e2009-06-09 22:53:47 +000023#if defined(__i386__)
24#include <sys/mman.h>
25#endif
26
Jack Palevich546b2242009-05-13 15:10:04 -070027#if defined(__arm__)
28#include <unistd.h>
29#endif
30
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Paleviche7b59062009-05-19 17:12:17 -070042#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070043#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070044#endif
Jack Palevicha6535612009-05-13 16:24:17 -070045
Jack Palevich30321cb2009-08-20 15:34:23 -070046#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
47#define ARM_USE_VFP
48#endif
49
Jack Palevich1cdef202009-05-22 12:06:27 -070050#include <acc/acc.h>
51
Jack Palevich09555c72009-05-27 12:25:55 -070052#define LOG_API(...) do {} while(0)
53// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070054
-b master422972c2009-06-17 19:13:52 -070055#define LOG_STACK(...) do {} while(0)
56// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
57
Jack Palevich9f51a262009-07-29 16:22:26 -070058#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070059// #define PROVIDE_TRACE_CODEGEN
60
Jack Palevich7f5b1a22009-08-17 16:54:56 -070061#define assert(b) assertImpl(b, __LINE__)
62
Jack Palevichbbf8ab52009-05-11 11:54:30 -070063namespace acc {
64
Jack Palevich8df46192009-07-07 14:48:51 -070065// Subset of STL vector.
66template<class E> class Vector {
67 public:
68 Vector() {
69 mpBase = 0;
70 mUsed = 0;
71 mSize = 0;
72 }
73
74 ~Vector() {
75 if (mpBase) {
76 for(size_t i = 0; i < mUsed; i++) {
77 mpBase[mUsed].~E();
78 }
79 free(mpBase);
80 }
81 }
82
83 inline E& operator[](size_t i) {
84 return mpBase[i];
85 }
86
87 inline E& front() {
88 return mpBase[0];
89 }
90
91 inline E& back() {
92 return mpBase[mUsed - 1];
93 }
94
95 void pop_back() {
96 mUsed -= 1;
97 mpBase[mUsed].~E();
98 }
99
100 void push_back(const E& item) {
101 * ensure(1) = item;
102 }
103
104 size_t size() {
105 return mUsed;
106 }
107
108private:
109 E* ensure(int n) {
110 size_t newUsed = mUsed + n;
111 if (newUsed > mSize) {
112 size_t newSize = mSize * 2 + 10;
113 if (newSize < newUsed) {
114 newSize = newUsed;
115 }
116 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
117 mSize = newSize;
118 }
119 E* result = mpBase + mUsed;
120 mUsed = newUsed;
121 return result;
122 }
123
124 E* mpBase;
125 size_t mUsed;
126 size_t mSize;
127};
128
Jack Palevichac0e95e2009-05-29 13:53:44 -0700129class ErrorSink {
130public:
131 void error(const char *fmt, ...) {
132 va_list ap;
133 va_start(ap, fmt);
134 verror(fmt, ap);
135 va_end(ap);
136 }
137
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700138 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700139 virtual void verror(const char* fmt, va_list ap) = 0;
140};
141
142class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700143 typedef int tokenid_t;
144 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700145 TY_INT, // 0
146 TY_CHAR, // 1
147 TY_SHORT, // 2
148 TY_VOID, // 3
149 TY_FLOAT, // 4
150 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700151 TY_POINTER, // 6
152 TY_ARRAY, // 7
153 TY_STRUCT, // 8
154 TY_FUNC, // 9
155 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700156 };
157
158 struct Type {
159 TypeTag tag;
Jack Palevichb6154502009-08-04 14:56:09 -0700160 tokenid_t id; // For function arguments, local vars
161 int length; // length of array
Jack Palevich8df46192009-07-07 14:48:51 -0700162 Type* pHead;
163 Type* pTail;
164 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700165
Jack Palevichba929a42009-07-17 10:20:32 -0700166 enum ExpressionType {
167 ET_RVALUE,
168 ET_LVALUE
169 };
170
171 struct ExpressionValue {
172 ExpressionValue() {
173 et = ET_RVALUE;
174 pType = NULL;
175 }
176 ExpressionType et;
177 Type* pType;
178 };
179
Jack Palevich21a15a22009-05-11 14:49:29 -0700180 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700181 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700182 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700183 ErrorSink* mErrorSink;
184 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700185 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700186
Jack Palevich21a15a22009-05-11 14:49:29 -0700187 void release() {
188 if (pProgramBase != 0) {
189 free(pProgramBase);
190 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700191 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700192 }
193
Jack Palevich0a280a02009-06-11 10:53:51 -0700194 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700195 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700196 bool overflow = newSize > mSize;
197 if (overflow && !mOverflowed) {
198 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700199 if (mErrorSink) {
200 mErrorSink->error("Code too large: %d bytes", newSize);
201 }
202 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700203 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700204 }
205
Jack Palevich21a15a22009-05-11 14:49:29 -0700206 public:
207 CodeBuf() {
208 pProgramBase = 0;
209 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700210 mErrorSink = 0;
211 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700212 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700213 }
214
215 ~CodeBuf() {
216 release();
217 }
218
219 void init(int size) {
220 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700221 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700222 pProgramBase = (char*) calloc(1, size);
223 ind = pProgramBase;
224 }
225
Jack Palevichac0e95e2009-05-29 13:53:44 -0700226 void setErrorSink(ErrorSink* pErrorSink) {
227 mErrorSink = pErrorSink;
228 }
229
Jack Palevich546b2242009-05-13 15:10:04 -0700230 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700231 if(check(4)) {
232 return 0;
233 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700234 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700235 * (int*) ind = n;
236 ind += 4;
237 return result;
238 }
239
Jack Palevich21a15a22009-05-11 14:49:29 -0700240 /*
241 * Output a byte. Handles all values, 0..ff.
242 */
243 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700244 if(check(1)) {
245 return;
246 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700247 *ind++ = n;
248 }
249
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 inline void* getBase() {
251 return (void*) pProgramBase;
252 }
253
Jack Palevich8b0624c2009-05-20 12:12:06 -0700254 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700255 return ind - pProgramBase;
256 }
257
Jack Palevich8b0624c2009-05-20 12:12:06 -0700258 intptr_t getPC() {
259 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 }
261 };
262
Jack Palevich1cdef202009-05-22 12:06:27 -0700263 /**
264 * A code generator creates an in-memory program, generating the code on
265 * the fly. There is one code generator implementation for each supported
266 * architecture.
267 *
268 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700269 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700270 * FP - a frame pointer for accessing function arguments and local
271 * variables.
272 * SP - a stack pointer for storing intermediate results while evaluating
273 * expressions. The stack pointer grows downwards.
274 *
275 * The function calling convention is that all arguments are placed on the
276 * stack such that the first argument has the lowest address.
277 * After the call, the result is in R0. The caller is responsible for
278 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700279 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700280 * FP and SP registers are saved.
281 */
282
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 class CodeGenerator {
284 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700285 CodeGenerator() {
286 mErrorSink = 0;
287 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700288 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700289 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700290 virtual ~CodeGenerator() {}
291
Jack Palevich22305132009-05-13 10:58:45 -0700292 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700293 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700294 pCodeBuf->setErrorSink(mErrorSink);
295 }
296
Jack Palevichb67b18f2009-06-11 21:12:23 -0700297 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700298 mErrorSink = pErrorSink;
299 if (pCodeBuf) {
300 pCodeBuf->setErrorSink(mErrorSink);
301 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700302 }
303
Jack Palevich58c30ee2009-07-17 16:35:23 -0700304 /* Give the code generator some utility types so it can
305 * use its own types as needed for the results of some
306 * operations like gcmp.
307 */
308
Jack Palevicha8f427f2009-07-13 18:40:08 -0700309 void setTypes(Type* pInt) {
310 mkpInt = pInt;
311 }
312
Jack Palevich1cdef202009-05-22 12:06:27 -0700313 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700314 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700315 * Save the old value of the FP.
316 * Set the new value of the FP.
317 * Convert from the native platform calling convention to
318 * our stack-based calling convention. This may require
319 * pushing arguments from registers to the stack.
320 * Allocate "N" bytes of stack space. N isn't known yet, so
321 * just emit the instructions for adjusting the stack, and return
322 * the address to patch up. The patching will be done in
323 * functionExit().
324 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700325 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700326 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700327
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 /* Emit a function epilog.
329 * Restore the old SP and FP register values.
330 * Return to the calling function.
331 * argCount - the number of arguments to the function.
332 * localVariableAddress - returned from functionEntry()
333 * localVariableSize - the size in bytes of the local variables.
334 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700335 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700336 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700337
Jack Palevich1cdef202009-05-22 12:06:27 -0700338 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700339 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700340
Jack Palevich1a539db2009-07-08 13:04:41 -0700341 /* Load floating point value from global address. */
342 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich1cdef202009-05-22 12:06:27 -0700344 /* Jump to a target, and return the address of the word that
345 * holds the target data, in case it needs to be fixed up later.
346 */
Jack Palevich22305132009-05-13 10:58:45 -0700347 virtual int gjmp(int t) = 0;
348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /* Test R0 and jump to a target if the test succeeds.
350 * l = 0: je, l == 1: jne
351 * Return the address of the word that holds the targed data, in
352 * case it needs to be fixed up later.
353 */
Jack Palevich22305132009-05-13 10:58:45 -0700354 virtual int gtst(bool l, int t) = 0;
355
Jack Palevich9eed7a22009-07-06 17:24:34 -0700356 /* Compare TOS against R0, and store the boolean result in R0.
357 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700358 * op specifies the comparison.
359 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700360 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700361
Jack Palevich9eed7a22009-07-06 17:24:34 -0700362 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700364 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700365 */
Jack Palevich546b2242009-05-13 15:10:04 -0700366 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700367
Jack Palevich9eed7a22009-07-06 17:24:34 -0700368 /* Compare 0 against R0, and store the boolean result in R0.
369 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700371 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700372
373 /* Perform the arithmetic op specified by op. 0 is the
374 * left argument, R0 is the right argument.
375 */
376 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700377
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700378 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700379 */
380 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700381
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700382 /* Turn R0, TOS into R0 TOS R0 */
383
384 virtual void over() = 0;
385
386 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700387 */
388 virtual void popR0() = 0;
389
Jack Palevich9eed7a22009-07-06 17:24:34 -0700390 /* Store R0 to the address stored in TOS.
391 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700393 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700394
Jack Palevich1cdef202009-05-22 12:06:27 -0700395 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700396 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700397 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700398
Jack Palevich1cdef202009-05-22 12:06:27 -0700399 /* Load the absolute address of a variable to R0.
400 * If ea <= LOCAL, then this is a local variable, or an
401 * argument, addressed relative to FP.
402 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700403 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700404 * et is ET_RVALUE for things like string constants, ET_LVALUE for
405 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700407 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700408
Jack Palevich9f51a262009-07-29 16:22:26 -0700409 /* Load the pc-relative address of a forward-referenced variable to R0.
410 * Return the address of the 4-byte constant so that it can be filled
411 * in later.
412 */
413 virtual int leaForward(int ea, Type* pPointerType) = 0;
414
Jack Palevich8df46192009-07-07 14:48:51 -0700415 /**
416 * Convert R0 to the given type.
417 */
Jack Palevichb6154502009-08-04 14:56:09 -0700418
419 void convertR0(Type* pType) {
420 convertR0Imp(pType, false);
421 }
422
423 void castR0(Type* pType) {
424 convertR0Imp(pType, true);
425 }
426
427 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700428
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 /* Emit code to adjust the stack for a function call. Return the
430 * label for the address of the instruction that adjusts the
431 * stack size. This will be passed as argument "a" to
432 * endFunctionCallArguments.
433 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700434 virtual int beginFunctionCallArguments() = 0;
435
Jack Palevich1cdef202009-05-22 12:06:27 -0700436 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700437 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700439 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Patch the function call preamble.
442 * a is the address returned from beginFunctionCallArguments
443 * l is the number of bytes the arguments took on the stack.
444 * Typically you would also emit code to convert the argument
445 * list into whatever the native function calling convention is.
446 * On ARM for example you would pop the first 5 arguments into
447 * R0..R4
448 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700449 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700450
Jack Palevich1cdef202009-05-22 12:06:27 -0700451 /* Emit a call to an unknown function. The argument "symbol" needs to
452 * be stored in the location where the address should go. It forms
453 * a chain. The address will be patched later.
454 * Return the address of the word that has to be patched.
455 */
Jack Palevich8df46192009-07-07 14:48:51 -0700456 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700457
Jack Palevich1cdef202009-05-22 12:06:27 -0700458 /* Call a function pointer. L is the number of bytes the arguments
459 * take on the stack. The address of the function is stored at
460 * location SP + l.
461 */
Jack Palevich8df46192009-07-07 14:48:51 -0700462 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700463
Jack Palevich1cdef202009-05-22 12:06:27 -0700464 /* Adjust SP after returning from a function call. l is the
465 * number of bytes of arguments stored on the stack. isIndirect
466 * is true if this was an indirect call. (In which case the
467 * address of the function is stored at location SP + l.)
468 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700469 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700470
Jack Palevich1cdef202009-05-22 12:06:27 -0700471 /* Print a disassembly of the assembled code to out. Return
472 * non-zero if there is an error.
473 */
Jack Palevicha6535612009-05-13 16:24:17 -0700474 virtual int disassemble(FILE* out) = 0;
475
Jack Palevich1cdef202009-05-22 12:06:27 -0700476 /* Generate a symbol at the current PC. t is the head of a
477 * linked list of addresses to patch.
478 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700479 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700480
Jack Palevich9f51a262009-07-29 16:22:26 -0700481 /* Resolve a forward reference function at the current PC.
482 * t is the head of a
483 * linked list of addresses to patch.
484 * (Like gsym, but using absolute address, not PC relative address.)
485 */
486 virtual void resolveForward(int t) = 0;
487
Jack Palevich1cdef202009-05-22 12:06:27 -0700488 /*
489 * Do any cleanup work required at the end of a compile.
490 * For example, an instruction cache might need to be
491 * invalidated.
492 * Return non-zero if there is an error.
493 */
494 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700495
Jack Palevicha6535612009-05-13 16:24:17 -0700496 /**
497 * Adjust relative branches by this amount.
498 */
499 virtual int jumpOffset() = 0;
500
Jack Palevich9eed7a22009-07-06 17:24:34 -0700501 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700502 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700503 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700504 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700505
506 /**
507 * Array element alignment (in bytes) for this type of data.
508 */
509 virtual size_t sizeOf(Type* type) = 0;
510
Jack Palevich9cbd2262009-07-08 16:48:41 -0700511 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700512 * Stack alignment of this type of data
513 */
514 virtual size_t stackAlignmentOf(Type* pType) = 0;
515
516 /**
517 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700518 */
519 virtual size_t stackSizeOf(Type* pType) = 0;
520
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700521 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700522 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700523 }
524
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700525 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700526 return mExpressionStack.back().et;
527 }
528
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700529 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700530 mExpressionStack.back().et = et;
531 }
532
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700533 virtual size_t getExpressionStackDepth() {
534 return mExpressionStack.size();
535 }
536
Jack Palevichb5e33312009-07-30 19:06:34 -0700537 virtual void forceR0RVal() {
538 if (getR0ExpressionType() == ET_LVALUE) {
539 loadR0FromR0();
540 }
541 }
542
Jack Palevich21a15a22009-05-11 14:49:29 -0700543 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700544 /*
545 * Output a byte. Handles all values, 0..ff.
546 */
547 void ob(int n) {
548 pCodeBuf->ob(n);
549 }
550
Jack Palevich8b0624c2009-05-20 12:12:06 -0700551 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700552 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700553 }
554
Jack Palevich8b0624c2009-05-20 12:12:06 -0700555 intptr_t getBase() {
556 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700557 }
558
Jack Palevich8b0624c2009-05-20 12:12:06 -0700559 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700560 return pCodeBuf->getPC();
561 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700562
563 intptr_t getSize() {
564 return pCodeBuf->getSize();
565 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700566
567 void error(const char* fmt,...) {
568 va_list ap;
569 va_start(ap, fmt);
570 mErrorSink->verror(fmt, ap);
571 va_end(ap);
572 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700573
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700574 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700575 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700576 error("code generator assertion failed at line %s:%d.", __FILE__, line);
577 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700578 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700579 }
580 }
Jack Palevich8df46192009-07-07 14:48:51 -0700581
582 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700583 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700584 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700585 mExpressionStack.back().et = ET_RVALUE;
586 }
587
588 void setR0Type(Type* pType, ExpressionType et) {
589 assert(pType != NULL);
590 mExpressionStack.back().pType = pType;
591 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700592 }
593
Jack Palevich8df46192009-07-07 14:48:51 -0700594 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700595 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700596 }
597
598 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700599 if (mExpressionStack.size()) {
600 mExpressionStack.push_back(mExpressionStack.back());
601 } else {
602 mExpressionStack.push_back(ExpressionValue());
603 }
604
Jack Palevich8df46192009-07-07 14:48:51 -0700605 }
606
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700607 void overType() {
608 size_t size = mExpressionStack.size();
609 if (size >= 2) {
610 mExpressionStack.push_back(mExpressionStack.back());
611 mExpressionStack[size-1] = mExpressionStack[size-2];
612 mExpressionStack[size-2] = mExpressionStack[size];
613 }
614 }
615
Jack Palevich8df46192009-07-07 14:48:51 -0700616 void popType() {
617 mExpressionStack.pop_back();
618 }
619
620 bool bitsSame(Type* pA, Type* pB) {
621 return collapseType(pA->tag) == collapseType(pB->tag);
622 }
623
624 TypeTag collapseType(TypeTag tag) {
625 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700626 TY_INT,
627 TY_INT,
628 TY_INT,
629 TY_VOID,
630 TY_FLOAT,
631 TY_DOUBLE,
632 TY_INT,
633 TY_INT,
634 TY_VOID,
635 TY_VOID,
636 TY_VOID
637 };
Jack Palevich8df46192009-07-07 14:48:51 -0700638 return collapsedTag[tag];
639 }
640
Jack Palevich1a539db2009-07-08 13:04:41 -0700641 TypeTag collapseTypeR0() {
642 return collapseType(getR0Type()->tag);
643 }
644
Jack Palevichb6154502009-08-04 14:56:09 -0700645 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700646 return isFloatTag(pType->tag);
647 }
648
Jack Palevichb6154502009-08-04 14:56:09 -0700649 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700650 return tag == TY_FLOAT || tag == TY_DOUBLE;
651 }
652
Jack Palevichb6154502009-08-04 14:56:09 -0700653 static bool isPointerType(Type* pType) {
654 return isPointerTag(pType->tag);
655 }
656
657 static bool isPointerTag(TypeTag tag) {
658 return tag == TY_POINTER || tag == TY_ARRAY;
659 }
660
661 Type* getPointerArithmeticResultType(Type* a, Type* b) {
662 TypeTag aTag = a->tag;
663 TypeTag bTag = b->tag;
664 if (aTag == TY_POINTER) {
665 return a;
666 }
667 if (bTag == TY_POINTER) {
668 return b;
669 }
670 if (aTag == TY_ARRAY) {
671 return a->pTail;
672 }
673 if (bTag == TY_ARRAY) {
674 return b->pTail;
675 }
676 return NULL;
677 }
678
Jack Palevicha8f427f2009-07-13 18:40:08 -0700679 Type* mkpInt;
680
Jack Palevich21a15a22009-05-11 14:49:29 -0700681 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700682 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700683 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700684 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700685 };
686
Jack Paleviche7b59062009-05-19 17:12:17 -0700687#ifdef PROVIDE_ARM_CODEGEN
688
Jack Palevich22305132009-05-13 10:58:45 -0700689 class ARMCodeGenerator : public CodeGenerator {
690 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700691 ARMCodeGenerator() {
692#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700693 LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700694#else
Jack Palevichc0f25332009-08-25 12:23:43 -0700695 LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700696#endif
697 }
-b master422972c2009-06-17 19:13:52 -0700698
Jack Palevich22305132009-05-13 10:58:45 -0700699 virtual ~ARMCodeGenerator() {}
700
701 /* returns address to patch with local variable size
702 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700703 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700704 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700705 // sp -> arg4 arg5 ...
706 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700707 int regArgCount = calcRegArgCount(pDecl);
708 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700709 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700710 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700711 }
712 // sp -> arg0 arg1 ...
713 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700714 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700715 // sp, fp -> oldfp, retadr, arg0 arg1 ....
716 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700717 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700718 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700719 // We don't know how many local variables we are going to use,
720 // but we will round the allocation up to a multiple of
721 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700722 }
723
Jack Palevichb7718b92009-07-09 22:00:24 -0700724 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700725 // Round local variable size up to a multiple of stack alignment
726 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
727 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700728 // Patch local variable allocation code:
729 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700730 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700731 }
Jack Palevich69796b62009-05-14 15:42:26 -0700732 *(char*) (localVariableAddress) = localVariableSize;
733
Jack Palevich30321cb2009-08-20 15:34:23 -0700734#ifdef ARM_USE_VFP
735 {
Jack Palevichc0f25332009-08-25 12:23:43 -0700736 Type* pReturnType = pDecl->pHead;
737 switch(pReturnType->tag) {
738 case TY_FLOAT:
739 o4(0xEE170A90); // fmrs r0, s15
740 break;
741 case TY_DOUBLE:
742 o4(0xEC510B17); // fmrrd r0, r1, d7
743 break;
744 default:
745 break;
746 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700747 }
748#endif
749
Jack Palevich69796b62009-05-14 15:42:26 -0700750 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
751 o4(0xE1A0E00B); // mov lr, fp
752 o4(0xE59BB000); // ldr fp, [fp]
753 o4(0xE28ED004); // add sp, lr, #4
754 // sp -> retadr, arg0, ...
755 o4(0xE8BD4000); // ldmfd sp!, {lr}
756 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700757
758 // We store the PC into the lr so we can adjust the sp before
759 // returning. We need to pull off the registers we pushed
760 // earlier. We don't need to actually store them anywhere,
761 // just adjust the stack.
762 int regArgCount = calcRegArgCount(pDecl);
763 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700764 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
765 }
766 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700767 }
768
769 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700770 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700771 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700772 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700773 }
774
Jack Palevich1a539db2009-07-08 13:04:41 -0700775 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700776 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700777 // Global, absolute address
778 o4(0xE59F0000); // ldr r0, .L1
779 o4(0xEA000000); // b .L99
780 o4(address); // .L1: .word ea
781 // .L99:
782
783 switch (pType->tag) {
784 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700785#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700786 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700787#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700788 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700789#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700790 break;
791 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700792#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700793 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700794#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700795 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700796#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700797 break;
798 default:
799 assert(false);
800 break;
801 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700802 }
803
Jack Palevich22305132009-05-13 10:58:45 -0700804 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700805 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700806 }
807
808 /* l = 0: je, l == 1: jne */
809 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700810 Type* pR0Type = getR0Type();
811 TypeTag tagR0 = pR0Type->tag;
812 switch(tagR0) {
813 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700814#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700815 o4(0xEEF57A40); // fcmpzs s15
816 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700817#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700818 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -0700819 o4(0xE3500000); // cmp r0,#0
820#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700821 break;
822 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700823#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700824 o4(0xEEB57B40); // fcmpzd d7
825 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700826#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700827 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -0700828 o4(0xE3500000); // cmp r0,#0
829#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700830 break;
831 default:
Jack Palevich30321cb2009-08-20 15:34:23 -0700832 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700833 break;
834 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700835 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
836 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700837 }
838
Jack Palevich58c30ee2009-07-17 16:35:23 -0700839 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700840 Type* pR0Type = getR0Type();
841 Type* pTOSType = getTOSType();
842 TypeTag tagR0 = collapseType(pR0Type->tag);
843 TypeTag tagTOS = collapseType(pTOSType->tag);
844 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700845 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700846 o4(0xE1510000); // cmp r1, r1
847 switch(op) {
848 case OP_EQUALS:
849 o4(0x03A00001); // moveq r0,#1
850 o4(0x13A00000); // movne r0,#0
851 break;
852 case OP_NOT_EQUALS:
853 o4(0x03A00000); // moveq r0,#0
854 o4(0x13A00001); // movne r0,#1
855 break;
856 case OP_LESS_EQUAL:
857 o4(0xD3A00001); // movle r0,#1
858 o4(0xC3A00000); // movgt r0,#0
859 break;
860 case OP_GREATER:
861 o4(0xD3A00000); // movle r0,#0
862 o4(0xC3A00001); // movgt r0,#1
863 break;
864 case OP_GREATER_EQUAL:
865 o4(0xA3A00001); // movge r0,#1
866 o4(0xB3A00000); // movlt r0,#0
867 break;
868 case OP_LESS:
869 o4(0xA3A00000); // movge r0,#0
870 o4(0xB3A00001); // movlt r0,#1
871 break;
872 default:
873 error("Unknown comparison op %d", op);
874 break;
875 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700876 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
877 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700878#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700879 o4(0xEEB46BC7); // fcmped d6, d7
880 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700881 switch(op) {
882 case OP_EQUALS:
883 o4(0x03A00001); // moveq r0,#1
884 o4(0x13A00000); // movne r0,#0
885 break;
886 case OP_NOT_EQUALS:
887 o4(0x03A00000); // moveq r0,#0
888 o4(0x13A00001); // movne r0,#1
889 break;
890 case OP_LESS_EQUAL:
891 o4(0xD3A00001); // movle r0,#1
892 o4(0xC3A00000); // movgt r0,#0
893 break;
894 case OP_GREATER:
895 o4(0xD3A00000); // movle r0,#0
896 o4(0xC3A00001); // movgt r0,#1
897 break;
898 case OP_GREATER_EQUAL:
899 o4(0xA3A00001); // movge r0,#1
900 o4(0xB3A00000); // movlt r0,#0
901 break;
902 case OP_LESS:
903 o4(0xA3A00000); // movge r0,#0
904 o4(0xB3A00001); // movlt r0,#1
905 break;
906 default:
907 error("Unknown comparison op %d", op);
908 break;
909 }
910#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700911 switch(op) {
912 case OP_EQUALS:
913 callRuntime((void*) runtime_cmp_eq_dd);
914 break;
915 case OP_NOT_EQUALS:
916 callRuntime((void*) runtime_cmp_ne_dd);
917 break;
918 case OP_LESS_EQUAL:
919 callRuntime((void*) runtime_cmp_le_dd);
920 break;
921 case OP_GREATER:
922 callRuntime((void*) runtime_cmp_gt_dd);
923 break;
924 case OP_GREATER_EQUAL:
925 callRuntime((void*) runtime_cmp_ge_dd);
926 break;
927 case OP_LESS:
928 callRuntime((void*) runtime_cmp_lt_dd);
929 break;
930 default:
931 error("Unknown comparison op %d", op);
932 break;
933 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700934#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700935 } else {
936 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700937#ifdef ARM_USE_VFP
938 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -0700939 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700940 switch(op) {
941 case OP_EQUALS:
942 o4(0x03A00001); // moveq r0,#1
943 o4(0x13A00000); // movne r0,#0
944 break;
945 case OP_NOT_EQUALS:
946 o4(0x03A00000); // moveq r0,#0
947 o4(0x13A00001); // movne r0,#1
948 break;
949 case OP_LESS_EQUAL:
950 o4(0xD3A00001); // movle r0,#1
951 o4(0xC3A00000); // movgt r0,#0
952 break;
953 case OP_GREATER:
954 o4(0xD3A00000); // movle r0,#0
955 o4(0xC3A00001); // movgt r0,#1
956 break;
957 case OP_GREATER_EQUAL:
958 o4(0xA3A00001); // movge r0,#1
959 o4(0xB3A00000); // movlt r0,#0
960 break;
961 case OP_LESS:
962 o4(0xA3A00000); // movge r0,#0
963 o4(0xB3A00001); // movlt r0,#1
964 break;
965 default:
966 error("Unknown comparison op %d", op);
967 break;
968 }
969#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700970 switch(op) {
971 case OP_EQUALS:
972 callRuntime((void*) runtime_cmp_eq_ff);
973 break;
974 case OP_NOT_EQUALS:
975 callRuntime((void*) runtime_cmp_ne_ff);
976 break;
977 case OP_LESS_EQUAL:
978 callRuntime((void*) runtime_cmp_le_ff);
979 break;
980 case OP_GREATER:
981 callRuntime((void*) runtime_cmp_gt_ff);
982 break;
983 case OP_GREATER_EQUAL:
984 callRuntime((void*) runtime_cmp_ge_ff);
985 break;
986 case OP_LESS:
987 callRuntime((void*) runtime_cmp_lt_ff);
988 break;
989 default:
990 error("Unknown comparison op %d", op);
991 break;
992 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700993#endif
Jack Palevich8de461d2009-05-14 17:21:45 -0700994 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700995 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700996 }
997
Jack Palevich546b2242009-05-13 15:10:04 -0700998 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700999 Type* pR0Type = getR0Type();
1000 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001001 TypeTag tagR0 = pR0Type->tag;
1002 TypeTag tagTOS = pTOSType->tag;
1003 bool isFloatR0 = isFloatTag(tagR0);
1004 bool isFloatTOS = isFloatTag(tagTOS);
1005 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001006 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001007 bool isPtrR0 = isPointerTag(tagR0);
1008 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001009 if (isPtrR0 || isPtrTOS) {
1010 if (isPtrR0 && isPtrTOS) {
1011 if (op != OP_MINUS) {
1012 error("Unsupported pointer-pointer operation %d.", op);
1013 }
1014 if (! typeEqual(pR0Type, pTOSType)) {
1015 error("Incompatible pointer types for subtraction.");
1016 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001017 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001018 setR0Type(mkpInt);
1019 int size = sizeOf(pR0Type->pHead);
1020 if (size != 1) {
1021 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001022 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001023 // TODO: Optimize for power-of-two.
1024 genOp(OP_DIV);
1025 }
1026 } else {
1027 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1028 error("Unsupported pointer-scalar operation %d", op);
1029 }
Jack Palevichb6154502009-08-04 14:56:09 -07001030 Type* pPtrType = getPointerArithmeticResultType(
1031 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001032 int size = sizeOf(pPtrType->pHead);
1033 if (size != 1) {
1034 // TODO: Optimize for power-of-two.
1035 liReg(size, 2);
1036 if (isPtrR0) {
1037 o4(0x0E0010192); // mul r1,r2,r1
1038 } else {
1039 o4(0x0E0000092); // mul r0,r2,r0
1040 }
1041 }
1042 switch(op) {
1043 case OP_PLUS:
1044 o4(0xE0810000); // add r0,r1,r0
1045 break;
1046 case OP_MINUS:
1047 o4(0xE0410000); // sub r0,r1,r0
1048 break;
1049 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001050 setR0Type(pPtrType);
1051 }
1052 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001053 switch(op) {
1054 case OP_MUL:
1055 o4(0x0E0000091); // mul r0,r1,r0
1056 break;
1057 case OP_DIV:
1058 callRuntime((void*) runtime_DIV);
1059 break;
1060 case OP_MOD:
1061 callRuntime((void*) runtime_MOD);
1062 break;
1063 case OP_PLUS:
1064 o4(0xE0810000); // add r0,r1,r0
1065 break;
1066 case OP_MINUS:
1067 o4(0xE0410000); // sub r0,r1,r0
1068 break;
1069 case OP_SHIFT_LEFT:
1070 o4(0xE1A00011); // lsl r0,r1,r0
1071 break;
1072 case OP_SHIFT_RIGHT:
1073 o4(0xE1A00051); // asr r0,r1,r0
1074 break;
1075 case OP_BIT_AND:
1076 o4(0xE0010000); // and r0,r1,r0
1077 break;
1078 case OP_BIT_XOR:
1079 o4(0xE0210000); // eor r0,r1,r0
1080 break;
1081 case OP_BIT_OR:
1082 o4(0xE1810000); // orr r0,r1,r0
1083 break;
1084 case OP_BIT_NOT:
1085 o4(0xE1E00000); // mvn r0, r0
1086 break;
1087 default:
1088 error("Unimplemented op %d\n", op);
1089 break;
1090 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001091 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001092 } else {
1093 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1094 if (pResultType->tag == TY_DOUBLE) {
1095 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001096
Jack Palevichb7718b92009-07-09 22:00:24 -07001097 switch(op) {
1098 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001099#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001100 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001101#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001102 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001103#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 break;
1105 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001106#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001107 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001108#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001109 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001110#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001111 break;
1112 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001113#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001114 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001115#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001116 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001117#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001118 break;
1119 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001120#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001121 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001122#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001123 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001124#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001125 break;
1126 default:
1127 error("Unsupported binary floating operation %d\n", op);
1128 break;
1129 }
1130 } else {
1131 setupFloatArgs();
1132 switch(op) {
1133 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001134#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001135 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001136#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001137 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001138#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001139 break;
1140 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001141#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001142 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001143#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001144 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001145#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001146 break;
1147 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001148#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001149 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001150#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001151 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001152#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001153 break;
1154 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001155#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001156 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001157#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001158 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001159#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001160 break;
1161 default:
1162 error("Unsupported binary floating operation %d\n", op);
1163 break;
1164 }
1165 }
1166 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001167 }
Jack Palevich22305132009-05-13 10:58:45 -07001168 }
1169
Jack Palevich58c30ee2009-07-17 16:35:23 -07001170 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001171 if (op != OP_LOGICAL_NOT) {
1172 error("Unknown unary cmp %d", op);
1173 } else {
1174 Type* pR0Type = getR0Type();
1175 TypeTag tag = collapseType(pR0Type->tag);
1176 switch(tag) {
1177 case TY_INT:
1178 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001179 o4(0xE1510000); // cmp r1, r0
1180 o4(0x03A00001); // moveq r0,#1
1181 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001182 break;
1183 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001184#ifdef ARM_USE_VFP
1185 o4(0xEEF57A40); // fcmpzs s15
1186 o4(0xEEF1FA10); // fmstat
1187 o4(0x03A00001); // moveq r0,#1
1188 o4(0x13A00000); // movne r0,#0
1189#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001190 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001191#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001192 break;
1193 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001194#ifdef ARM_USE_VFP
1195 o4(0xEEB57B40); // fcmpzd d7
1196 o4(0xEEF1FA10); // fmstat
1197 o4(0x03A00001); // moveq r0,#1
1198 o4(0x13A00000); // movne r0,#0
1199#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001200 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001201#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001202 break;
1203 default:
1204 error("gUnaryCmp unsupported type");
1205 break;
1206 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001207 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001208 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001209 }
1210
1211 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001212 Type* pR0Type = getR0Type();
1213 TypeTag tag = collapseType(pR0Type->tag);
1214 switch(tag) {
1215 case TY_INT:
1216 switch(op) {
1217 case OP_MINUS:
1218 o4(0xE3A01000); // mov r1, #0
1219 o4(0xE0410000); // sub r0,r1,r0
1220 break;
1221 case OP_BIT_NOT:
1222 o4(0xE1E00000); // mvn r0, r0
1223 break;
1224 default:
1225 error("Unknown unary op %d\n", op);
1226 break;
1227 }
1228 break;
1229 case TY_FLOAT:
1230 case TY_DOUBLE:
1231 switch (op) {
1232 case OP_MINUS:
1233 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001234#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001235 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001236#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001237 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001238#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001239 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001240#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001241 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001242#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001243 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001244#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001245 }
1246 break;
1247 case OP_BIT_NOT:
1248 error("Can't apply '~' operator to a float or double.");
1249 break;
1250 default:
1251 error("Unknown unary op %d\n", op);
1252 break;
1253 }
1254 break;
1255 default:
1256 error("genUnaryOp unsupported type");
1257 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001258 }
Jack Palevich22305132009-05-13 10:58:45 -07001259 }
1260
Jack Palevich1cdef202009-05-22 12:06:27 -07001261 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001262 Type* pR0Type = getR0Type();
1263 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001264
1265#ifdef ARM_USE_VFP
1266 switch (r0ct ) {
1267 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001268 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001269 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001270 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001271 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001272 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001273 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001274 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001275 default:
1276 o4(0xE92D0001); // stmfd sp!,{r0}
1277 mStackUse += 4;
1278 }
1279#else
1280
Jack Palevichb7718b92009-07-09 22:00:24 -07001281 if (r0ct != TY_DOUBLE) {
1282 o4(0xE92D0001); // stmfd sp!,{r0}
1283 mStackUse += 4;
1284 } else {
1285 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1286 mStackUse += 8;
1287 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001288#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001289 pushType();
-b master422972c2009-06-17 19:13:52 -07001290 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001291 }
1292
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001293 virtual void over() {
1294 // We know it's only used for int-ptr ops (++/--)
1295
1296 Type* pR0Type = getR0Type();
1297 TypeTag r0ct = collapseType(pR0Type->tag);
1298
1299 Type* pTOSType = getTOSType();
1300 TypeTag tosct = collapseType(pTOSType->tag);
1301
1302 assert (r0ct == TY_INT && tosct == TY_INT);
1303
1304 o4(0xE8BD0002); // ldmfd sp!,{r1}
1305 o4(0xE92D0001); // stmfd sp!,{r0}
1306 o4(0xE92D0002); // stmfd sp!,{r1}
1307 overType();
1308 mStackUse += 4;
1309 }
1310
Jack Palevich58c30ee2009-07-17 16:35:23 -07001311 virtual void popR0() {
1312 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001313 TypeTag tosct = collapseType(pTOSType->tag);
1314#ifdef ARM_USE_VFP
1315 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001316 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001317 }
1318#endif
1319 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001320 case TY_INT:
1321 case TY_FLOAT:
1322 o4(0xE8BD0001); // ldmfd sp!,{r0}
1323 mStackUse -= 4;
1324 break;
1325 case TY_DOUBLE:
1326 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1327 mStackUse -= 8;
1328 break;
1329 default:
1330 error("Can't pop this type.");
1331 break;
1332 }
1333 popType();
1334 LOG_STACK("popR0: %d\n", mStackUse);
1335 }
1336
1337 virtual void storeR0ToTOS() {
1338 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001339 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001340 Type* pDestType = pPointerType->pHead;
1341 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001342 o4(0xE8BD0004); // ldmfd sp!,{r2}
1343 popType();
-b master422972c2009-06-17 19:13:52 -07001344 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001345 switch (pDestType->tag) {
1346 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001347 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001348 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001349 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001350 case TY_FLOAT:
1351#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001352 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001353#else
1354 o4(0xE5820000); // str r0, [r2]
1355#endif
1356 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001357 case TY_SHORT:
1358 o4(0xE1C200B0); // strh r0, [r2]
1359 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001360 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001361 o4(0xE5C20000); // strb r0, [r2]
1362 break;
1363 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001364#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001365 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001366#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001367 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001368#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001369 break;
1370 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001371 error("storeR0ToTOS: unimplemented type %d",
1372 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001373 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001374 }
Jack Palevich22305132009-05-13 10:58:45 -07001375 }
1376
Jack Palevich58c30ee2009-07-17 16:35:23 -07001377 virtual void loadR0FromR0() {
1378 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001379 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001380 Type* pNewType = pPointerType->pHead;
1381 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001382 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001383 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001384 case TY_INT:
1385 o4(0xE5900000); // ldr r0, [r0]
1386 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001387 case TY_FLOAT:
1388#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001389 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001390#else
1391 o4(0xE5900000); // ldr r0, [r0]
1392#endif
1393 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001394 case TY_SHORT:
1395 o4(0xE1D000F0); // ldrsh r0, [r0]
1396 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001397 case TY_CHAR:
1398 o4(0xE5D00000); // ldrb r0, [r0]
1399 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001400 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001401#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001402 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001403#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001404 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001405#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001406 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001407 case TY_ARRAY:
1408 pNewType = pNewType->pTail;
1409 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001410 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001411 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001412 break;
1413 }
Jack Palevich80e49722009-08-04 15:39:49 -07001414 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001415 }
1416
Jack Palevichb5e33312009-07-30 19:06:34 -07001417 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001418 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001419 // Local, fp relative
1420 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1421 error("Offset out of range: %08x", ea);
1422 }
1423 if (ea < 0) {
1424 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1425 } else {
1426 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1427 }
Jack Palevichbd894902009-05-14 19:35:31 -07001428 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001429 // Global, absolute.
1430 o4(0xE59F0000); // ldr r0, .L1
1431 o4(0xEA000000); // b .L99
1432 o4(ea); // .L1: .word 0
1433 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001434 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001435 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001436 }
1437
Jack Palevich9f51a262009-07-29 16:22:26 -07001438 virtual int leaForward(int ea, Type* pPointerType) {
1439 setR0Type(pPointerType);
1440 int result = ea;
1441 int pc = getPC();
1442 int offset = 0;
1443 if (ea) {
1444 offset = (pc - ea - 8) >> 2;
1445 if ((offset & 0xffff) != offset) {
1446 error("function forward reference out of bounds");
1447 }
1448 } else {
1449 offset = 0;
1450 }
1451 o4(0xE59F0000 | offset); // ldr r0, .L1
1452
1453 if (ea == 0) {
1454 o4(0xEA000000); // b .L99
1455 result = o4(ea); // .L1: .word 0
1456 // .L99:
1457 }
1458 return result;
1459 }
1460
Jack Palevichb6154502009-08-04 14:56:09 -07001461 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001462 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001463 if (isPointerType(pType) && isPointerType(pR0Type)) {
1464 Type* pA = pR0Type;
1465 Type* pB = pType;
1466 // Array decays to pointer
1467 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1468 pA = pA->pTail;
1469 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001470 if (! (typeEqual(pA, pB)
1471 || pB->pHead->tag == TY_VOID
1472 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1473 )) {
1474 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001475 }
Jack Palevichb6154502009-08-04 14:56:09 -07001476 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001477 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001478 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001479 TypeTag r0Tag = collapseType(pR0Type->tag);
1480 TypeTag destTag = collapseType(pType->tag);
1481 if (r0Tag == TY_INT) {
1482 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001483#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001484 o4(0xEE070A90); // fmsr s15, r0
1485 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001486
1487#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001488 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001489#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001490 } else {
1491 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001492#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001493 o4(0xEE070A90); // fmsr s15, r0
1494 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001495
1496#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001497 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001498#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001499 }
1500 } else if (r0Tag == TY_FLOAT) {
1501 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001502#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001503 o4(0xEEFD7AE7); // ftosizs s15, s15
1504 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001505#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001506 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001507#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001508 } else {
1509 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001510#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001511 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001512#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001513 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001514#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001515 }
1516 } else {
1517 assert (r0Tag == TY_DOUBLE);
1518 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001519#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001520 o4(0xEEFD7BC7); // ftosizd s15, d7
1521 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001522#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001523 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001524#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001525 } else {
1526 assert(destTag == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001527#ifdef ARM_USE_VFP
1528 o4(0xEEF77BC7); // fcvtsd s15, d7
1529#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001530 callRuntime((void*) runtime_double_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001531#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001532 }
1533 }
Jack Palevich8df46192009-07-07 14:48:51 -07001534 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001535 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001536 }
1537
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001538 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001539 return o4(0xE24DDF00); // Placeholder
1540 }
1541
Jack Palevich8148c5b2009-07-16 18:24:47 -07001542 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001543 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001544 Type* pR0Type = getR0Type();
1545 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001546#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 switch(r0ct) {
1548 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001549 if (l < 0 || l > 4096-4) {
1550 error("l out of range for stack offset: 0x%08x", l);
1551 }
1552 o4(0xE58D0000 | l); // str r0, [sp, #l]
1553 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001554 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001555 if (l < 0 || l > 1020 || (l & 3)) {
1556 error("l out of range for stack offset: 0x%08x", l);
1557 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001558 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001559 return 4;
1560 case TY_DOUBLE: {
1561 // Align to 8 byte boundary
1562 int l2 = (l + 7) & ~7;
1563 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1564 error("l out of range for stack offset: 0x%08x", l);
1565 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001566 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001567 return (l2 - l) + 8;
1568 }
1569 default:
1570 assert(false);
1571 return 0;
1572 }
1573#else
1574 switch(r0ct) {
1575 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001576 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001577 if (l < 0 || l > 4096-4) {
1578 error("l out of range for stack offset: 0x%08x", l);
1579 }
1580 o4(0xE58D0000 + l); // str r0, [sp, #l]
1581 return 4;
1582 case TY_DOUBLE: {
1583 // Align to 8 byte boundary
1584 int l2 = (l + 7) & ~7;
1585 if (l2 < 0 || l2 > 4096-8) {
1586 error("l out of range for stack offset: 0x%08x", l);
1587 }
1588 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1589 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1590 return (l2 - l) + 8;
1591 }
1592 default:
1593 assert(false);
1594 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001595 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001596#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001597 }
1598
Jack Palevichb7718b92009-07-09 22:00:24 -07001599 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001600 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001601 // Have to calculate register arg count from actual stack size,
1602 // in order to properly handle ... functions.
1603 int regArgCount = l >> 2;
1604 if (regArgCount > 4) {
1605 regArgCount = 4;
1606 }
1607 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001608 argumentStackUse -= regArgCount * 4;
1609 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1610 }
1611 mStackUse += argumentStackUse;
1612
1613 // Align stack.
1614 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1615 * STACK_ALIGNMENT);
1616 mStackAlignmentAdjustment = 0;
1617 if (missalignment > 0) {
1618 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1619 }
1620 l += mStackAlignmentAdjustment;
1621
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001622 if (l < 0 || l > 0x3FC) {
1623 error("L out of range for stack adjustment: 0x%08x", l);
1624 }
1625 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001626 mStackUse += mStackAlignmentAdjustment;
1627 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1628 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001629 }
1630
Jack Palevich8df46192009-07-07 14:48:51 -07001631 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001632 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001633 // Forward calls are always short (local)
1634 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001635 }
1636
Jack Palevich8df46192009-07-07 14:48:51 -07001637 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001638 assert(pFunc->tag == TY_FUNC);
1639 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001640 int argCount = l >> 2;
1641 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001642 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001643 if (adjustedL < 0 || adjustedL > 4096-4) {
1644 error("l out of range for stack offset: 0x%08x", l);
1645 }
1646 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1647 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001648 Type* pReturnType = pFunc->pHead;
1649 setR0Type(pReturnType);
1650#ifdef ARM_USE_VFP
1651 switch(pReturnType->tag) {
1652 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001653 o4(0xEE070A90); // fmsr s15, r0
1654 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001655 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001656 o4(0xEC410B17); // fmdrr d7, r0, r1
1657 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001658 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001659 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001660 }
1661#endif
Jack Palevich22305132009-05-13 10:58:45 -07001662 }
1663
Jack Palevichb7718b92009-07-09 22:00:24 -07001664 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001665 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001666 // Have to calculate register arg count from actual stack size,
1667 // in order to properly handle ... functions.
1668 int regArgCount = l >> 2;
1669 if (regArgCount > 4) {
1670 regArgCount = 4;
1671 }
1672 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001673 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1674 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001675 if (stackUse) {
1676 if (stackUse < 0 || stackUse > 255) {
1677 error("L out of range for stack adjustment: 0x%08x", l);
1678 }
1679 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001680 mStackUse -= stackUse * 4;
1681 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001682 }
Jack Palevich22305132009-05-13 10:58:45 -07001683 }
1684
Jack Palevicha6535612009-05-13 16:24:17 -07001685 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001686 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001687 }
1688
1689 /* output a symbol and patch all calls to it */
1690 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001691 int n;
1692 int base = getBase();
1693 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001694 while (t) {
1695 int data = * (int*) t;
1696 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1697 if (decodedOffset == 0) {
1698 n = 0;
1699 } else {
1700 n = base + decodedOffset; /* next value */
1701 }
1702 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1703 | encodeRelAddress(pc - t - 8);
1704 t = n;
1705 }
1706 }
1707
Jack Palevich9f51a262009-07-29 16:22:26 -07001708 /* output a symbol and patch all calls to it */
1709 virtual void resolveForward(int t) {
1710 if (t) {
1711 int pc = getPC();
1712 *(int *) t = pc;
1713 }
1714 }
1715
Jack Palevich1cdef202009-05-22 12:06:27 -07001716 virtual int finishCompile() {
1717#if defined(__arm__)
1718 const long base = long(getBase());
1719 const long curr = long(getPC());
1720 int err = cacheflush(base, curr, 0);
1721 return err;
1722#else
1723 return 0;
1724#endif
1725 }
1726
Jack Palevicha6535612009-05-13 16:24:17 -07001727 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001728#ifdef ENABLE_ARM_DISASSEMBLY
1729 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001730 disasm_interface_t di;
1731 di.di_readword = disassemble_readword;
1732 di.di_printaddr = disassemble_printaddr;
1733 di.di_printf = disassemble_printf;
1734
1735 int base = getBase();
1736 int pc = getPC();
1737 for(int i = base; i < pc; i += 4) {
1738 fprintf(out, "%08x: %08x ", i, *(int*) i);
1739 ::disasm(&di, i, 0);
1740 }
Jack Palevich09555c72009-05-27 12:25:55 -07001741#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001742 return 0;
1743 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001744
Jack Palevich9eed7a22009-07-06 17:24:34 -07001745 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001746 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001747 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001748 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001749 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001750 case TY_CHAR:
1751 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001752 case TY_SHORT:
1753 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001754 case TY_DOUBLE:
1755 return 8;
1756 default:
1757 return 4;
1758 }
1759 }
1760
1761 /**
1762 * Array element alignment (in bytes) for this type of data.
1763 */
1764 virtual size_t sizeOf(Type* pType){
1765 switch(pType->tag) {
1766 case TY_INT:
1767 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001768 case TY_SHORT:
1769 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001770 case TY_CHAR:
1771 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001772 case TY_FLOAT:
1773 return 4;
1774 case TY_DOUBLE:
1775 return 8;
1776 case TY_POINTER:
1777 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001778 case TY_ARRAY:
1779 return pType->length * sizeOf(pType->pHead);
1780 default:
1781 error("Unsupported type %d", pType->tag);
1782 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001783 }
1784 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001785
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001786 virtual size_t stackAlignmentOf(Type* pType) {
1787 switch(pType->tag) {
1788 case TY_DOUBLE:
1789 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001790 case TY_ARRAY:
1791 return stackAlignmentOf(pType->pHead);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001792 default:
1793 return 4;
1794 }
1795 }
1796
Jack Palevich9cbd2262009-07-08 16:48:41 -07001797 virtual size_t stackSizeOf(Type* pType) {
1798 switch(pType->tag) {
1799 case TY_DOUBLE:
1800 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001801 case TY_ARRAY:
1802 return sizeOf(pType);
1803 case TY_FUNC:
1804 error("stackSizeOf func not supported");
1805 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001806 default:
1807 return 4;
1808 }
1809 }
1810
Jack Palevich22305132009-05-13 10:58:45 -07001811 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001812 static FILE* disasmOut;
1813
1814 static u_int
1815 disassemble_readword(u_int address)
1816 {
1817 return(*((u_int *)address));
1818 }
1819
1820 static void
1821 disassemble_printaddr(u_int address)
1822 {
1823 fprintf(disasmOut, "0x%08x", address);
1824 }
1825
1826 static void
1827 disassemble_printf(const char *fmt, ...) {
1828 va_list ap;
1829 va_start(ap, fmt);
1830 vfprintf(disasmOut, fmt, ap);
1831 va_end(ap);
1832 }
1833
1834 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1835
1836 /** Encode a relative address that might also be
1837 * a label.
1838 */
1839 int encodeAddress(int value) {
1840 int base = getBase();
1841 if (value >= base && value <= getPC() ) {
1842 // This is a label, encode it relative to the base.
1843 value = value - base;
1844 }
1845 return encodeRelAddress(value);
1846 }
1847
1848 int encodeRelAddress(int value) {
1849 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1850 }
Jack Palevich22305132009-05-13 10:58:45 -07001851
Jack Palevichb7718b92009-07-09 22:00:24 -07001852 int calcRegArgCount(Type* pDecl) {
1853 int reg = 0;
1854 Type* pArgs = pDecl->pTail;
1855 while (pArgs && reg < 4) {
1856 Type* pArg = pArgs->pHead;
1857 if ( pArg->tag == TY_DOUBLE) {
1858 int evenReg = (reg + 1) & ~1;
1859 if (evenReg >= 4) {
1860 break;
1861 }
1862 reg = evenReg + 2;
1863 } else {
1864 reg++;
1865 }
1866 pArgs = pArgs->pTail;
1867 }
1868 return reg;
1869 }
1870
Jack Palevich58c30ee2009-07-17 16:35:23 -07001871 void setupIntPtrArgs() {
1872 o4(0xE8BD0002); // ldmfd sp!,{r1}
1873 mStackUse -= 4;
1874 popType();
1875 }
1876
Jack Palevich30321cb2009-08-20 15:34:23 -07001877 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001878 * Make sure both R0 and TOS are floats. (Could be ints)
1879 * We know that at least one of R0 and TOS is already a float
1880 */
1881 void setupFloatArgs() {
1882 Type* pR0Type = getR0Type();
1883 Type* pTOSType = getTOSType();
1884 TypeTag tagR0 = collapseType(pR0Type->tag);
1885 TypeTag tagTOS = collapseType(pTOSType->tag);
1886 if (tagR0 != TY_FLOAT) {
1887 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001888#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001889 o4(0xEE070A90); // fmsr s15, r0
1890 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001891#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001892 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001893#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001894 }
1895 if (tagTOS != TY_FLOAT) {
1896 assert(tagTOS == TY_INT);
1897 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001898#ifdef ARM_USE_VFP
1899 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07001900 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07001901#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001902 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1903 o4(0xE59D0004); // ldr r0, [sp, #4]
1904 callRuntime((void*) runtime_int_to_float);
1905 o4(0xE1A01000); // mov r1, r0
1906 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1907 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001908#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001909 } else {
1910 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001911#ifdef ARM_USE_VFP
1912 o4(0xECBD7A01); // fldmfds sp!, {s14}
1913
1914#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001915 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001916#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001917 }
1918 mStackUse -= 4;
1919 popType();
1920 }
1921
Jack Palevich30321cb2009-08-20 15:34:23 -07001922 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001923 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1924 * We know that at least one of R0 and TOS are already a double.
1925 */
1926
1927 void setupDoubleArgs() {
1928 Type* pR0Type = getR0Type();
1929 Type* pTOSType = getTOSType();
1930 TypeTag tagR0 = collapseType(pR0Type->tag);
1931 TypeTag tagTOS = collapseType(pTOSType->tag);
1932 if (tagR0 != TY_DOUBLE) {
1933 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001934#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001935 o4(0xEE070A90); // fmsr s15, r0
1936 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001937
1938#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001939 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001940#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001941 } else {
1942 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001943#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001944 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001945#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001946 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001947#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001948 }
1949 }
1950 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001951#ifdef ARM_USE_VFP
1952 if (tagTOS == TY_INT) {
1953 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001954 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001955 } else {
1956 assert(tagTOS == TY_FLOAT);
1957 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001958 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001959 }
1960#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001961 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1962 o4(0xE59D0008); // ldr r0, [sp, #8]
1963 if (tagTOS == TY_INT) {
1964 callRuntime((void*) runtime_int_to_double);
1965 } else {
1966 assert(tagTOS == TY_FLOAT);
1967 callRuntime((void*) runtime_float_to_double);
1968 }
1969 o4(0xE1A02000); // mov r2, r0
1970 o4(0xE1A03001); // mov r3, r1
1971 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1972 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001973#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001974 mStackUse -= 4;
1975 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001976#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001977 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07001978#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001979 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07001980#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001981 mStackUse -= 8;
1982 }
1983 popType();
1984 }
1985
Jack Palevicha8f427f2009-07-13 18:40:08 -07001986 void liReg(int t, int reg) {
1987 assert(reg >= 0 && reg < 16);
1988 int rN = (reg & 0xf) << 12;
1989 if (t >= 0 && t < 255) {
1990 o4((0xE3A00000 + t) | rN); // mov rN, #0
1991 } else if (t >= -256 && t < 0) {
1992 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001993 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001994 } else {
1995 o4(0xE51F0000 | rN); // ldr rN, .L3
1996 o4(0xEA000000); // b .L99
1997 o4(t); // .L3: .word 0
1998 // .L99:
1999 }
2000 }
2001
Jack Palevichb7718b92009-07-09 22:00:24 -07002002 void callRuntime(void* fn) {
2003 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002004 o4(0xEA000000); // b .L99
2005 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002006 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002007 }
2008
Jack Palevichb7718b92009-07-09 22:00:24 -07002009 // Integer math:
2010
2011 static int runtime_DIV(int b, int a) {
2012 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002013 }
2014
Jack Palevichb7718b92009-07-09 22:00:24 -07002015 static int runtime_MOD(int b, int a) {
2016 return a % b;
2017 }
2018
Jack Palevich30321cb2009-08-20 15:34:23 -07002019#ifndef ARM_USE_VFP
2020
Jack Palevichb7718b92009-07-09 22:00:24 -07002021 // Comparison to zero
2022
2023 static int runtime_is_non_zero_f(float a) {
2024 return a != 0;
2025 }
2026
2027 static int runtime_is_non_zero_d(double a) {
2028 return a != 0;
2029 }
2030
2031 // Comparison to zero
2032
2033 static int runtime_is_zero_f(float a) {
2034 return a == 0;
2035 }
2036
2037 static int runtime_is_zero_d(double a) {
2038 return a == 0;
2039 }
2040
2041 // Type conversion
2042
2043 static int runtime_float_to_int(float a) {
2044 return (int) a;
2045 }
2046
2047 static double runtime_float_to_double(float a) {
2048 return (double) a;
2049 }
2050
2051 static int runtime_double_to_int(double a) {
2052 return (int) a;
2053 }
2054
2055 static float runtime_double_to_float(double a) {
2056 return (float) a;
2057 }
2058
2059 static float runtime_int_to_float(int a) {
2060 return (float) a;
2061 }
2062
2063 static double runtime_int_to_double(int a) {
2064 return (double) a;
2065 }
2066
2067 // Comparisons float
2068
2069 static int runtime_cmp_eq_ff(float b, float a) {
2070 return a == b;
2071 }
2072
2073 static int runtime_cmp_ne_ff(float b, float a) {
2074 return a != b;
2075 }
2076
2077 static int runtime_cmp_lt_ff(float b, float a) {
2078 return a < b;
2079 }
2080
2081 static int runtime_cmp_le_ff(float b, float a) {
2082 return a <= b;
2083 }
2084
2085 static int runtime_cmp_ge_ff(float b, float a) {
2086 return a >= b;
2087 }
2088
2089 static int runtime_cmp_gt_ff(float b, float a) {
2090 return a > b;
2091 }
2092
2093 // Comparisons double
2094
2095 static int runtime_cmp_eq_dd(double b, double a) {
2096 return a == b;
2097 }
2098
2099 static int runtime_cmp_ne_dd(double b, double a) {
2100 return a != b;
2101 }
2102
2103 static int runtime_cmp_lt_dd(double b, double a) {
2104 return a < b;
2105 }
2106
2107 static int runtime_cmp_le_dd(double b, double a) {
2108 return a <= b;
2109 }
2110
2111 static int runtime_cmp_ge_dd(double b, double a) {
2112 return a >= b;
2113 }
2114
2115 static int runtime_cmp_gt_dd(double b, double a) {
2116 return a > b;
2117 }
2118
2119 // Math float
2120
2121 static float runtime_op_add_ff(float b, float a) {
2122 return a + b;
2123 }
2124
2125 static float runtime_op_sub_ff(float b, float a) {
2126 return a - b;
2127 }
2128
2129 static float runtime_op_mul_ff(float b, float a) {
2130 return a * b;
2131 }
2132
2133 static float runtime_op_div_ff(float b, float a) {
2134 return a / b;
2135 }
2136
2137 static float runtime_op_neg_f(float a) {
2138 return -a;
2139 }
2140
2141 // Math double
2142
2143 static double runtime_op_add_dd(double b, double a) {
2144 return a + b;
2145 }
2146
2147 static double runtime_op_sub_dd(double b, double a) {
2148 return a - b;
2149 }
2150
2151 static double runtime_op_mul_dd(double b, double a) {
2152 return a * b;
2153 }
2154
2155 static double runtime_op_div_dd(double b, double a) {
2156 return a / b;
2157 }
2158
2159 static double runtime_op_neg_d(double a) {
2160 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002161 }
-b master422972c2009-06-17 19:13:52 -07002162
Jack Palevich30321cb2009-08-20 15:34:23 -07002163#endif
2164
-b master422972c2009-06-17 19:13:52 -07002165 static const int STACK_ALIGNMENT = 8;
2166 int mStackUse;
2167 // This variable holds the amount we adjusted the stack in the most
2168 // recent endFunctionCallArguments call. It's examined by the
2169 // following adjustStackAfterCall call.
2170 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002171 };
2172
Jack Palevich09555c72009-05-27 12:25:55 -07002173#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002174
2175#ifdef PROVIDE_X86_CODEGEN
2176
Jack Palevich21a15a22009-05-11 14:49:29 -07002177 class X86CodeGenerator : public CodeGenerator {
2178 public:
2179 X86CodeGenerator() {}
2180 virtual ~X86CodeGenerator() {}
2181
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002182 /* returns address to patch with local variable size
2183 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002184 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002185 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2186 return oad(0xec81, 0); /* sub $xxx, %esp */
2187 }
2188
Jack Palevichb7718b92009-07-09 22:00:24 -07002189 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002190 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002191 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002192 }
2193
Jack Palevich21a15a22009-05-11 14:49:29 -07002194 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002195 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002196 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002197 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002198 }
2199
Jack Palevich1a539db2009-07-08 13:04:41 -07002200 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002201 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002202 switch (pType->tag) {
2203 case TY_FLOAT:
2204 oad(0x05D9, address); // flds
2205 break;
2206 case TY_DOUBLE:
2207 oad(0x05DD, address); // fldl
2208 break;
2209 default:
2210 assert(false);
2211 break;
2212 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002213 }
2214
Jack Palevich22305132009-05-13 10:58:45 -07002215 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002216 return psym(0xe9, t);
2217 }
2218
2219 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002220 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002221 Type* pR0Type = getR0Type();
2222 TypeTag tagR0 = pR0Type->tag;
2223 bool isFloatR0 = isFloatTag(tagR0);
2224 if (isFloatR0) {
2225 o(0xeed9); // fldz
2226 o(0xe9da); // fucompp
2227 o(0xe0df); // fnstsw %ax
2228 o(0x9e); // sahf
2229 } else {
2230 o(0xc085); // test %eax, %eax
2231 }
2232 // Use two output statements to generate one instruction.
2233 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002234 return psym(0x84 + l, t);
2235 }
2236
Jack Palevich58c30ee2009-07-17 16:35:23 -07002237 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002238 Type* pR0Type = getR0Type();
2239 Type* pTOSType = getTOSType();
2240 TypeTag tagR0 = pR0Type->tag;
2241 TypeTag tagTOS = pTOSType->tag;
2242 bool isFloatR0 = isFloatTag(tagR0);
2243 bool isFloatTOS = isFloatTag(tagTOS);
2244 if (!isFloatR0 && !isFloatTOS) {
2245 int t = decodeOp(op);
2246 o(0x59); /* pop %ecx */
2247 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002248 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002249 o(0x0f); /* setxx %al */
2250 o(t + 0x90);
2251 o(0xc0);
2252 popType();
2253 } else {
2254 setupFloatOperands();
2255 switch (op) {
2256 case OP_EQUALS:
2257 o(0xe9da); // fucompp
2258 o(0xe0df); // fnstsw %ax
2259 o(0x9e); // sahf
2260 o(0xc0940f); // sete %al
2261 o(0xc29b0f); // setnp %dl
2262 o(0xd021); // andl %edx, %eax
2263 break;
2264 case OP_NOT_EQUALS:
2265 o(0xe9da); // fucompp
2266 o(0xe0df); // fnstsw %ax
2267 o(0x9e); // sahf
2268 o(0xc0950f); // setne %al
2269 o(0xc29a0f); // setp %dl
2270 o(0xd009); // orl %edx, %eax
2271 break;
2272 case OP_GREATER_EQUAL:
2273 o(0xe9da); // fucompp
2274 o(0xe0df); // fnstsw %ax
2275 o(0x05c4f6); // testb $5, %ah
2276 o(0xc0940f); // sete %al
2277 break;
2278 case OP_LESS:
2279 o(0xc9d9); // fxch %st(1)
2280 o(0xe9da); // fucompp
2281 o(0xe0df); // fnstsw %ax
2282 o(0x9e); // sahf
2283 o(0xc0970f); // seta %al
2284 break;
2285 case OP_LESS_EQUAL:
2286 o(0xc9d9); // fxch %st(1)
2287 o(0xe9da); // fucompp
2288 o(0xe0df); // fnstsw %ax
2289 o(0x9e); // sahf
2290 o(0xc0930f); // setea %al
2291 break;
2292 case OP_GREATER:
2293 o(0xe9da); // fucompp
2294 o(0xe0df); // fnstsw %ax
2295 o(0x45c4f6); // testb $69, %ah
2296 o(0xc0940f); // sete %al
2297 break;
2298 default:
2299 error("Unknown comparison op");
2300 }
2301 o(0xc0b60f); // movzbl %al, %eax
2302 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002303 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002304 }
2305
Jack Palevich546b2242009-05-13 15:10:04 -07002306 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002307 Type* pR0Type = getR0Type();
2308 Type* pTOSType = getTOSType();
2309 TypeTag tagR0 = pR0Type->tag;
2310 TypeTag tagTOS = pTOSType->tag;
2311 bool isFloatR0 = isFloatTag(tagR0);
2312 bool isFloatTOS = isFloatTag(tagTOS);
2313 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002314 bool isPtrR0 = isPointerTag(tagR0);
2315 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002316 if (isPtrR0 || isPtrTOS) {
2317 if (isPtrR0 && isPtrTOS) {
2318 if (op != OP_MINUS) {
2319 error("Unsupported pointer-pointer operation %d.", op);
2320 }
2321 if (! typeEqual(pR0Type, pTOSType)) {
2322 error("Incompatible pointer types for subtraction.");
2323 }
2324 o(0x59); /* pop %ecx */
2325 o(decodeOp(op));
2326 popType();
2327 setR0Type(mkpInt);
2328 int size = sizeOf(pR0Type->pHead);
2329 if (size != 1) {
2330 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002331 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002332 // TODO: Optimize for power-of-two.
2333 genOp(OP_DIV);
2334 }
2335 } else {
2336 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2337 error("Unsupported pointer-scalar operation %d", op);
2338 }
Jack Palevichb6154502009-08-04 14:56:09 -07002339 Type* pPtrType = getPointerArithmeticResultType(
2340 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002341 o(0x59); /* pop %ecx */
2342 int size = sizeOf(pPtrType->pHead);
2343 if (size != 1) {
2344 // TODO: Optimize for power-of-two.
2345 if (isPtrR0) {
2346 oad(0xC969, size); // imull $size, %ecx
2347 } else {
2348 oad(0xC069, size); // mul $size, %eax
2349 }
2350 }
2351 o(decodeOp(op));
2352 popType();
2353 setR0Type(pPtrType);
2354 }
2355 } else {
2356 o(0x59); /* pop %ecx */
2357 o(decodeOp(op));
2358 if (op == OP_MOD)
2359 o(0x92); /* xchg %edx, %eax */
2360 popType();
2361 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002362 } else {
2363 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2364 setupFloatOperands();
2365 // Both float. x87 R0 == left hand, x87 R1 == right hand
2366 switch (op) {
2367 case OP_MUL:
2368 o(0xc9de); // fmulp
2369 break;
2370 case OP_DIV:
2371 o(0xf1de); // fdivp
2372 break;
2373 case OP_PLUS:
2374 o(0xc1de); // faddp
2375 break;
2376 case OP_MINUS:
2377 o(0xe1de); // fsubp
2378 break;
2379 default:
2380 error("Unsupported binary floating operation.");
2381 break;
2382 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002383 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002384 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002385 }
2386
Jack Palevich58c30ee2009-07-17 16:35:23 -07002387 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002388 if (op != OP_LOGICAL_NOT) {
2389 error("Unknown unary cmp %d", op);
2390 } else {
2391 Type* pR0Type = getR0Type();
2392 TypeTag tag = collapseType(pR0Type->tag);
2393 switch(tag) {
2394 case TY_INT: {
2395 oad(0xb9, 0); /* movl $0, %ecx */
2396 int t = decodeOp(op);
2397 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002398 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002399 o(0x0f); /* setxx %al */
2400 o(t + 0x90);
2401 o(0xc0);
2402 }
2403 break;
2404 case TY_FLOAT:
2405 case TY_DOUBLE:
2406 o(0xeed9); // fldz
2407 o(0xe9da); // fucompp
2408 o(0xe0df); // fnstsw %ax
2409 o(0x9e); // sahf
2410 o(0xc0950f); // setne %al
2411 o(0xc29a0f); // setp %dl
2412 o(0xd009); // orl %edx, %eax
2413 o(0xc0b60f); // movzbl %al, %eax
2414 o(0x01f083); // xorl $1, %eax
2415 break;
2416 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002417 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002418 break;
2419 }
2420 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002421 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002422 }
2423
2424 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002425 Type* pR0Type = getR0Type();
2426 TypeTag tag = collapseType(pR0Type->tag);
2427 switch(tag) {
2428 case TY_INT:
2429 oad(0xb9, 0); /* movl $0, %ecx */
2430 o(decodeOp(op));
2431 break;
2432 case TY_FLOAT:
2433 case TY_DOUBLE:
2434 switch (op) {
2435 case OP_MINUS:
2436 o(0xe0d9); // fchs
2437 break;
2438 case OP_BIT_NOT:
2439 error("Can't apply '~' operator to a float or double.");
2440 break;
2441 default:
2442 error("Unknown unary op %d\n", op);
2443 break;
2444 }
2445 break;
2446 default:
2447 error("genUnaryOp unsupported type");
2448 break;
2449 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002450 }
2451
Jack Palevich1cdef202009-05-22 12:06:27 -07002452 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002453 Type* pR0Type = getR0Type();
2454 TypeTag r0ct = collapseType(pR0Type->tag);
2455 switch(r0ct) {
2456 case TY_INT:
2457 o(0x50); /* push %eax */
2458 break;
2459 case TY_FLOAT:
2460 o(0x50); /* push %eax */
2461 o(0x241cd9); // fstps 0(%esp)
2462 break;
2463 case TY_DOUBLE:
2464 o(0x50); /* push %eax */
2465 o(0x50); /* push %eax */
2466 o(0x241cdd); // fstpl 0(%esp)
2467 break;
2468 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002469 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002470 break;
2471 }
Jack Palevich8df46192009-07-07 14:48:51 -07002472 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002473 }
2474
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002475 virtual void over() {
2476 // We know it's only used for int-ptr ops (++/--)
2477
2478 Type* pR0Type = getR0Type();
2479 TypeTag r0ct = collapseType(pR0Type->tag);
2480
2481 Type* pTOSType = getTOSType();
2482 TypeTag tosct = collapseType(pTOSType->tag);
2483
2484 assert (r0ct == TY_INT && tosct == TY_INT);
2485
2486 o(0x59); /* pop %ecx */
2487 o(0x50); /* push %eax */
2488 o(0x51); /* push %ecx */
2489
2490 overType();
2491 }
2492
Jack Palevich58c30ee2009-07-17 16:35:23 -07002493 virtual void popR0() {
2494 Type* pR0Type = getR0Type();
2495 TypeTag r0ct = collapseType(pR0Type->tag);
2496 switch(r0ct) {
2497 case TY_INT:
2498 o(0x58); /* popl %eax */
2499 break;
2500 case TY_FLOAT:
2501 o(0x2404d9); // flds (%esp)
2502 o(0x58); /* popl %eax */
2503 break;
2504 case TY_DOUBLE:
2505 o(0x2404dd); // fldl (%esp)
2506 o(0x58); /* popl %eax */
2507 o(0x58); /* popl %eax */
2508 break;
2509 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002510 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002511 break;
2512 }
2513 popType();
2514 }
2515
2516 virtual void storeR0ToTOS() {
2517 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002518 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002519 Type* pTargetType = pPointerType->pHead;
2520 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002521 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002522 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002523 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002524 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002525 case TY_INT:
2526 o(0x0189); /* movl %eax/%al, (%ecx) */
2527 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002528 case TY_SHORT:
2529 o(0x018966); /* movw %ax, (%ecx) */
2530 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002531 case TY_CHAR:
2532 o(0x0188); /* movl %eax/%al, (%ecx) */
2533 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002534 case TY_FLOAT:
2535 o(0x19d9); /* fstps (%ecx) */
2536 break;
2537 case TY_DOUBLE:
2538 o(0x19dd); /* fstpl (%ecx) */
2539 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002540 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002541 error("storeR0ToTOS: unsupported type %d",
2542 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002543 break;
2544 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002545 }
2546
Jack Palevich58c30ee2009-07-17 16:35:23 -07002547 virtual void loadR0FromR0() {
2548 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002549 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002550 Type* pNewType = pPointerType->pHead;
2551 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002552 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002553 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002554 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002555 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002556 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002557 case TY_SHORT:
2558 o(0xbf0f); /* movswl (%eax), %eax */
2559 ob(0);
2560 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002561 case TY_CHAR:
2562 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002563 ob(0); /* add zero in code */
2564 break;
2565 case TY_FLOAT:
2566 o2(0x00d9); // flds (%eax)
2567 break;
2568 case TY_DOUBLE:
2569 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002570 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002571 case TY_ARRAY:
2572 pNewType = pNewType->pTail;
2573 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002574 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002575 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002576 break;
2577 }
Jack Palevich80e49722009-08-04 15:39:49 -07002578 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002579 }
2580
Jack Palevichb5e33312009-07-30 19:06:34 -07002581 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002582 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002583 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002584 }
2585
Jack Palevich9f51a262009-07-29 16:22:26 -07002586 virtual int leaForward(int ea, Type* pPointerType) {
2587 oad(0xb8, ea); /* mov $xx, %eax */
2588 setR0Type(pPointerType);
2589 return getPC() - 4;
2590 }
2591
Jack Palevichb6154502009-08-04 14:56:09 -07002592 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002593 Type* pR0Type = getR0Type();
2594 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002595 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002596 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002597 return;
2598 }
Jack Palevichb6154502009-08-04 14:56:09 -07002599 if (isPointerType(pType) && isPointerType(pR0Type)) {
2600 Type* pA = pR0Type;
2601 Type* pB = pType;
2602 // Array decays to pointer
2603 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2604 pA = pA->pTail;
2605 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002606 if (! (typeEqual(pA, pB)
2607 || pB->pHead->tag == TY_VOID
2608 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2609 )) {
2610 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002611 }
Jack Palevichb6154502009-08-04 14:56:09 -07002612 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002613 // do nothing special
2614 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2615 // do nothing special, both held in same register on x87.
2616 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002617 TypeTag r0Tag = collapseType(pR0Type->tag);
2618 TypeTag destTag = collapseType(pType->tag);
2619 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2620 // Convert R0 from int to float
2621 o(0x50); // push %eax
2622 o(0x2404DB); // fildl 0(%esp)
2623 o(0x58); // pop %eax
2624 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2625 // Convert R0 from float to int. Complicated because
2626 // need to save and restore the rounding mode.
2627 o(0x50); // push %eax
2628 o(0x50); // push %eax
2629 o(0x02247cD9); // fnstcw 2(%esp)
2630 o(0x2444b70f); // movzwl 2(%esp), %eax
2631 o(0x02);
2632 o(0x0cb4); // movb $12, %ah
2633 o(0x24048966); // movw %ax, 0(%esp)
2634 o(0x242cd9); // fldcw 0(%esp)
2635 o(0x04245cdb); // fistpl 4(%esp)
2636 o(0x02246cd9); // fldcw 2(%esp)
2637 o(0x58); // pop %eax
2638 o(0x58); // pop %eax
2639 } else {
2640 error("Incompatible types old: %d new: %d",
2641 pR0Type->tag, pType->tag);
2642 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002643 }
2644 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002645 }
2646
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002647 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002648 return oad(0xec81, 0); /* sub $xxx, %esp */
2649 }
2650
Jack Palevich8148c5b2009-07-16 18:24:47 -07002651 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2652 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002653 Type* pR0Type = getR0Type();
2654 TypeTag r0ct = collapseType(pR0Type->tag);
2655 switch(r0ct) {
2656 case TY_INT:
2657 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2658 return 4;
2659 case TY_FLOAT:
2660 oad(0x249CD9, l); /* fstps xxx(%esp) */
2661 return 4;
2662 case TY_DOUBLE:
2663 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2664 return 8;
2665 default:
2666 assert(false);
2667 return 0;
2668 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002669 }
2670
Jack Palevichb7718b92009-07-09 22:00:24 -07002671 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002672 * (int*) a = l;
2673 }
2674
Jack Palevich8df46192009-07-07 14:48:51 -07002675 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002676 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002677 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002678 return psym(0xe8, symbol); /* call xxx */
2679 }
2680
Jack Palevich8df46192009-07-07 14:48:51 -07002681 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002682 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002683 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002684 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002685 oad(0x2494ff, l); /* call *xxx(%esp) */
2686 }
2687
Jack Palevichb7718b92009-07-09 22:00:24 -07002688 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002689 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002690 if (isIndirect) {
2691 l += 4;
2692 }
-b master422972c2009-06-17 19:13:52 -07002693 if (l > 0) {
2694 oad(0xc481, l); /* add $xxx, %esp */
2695 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002696 }
2697
Jack Palevicha6535612009-05-13 16:24:17 -07002698 virtual int jumpOffset() {
2699 return 5;
2700 }
2701
2702 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002703 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002704 }
2705
Jack Paleviche7b59062009-05-19 17:12:17 -07002706 /* output a symbol and patch all calls to it */
2707 virtual void gsym(int t) {
2708 int n;
2709 int pc = getPC();
2710 while (t) {
2711 n = *(int *) t; /* next value */
2712 *(int *) t = pc - t - 4;
2713 t = n;
2714 }
2715 }
2716
Jack Palevich9f51a262009-07-29 16:22:26 -07002717 /* output a symbol and patch all calls to it, using absolute address */
2718 virtual void resolveForward(int t) {
2719 int n;
2720 int pc = getPC();
2721 while (t) {
2722 n = *(int *) t; /* next value */
2723 *(int *) t = pc;
2724 t = n;
2725 }
2726 }
2727
Jack Palevich1cdef202009-05-22 12:06:27 -07002728 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002729 size_t pagesize = 4096;
2730 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2731 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2732 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2733 if (err) {
2734 error("mprotect() failed: %d", errno);
2735 }
2736 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002737 }
2738
Jack Palevich9eed7a22009-07-06 17:24:34 -07002739 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002740 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002741 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002742 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002743 switch (pType->tag) {
2744 case TY_CHAR:
2745 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002746 case TY_SHORT:
2747 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002748 case TY_ARRAY:
2749 return alignmentOf(pType->pHead);
2750 case TY_FUNC:
2751 error("alignment of func not supported");
2752 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002753 default:
2754 return 4;
2755 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002756 }
2757
2758 /**
2759 * Array element alignment (in bytes) for this type of data.
2760 */
2761 virtual size_t sizeOf(Type* pType){
2762 switch(pType->tag) {
2763 case TY_INT:
2764 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002765 case TY_SHORT:
2766 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002767 case TY_CHAR:
2768 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002769 case TY_FLOAT:
2770 return 4;
2771 case TY_DOUBLE:
2772 return 8;
2773 case TY_POINTER:
2774 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002775 case TY_ARRAY:
2776 return pType->length * sizeOf(pType->pHead);
2777 default:
2778 error("Unsupported type %d", pType->tag);
2779 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002780 }
2781 }
2782
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002783 virtual size_t stackAlignmentOf(Type* pType){
2784 return 4;
2785 }
2786
Jack Palevich9cbd2262009-07-08 16:48:41 -07002787 virtual size_t stackSizeOf(Type* pType) {
2788 switch(pType->tag) {
2789 case TY_DOUBLE:
2790 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07002791 case TY_ARRAY:
2792 return sizeOf(pType);
2793 case TY_FUNC:
2794 error("stackSizeOf func not supported");
2795 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002796 default:
2797 return 4;
2798 }
2799 }
2800
Jack Palevich21a15a22009-05-11 14:49:29 -07002801 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002802
2803 /** Output 1 to 4 bytes.
2804 *
2805 */
2806 void o(int n) {
2807 /* cannot use unsigned, so we must do a hack */
2808 while (n && n != -1) {
2809 ob(n & 0xff);
2810 n = n >> 8;
2811 }
2812 }
2813
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002814 /* Output exactly 2 bytes
2815 */
2816 void o2(int n) {
2817 ob(n & 0xff);
2818 ob(0xff & (n >> 8));
2819 }
2820
Jack Paleviche7b59062009-05-19 17:12:17 -07002821 /* psym is used to put an instruction with a data field which is a
2822 reference to a symbol. It is in fact the same as oad ! */
2823 int psym(int n, int t) {
2824 return oad(n, t);
2825 }
2826
2827 /* instruction + address */
2828 int oad(int n, int t) {
2829 o(n);
2830 int result = getPC();
2831 o4(t);
2832 return result;
2833 }
2834
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002835 static const int operatorHelper[];
2836
2837 int decodeOp(int op) {
2838 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002839 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002840 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002841 }
2842 return operatorHelper[op];
2843 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002844
Jack Palevich546b2242009-05-13 15:10:04 -07002845 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002846 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002847 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002848 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002849
2850 void setupFloatOperands() {
2851 Type* pR0Type = getR0Type();
2852 Type* pTOSType = getTOSType();
2853 TypeTag tagR0 = pR0Type->tag;
2854 TypeTag tagTOS = pTOSType->tag;
2855 bool isFloatR0 = isFloatTag(tagR0);
2856 bool isFloatTOS = isFloatTag(tagTOS);
2857 if (! isFloatR0) {
2858 // Convert R0 from int to float
2859 o(0x50); // push %eax
2860 o(0x2404DB); // fildl 0(%esp)
2861 o(0x58); // pop %eax
2862 }
2863 if (! isFloatTOS){
2864 o(0x2404DB); // fildl 0(%esp);
2865 o(0x58); // pop %eax
2866 } else {
2867 if (tagTOS == TY_FLOAT) {
2868 o(0x2404d9); // flds (%esp)
2869 o(0x58); // pop %eax
2870 } else {
2871 o(0x2404dd); // fldl (%esp)
2872 o(0x58); // pop %eax
2873 o(0x58); // pop %eax
2874 }
2875 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002876 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002877 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002878 };
2879
Jack Paleviche7b59062009-05-19 17:12:17 -07002880#endif // PROVIDE_X86_CODEGEN
2881
Jack Palevichb67b18f2009-06-11 21:12:23 -07002882#ifdef PROVIDE_TRACE_CODEGEN
2883 class TraceCodeGenerator : public CodeGenerator {
2884 private:
2885 CodeGenerator* mpBase;
2886
2887 public:
2888 TraceCodeGenerator(CodeGenerator* pBase) {
2889 mpBase = pBase;
2890 }
2891
2892 virtual ~TraceCodeGenerator() {
2893 delete mpBase;
2894 }
2895
2896 virtual void init(CodeBuf* pCodeBuf) {
2897 mpBase->init(pCodeBuf);
2898 }
2899
2900 void setErrorSink(ErrorSink* pErrorSink) {
2901 mpBase->setErrorSink(pErrorSink);
2902 }
2903
2904 /* returns address to patch with local variable size
2905 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002906 virtual int functionEntry(Type* pDecl) {
2907 int result = mpBase->functionEntry(pDecl);
2908 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002909 return result;
2910 }
2911
Jack Palevichb7718b92009-07-09 22:00:24 -07002912 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2913 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2914 localVariableAddress, localVariableSize);
2915 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002916 }
2917
2918 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002919 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002920 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002921 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002922 }
2923
Jack Palevich1a539db2009-07-08 13:04:41 -07002924 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002925 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002926 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002927 }
2928
Jack Palevichb67b18f2009-06-11 21:12:23 -07002929 virtual int gjmp(int t) {
2930 int result = mpBase->gjmp(t);
2931 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2932 return result;
2933 }
2934
2935 /* l = 0: je, l == 1: jne */
2936 virtual int gtst(bool l, int t) {
2937 int result = mpBase->gtst(l, t);
2938 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2939 return result;
2940 }
2941
Jack Palevich58c30ee2009-07-17 16:35:23 -07002942 virtual void gcmp(int op) {
2943 fprintf(stderr, "gcmp(%d)\n", op);
2944 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002945 }
2946
2947 virtual void genOp(int op) {
2948 fprintf(stderr, "genOp(%d)\n", op);
2949 mpBase->genOp(op);
2950 }
2951
Jack Palevich9eed7a22009-07-06 17:24:34 -07002952
Jack Palevich58c30ee2009-07-17 16:35:23 -07002953 virtual void gUnaryCmp(int op) {
2954 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2955 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002956 }
2957
2958 virtual void genUnaryOp(int op) {
2959 fprintf(stderr, "genUnaryOp(%d)\n", op);
2960 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002961 }
2962
2963 virtual void pushR0() {
2964 fprintf(stderr, "pushR0()\n");
2965 mpBase->pushR0();
2966 }
2967
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002968 virtual void over() {
2969 fprintf(stderr, "over()\n");
2970 mpBase->over();
2971 }
2972
Jack Palevich58c30ee2009-07-17 16:35:23 -07002973 virtual void popR0() {
2974 fprintf(stderr, "popR0()\n");
2975 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002976 }
2977
Jack Palevich58c30ee2009-07-17 16:35:23 -07002978 virtual void storeR0ToTOS() {
2979 fprintf(stderr, "storeR0ToTOS()\n");
2980 mpBase->storeR0ToTOS();
2981 }
2982
2983 virtual void loadR0FromR0() {
2984 fprintf(stderr, "loadR0FromR0()\n");
2985 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002986 }
2987
Jack Palevichb5e33312009-07-30 19:06:34 -07002988 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2989 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
2990 pPointerType->pHead->tag, et);
2991 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002992 }
2993
Jack Palevich9f51a262009-07-29 16:22:26 -07002994 virtual int leaForward(int ea, Type* pPointerType) {
2995 fprintf(stderr, "leaForward(%d)\n", ea);
2996 return mpBase->leaForward(ea, pPointerType);
2997 }
2998
Jack Palevich30321cb2009-08-20 15:34:23 -07002999 virtual void convertR0Imp(Type* pType, bool isCast){
3000 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3001 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003002 }
3003
3004 virtual int beginFunctionCallArguments() {
3005 int result = mpBase->beginFunctionCallArguments();
3006 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3007 return result;
3008 }
3009
Jack Palevich8148c5b2009-07-16 18:24:47 -07003010 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3011 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3012 pArgType->tag);
3013 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003014 }
3015
Jack Palevichb7718b92009-07-09 22:00:24 -07003016 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003017 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003018 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003019 }
3020
Jack Palevich8df46192009-07-07 14:48:51 -07003021 virtual int callForward(int symbol, Type* pFunc) {
3022 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003023 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3024 return result;
3025 }
3026
Jack Palevich8df46192009-07-07 14:48:51 -07003027 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003028 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3029 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003030 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003031 }
3032
Jack Palevichb7718b92009-07-09 22:00:24 -07003033 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3034 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3035 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003036 }
3037
3038 virtual int jumpOffset() {
3039 return mpBase->jumpOffset();
3040 }
3041
3042 virtual int disassemble(FILE* out) {
3043 return mpBase->disassemble(out);
3044 }
3045
3046 /* output a symbol and patch all calls to it */
3047 virtual void gsym(int t) {
3048 fprintf(stderr, "gsym(%d)\n", t);
3049 mpBase->gsym(t);
3050 }
3051
Jack Palevich9f51a262009-07-29 16:22:26 -07003052 virtual void resolveForward(int t) {
3053 mpBase->resolveForward(t);
3054 }
3055
Jack Palevichb67b18f2009-06-11 21:12:23 -07003056 virtual int finishCompile() {
3057 int result = mpBase->finishCompile();
3058 fprintf(stderr, "finishCompile() = %d\n", result);
3059 return result;
3060 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003061
3062 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003063 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003064 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003065 virtual size_t alignmentOf(Type* pType){
3066 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003067 }
3068
3069 /**
3070 * Array element alignment (in bytes) for this type of data.
3071 */
3072 virtual size_t sizeOf(Type* pType){
3073 return mpBase->sizeOf(pType);
3074 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003075
Jack Palevich9cbd2262009-07-08 16:48:41 -07003076
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003077 virtual size_t stackAlignmentOf(Type* pType) {
3078 return mpBase->stackAlignmentOf(pType);
3079 }
3080
3081
Jack Palevich9cbd2262009-07-08 16:48:41 -07003082 virtual size_t stackSizeOf(Type* pType) {
3083 return mpBase->stackSizeOf(pType);
3084 }
3085
Jack Palevich1a539db2009-07-08 13:04:41 -07003086 virtual Type* getR0Type() {
3087 return mpBase->getR0Type();
3088 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003089
3090 virtual ExpressionType getR0ExpressionType() {
3091 return mpBase->getR0ExpressionType();
3092 }
3093
3094 virtual void setR0ExpressionType(ExpressionType et) {
3095 mpBase->setR0ExpressionType(et);
3096 }
3097
3098 virtual size_t getExpressionStackDepth() {
3099 return mpBase->getExpressionStackDepth();
3100 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003101
3102 virtual void forceR0RVal() {
3103 return mpBase->forceR0RVal();
3104 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003105 };
3106
3107#endif // PROVIDE_TRACE_CODEGEN
3108
Jack Palevich569f1352009-06-29 14:29:08 -07003109 class Arena {
3110 public:
3111 // Used to record a given allocation amount.
3112 // Used:
3113 // Mark mark = arena.mark();
3114 // ... lots of arena.allocate()
3115 // arena.free(mark);
3116
3117 struct Mark {
3118 size_t chunk;
3119 size_t offset;
3120 };
3121
3122 Arena() {
3123 mCurrentChunk = 0;
3124 Chunk start(CHUNK_SIZE);
3125 mData.push_back(start);
3126 }
3127
3128 ~Arena() {
3129 for(size_t i = 0; i < mData.size(); i++) {
3130 mData[i].free();
3131 }
3132 }
3133
3134 // Alloc using the standard alignment size safe for any variable
3135 void* alloc(size_t size) {
3136 return alloc(size, 8);
3137 }
3138
3139 Mark mark(){
3140 Mark result;
3141 result.chunk = mCurrentChunk;
3142 result.offset = mData[mCurrentChunk].mOffset;
3143 return result;
3144 }
3145
3146 void freeToMark(const Mark& mark) {
3147 mCurrentChunk = mark.chunk;
3148 mData[mCurrentChunk].mOffset = mark.offset;
3149 }
3150
3151 private:
3152 // Allocate memory aligned to a given size
3153 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3154 // Memory is not zero filled.
3155
3156 void* alloc(size_t size, size_t alignment) {
3157 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3158 if (mCurrentChunk + 1 < mData.size()) {
3159 mCurrentChunk++;
3160 } else {
3161 size_t allocSize = CHUNK_SIZE;
3162 if (allocSize < size + alignment - 1) {
3163 allocSize = size + alignment - 1;
3164 }
3165 Chunk chunk(allocSize);
3166 mData.push_back(chunk);
3167 mCurrentChunk++;
3168 }
3169 }
3170 return mData[mCurrentChunk].allocate(size, alignment);
3171 }
3172
3173 static const size_t CHUNK_SIZE = 128*1024;
3174 // Note: this class does not deallocate its
3175 // memory when it's destroyed. It depends upon
3176 // its parent to deallocate the memory.
3177 struct Chunk {
3178 Chunk() {
3179 mpData = 0;
3180 mSize = 0;
3181 mOffset = 0;
3182 }
3183
3184 Chunk(size_t size) {
3185 mSize = size;
3186 mpData = (char*) malloc(size);
3187 mOffset = 0;
3188 }
3189
3190 ~Chunk() {
3191 // Doesn't deallocate memory.
3192 }
3193
3194 void* allocate(size_t size, size_t alignment) {
3195 size_t alignedOffset = aligned(mOffset, alignment);
3196 void* result = mpData + alignedOffset;
3197 mOffset = alignedOffset + size;
3198 return result;
3199 }
3200
3201 void free() {
3202 if (mpData) {
3203 ::free(mpData);
3204 mpData = 0;
3205 }
3206 }
3207
3208 size_t remainingCapacity(size_t alignment) {
3209 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3210 }
3211
3212 // Assume alignment is a power of two
3213 inline size_t aligned(size_t v, size_t alignment) {
3214 size_t mask = alignment-1;
3215 return (v + mask) & ~mask;
3216 }
3217
3218 char* mpData;
3219 size_t mSize;
3220 size_t mOffset;
3221 };
3222
3223 size_t mCurrentChunk;
3224
3225 Vector<Chunk> mData;
3226 };
3227
Jack Palevich569f1352009-06-29 14:29:08 -07003228 struct VariableInfo;
3229
3230 struct Token {
3231 int hash;
3232 size_t length;
3233 char* pText;
3234 tokenid_t id;
3235
3236 // Current values for the token
3237 char* mpMacroDefinition;
3238 VariableInfo* mpVariableInfo;
3239 };
3240
3241 class TokenTable {
3242 public:
3243 // Don't use 0..0xff, allows characters and operators to be tokens too.
3244
3245 static const int TOKEN_BASE = 0x100;
3246 TokenTable() {
3247 mpMap = hashmapCreate(128, hashFn, equalsFn);
3248 }
3249
3250 ~TokenTable() {
3251 hashmapFree(mpMap);
3252 }
3253
3254 void setArena(Arena* pArena) {
3255 mpArena = pArena;
3256 }
3257
3258 // Returns a token for a given string of characters.
3259 tokenid_t intern(const char* pText, size_t length) {
3260 Token probe;
3261 int hash = hashmapHash((void*) pText, length);
3262 {
3263 Token probe;
3264 probe.hash = hash;
3265 probe.length = length;
3266 probe.pText = (char*) pText;
3267 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3268 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003269 return pValue->id;
3270 }
3271 }
3272
3273 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3274 memset(pToken, 0, sizeof(*pToken));
3275 pToken->hash = hash;
3276 pToken->length = length;
3277 pToken->pText = (char*) mpArena->alloc(length + 1);
3278 memcpy(pToken->pText, pText, length);
3279 pToken->pText[length] = 0;
3280 pToken->id = mTokens.size() + TOKEN_BASE;
3281 mTokens.push_back(pToken);
3282 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003283 return pToken->id;
3284 }
3285
3286 // Return the Token for a given tokenid.
3287 Token& operator[](tokenid_t id) {
3288 return *mTokens[id - TOKEN_BASE];
3289 }
3290
3291 inline size_t size() {
3292 return mTokens.size();
3293 }
3294
3295 private:
3296
3297 static int hashFn(void* pKey) {
3298 Token* pToken = (Token*) pKey;
3299 return pToken->hash;
3300 }
3301
3302 static bool equalsFn(void* keyA, void* keyB) {
3303 Token* pTokenA = (Token*) keyA;
3304 Token* pTokenB = (Token*) keyB;
3305 // Don't need to compare hash values, they should always be equal
3306 return pTokenA->length == pTokenB->length
3307 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3308 }
3309
3310 Hashmap* mpMap;
3311 Vector<Token*> mTokens;
3312 Arena* mpArena;
3313 };
3314
Jack Palevich1cdef202009-05-22 12:06:27 -07003315 class InputStream {
3316 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003317 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003318 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003319 };
3320
3321 class TextInputStream : public InputStream {
3322 public:
3323 TextInputStream(const char* text, size_t textLength)
3324 : pText(text), mTextLength(textLength), mPosition(0) {
3325 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003326
Jack Palevichdc456462009-07-16 16:50:56 -07003327 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003328 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3329 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003330
Jack Palevichdc456462009-07-16 16:50:56 -07003331 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003332 const char* pText;
3333 size_t mTextLength;
3334 size_t mPosition;
3335 };
3336
Jack Palevicheedf9d22009-06-04 16:23:40 -07003337 class String {
3338 public:
3339 String() {
3340 mpBase = 0;
3341 mUsed = 0;
3342 mSize = 0;
3343 }
3344
Jack Palevich303d8ff2009-06-11 19:06:24 -07003345 String(const char* item, int len, bool adopt) {
3346 if (len < 0) {
3347 len = strlen(item);
3348 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003349 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003350 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003351 mUsed = len;
3352 mSize = len + 1;
3353 } else {
3354 mpBase = 0;
3355 mUsed = 0;
3356 mSize = 0;
3357 appendBytes(item, len);
3358 }
3359 }
3360
Jack Palevich303d8ff2009-06-11 19:06:24 -07003361 String(const String& other) {
3362 mpBase = 0;
3363 mUsed = 0;
3364 mSize = 0;
3365 appendBytes(other.getUnwrapped(), other.len());
3366 }
3367
Jack Palevicheedf9d22009-06-04 16:23:40 -07003368 ~String() {
3369 if (mpBase) {
3370 free(mpBase);
3371 }
3372 }
3373
Jack Palevicha6baa232009-06-12 11:25:59 -07003374 String& operator=(const String& other) {
3375 clear();
3376 appendBytes(other.getUnwrapped(), other.len());
3377 return *this;
3378 }
3379
Jack Palevich303d8ff2009-06-11 19:06:24 -07003380 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003381 return mpBase;
3382 }
3383
Jack Palevich303d8ff2009-06-11 19:06:24 -07003384 void clear() {
3385 mUsed = 0;
3386 if (mSize > 0) {
3387 mpBase[0] = 0;
3388 }
3389 }
3390
Jack Palevicheedf9d22009-06-04 16:23:40 -07003391 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003392 appendBytes(s, strlen(s));
3393 }
3394
3395 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003396 memcpy(ensure(n), s, n + 1);
3397 }
3398
3399 void append(char c) {
3400 * ensure(1) = c;
3401 }
3402
Jack Palevich86351982009-06-30 18:09:56 -07003403 void append(String& other) {
3404 appendBytes(other.getUnwrapped(), other.len());
3405 }
3406
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003407 char* orphan() {
3408 char* result = mpBase;
3409 mpBase = 0;
3410 mUsed = 0;
3411 mSize = 0;
3412 return result;
3413 }
3414
Jack Palevicheedf9d22009-06-04 16:23:40 -07003415 void printf(const char* fmt,...) {
3416 va_list ap;
3417 va_start(ap, fmt);
3418 vprintf(fmt, ap);
3419 va_end(ap);
3420 }
3421
3422 void vprintf(const char* fmt, va_list ap) {
3423 char* temp;
3424 int numChars = vasprintf(&temp, fmt, ap);
3425 memcpy(ensure(numChars), temp, numChars+1);
3426 free(temp);
3427 }
3428
Jack Palevich303d8ff2009-06-11 19:06:24 -07003429 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003430 return mUsed;
3431 }
3432
3433 private:
3434 char* ensure(int n) {
3435 size_t newUsed = mUsed + n;
3436 if (newUsed > mSize) {
3437 size_t newSize = mSize * 2 + 10;
3438 if (newSize < newUsed) {
3439 newSize = newUsed;
3440 }
3441 mpBase = (char*) realloc(mpBase, newSize + 1);
3442 mSize = newSize;
3443 }
3444 mpBase[newUsed] = '\0';
3445 char* result = mpBase + mUsed;
3446 mUsed = newUsed;
3447 return result;
3448 }
3449
3450 char* mpBase;
3451 size_t mUsed;
3452 size_t mSize;
3453 };
3454
Jack Palevich569f1352009-06-29 14:29:08 -07003455 void internKeywords() {
3456 // Note: order has to match TOK_ constants
3457 static const char* keywords[] = {
3458 "int",
3459 "char",
3460 "void",
3461 "if",
3462 "else",
3463 "while",
3464 "break",
3465 "return",
3466 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003467 "auto",
3468 "case",
3469 "const",
3470 "continue",
3471 "default",
3472 "do",
3473 "double",
3474 "enum",
3475 "extern",
3476 "float",
3477 "goto",
3478 "long",
3479 "register",
3480 "short",
3481 "signed",
3482 "sizeof",
3483 "static",
3484 "struct",
3485 "switch",
3486 "typedef",
3487 "union",
3488 "unsigned",
3489 "volatile",
3490 "_Bool",
3491 "_Complex",
3492 "_Imaginary",
3493 "inline",
3494 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003495
3496 // predefined tokens that can also be symbols start here:
3497 "pragma",
3498 "define",
3499 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003500 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003501
Jack Palevich569f1352009-06-29 14:29:08 -07003502 for(int i = 0; keywords[i]; i++) {
3503 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003504 }
Jack Palevich569f1352009-06-29 14:29:08 -07003505 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003506
Jack Palevich36d94142009-06-08 15:55:32 -07003507 struct InputState {
3508 InputStream* pStream;
3509 int oldCh;
3510 };
3511
Jack Palevich2db168f2009-06-11 14:29:47 -07003512 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003513 void* pAddress;
3514 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003515 tokenid_t tok;
3516 size_t level;
3517 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003518 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003519 };
3520
Jack Palevich303d8ff2009-06-11 19:06:24 -07003521 class SymbolStack {
3522 public:
3523 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003524 mpArena = 0;
3525 mpTokenTable = 0;
3526 }
3527
3528 void setArena(Arena* pArena) {
3529 mpArena = pArena;
3530 }
3531
3532 void setTokenTable(TokenTable* pTokenTable) {
3533 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003534 }
3535
3536 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003537 Mark mark;
3538 mark.mArenaMark = mpArena->mark();
3539 mark.mSymbolHead = mStack.size();
3540 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003541 }
3542
3543 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003544 // Undo any shadowing that was done:
3545 Mark mark = mLevelStack.back();
3546 mLevelStack.pop_back();
3547 while (mStack.size() > mark.mSymbolHead) {
3548 VariableInfo* pV = mStack.back();
3549 mStack.pop_back();
3550 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003551 }
Jack Palevich569f1352009-06-29 14:29:08 -07003552 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003553 }
3554
Jack Palevich569f1352009-06-29 14:29:08 -07003555 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3556 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3557 return pV && pV->level == level();
3558 }
3559
3560 VariableInfo* add(tokenid_t tok) {
3561 Token& token = (*mpTokenTable)[tok];
3562 VariableInfo* pOldV = token.mpVariableInfo;
3563 VariableInfo* pNewV =
3564 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3565 memset(pNewV, 0, sizeof(VariableInfo));
3566 pNewV->tok = tok;
3567 pNewV->level = level();
3568 pNewV->pOldDefinition = pOldV;
3569 token.mpVariableInfo = pNewV;
3570 mStack.push_back(pNewV);
3571 return pNewV;
3572 }
3573
Jack Palevich86351982009-06-30 18:09:56 -07003574 VariableInfo* add(Type* pType) {
3575 VariableInfo* pVI = add(pType->id);
3576 pVI->pType = pType;
3577 return pVI;
3578 }
3579
Jack Palevich569f1352009-06-29 14:29:08 -07003580 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3581 for (size_t i = 0; i < mStack.size(); i++) {
3582 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003583 break;
3584 }
3585 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003586 }
3587
Jack Palevich303d8ff2009-06-11 19:06:24 -07003588 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003589 inline size_t level() {
3590 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003591 }
3592
Jack Palevich569f1352009-06-29 14:29:08 -07003593 struct Mark {
3594 Arena::Mark mArenaMark;
3595 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003596 };
3597
Jack Palevich569f1352009-06-29 14:29:08 -07003598 Arena* mpArena;
3599 TokenTable* mpTokenTable;
3600 Vector<VariableInfo*> mStack;
3601 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003602 };
Jack Palevich36d94142009-06-08 15:55:32 -07003603
3604 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003605 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003606 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003607 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003608 int tokl; // token operator level
3609 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003610 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003611 intptr_t loc; // local variable index
3612 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003613 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003614 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003615 char* dptr; // Macro state: Points to macro text during macro playback.
3616 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003617 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003618 ACCSymbolLookupFn mpSymbolLookupFn;
3619 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003620
3621 // Arena for the duration of the compile
3622 Arena mGlobalArena;
3623 // Arena for data that's only needed when compiling a single function
3624 Arena mLocalArena;
3625
Jack Palevich2ff5c222009-07-23 15:11:22 -07003626 Arena* mpCurrentArena;
3627
Jack Palevich569f1352009-06-29 14:29:08 -07003628 TokenTable mTokenTable;
3629 SymbolStack mGlobals;
3630 SymbolStack mLocals;
3631
Jack Palevich40600de2009-07-01 15:32:35 -07003632 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003633 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003634 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003635 Type* mkpChar; // char
3636 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003637 Type* mkpFloat;
3638 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003639 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003640 Type* mkpIntPtr;
3641 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003642 Type* mkpFloatPtr;
3643 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003644 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003645
Jack Palevich36d94142009-06-08 15:55:32 -07003646 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003647 int mLineNumber;
3648 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003649
3650 CodeBuf codeBuf;
3651 CodeGenerator* pGen;
3652
Jack Palevicheedf9d22009-06-04 16:23:40 -07003653 String mErrorBuf;
3654
Jack Palevicheedf9d22009-06-04 16:23:40 -07003655 String mPragmas;
3656 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003657 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003658
Jack Palevich21a15a22009-05-11 14:49:29 -07003659 static const int ALLOC_SIZE = 99999;
3660
Jack Palevich303d8ff2009-06-11 19:06:24 -07003661 static const int TOK_DUMMY = 1;
3662 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003663 static const int TOK_NUM_FLOAT = 3;
3664 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003665 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003666
3667 // 3..255 are character and/or operators
3668
Jack Palevich2db168f2009-06-11 14:29:47 -07003669 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003670 // Order has to match string list in "internKeywords".
3671 enum {
3672 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3673 TOK_INT = TOK_KEYWORD,
3674 TOK_CHAR,
3675 TOK_VOID,
3676 TOK_IF,
3677 TOK_ELSE,
3678 TOK_WHILE,
3679 TOK_BREAK,
3680 TOK_RETURN,
3681 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003682 TOK_AUTO,
3683 TOK_CASE,
3684 TOK_CONST,
3685 TOK_CONTINUE,
3686 TOK_DEFAULT,
3687 TOK_DO,
3688 TOK_DOUBLE,
3689 TOK_ENUM,
3690 TOK_EXTERN,
3691 TOK_FLOAT,
3692 TOK_GOTO,
3693 TOK_LONG,
3694 TOK_REGISTER,
3695 TOK_SHORT,
3696 TOK_SIGNED,
3697 TOK_SIZEOF,
3698 TOK_STATIC,
3699 TOK_STRUCT,
3700 TOK_SWITCH,
3701 TOK_TYPEDEF,
3702 TOK_UNION,
3703 TOK_UNSIGNED,
3704 TOK_VOLATILE,
3705 TOK__BOOL,
3706 TOK__COMPLEX,
3707 TOK__IMAGINARY,
3708 TOK_INLINE,
3709 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003710
3711 // Symbols start after keywords
3712
3713 TOK_SYMBOL,
3714 TOK_PRAGMA = TOK_SYMBOL,
3715 TOK_DEFINE,
3716 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003717 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003718
3719 static const int LOCAL = 0x200;
3720
3721 static const int SYM_FORWARD = 0;
3722 static const int SYM_DEFINE = 1;
3723
3724 /* tokens in string heap */
3725 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003726
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003727 static const int OP_INCREMENT = 0;
3728 static const int OP_DECREMENT = 1;
3729 static const int OP_MUL = 2;
3730 static const int OP_DIV = 3;
3731 static const int OP_MOD = 4;
3732 static const int OP_PLUS = 5;
3733 static const int OP_MINUS = 6;
3734 static const int OP_SHIFT_LEFT = 7;
3735 static const int OP_SHIFT_RIGHT = 8;
3736 static const int OP_LESS_EQUAL = 9;
3737 static const int OP_GREATER_EQUAL = 10;
3738 static const int OP_LESS = 11;
3739 static const int OP_GREATER = 12;
3740 static const int OP_EQUALS = 13;
3741 static const int OP_NOT_EQUALS = 14;
3742 static const int OP_LOGICAL_AND = 15;
3743 static const int OP_LOGICAL_OR = 16;
3744 static const int OP_BIT_AND = 17;
3745 static const int OP_BIT_XOR = 18;
3746 static const int OP_BIT_OR = 19;
3747 static const int OP_BIT_NOT = 20;
3748 static const int OP_LOGICAL_NOT = 21;
3749 static const int OP_COUNT = 22;
3750
3751 /* Operators are searched from front, the two-character operators appear
3752 * before the single-character operators with the same first character.
3753 * @ is used to pad out single-character operators.
3754 */
3755 static const char* operatorChars;
3756 static const char operatorLevel[];
3757
Jack Palevich569f1352009-06-29 14:29:08 -07003758 /* Called when we detect an internal problem. Does nothing in production.
3759 *
3760 */
3761 void internalError() {
3762 * (char*) 0 = 0;
3763 }
3764
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003765 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003766 if (!isTrue) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003767 LOGD("assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003768 internalError();
3769 }
Jack Palevich86351982009-06-30 18:09:56 -07003770 }
3771
Jack Palevich40600de2009-07-01 15:32:35 -07003772 bool isSymbol(tokenid_t t) {
3773 return t >= TOK_SYMBOL &&
3774 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3775 }
3776
3777 bool isSymbolOrKeyword(tokenid_t t) {
3778 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003779 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003780 }
3781
Jack Palevich86351982009-06-30 18:09:56 -07003782 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003783 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003784 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3785 if (pV && pV->tok != t) {
3786 internalError();
3787 }
3788 return pV;
3789 }
3790
3791 inline bool isDefined(tokenid_t t) {
3792 return t >= TOK_SYMBOL && VI(t) != 0;
3793 }
3794
Jack Palevich40600de2009-07-01 15:32:35 -07003795 const char* nameof(tokenid_t t) {
3796 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003797 return mTokenTable[t].pText;
3798 }
3799
Jack Palevich21a15a22009-05-11 14:49:29 -07003800 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003801 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003802 }
3803
3804 void inp() {
3805 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003806 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003807 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003808 dptr = 0;
3809 ch = dch;
3810 }
Jack Palevichdc456462009-07-16 16:50:56 -07003811 } else {
3812 if (mbBumpLine) {
3813 mLineNumber++;
3814 mbBumpLine = false;
3815 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003816 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003817 if (ch == '\n') {
3818 mbBumpLine = true;
3819 }
3820 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003821#if 0
3822 printf("ch='%c' 0x%x\n", ch, ch);
3823#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003824 }
3825
3826 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003827 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003828 }
3829
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003830 int decodeHex(int c) {
3831 if (isdigit(c)) {
3832 c -= '0';
3833 } else if (c <= 'F') {
3834 c = c - 'A' + 10;
3835 } else {
3836 c =c - 'a' + 10;
3837 }
3838 return c;
3839 }
3840
Jack Palevichb4758ff2009-06-12 12:49:14 -07003841 /* read a character constant, advances ch to after end of constant */
3842 int getq() {
3843 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003844 if (ch == '\\') {
3845 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003846 if (isoctal(ch)) {
3847 // 1 to 3 octal characters.
3848 val = 0;
3849 for(int i = 0; i < 3; i++) {
3850 if (isoctal(ch)) {
3851 val = (val << 3) + ch - '0';
3852 inp();
3853 }
3854 }
3855 return val;
3856 } else if (ch == 'x' || ch == 'X') {
3857 // N hex chars
3858 inp();
3859 if (! isxdigit(ch)) {
3860 error("'x' character escape requires at least one digit.");
3861 } else {
3862 val = 0;
3863 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003864 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003865 inp();
3866 }
3867 }
3868 } else {
3869 int val = ch;
3870 switch (ch) {
3871 case 'a':
3872 val = '\a';
3873 break;
3874 case 'b':
3875 val = '\b';
3876 break;
3877 case 'f':
3878 val = '\f';
3879 break;
3880 case 'n':
3881 val = '\n';
3882 break;
3883 case 'r':
3884 val = '\r';
3885 break;
3886 case 't':
3887 val = '\t';
3888 break;
3889 case 'v':
3890 val = '\v';
3891 break;
3892 case '\\':
3893 val = '\\';
3894 break;
3895 case '\'':
3896 val = '\'';
3897 break;
3898 case '"':
3899 val = '"';
3900 break;
3901 case '?':
3902 val = '?';
3903 break;
3904 default:
3905 error("Undefined character escape %c", ch);
3906 break;
3907 }
3908 inp();
3909 return val;
3910 }
3911 } else {
3912 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003913 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003914 return val;
3915 }
3916
3917 static bool isoctal(int ch) {
3918 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003919 }
3920
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003921 bool acceptCh(int c) {
3922 bool result = c == ch;
3923 if (result) {
3924 pdef(ch);
3925 inp();
3926 }
3927 return result;
3928 }
3929
3930 bool acceptDigitsCh() {
3931 bool result = false;
3932 while (isdigit(ch)) {
3933 result = true;
3934 pdef(ch);
3935 inp();
3936 }
3937 return result;
3938 }
3939
3940 void parseFloat() {
3941 tok = TOK_NUM_DOUBLE;
3942 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003943 if(mTokenString.len() == 0) {
3944 mTokenString.append('0');
3945 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003946 acceptCh('.');
3947 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003948 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003949 acceptCh('-') || acceptCh('+');
3950 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003951 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003952 if (ch == 'f' || ch == 'F') {
3953 tok = TOK_NUM_FLOAT;
3954 inp();
3955 } else if (ch == 'l' || ch == 'L') {
3956 inp();
3957 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003958 }
3959 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003960 char* pEnd = pText + strlen(pText);
3961 char* pEndPtr = 0;
3962 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003963 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003964 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003965 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003966 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003967 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003968 if (errno || pEndPtr != pEnd) {
3969 error("Can't parse constant: %s", pText);
3970 }
3971 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003972 }
3973
Jack Palevich21a15a22009-05-11 14:49:29 -07003974 void next() {
3975 int l, a;
3976
Jack Palevich546b2242009-05-13 15:10:04 -07003977 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003978 if (ch == '#') {
3979 inp();
3980 next();
3981 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003982 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003983 } else if (tok == TOK_PRAGMA) {
3984 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003985 } else if (tok == TOK_LINE) {
3986 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003987 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003988 error("Unsupported preprocessor directive \"%s\"",
3989 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003990 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003991 }
3992 inp();
3993 }
3994 tokl = 0;
3995 tok = ch;
3996 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003997 if (isdigit(ch) || ch == '.') {
3998 // Start of a numeric constant. Could be integer, float, or
3999 // double, won't know until we look further.
4000 mTokenString.clear();
4001 pdef(ch);
4002 inp();
4003 int base = 10;
4004 if (tok == '0') {
4005 if (ch == 'x' || ch == 'X') {
4006 base = 16;
4007 tok = TOK_NUM;
4008 tokc = 0;
4009 inp();
4010 while ( isxdigit(ch) ) {
4011 tokc = (tokc << 4) + decodeHex(ch);
4012 inp();
4013 }
4014 } else if (isoctal(ch)){
4015 base = 8;
4016 tok = TOK_NUM;
4017 tokc = 0;
4018 while ( isoctal(ch) ) {
4019 tokc = (tokc << 3) + (ch - '0');
4020 inp();
4021 }
4022 }
4023 } else if (isdigit(tok)){
4024 acceptDigitsCh();
4025 }
4026 if (base == 10) {
4027 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4028 parseFloat();
4029 } else {
4030 // It's an integer constant
4031 char* pText = mTokenString.getUnwrapped();
4032 char* pEnd = pText + strlen(pText);
4033 char* pEndPtr = 0;
4034 errno = 0;
4035 tokc = strtol(pText, &pEndPtr, base);
4036 if (errno || pEndPtr != pEnd) {
4037 error("Can't parse constant: %s %d %d", pText, base, errno);
4038 }
4039 tok = TOK_NUM;
4040 }
4041 }
4042 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004043 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004044 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004045 pdef(ch);
4046 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004047 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004048 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004049 if (! mbSuppressMacroExpansion) {
4050 // Is this a macro?
4051 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4052 if (pMacroDefinition) {
4053 // Yes, it is a macro
4054 dptr = pMacroDefinition;
4055 dch = ch;
4056 inp();
4057 next();
4058 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004059 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004060 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004061 inp();
4062 if (tok == '\'') {
4063 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004064 tokc = getq();
4065 if (ch != '\'') {
4066 error("Expected a ' character, got %c", ch);
4067 } else {
4068 inp();
4069 }
Jack Palevich546b2242009-05-13 15:10:04 -07004070 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004071 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004072 while (ch && ch != EOF) {
4073 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004074 inp();
4075 inp();
4076 if (ch == '/')
4077 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004078 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004079 if (ch == EOF) {
4080 error("End of file inside comment.");
4081 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004082 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004083 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004084 } else if ((tok == '/') & (ch == '/')) {
4085 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004086 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004087 inp();
4088 }
4089 inp();
4090 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07004091 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004092 const char* t = operatorChars;
4093 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004094 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004095 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004096 tokl = operatorLevel[opIndex];
4097 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004098 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004099#if 0
4100 printf("%c%c -> tokl=%d tokc=0x%x\n",
4101 l, a, tokl, tokc);
4102#endif
4103 if (a == ch) {
4104 inp();
4105 tok = TOK_DUMMY; /* dummy token for double tokens */
4106 }
Jack Palevich0c017742009-07-31 12:00:39 -07004107 /* check for op=, valid for * / % + - << >> & ^ | */
4108 if (ch == '=' &&
4109 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004110 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004111 inp();
4112 tok = TOK_OP_ASSIGNMENT;
4113 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004114 break;
4115 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004116 opIndex++;
4117 }
4118 if (l == 0) {
4119 tokl = 0;
4120 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004121 }
4122 }
4123 }
4124#if 0
4125 {
Jack Palevich569f1352009-06-29 14:29:08 -07004126 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004127 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004128 fprintf(stderr, "%s\n", buf.getUnwrapped());
4129 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004130#endif
4131 }
4132
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004133 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004134 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004135 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004136 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004137 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004138 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004139 if (ch == '(') {
4140 delete pName;
4141 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004142 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004143 }
4144 while (isspace(ch)) {
4145 inp();
4146 }
Jack Palevich569f1352009-06-29 14:29:08 -07004147 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004148 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004149 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004150 // Check for '//' comments.
4151 if (appendToValue && ch == '/') {
4152 inp();
4153 if (ch == '/') {
4154 appendToValue = false;
4155 } else {
4156 value.append('/');
4157 }
4158 }
4159 if (appendToValue && ch != EOF) {
4160 value.append(ch);
4161 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004162 inp();
4163 }
Jack Palevich569f1352009-06-29 14:29:08 -07004164 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4165 memcpy(pDefn, value.getUnwrapped(), value.len());
4166 pDefn[value.len()] = 0;
4167 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004168 }
4169
Jack Palevicheedf9d22009-06-04 16:23:40 -07004170 void doPragma() {
4171 // # pragma name(val)
4172 int state = 0;
4173 while(ch != EOF && ch != '\n' && state < 10) {
4174 switch(state) {
4175 case 0:
4176 if (isspace(ch)) {
4177 inp();
4178 } else {
4179 state++;
4180 }
4181 break;
4182 case 1:
4183 if (isalnum(ch)) {
4184 mPragmas.append(ch);
4185 inp();
4186 } else if (ch == '(') {
4187 mPragmas.append(0);
4188 inp();
4189 state++;
4190 } else {
4191 state = 11;
4192 }
4193 break;
4194 case 2:
4195 if (isalnum(ch)) {
4196 mPragmas.append(ch);
4197 inp();
4198 } else if (ch == ')') {
4199 mPragmas.append(0);
4200 inp();
4201 state = 10;
4202 } else {
4203 state = 11;
4204 }
4205 break;
4206 }
4207 }
4208 if(state != 10) {
4209 error("Unexpected pragma syntax");
4210 }
4211 mPragmaStringCount += 2;
4212 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004213
Jack Palevichdc456462009-07-16 16:50:56 -07004214 void doLine() {
4215 // # line number { "filename "}
4216 next();
4217 if (tok != TOK_NUM) {
4218 error("Expected a line-number");
4219 } else {
4220 mLineNumber = tokc-1; // The end-of-line will increment it.
4221 }
4222 while(ch != EOF && ch != '\n') {
4223 inp();
4224 }
4225 }
4226
Jack Palevichac0e95e2009-05-29 13:53:44 -07004227 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004228 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004229 mErrorBuf.vprintf(fmt, ap);
4230 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004231 }
4232
Jack Palevich8b0624c2009-05-20 12:12:06 -07004233 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004234 if (tok != c) {
4235 error("'%c' expected", c);
4236 }
4237 next();
4238 }
4239
Jack Palevich86351982009-06-30 18:09:56 -07004240 bool accept(intptr_t c) {
4241 if (tok == c) {
4242 next();
4243 return true;
4244 }
4245 return false;
4246 }
4247
Jack Palevich40600de2009-07-01 15:32:35 -07004248 bool acceptStringLiteral() {
4249 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004250 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004251 // This while loop merges multiple adjacent string constants.
4252 while (tok == '"') {
4253 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004254 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004255 }
4256 if (ch != '"') {
4257 error("Unterminated string constant.");
4258 }
4259 inp();
4260 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004261 }
Jack Palevich40600de2009-07-01 15:32:35 -07004262 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004263 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004264 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004265 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004266
4267 return true;
4268 }
4269 return false;
4270 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004271
Jack Palevichb1544ca2009-07-16 15:09:20 -07004272 void linkGlobal(tokenid_t t, bool isFunction) {
4273 VariableInfo* pVI = VI(t);
4274 void* n = NULL;
4275 if (mpSymbolLookupFn) {
4276 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4277 }
4278 if (pVI->pType == NULL) {
4279 if (isFunction) {
4280 pVI->pType = mkpIntFn;
4281 } else {
4282 pVI->pType = mkpInt;
4283 }
4284 }
4285 pVI->pAddress = n;
4286 }
4287
Jack Palevich29daf572009-07-30 19:38:55 -07004288 void unaryOrAssignment() {
4289 unary();
4290 if (accept('=')) {
4291 checkLVal();
4292 pGen->pushR0();
4293 expr();
4294 pGen->forceR0RVal();
4295 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004296 } else if (tok == TOK_OP_ASSIGNMENT) {
4297 int t = tokc;
4298 next();
4299 checkLVal();
4300 pGen->pushR0();
4301 pGen->forceR0RVal();
4302 pGen->pushR0();
4303 expr();
4304 pGen->forceR0RVal();
4305 pGen->genOp(t);
4306 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004307 }
4308 }
4309
Jack Palevich40600de2009-07-01 15:32:35 -07004310 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004311 */
Jack Palevich29daf572009-07-30 19:38:55 -07004312 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004313 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004314 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004315 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004316 if (acceptStringLiteral()) {
4317 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004318 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004319 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004320 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004321 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004322 t = tok;
4323 next();
4324 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004325 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004326 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004327 // Align to 4-byte boundary
4328 glo = (char*) (((intptr_t) glo + 3) & -4);
4329 * (float*) glo = (float) ad;
4330 pGen->loadFloat((int) glo, mkpFloat);
4331 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004332 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004333 // Align to 8-byte boundary
4334 glo = (char*) (((intptr_t) glo + 7) & -8);
4335 * (double*) glo = ad;
4336 pGen->loadFloat((int) glo, mkpDouble);
4337 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004338 } else if (c == 2) {
4339 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004340 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004341 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004342 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004343 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004344 else if (t == '+') {
4345 // ignore unary plus.
4346 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004347 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004348 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004349 } else if (c == 11) {
4350 // pre increment / pre decrement
4351 unary();
4352 doIncDec(a == OP_INCREMENT, 0);
4353 }
4354 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004355 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004356 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004357 if (pCast) {
4358 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004359 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004360 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004361 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004362 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004363 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004364 skip(')');
4365 }
4366 } else if (t == '*') {
4367 /* This is a pointer dereference.
4368 */
Jack Palevich29daf572009-07-30 19:38:55 -07004369 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004370 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004371 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004372 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004373 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4374 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004375 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004376 } else if (t == EOF ) {
4377 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004378 } else if (t == ';') {
4379 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004380 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004381 // Don't have to do anything special here, the error
4382 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004383 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004384 if (!isDefined(t)) {
4385 mGlobals.add(t);
4386 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004387 }
Jack Palevich8df46192009-07-07 14:48:51 -07004388 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004389 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004390 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004391 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004392 linkGlobal(t, tok == '(');
4393 n = (intptr_t) pVI->pAddress;
4394 if (!n && tok != '(') {
4395 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004396 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004397 }
Jack Palevich29daf572009-07-30 19:38:55 -07004398 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004399 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004400 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004401 linkGlobal(t, false);
4402 n = (intptr_t) pVI->pAddress;
4403 if (!n) {
4404 error("Undeclared variable %s\n", nameof(t));
4405 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004406 }
Jack Palevich5b659092009-07-31 14:55:07 -07004407 }
4408 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004409 Type* pVal;
4410 ExpressionType et;
4411 if (pVI->pType->tag == TY_ARRAY) {
4412 pVal = pVI->pType;
4413 et = ET_RVALUE;
4414 } else {
4415 pVal = createPtrType(pVI->pType);
4416 et = ET_LVALUE;
4417 }
Jack Palevich5b659092009-07-31 14:55:07 -07004418 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004419 int tag = pVal->pHead->tag;
4420 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004421 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004422 }
Jack Palevich5b659092009-07-31 14:55:07 -07004423 pGen->leaR0(n, pVal, et);
4424 } else {
4425 pVI->pForward = (void*) pGen->leaForward(
4426 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004427 }
4428 }
4429 }
4430
Jack Palevich5b659092009-07-31 14:55:07 -07004431 /* Now handle postfix operators */
4432 for(;;) {
4433 if (tokl == 11) {
4434 // post inc / post dec
4435 doIncDec(tokc == OP_INCREMENT, true);
4436 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004437 } else if (accept('[')) {
4438 // Array reference
4439 pGen->forceR0RVal();
4440 pGen->pushR0();
4441 commaExpr();
4442 pGen->forceR0RVal();
4443 pGen->genOp(OP_PLUS);
4444 doPointer();
4445 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004446 } else if (accept('(')) {
4447 /* function call */
4448 Type* pDecl = NULL;
4449 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004450 Type* pFn = pGen->getR0Type();
4451 assert(pFn->tag == TY_POINTER);
4452 assert(pFn->pHead->tag == TY_FUNC);
4453 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004454 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004455 Type* pArgList = pDecl->pTail;
4456 bool varArgs = pArgList == NULL;
4457 /* push args and invert order */
4458 a = pGen->beginFunctionCallArguments();
4459 int l = 0;
4460 int argCount = 0;
4461 while (tok != ')' && tok != EOF) {
4462 if (! varArgs && !pArgList) {
4463 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004464 }
Jack Palevich5b659092009-07-31 14:55:07 -07004465 expr();
4466 pGen->forceR0RVal();
4467 Type* pTargetType;
4468 if (pArgList) {
4469 pTargetType = pArgList->pHead;
4470 pArgList = pArgList->pTail;
4471 } else {
4472 // This is a ... function, just pass arguments in their
4473 // natural type.
4474 pTargetType = pGen->getR0Type();
4475 if (pTargetType->tag == TY_FLOAT) {
4476 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004477 } else if (pTargetType->tag == TY_ARRAY) {
4478 // Pass arrays by pointer.
4479 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004480 }
4481 }
4482 if (pTargetType->tag == TY_VOID) {
4483 error("Can't pass void value for argument %d",
4484 argCount + 1);
4485 } else {
4486 l += pGen->storeR0ToArg(l, pTargetType);
4487 }
4488 if (accept(',')) {
4489 // fine
4490 } else if ( tok != ')') {
4491 error("Expected ',' or ')'");
4492 }
4493 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004494 }
Jack Palevich5b659092009-07-31 14:55:07 -07004495 if (! varArgs && pArgList) {
4496 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004497 }
Jack Palevich5b659092009-07-31 14:55:07 -07004498 pGen->endFunctionCallArguments(pDecl, a, l);
4499 skip(')');
4500 pGen->callIndirect(l, pDecl);
4501 pGen->adjustStackAfterCall(pDecl, l, true);
4502 } else {
4503 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004504 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004505 }
4506 }
4507
Jack Palevichaaac9282009-07-31 14:34:34 -07004508 void doIncDec(int isInc, int isPost) {
4509 // R0 already has the lval
4510 checkLVal();
4511 int lit = isInc ? 1 : -1;
4512 pGen->pushR0();
4513 pGen->loadR0FromR0();
4514 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004515 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4516 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004517 error("++/-- illegal for this type. %d", tag);
4518 }
4519 if (isPost) {
4520 pGen->over();
4521 pGen->pushR0();
4522 pGen->li(lit);
4523 pGen->genOp(OP_PLUS);
4524 pGen->storeR0ToTOS();
4525 pGen->popR0();
4526 } else {
4527 pGen->pushR0();
4528 pGen->li(lit);
4529 pGen->genOp(OP_PLUS);
4530 pGen->over();
4531 pGen->storeR0ToTOS();
4532 pGen->popR0();
4533 }
4534 }
4535
Jack Palevich47cbea92009-07-31 15:25:53 -07004536 void doPointer() {
4537 pGen->forceR0RVal();
4538 Type* pR0Type = pGen->getR0Type();
4539 if (pR0Type->tag != TY_POINTER) {
4540 error("Expected a pointer type.");
4541 } else {
4542 if (pR0Type->pHead->tag != TY_FUNC) {
4543 pGen->setR0ExpressionType(ET_LVALUE);
4544 }
4545 }
4546 }
4547
Jack Palevich40600de2009-07-01 15:32:35 -07004548 /* Recursive descent parser for binary operations.
4549 */
4550 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004551 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004552 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004553 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004554 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004555 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004556 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004557 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004558 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004559 t = tokc;
4560 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004561 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004562 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004563 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004564 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004565 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004566 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004567 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004568 // Check for syntax error.
4569 if (pGen->getR0Type() == NULL) {
4570 // We failed to parse a right-hand argument.
4571 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004572 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004573 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004574 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004575 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004576 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004577 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004578 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004579 }
4580 }
4581 }
4582 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004583 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004584 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004585 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004586 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004587 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004588 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004589 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004590 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004591 }
4592 }
4593 }
4594
Jack Palevich43aaee32009-07-31 14:01:37 -07004595 void commaExpr() {
4596 for(;;) {
4597 expr();
4598 if (!accept(',')) {
4599 break;
4600 }
4601 }
4602 }
4603
Jack Palevich21a15a22009-05-11 14:49:29 -07004604 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004605 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004606 }
4607
4608 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004609 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004610 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004611 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004612 }
4613
Jack Palevicha6baa232009-06-12 11:25:59 -07004614 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004615 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004616
Jack Palevich95727a02009-07-06 12:07:15 -07004617 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004618 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004619 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004620 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004621 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004622 next();
4623 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004624 a = test_expr();
4625 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004626 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004627 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004628 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004629 n = pGen->gjmp(0); /* jmp */
4630 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004631 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004632 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004633 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004634 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004635 }
Jack Palevich546b2242009-05-13 15:10:04 -07004636 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004637 t = tok;
4638 next();
4639 skip('(');
4640 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004641 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004642 a = test_expr();
4643 } else {
4644 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004645 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004646 skip(';');
4647 n = codeBuf.getPC();
4648 a = 0;
4649 if (tok != ';')
4650 a = test_expr();
4651 skip(';');
4652 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004653 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004654 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004655 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004656 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004657 n = t + 4;
4658 }
4659 }
4660 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004661 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004662 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004663 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004664 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004665 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004666 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004667 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004668 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004669 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004670 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004671 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004672 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004673 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004674 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004675 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004676 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004677 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004678 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004679 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004680 if (pReturnType->tag == TY_VOID) {
4681 error("Must not return a value from a void function");
4682 } else {
4683 pGen->convertR0(pReturnType);
4684 }
4685 } else {
4686 if (pReturnType->tag != TY_VOID) {
4687 error("Must specify a value here");
4688 }
Jack Palevich8df46192009-07-07 14:48:51 -07004689 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004690 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004691 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004692 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004693 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004694 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004695 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004696 }
4697 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004698
Jack Palevicha8f427f2009-07-13 18:40:08 -07004699 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004700 if (a == b) {
4701 return true;
4702 }
4703 if (a == NULL || b == NULL) {
4704 return false;
4705 }
4706 TypeTag at = a->tag;
4707 if (at != b->tag) {
4708 return false;
4709 }
4710 if (at == TY_POINTER) {
4711 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004712 } else if (at == TY_ARRAY) {
4713 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004714 } else if (at == TY_FUNC || at == TY_PARAM) {
4715 return typeEqual(a->pHead, b->pHead)
4716 && typeEqual(a->pTail, b->pTail);
4717 }
4718 return true;
4719 }
4720
Jack Palevich2ff5c222009-07-23 15:11:22 -07004721 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004722 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004723 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004724 memset(pType, 0, sizeof(*pType));
4725 pType->tag = tag;
4726 pType->pHead = pHead;
4727 pType->pTail = pTail;
4728 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004729 }
4730
Jack Palevich2ff5c222009-07-23 15:11:22 -07004731 Type* createPtrType(Type* pType) {
4732 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004733 }
4734
4735 /**
4736 * Try to print a type in declaration order
4737 */
Jack Palevich86351982009-06-30 18:09:56 -07004738 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004739 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004740 if (pType == NULL) {
4741 buffer.appendCStr("null");
4742 return;
4743 }
Jack Palevich3f226492009-07-02 14:46:19 -07004744 decodeTypeImp(buffer, pType);
4745 }
4746
4747 void decodeTypeImp(String& buffer, Type* pType) {
4748 decodeTypeImpPrefix(buffer, pType);
4749
Jack Palevich86351982009-06-30 18:09:56 -07004750 String temp;
4751 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004752 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004753 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004754 }
4755
4756 decodeTypeImpPostfix(buffer, pType);
4757 }
4758
4759 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4760 TypeTag tag = pType->tag;
4761
Jack Palevich37c54bd2009-07-14 18:35:36 -07004762 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004763 switch (tag) {
4764 case TY_INT:
4765 buffer.appendCStr("int");
4766 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004767 case TY_SHORT:
4768 buffer.appendCStr("short");
4769 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004770 case TY_CHAR:
4771 buffer.appendCStr("char");
4772 break;
4773 case TY_VOID:
4774 buffer.appendCStr("void");
4775 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004776 case TY_FLOAT:
4777 buffer.appendCStr("float");
4778 break;
4779 case TY_DOUBLE:
4780 buffer.appendCStr("double");
4781 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004782 default:
4783 break;
4784 }
Jack Palevich86351982009-06-30 18:09:56 -07004785 buffer.append(' ');
4786 }
Jack Palevich3f226492009-07-02 14:46:19 -07004787
4788 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004789 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004790 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004791 case TY_SHORT:
4792 break;
Jack Palevich86351982009-06-30 18:09:56 -07004793 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004794 break;
4795 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004796 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004797 case TY_FLOAT:
4798 break;
4799 case TY_DOUBLE:
4800 break;
Jack Palevich86351982009-06-30 18:09:56 -07004801 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004802 decodeTypeImpPrefix(buffer, pType->pHead);
4803 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4804 buffer.append('(');
4805 }
4806 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004807 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004808 case TY_ARRAY:
4809 decodeTypeImpPrefix(buffer, pType->pHead);
4810 break;
Jack Palevich86351982009-06-30 18:09:56 -07004811 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004812 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004813 break;
4814 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004815 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004816 break;
4817 default:
4818 String temp;
4819 temp.printf("Unknown tag %d", pType->tag);
4820 buffer.append(temp);
4821 break;
4822 }
Jack Palevich3f226492009-07-02 14:46:19 -07004823 }
4824
4825 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4826 TypeTag tag = pType->tag;
4827
4828 switch(tag) {
4829 case TY_POINTER:
4830 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4831 buffer.append(')');
4832 }
4833 decodeTypeImpPostfix(buffer, pType->pHead);
4834 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004835 case TY_ARRAY:
4836 {
4837 String temp;
4838 temp.printf("[%d]", pType->length);
4839 buffer.append(temp);
4840 }
4841 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004842 case TY_FUNC:
4843 buffer.append('(');
4844 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4845 decodeTypeImp(buffer, pArg);
4846 if (pArg->pTail) {
4847 buffer.appendCStr(", ");
4848 }
4849 }
4850 buffer.append(')');
4851 break;
4852 default:
4853 break;
Jack Palevich86351982009-06-30 18:09:56 -07004854 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004855 }
4856
Jack Palevich86351982009-06-30 18:09:56 -07004857 void printType(Type* pType) {
4858 String buffer;
4859 decodeType(buffer, pType);
4860 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004861 }
4862
Jack Palevich2ff5c222009-07-23 15:11:22 -07004863 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004864 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004865 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004866 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004867 } else if (tok == TOK_SHORT) {
4868 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004869 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004870 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004871 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004872 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004873 } else if (tok == TOK_FLOAT) {
4874 pType = mkpFloat;
4875 } else if (tok == TOK_DOUBLE) {
4876 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004877 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004878 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004879 }
4880 next();
Jack Palevich86351982009-06-30 18:09:56 -07004881 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004882 }
4883
Jack Palevich2ff5c222009-07-23 15:11:22 -07004884 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004885 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004886 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004887 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004888 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004889 if (declName) {
4890 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004891 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004892 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004893
Jack Palevich86351982009-06-30 18:09:56 -07004894 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004895 pType->length = pOldType->length;
4896 } else if (nameRequired) {
4897 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004898 }
Jack Palevich3f226492009-07-02 14:46:19 -07004899 // fprintf(stderr, "Parsed a declaration: ");
4900 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004901 if (reportFailure) {
4902 return NULL;
4903 }
Jack Palevich86351982009-06-30 18:09:56 -07004904 return pType;
4905 }
4906
Jack Palevich2ff5c222009-07-23 15:11:22 -07004907 Type* expectDeclaration(Type* pBaseType) {
4908 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004909 if (! pType) {
4910 error("Expected a declaration");
4911 }
4912 return pType;
4913 }
4914
Jack Palevich3f226492009-07-02 14:46:19 -07004915 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004916 Type* acceptCastTypeDeclaration() {
4917 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004918 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004919 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004920 }
Jack Palevich86351982009-06-30 18:09:56 -07004921 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004922 }
4923
Jack Palevich2ff5c222009-07-23 15:11:22 -07004924 Type* expectCastTypeDeclaration() {
4925 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004926 if (! pType) {
4927 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004928 }
Jack Palevich3f226492009-07-02 14:46:19 -07004929 return pType;
4930 }
4931
4932 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004933 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004934 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004935 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004936 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004937 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004938 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004939 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004940 return pType;
4941 }
4942
4943 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004944 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004945 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004946 // direct-dcl :
4947 // name
4948 // (dcl)
4949 // direct-dcl()
4950 // direct-dcl[]
4951 Type* pNewHead = NULL;
4952 if (accept('(')) {
4953 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004954 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004955 skip(')');
4956 } else if ((declName = acceptSymbol()) != 0) {
4957 if (nameAllowed == false && declName) {
4958 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004959 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004960 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004961 } else if (nameRequired && ! declName) {
4962 String temp;
4963 decodeToken(temp, tok, true);
4964 error("Expected name. Got %s", temp.getUnwrapped());
4965 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004966 }
Jack Palevichb6154502009-08-04 14:56:09 -07004967 for(;;) {
4968 if (accept('(')) {
4969 // Function declaration
4970 Type* pTail = acceptArgs(nameAllowed);
4971 pType = createType(TY_FUNC, pType, pTail);
4972 skip(')');
4973 } if (accept('[')) {
4974 if (tok != ']') {
4975 if (tok != TOK_NUM || tokc <= 0) {
4976 error("Expected positive integer constant");
4977 } else {
4978 Type* pDecayType = createPtrType(pType);
4979 pType = createType(TY_ARRAY, pType, pDecayType);
4980 pType->length = tokc;
4981 }
4982 next();
4983 }
4984 skip(']');
4985 } else {
4986 break;
4987 }
Jack Palevich86351982009-06-30 18:09:56 -07004988 }
Jack Palevich3f226492009-07-02 14:46:19 -07004989
4990 if (pNewHead) {
4991 Type* pA = pNewHead;
4992 while (pA->pHead) {
4993 pA = pA->pHead;
4994 }
4995 pA->pHead = pType;
4996 pType = pNewHead;
4997 }
Jack Palevich86351982009-06-30 18:09:56 -07004998 return pType;
4999 }
5000
Jack Palevich2ff5c222009-07-23 15:11:22 -07005001 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005002 Type* pHead = NULL;
5003 Type* pTail = NULL;
5004 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005005 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005006 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005007 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005008 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005009 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005010 if (!pHead) {
5011 pHead = pParam;
5012 pTail = pParam;
5013 } else {
5014 pTail->pTail = pParam;
5015 pTail = pParam;
5016 }
5017 }
5018 }
5019 if (! accept(',')) {
5020 break;
5021 }
5022 }
5023 return pHead;
5024 }
5025
Jack Palevich2ff5c222009-07-23 15:11:22 -07005026 Type* expectPrimitiveType() {
5027 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005028 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005029 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005030 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005031 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005032 }
Jack Palevich86351982009-06-30 18:09:56 -07005033 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005034 }
5035
Jack Palevichb5e33312009-07-30 19:06:34 -07005036 void checkLVal() {
5037 if (pGen->getR0ExpressionType() != ET_LVALUE) {
5038 error("Expected an lval");
5039 }
5040 }
5041
Jack Palevich86351982009-06-30 18:09:56 -07005042 void addGlobalSymbol(Type* pDecl) {
5043 tokenid_t t = pDecl->id;
5044 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005045 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005046 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005047 }
Jack Palevich86351982009-06-30 18:09:56 -07005048 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005049 }
5050
Jack Palevich86351982009-06-30 18:09:56 -07005051 void reportDuplicate(tokenid_t t) {
5052 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005053 }
5054
Jack Palevich86351982009-06-30 18:09:56 -07005055 void addLocalSymbol(Type* pDecl) {
5056 tokenid_t t = pDecl->id;
5057 if (mLocals.isDefinedAtCurrentLevel(t)) {
5058 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005059 }
Jack Palevich86351982009-06-30 18:09:56 -07005060 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005061 }
5062
Jack Palevich95727a02009-07-06 12:07:15 -07005063 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005064 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005065
Jack Palevich95727a02009-07-06 12:07:15 -07005066 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005067 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005068 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005069 if (!pDecl) {
5070 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005071 }
Jack Palevich86351982009-06-30 18:09:56 -07005072 int variableAddress = 0;
5073 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005074 size_t alignment = pGen->stackAlignmentOf(pDecl);
5075 size_t alignmentMask = ~ (alignment - 1);
5076 size_t sizeOf = pGen->sizeOf(pDecl);
5077 loc = (loc + alignment - 1) & alignmentMask;
5078 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5079 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005080 variableAddress = -loc;
5081 VI(pDecl->id)->pAddress = (void*) variableAddress;
5082 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005083 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005084 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005085 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005086 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005087 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005088 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005089 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005090 if (tok == ',')
5091 next();
5092 }
5093 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005094 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005095 }
5096 }
5097
Jack Palevichf1728be2009-06-12 13:53:51 -07005098 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005099 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005100 }
5101
Jack Palevich37c54bd2009-07-14 18:35:36 -07005102 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005103 if (token == EOF ) {
5104 buffer.printf("EOF");
5105 } else if (token == TOK_NUM) {
5106 buffer.printf("numeric constant");
5107 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005108 if (token < 32) {
5109 buffer.printf("'\\x%02x'", token);
5110 } else {
5111 buffer.printf("'%c'", token);
5112 }
Jack Palevich569f1352009-06-29 14:29:08 -07005113 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005114 if (quote) {
5115 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5116 buffer.printf("keyword \"%s\"", nameof(token));
5117 } else {
5118 buffer.printf("symbol \"%s\"", nameof(token));
5119 }
5120 } else {
5121 buffer.printf("%s", nameof(token));
5122 }
Jack Palevich569f1352009-06-29 14:29:08 -07005123 }
5124 }
5125
Jack Palevich40600de2009-07-01 15:32:35 -07005126 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005127 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005128 if (!result) {
5129 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005130 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005131 error("Expected symbol. Got %s", temp.getUnwrapped());
5132 }
5133 return result;
5134 }
5135
Jack Palevich86351982009-06-30 18:09:56 -07005136 tokenid_t acceptSymbol() {
5137 tokenid_t result = 0;
5138 if (tok >= TOK_SYMBOL) {
5139 result = tok;
5140 next();
Jack Palevich86351982009-06-30 18:09:56 -07005141 }
5142 return result;
5143 }
5144
Jack Palevichb7c81e92009-06-04 19:56:13 -07005145 void globalDeclarations() {
5146 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005147 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005148 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005149 break;
5150 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005151 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005152 if (!pDecl) {
5153 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005154 }
Jack Palevich86351982009-06-30 18:09:56 -07005155 if (! isDefined(pDecl->id)) {
5156 addGlobalSymbol(pDecl);
5157 }
5158 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005159 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005160 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005161 }
Jack Palevich86351982009-06-30 18:09:56 -07005162 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005163 // it's a variable declaration
5164 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005165 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005166 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005167 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005168 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005169 }
Jack Palevich86351982009-06-30 18:09:56 -07005170 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005171 if (tok == TOK_NUM) {
5172 if (name) {
5173 * (int*) name->pAddress = tokc;
5174 }
5175 next();
5176 } else {
5177 error("Expected an integer constant");
5178 }
5179 }
Jack Palevich86351982009-06-30 18:09:56 -07005180 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005181 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005182 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005183 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005184 if (!pDecl) {
5185 break;
5186 }
5187 if (! isDefined(pDecl->id)) {
5188 addGlobalSymbol(pDecl);
5189 }
5190 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005191 }
5192 skip(';');
5193 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005194 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005195 if (accept(';')) {
5196 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005197 } else if (tok != '{') {
5198 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005199 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005200 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07005201 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005202 /* patch forward references */
5203 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005204 /* put function address */
5205 name->pAddress = (void*) codeBuf.getPC();
5206 }
5207 // Calculate stack offsets for parameters
5208 mLocals.pushLevel();
5209 intptr_t a = 8;
5210 int argCount = 0;
5211 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5212 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005213 if (pArg->id) {
5214 addLocalSymbol(pArg);
5215 }
Jack Palevich95727a02009-07-06 12:07:15 -07005216 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005217 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07005218 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005219 if (pArg->id) {
5220 VI(pArg->id)->pAddress = (void*) a;
5221 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005222 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07005223 argCount++;
5224 }
5225 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005226 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005227 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005228 block(0, true);
5229 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005230 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005231 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005232 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07005233 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005234 }
5235 }
5236 }
5237
Jack Palevich9cbd2262009-07-08 16:48:41 -07005238 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5239 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5240 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005241 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005242 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07005243 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005244 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005245 char* result = (char*) base;
5246 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005247 return result;
5248 }
5249
Jack Palevich21a15a22009-05-11 14:49:29 -07005250 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005251 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005252 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005253 pGlobalBase = 0;
5254 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005255 if (pGen) {
5256 delete pGen;
5257 pGen = 0;
5258 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005259 if (file) {
5260 delete file;
5261 file = 0;
5262 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005263 }
5264
Jack Palevich8c246a92009-07-14 21:14:10 -07005265 // One-time initialization, when class is constructed.
5266 void init() {
5267 mpSymbolLookupFn = 0;
5268 mpSymbolLookupContext = 0;
5269 }
5270
Jack Palevich21a15a22009-05-11 14:49:29 -07005271 void clear() {
5272 tok = 0;
5273 tokc = 0;
5274 tokl = 0;
5275 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005276 rsym = 0;
5277 loc = 0;
5278 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005279 dptr = 0;
5280 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005281 file = 0;
5282 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005283 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005284 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005285 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005286 mLineNumber = 1;
5287 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005288 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005289 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005290
Jack Palevich22305132009-05-13 10:58:45 -07005291 void setArchitecture(const char* architecture) {
5292 delete pGen;
5293 pGen = 0;
5294
5295 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005296#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005297 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005298 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005299 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005300#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005301#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005302 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005303 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005304 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005305#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005306 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005307 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005308 }
5309 }
5310
5311 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005312#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005313 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005314#elif defined(DEFAULT_X86_CODEGEN)
5315 pGen = new X86CodeGenerator();
5316#endif
5317 }
5318 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005319 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005320 } else {
5321 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005322 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005323 }
5324 }
5325
Jack Palevich77ae76e2009-05-10 19:59:24 -07005326public:
Jack Palevich22305132009-05-13 10:58:45 -07005327 struct args {
5328 args() {
5329 architecture = 0;
5330 }
5331 const char* architecture;
5332 };
5333
Jack Paleviche7b59062009-05-19 17:12:17 -07005334 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005335 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005336 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005337 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005338
Jack Paleviche7b59062009-05-19 17:12:17 -07005339 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005340 cleanup();
5341 }
5342
Jack Palevich8c246a92009-07-14 21:14:10 -07005343 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5344 mpSymbolLookupFn = pFn;
5345 mpSymbolLookupContext = pContext;
5346 }
5347
Jack Palevich1cdef202009-05-22 12:06:27 -07005348 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005349 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005350
Jack Palevich2ff5c222009-07-23 15:11:22 -07005351 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005352 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005353 cleanup();
5354 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005355 mTokenTable.setArena(&mGlobalArena);
5356 mGlobals.setArena(&mGlobalArena);
5357 mGlobals.setTokenTable(&mTokenTable);
5358 mLocals.setArena(&mLocalArena);
5359 mLocals.setTokenTable(&mTokenTable);
5360
5361 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005362 codeBuf.init(ALLOC_SIZE);
5363 setArchitecture(NULL);
5364 if (!pGen) {
5365 return -1;
5366 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005367#ifdef PROVIDE_TRACE_CODEGEN
5368 pGen = new TraceCodeGenerator(pGen);
5369#endif
5370 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005371 pGen->init(&codeBuf);
5372 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005373 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5374 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005375 inp();
5376 next();
5377 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005378 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005379 result = pGen->finishCompile();
5380 if (result == 0) {
5381 if (mErrorBuf.len()) {
5382 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005383 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005384 }
Jack Palevichce105a92009-07-16 14:30:33 -07005385 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005386 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005387 }
5388
Jack Palevich86351982009-06-30 18:09:56 -07005389 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005390 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005391 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005392 mkpChar = createType(TY_CHAR, NULL, NULL);
5393 mkpVoid = createType(TY_VOID, NULL, NULL);
5394 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5395 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5396 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5397 mkpIntPtr = createPtrType(mkpInt);
5398 mkpCharPtr = createPtrType(mkpChar);
5399 mkpFloatPtr = createPtrType(mkpFloat);
5400 mkpDoublePtr = createPtrType(mkpDouble);
5401 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005402 }
5403
Jack Palevicha6baa232009-06-12 11:25:59 -07005404 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005405 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005406 }
5407
Jack Palevich569f1352009-06-29 14:29:08 -07005408 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005409 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005410 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005411 }
5412
Jack Palevich569f1352009-06-29 14:29:08 -07005413 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005414 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005415 error("Undefined forward reference: %s",
5416 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005417 }
5418 return true;
5419 }
5420
Jack Palevich21a15a22009-05-11 14:49:29 -07005421 int dump(FILE* out) {
5422 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5423 return 0;
5424 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005425
Jack Palevicha6535612009-05-13 16:24:17 -07005426 int disassemble(FILE* out) {
5427 return pGen->disassemble(out);
5428 }
5429
Jack Palevich1cdef202009-05-22 12:06:27 -07005430 /* Look through the symbol table to find a symbol.
5431 * If found, return its value.
5432 */
5433 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005434 if (mCompileResult == 0) {
5435 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5436 VariableInfo* pVariableInfo = VI(tok);
5437 if (pVariableInfo) {
5438 return pVariableInfo->pAddress;
5439 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005440 }
5441 return NULL;
5442 }
5443
Jack Palevicheedf9d22009-06-04 16:23:40 -07005444 void getPragmas(ACCsizei* actualStringCount,
5445 ACCsizei maxStringCount, ACCchar** strings) {
5446 int stringCount = mPragmaStringCount;
5447 if (actualStringCount) {
5448 *actualStringCount = stringCount;
5449 }
5450 if (stringCount > maxStringCount) {
5451 stringCount = maxStringCount;
5452 }
5453 if (strings) {
5454 char* pPragmas = mPragmas.getUnwrapped();
5455 while (stringCount-- > 0) {
5456 *strings++ = pPragmas;
5457 pPragmas += strlen(pPragmas) + 1;
5458 }
5459 }
5460 }
5461
Jack Palevichac0e95e2009-05-29 13:53:44 -07005462 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005463 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005464 }
5465
Jack Palevich77ae76e2009-05-10 19:59:24 -07005466};
5467
Jack Paleviche7b59062009-05-19 17:12:17 -07005468const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005469 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5470
Jack Paleviche7b59062009-05-19 17:12:17 -07005471const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005472 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5473 5, 5, /* ==, != */
5474 9, 10, /* &&, || */
5475 6, 7, 8, /* & ^ | */
5476 2, 2 /* ~ ! */
5477 };
5478
Jack Palevich8b0624c2009-05-20 12:12:06 -07005479#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005480FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005481#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005482
Jack Palevich8b0624c2009-05-20 12:12:06 -07005483#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005484const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005485 0x1, // ++
5486 0xff, // --
5487 0xc1af0f, // *
5488 0xf9f79991, // /
5489 0xf9f79991, // % (With manual assist to swap results)
5490 0xc801, // +
5491 0xd8f7c829, // -
5492 0xe0d391, // <<
5493 0xf8d391, // >>
5494 0xe, // <=
5495 0xd, // >=
5496 0xc, // <
5497 0xf, // >
5498 0x4, // ==
5499 0x5, // !=
5500 0x0, // &&
5501 0x1, // ||
5502 0xc821, // &
5503 0xc831, // ^
5504 0xc809, // |
5505 0xd0f7, // ~
5506 0x4 // !
5507};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005508#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005509
Jack Palevich1cdef202009-05-22 12:06:27 -07005510struct ACCscript {
5511 ACCscript() {
5512 text = 0;
5513 textLength = 0;
5514 accError = ACC_NO_ERROR;
5515 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005516
Jack Palevich1cdef202009-05-22 12:06:27 -07005517 ~ACCscript() {
5518 delete text;
5519 }
Jack Palevich546b2242009-05-13 15:10:04 -07005520
Jack Palevich8c246a92009-07-14 21:14:10 -07005521 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5522 compiler.registerSymbolCallback(pFn, pContext);
5523 }
5524
Jack Palevich1cdef202009-05-22 12:06:27 -07005525 void setError(ACCenum error) {
5526 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5527 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005528 }
5529 }
5530
Jack Palevich1cdef202009-05-22 12:06:27 -07005531 ACCenum getError() {
5532 ACCenum result = accError;
5533 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005534 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005535 }
5536
Jack Palevich1cdef202009-05-22 12:06:27 -07005537 Compiler compiler;
5538 char* text;
5539 int textLength;
5540 ACCenum accError;
5541};
5542
5543
5544extern "C"
5545ACCscript* accCreateScript() {
5546 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005547}
Jack Palevich1cdef202009-05-22 12:06:27 -07005548
5549extern "C"
5550ACCenum accGetError( ACCscript* script ) {
5551 return script->getError();
5552}
5553
5554extern "C"
5555void accDeleteScript(ACCscript* script) {
5556 delete script;
5557}
5558
5559extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005560void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5561 ACCvoid* pContext) {
5562 script->registerSymbolCallback(pFn, pContext);
5563}
5564
5565extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005566void accScriptSource(ACCscript* script,
5567 ACCsizei count,
5568 const ACCchar ** string,
5569 const ACCint * length) {
5570 int totalLength = 0;
5571 for(int i = 0; i < count; i++) {
5572 int len = -1;
5573 const ACCchar* s = string[i];
5574 if (length) {
5575 len = length[i];
5576 }
5577 if (len < 0) {
5578 len = strlen(s);
5579 }
5580 totalLength += len;
5581 }
5582 delete script->text;
5583 char* text = new char[totalLength + 1];
5584 script->text = text;
5585 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005586 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005587 for(int i = 0; i < count; i++) {
5588 int len = -1;
5589 const ACCchar* s = string[i];
5590 if (length) {
5591 len = length[i];
5592 }
5593 if (len < 0) {
5594 len = strlen(s);
5595 }
Jack Palevich09555c72009-05-27 12:25:55 -07005596 memcpy(dest, s, len);
5597 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005598 }
5599 text[totalLength] = '\0';
5600}
5601
5602extern "C"
5603void accCompileScript(ACCscript* script) {
5604 int result = script->compiler.compile(script->text, script->textLength);
5605 if (result) {
5606 script->setError(ACC_INVALID_OPERATION);
5607 }
5608}
5609
5610extern "C"
5611void accGetScriptiv(ACCscript* script,
5612 ACCenum pname,
5613 ACCint * params) {
5614 switch (pname) {
5615 case ACC_INFO_LOG_LENGTH:
5616 *params = 0;
5617 break;
5618 }
5619}
5620
5621extern "C"
5622void accGetScriptInfoLog(ACCscript* script,
5623 ACCsizei maxLength,
5624 ACCsizei * length,
5625 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005626 char* message = script->compiler.getErrorMessage();
5627 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005628 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005629 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005630 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005631 if (infoLog && maxLength > 0) {
5632 int trimmedLength = maxLength < messageLength ?
5633 maxLength : messageLength;
5634 memcpy(infoLog, message, trimmedLength);
5635 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005636 }
5637}
5638
5639extern "C"
5640void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5641 ACCvoid ** address) {
5642 void* value = script->compiler.lookup(name);
5643 if (value) {
5644 *address = value;
5645 } else {
5646 script->setError(ACC_INVALID_VALUE);
5647 }
5648}
5649
Jack Palevicheedf9d22009-06-04 16:23:40 -07005650extern "C"
5651void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5652 ACCsizei maxStringCount, ACCchar** strings){
5653 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5654}
5655
-b master422972c2009-06-17 19:13:52 -07005656extern "C"
5657void accDisassemble(ACCscript* script) {
5658 script->compiler.disassemble(stderr);
5659}
5660
Jack Palevicheedf9d22009-06-04 16:23:40 -07005661
Jack Palevich1cdef202009-05-22 12:06:27 -07005662} // namespace acc
5663