blob: 73f7ef8d14f5ff91cd52a2b9bfdc595d2c96c20a [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 Palevich61de31f2009-09-08 11:06:40 -070016#include <limits.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070017#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070018#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070020#include <stdlib.h>
21#include <string.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070022#include <unistd.h>
23
Jack Palevich2d11dfb2009-06-08 14:34:26 -070024#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070025
Jack Palevich8dc662e2009-06-09 22:53:47 +000026#if defined(__i386__)
27#include <sys/mman.h>
28#endif
29
Jack Palevich546b2242009-05-13 15:10:04 -070030
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 Palevich61de31f2009-09-08 11:06:40 -070061// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
62// #define DEBUG_SAVE_INPUT_TO_FILE
63
64#ifdef ARM_USE_VFP
65#define DEBUG_DUMP_PATTERN "/sdcard/acc_dump/%d.c"
66#else
67#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
68#endif
69
Jack Palevich7f5b1a22009-08-17 16:54:56 -070070#define assert(b) assertImpl(b, __LINE__)
71
Jack Palevichbbf8ab52009-05-11 11:54:30 -070072namespace acc {
73
Jack Palevich8df46192009-07-07 14:48:51 -070074// Subset of STL vector.
75template<class E> class Vector {
76 public:
77 Vector() {
78 mpBase = 0;
79 mUsed = 0;
80 mSize = 0;
81 }
82
83 ~Vector() {
84 if (mpBase) {
85 for(size_t i = 0; i < mUsed; i++) {
86 mpBase[mUsed].~E();
87 }
88 free(mpBase);
89 }
90 }
91
92 inline E& operator[](size_t i) {
93 return mpBase[i];
94 }
95
96 inline E& front() {
97 return mpBase[0];
98 }
99
100 inline E& back() {
101 return mpBase[mUsed - 1];
102 }
103
104 void pop_back() {
105 mUsed -= 1;
106 mpBase[mUsed].~E();
107 }
108
109 void push_back(const E& item) {
110 * ensure(1) = item;
111 }
112
113 size_t size() {
114 return mUsed;
115 }
116
117private:
118 E* ensure(int n) {
119 size_t newUsed = mUsed + n;
120 if (newUsed > mSize) {
121 size_t newSize = mSize * 2 + 10;
122 if (newSize < newUsed) {
123 newSize = newUsed;
124 }
125 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
126 mSize = newSize;
127 }
128 E* result = mpBase + mUsed;
129 mUsed = newUsed;
130 return result;
131 }
132
133 E* mpBase;
134 size_t mUsed;
135 size_t mSize;
136};
137
Jack Palevichac0e95e2009-05-29 13:53:44 -0700138class ErrorSink {
139public:
140 void error(const char *fmt, ...) {
141 va_list ap;
142 va_start(ap, fmt);
143 verror(fmt, ap);
144 va_end(ap);
145 }
146
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700147 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700148 virtual void verror(const char* fmt, va_list ap) = 0;
149};
150
151class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700152 typedef int tokenid_t;
153 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700154 TY_INT, // 0
155 TY_CHAR, // 1
156 TY_SHORT, // 2
157 TY_VOID, // 3
158 TY_FLOAT, // 4
159 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700160 TY_POINTER, // 6
161 TY_ARRAY, // 7
162 TY_STRUCT, // 8
163 TY_FUNC, // 9
164 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700165 };
166
167 struct Type {
168 TypeTag tag;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700169 tokenid_t id; // For function arguments, global vars, local vars, struct elements
170 tokenid_t structTag; // For structs the name of the struct
171 int length; // length of array, offset of struct element. -1 means struct is forward defined
172 int alignment; // for structs only
173 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700174 Type* pTail;
175 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700176
Jack Palevichba929a42009-07-17 10:20:32 -0700177 enum ExpressionType {
178 ET_RVALUE,
179 ET_LVALUE
180 };
181
182 struct ExpressionValue {
183 ExpressionValue() {
184 et = ET_RVALUE;
185 pType = NULL;
186 }
187 ExpressionType et;
188 Type* pType;
189 };
190
Jack Palevich21a15a22009-05-11 14:49:29 -0700191 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700192 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700193 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 ErrorSink* mErrorSink;
195 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700196 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700197
Jack Palevich21a15a22009-05-11 14:49:29 -0700198 void release() {
199 if (pProgramBase != 0) {
200 free(pProgramBase);
201 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700202 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700203 }
204
Jack Palevich0a280a02009-06-11 10:53:51 -0700205 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700206 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700207 bool overflow = newSize > mSize;
208 if (overflow && !mOverflowed) {
209 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700210 if (mErrorSink) {
211 mErrorSink->error("Code too large: %d bytes", newSize);
212 }
213 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700214 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700215 }
216
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 public:
218 CodeBuf() {
219 pProgramBase = 0;
220 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700221 mErrorSink = 0;
222 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700223 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700224 }
225
226 ~CodeBuf() {
227 release();
228 }
229
230 void init(int size) {
231 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700232 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700233 pProgramBase = (char*) calloc(1, size);
234 ind = pProgramBase;
235 }
236
Jack Palevichac0e95e2009-05-29 13:53:44 -0700237 void setErrorSink(ErrorSink* pErrorSink) {
238 mErrorSink = pErrorSink;
239 }
240
Jack Palevich546b2242009-05-13 15:10:04 -0700241 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700242 if(check(4)) {
243 return 0;
244 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700245 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700246 * (int*) ind = n;
247 ind += 4;
248 return result;
249 }
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 /*
252 * Output a byte. Handles all values, 0..ff.
253 */
254 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700255 if(check(1)) {
256 return;
257 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 *ind++ = n;
259 }
260
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 inline void* getBase() {
262 return (void*) pProgramBase;
263 }
264
Jack Palevich8b0624c2009-05-20 12:12:06 -0700265 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700266 return ind - pProgramBase;
267 }
268
Jack Palevich8b0624c2009-05-20 12:12:06 -0700269 intptr_t getPC() {
270 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700271 }
272 };
273
Jack Palevich1cdef202009-05-22 12:06:27 -0700274 /**
275 * A code generator creates an in-memory program, generating the code on
276 * the fly. There is one code generator implementation for each supported
277 * architecture.
278 *
279 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700280 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700281 * FP - a frame pointer for accessing function arguments and local
282 * variables.
283 * SP - a stack pointer for storing intermediate results while evaluating
284 * expressions. The stack pointer grows downwards.
285 *
286 * The function calling convention is that all arguments are placed on the
287 * stack such that the first argument has the lowest address.
288 * After the call, the result is in R0. The caller is responsible for
289 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700290 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700291 * FP and SP registers are saved.
292 */
293
Jack Palevich21a15a22009-05-11 14:49:29 -0700294 class CodeGenerator {
295 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700296 CodeGenerator() {
297 mErrorSink = 0;
298 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700299 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700300 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700301 virtual ~CodeGenerator() {}
302
Jack Palevich22305132009-05-13 10:58:45 -0700303 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700304 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700305 pCodeBuf->setErrorSink(mErrorSink);
306 }
307
Jack Palevichb67b18f2009-06-11 21:12:23 -0700308 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700309 mErrorSink = pErrorSink;
310 if (pCodeBuf) {
311 pCodeBuf->setErrorSink(mErrorSink);
312 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700313 }
314
Jack Palevich58c30ee2009-07-17 16:35:23 -0700315 /* Give the code generator some utility types so it can
316 * use its own types as needed for the results of some
317 * operations like gcmp.
318 */
319
Jack Palevicha8f427f2009-07-13 18:40:08 -0700320 void setTypes(Type* pInt) {
321 mkpInt = pInt;
322 }
323
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700325 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700326 * Save the old value of the FP.
327 * Set the new value of the FP.
328 * Convert from the native platform calling convention to
329 * our stack-based calling convention. This may require
330 * pushing arguments from registers to the stack.
331 * Allocate "N" bytes of stack space. N isn't known yet, so
332 * just emit the instructions for adjusting the stack, and return
333 * the address to patch up. The patching will be done in
334 * functionExit().
335 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700336 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700337 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700338
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 /* Emit a function epilog.
340 * Restore the old SP and FP register values.
341 * Return to the calling function.
342 * argCount - the number of arguments to the function.
343 * localVariableAddress - returned from functionEntry()
344 * localVariableSize - the size in bytes of the local variables.
345 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700346 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700350 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700351
Jack Palevich1a539db2009-07-08 13:04:41 -0700352 /* Load floating point value from global address. */
353 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700354
Jack Palevich9221bcc2009-08-26 16:15:07 -0700355 /* Add the struct offset in bytes to R0, change the type to pType */
356 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
357
Jack Palevich1cdef202009-05-22 12:06:27 -0700358 /* Jump to a target, and return the address of the word that
359 * holds the target data, in case it needs to be fixed up later.
360 */
Jack Palevich22305132009-05-13 10:58:45 -0700361 virtual int gjmp(int t) = 0;
362
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 /* Test R0 and jump to a target if the test succeeds.
364 * l = 0: je, l == 1: jne
365 * Return the address of the word that holds the targed data, in
366 * case it needs to be fixed up later.
367 */
Jack Palevich22305132009-05-13 10:58:45 -0700368 virtual int gtst(bool l, int t) = 0;
369
Jack Palevich9eed7a22009-07-06 17:24:34 -0700370 /* Compare TOS against R0, and store the boolean result in R0.
371 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 * op specifies the comparison.
373 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700374 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700375
Jack Palevich9eed7a22009-07-06 17:24:34 -0700376 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700378 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700379 */
Jack Palevich546b2242009-05-13 15:10:04 -0700380 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700381
Jack Palevich9eed7a22009-07-06 17:24:34 -0700382 /* Compare 0 against R0, and store the boolean result in R0.
383 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700384 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700385 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700386
387 /* Perform the arithmetic op specified by op. 0 is the
388 * left argument, R0 is the right argument.
389 */
390 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700391
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700392 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 */
394 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700395
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700396 /* Turn R0, TOS into R0 TOS R0 */
397
398 virtual void over() = 0;
399
400 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700401 */
402 virtual void popR0() = 0;
403
Jack Palevich9eed7a22009-07-06 17:24:34 -0700404 /* Store R0 to the address stored in TOS.
405 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700407 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700408
Jack Palevich1cdef202009-05-22 12:06:27 -0700409 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700411 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700412
Jack Palevich1cdef202009-05-22 12:06:27 -0700413 /* Load the absolute address of a variable to R0.
414 * If ea <= LOCAL, then this is a local variable, or an
415 * argument, addressed relative to FP.
416 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700417 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700418 * et is ET_RVALUE for things like string constants, ET_LVALUE for
419 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700421 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700422
Jack Palevich9f51a262009-07-29 16:22:26 -0700423 /* Load the pc-relative address of a forward-referenced variable to R0.
424 * Return the address of the 4-byte constant so that it can be filled
425 * in later.
426 */
427 virtual int leaForward(int ea, Type* pPointerType) = 0;
428
Jack Palevich8df46192009-07-07 14:48:51 -0700429 /**
430 * Convert R0 to the given type.
431 */
Jack Palevichb6154502009-08-04 14:56:09 -0700432
433 void convertR0(Type* pType) {
434 convertR0Imp(pType, false);
435 }
436
437 void castR0(Type* pType) {
438 convertR0Imp(pType, true);
439 }
440
441 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700442
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 /* Emit code to adjust the stack for a function call. Return the
444 * label for the address of the instruction that adjusts the
445 * stack size. This will be passed as argument "a" to
446 * endFunctionCallArguments.
447 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700448 virtual int beginFunctionCallArguments() = 0;
449
Jack Palevich1cdef202009-05-22 12:06:27 -0700450 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700451 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700452 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700453 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700454
Jack Palevich1cdef202009-05-22 12:06:27 -0700455 /* Patch the function call preamble.
456 * a is the address returned from beginFunctionCallArguments
457 * l is the number of bytes the arguments took on the stack.
458 * Typically you would also emit code to convert the argument
459 * list into whatever the native function calling convention is.
460 * On ARM for example you would pop the first 5 arguments into
461 * R0..R4
462 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700463 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700464
Jack Palevich1cdef202009-05-22 12:06:27 -0700465 /* Emit a call to an unknown function. The argument "symbol" needs to
466 * be stored in the location where the address should go. It forms
467 * a chain. The address will be patched later.
468 * Return the address of the word that has to be patched.
469 */
Jack Palevich8df46192009-07-07 14:48:51 -0700470 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700471
Jack Palevich1cdef202009-05-22 12:06:27 -0700472 /* Call a function pointer. L is the number of bytes the arguments
473 * take on the stack. The address of the function is stored at
474 * location SP + l.
475 */
Jack Palevich8df46192009-07-07 14:48:51 -0700476 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700477
Jack Palevich1cdef202009-05-22 12:06:27 -0700478 /* Adjust SP after returning from a function call. l is the
479 * number of bytes of arguments stored on the stack. isIndirect
480 * is true if this was an indirect call. (In which case the
481 * address of the function is stored at location SP + l.)
482 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700483 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700484
Jack Palevich1cdef202009-05-22 12:06:27 -0700485 /* Print a disassembly of the assembled code to out. Return
486 * non-zero if there is an error.
487 */
Jack Palevicha6535612009-05-13 16:24:17 -0700488 virtual int disassemble(FILE* out) = 0;
489
Jack Palevich1cdef202009-05-22 12:06:27 -0700490 /* Generate a symbol at the current PC. t is the head of a
491 * linked list of addresses to patch.
492 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700493 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700494
Jack Palevich9f51a262009-07-29 16:22:26 -0700495 /* Resolve a forward reference function at the current PC.
496 * t is the head of a
497 * linked list of addresses to patch.
498 * (Like gsym, but using absolute address, not PC relative address.)
499 */
500 virtual void resolveForward(int t) = 0;
501
Jack Palevich1cdef202009-05-22 12:06:27 -0700502 /*
503 * Do any cleanup work required at the end of a compile.
504 * For example, an instruction cache might need to be
505 * invalidated.
506 * Return non-zero if there is an error.
507 */
508 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700509
Jack Palevicha6535612009-05-13 16:24:17 -0700510 /**
511 * Adjust relative branches by this amount.
512 */
513 virtual int jumpOffset() = 0;
514
Jack Palevich9eed7a22009-07-06 17:24:34 -0700515 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700516 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700517 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700518 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700519
520 /**
521 * Array element alignment (in bytes) for this type of data.
522 */
523 virtual size_t sizeOf(Type* type) = 0;
524
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700525 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700526 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700527 }
528
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700529 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700530 return mExpressionStack.back().et;
531 }
532
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700533 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700534 mExpressionStack.back().et = et;
535 }
536
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700537 virtual size_t getExpressionStackDepth() {
538 return mExpressionStack.size();
539 }
540
Jack Palevichb5e33312009-07-30 19:06:34 -0700541 virtual void forceR0RVal() {
542 if (getR0ExpressionType() == ET_LVALUE) {
543 loadR0FromR0();
544 }
545 }
546
Jack Palevich21a15a22009-05-11 14:49:29 -0700547 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700548 /*
549 * Output a byte. Handles all values, 0..ff.
550 */
551 void ob(int n) {
552 pCodeBuf->ob(n);
553 }
554
Jack Palevich8b0624c2009-05-20 12:12:06 -0700555 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700556 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700557 }
558
Jack Palevich8b0624c2009-05-20 12:12:06 -0700559 intptr_t getBase() {
560 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700561 }
562
Jack Palevich8b0624c2009-05-20 12:12:06 -0700563 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700564 return pCodeBuf->getPC();
565 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700566
567 intptr_t getSize() {
568 return pCodeBuf->getSize();
569 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700570
571 void error(const char* fmt,...) {
572 va_list ap;
573 va_start(ap, fmt);
574 mErrorSink->verror(fmt, ap);
575 va_end(ap);
576 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700577
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700578 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700579 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700580 error("code generator assertion failed at line %s:%d.", __FILE__, line);
581 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700582 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700583 }
584 }
Jack Palevich8df46192009-07-07 14:48:51 -0700585
586 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700587 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700588 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700589 mExpressionStack.back().et = ET_RVALUE;
590 }
591
592 void setR0Type(Type* pType, ExpressionType et) {
593 assert(pType != NULL);
594 mExpressionStack.back().pType = pType;
595 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700596 }
597
Jack Palevich8df46192009-07-07 14:48:51 -0700598 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700599 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700600 }
601
602 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700603 if (mExpressionStack.size()) {
604 mExpressionStack.push_back(mExpressionStack.back());
605 } else {
606 mExpressionStack.push_back(ExpressionValue());
607 }
608
Jack Palevich8df46192009-07-07 14:48:51 -0700609 }
610
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700611 void overType() {
612 size_t size = mExpressionStack.size();
613 if (size >= 2) {
614 mExpressionStack.push_back(mExpressionStack.back());
615 mExpressionStack[size-1] = mExpressionStack[size-2];
616 mExpressionStack[size-2] = mExpressionStack[size];
617 }
618 }
619
Jack Palevich8df46192009-07-07 14:48:51 -0700620 void popType() {
621 mExpressionStack.pop_back();
622 }
623
624 bool bitsSame(Type* pA, Type* pB) {
625 return collapseType(pA->tag) == collapseType(pB->tag);
626 }
627
628 TypeTag collapseType(TypeTag tag) {
629 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700630 TY_INT,
631 TY_INT,
632 TY_INT,
633 TY_VOID,
634 TY_FLOAT,
635 TY_DOUBLE,
636 TY_INT,
637 TY_INT,
638 TY_VOID,
639 TY_VOID,
640 TY_VOID
641 };
Jack Palevich8df46192009-07-07 14:48:51 -0700642 return collapsedTag[tag];
643 }
644
Jack Palevich1a539db2009-07-08 13:04:41 -0700645 TypeTag collapseTypeR0() {
646 return collapseType(getR0Type()->tag);
647 }
648
Jack Palevichb6154502009-08-04 14:56:09 -0700649 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700650 return isFloatTag(pType->tag);
651 }
652
Jack Palevichb6154502009-08-04 14:56:09 -0700653 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700654 return tag == TY_FLOAT || tag == TY_DOUBLE;
655 }
656
Jack Palevichb6154502009-08-04 14:56:09 -0700657 static bool isPointerType(Type* pType) {
658 return isPointerTag(pType->tag);
659 }
660
661 static bool isPointerTag(TypeTag tag) {
662 return tag == TY_POINTER || tag == TY_ARRAY;
663 }
664
665 Type* getPointerArithmeticResultType(Type* a, Type* b) {
666 TypeTag aTag = a->tag;
667 TypeTag bTag = b->tag;
668 if (aTag == TY_POINTER) {
669 return a;
670 }
671 if (bTag == TY_POINTER) {
672 return b;
673 }
674 if (aTag == TY_ARRAY) {
675 return a->pTail;
676 }
677 if (bTag == TY_ARRAY) {
678 return b->pTail;
679 }
680 return NULL;
681 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700682 Type* mkpInt;
683
Jack Palevich21a15a22009-05-11 14:49:29 -0700684 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700685 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700686 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700687 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700688 };
689
Jack Paleviche7b59062009-05-19 17:12:17 -0700690#ifdef PROVIDE_ARM_CODEGEN
691
Jack Palevich22305132009-05-13 10:58:45 -0700692 class ARMCodeGenerator : public CodeGenerator {
693 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700694 ARMCodeGenerator() {
695#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700696 LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700697#else
Jack Palevichc0f25332009-08-25 12:23:43 -0700698 LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700699#endif
700 }
-b master422972c2009-06-17 19:13:52 -0700701
Jack Palevich22305132009-05-13 10:58:45 -0700702 virtual ~ARMCodeGenerator() {}
703
704 /* returns address to patch with local variable size
705 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700706 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700707 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700708 // sp -> arg4 arg5 ...
709 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700710 int regArgCount = calcRegArgCount(pDecl);
711 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700712 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700713 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700714 }
715 // sp -> arg0 arg1 ...
716 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700717 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700718 // sp, fp -> oldfp, retadr, arg0 arg1 ....
719 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700720 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700721 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700722 // We don't know how many local variables we are going to use,
723 // but we will round the allocation up to a multiple of
724 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700725 }
726
Jack Palevichb7718b92009-07-09 22:00:24 -0700727 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700728 // Round local variable size up to a multiple of stack alignment
729 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
730 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700731 // Patch local variable allocation code:
732 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700733 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700734 }
Jack Palevich69796b62009-05-14 15:42:26 -0700735 *(char*) (localVariableAddress) = localVariableSize;
736
Jack Palevich30321cb2009-08-20 15:34:23 -0700737#ifdef ARM_USE_VFP
738 {
Jack Palevichc0f25332009-08-25 12:23:43 -0700739 Type* pReturnType = pDecl->pHead;
740 switch(pReturnType->tag) {
741 case TY_FLOAT:
742 o4(0xEE170A90); // fmrs r0, s15
743 break;
744 case TY_DOUBLE:
745 o4(0xEC510B17); // fmrrd r0, r1, d7
746 break;
747 default:
748 break;
749 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700750 }
751#endif
752
Jack Palevich69796b62009-05-14 15:42:26 -0700753 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
754 o4(0xE1A0E00B); // mov lr, fp
755 o4(0xE59BB000); // ldr fp, [fp]
756 o4(0xE28ED004); // add sp, lr, #4
757 // sp -> retadr, arg0, ...
758 o4(0xE8BD4000); // ldmfd sp!, {lr}
759 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700760
761 // We store the PC into the lr so we can adjust the sp before
762 // returning. We need to pull off the registers we pushed
763 // earlier. We don't need to actually store them anywhere,
764 // just adjust the stack.
765 int regArgCount = calcRegArgCount(pDecl);
766 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700767 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
768 }
769 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700770 }
771
772 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700773 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700774 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700775 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700776 }
777
Jack Palevich1a539db2009-07-08 13:04:41 -0700778 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700779 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700780 // Global, absolute address
781 o4(0xE59F0000); // ldr r0, .L1
782 o4(0xEA000000); // b .L99
783 o4(address); // .L1: .word ea
784 // .L99:
785
786 switch (pType->tag) {
787 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700788#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700789 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700790#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700791 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700792#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700793 break;
794 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700795#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700796 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700797#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700798 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -0700799#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700800 break;
801 default:
802 assert(false);
803 break;
804 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700805 }
806
Jack Palevich9221bcc2009-08-26 16:15:07 -0700807
808 virtual void addStructOffsetR0(int offset, Type* pType) {
809 if (offset) {
810 size_t immediate = 0;
811 if (encode12BitImmediate(offset, &immediate)) {
812 o4(0xE2800000 | immediate); // add r0, r0, #offset
813 } else {
814 error("structure offset out of range: %d", offset);
815 }
816 }
817 setR0Type(pType, ET_LVALUE);
818 }
819
Jack Palevich22305132009-05-13 10:58:45 -0700820 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700821 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700822 }
823
824 /* l = 0: je, l == 1: jne */
825 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700826 Type* pR0Type = getR0Type();
827 TypeTag tagR0 = pR0Type->tag;
828 switch(tagR0) {
829 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -0700830#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700831 o4(0xEEF57A40); // fcmpzs s15
832 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700833#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700834 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -0700835 o4(0xE3500000); // cmp r0,#0
836#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700837 break;
838 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -0700839#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700840 o4(0xEEB57B40); // fcmpzd d7
841 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700842#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700843 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -0700844 o4(0xE3500000); // cmp r0,#0
845#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700846 break;
847 default:
Jack Palevich30321cb2009-08-20 15:34:23 -0700848 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700849 break;
850 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700851 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
852 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700853 }
854
Jack Palevich58c30ee2009-07-17 16:35:23 -0700855 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700856 Type* pR0Type = getR0Type();
857 Type* pTOSType = getTOSType();
858 TypeTag tagR0 = collapseType(pR0Type->tag);
859 TypeTag tagTOS = collapseType(pTOSType->tag);
860 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700861 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700862 o4(0xE1510000); // cmp r1, r1
863 switch(op) {
864 case OP_EQUALS:
865 o4(0x03A00001); // moveq r0,#1
866 o4(0x13A00000); // movne r0,#0
867 break;
868 case OP_NOT_EQUALS:
869 o4(0x03A00000); // moveq r0,#0
870 o4(0x13A00001); // movne r0,#1
871 break;
872 case OP_LESS_EQUAL:
873 o4(0xD3A00001); // movle r0,#1
874 o4(0xC3A00000); // movgt r0,#0
875 break;
876 case OP_GREATER:
877 o4(0xD3A00000); // movle r0,#0
878 o4(0xC3A00001); // movgt r0,#1
879 break;
880 case OP_GREATER_EQUAL:
881 o4(0xA3A00001); // movge r0,#1
882 o4(0xB3A00000); // movlt r0,#0
883 break;
884 case OP_LESS:
885 o4(0xA3A00000); // movge r0,#0
886 o4(0xB3A00001); // movlt r0,#1
887 break;
888 default:
889 error("Unknown comparison op %d", op);
890 break;
891 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700892 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
893 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700894#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -0700895 o4(0xEEB46BC7); // fcmped d6, d7
896 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700897 switch(op) {
898 case OP_EQUALS:
899 o4(0x03A00001); // moveq r0,#1
900 o4(0x13A00000); // movne r0,#0
901 break;
902 case OP_NOT_EQUALS:
903 o4(0x03A00000); // moveq r0,#0
904 o4(0x13A00001); // movne r0,#1
905 break;
906 case OP_LESS_EQUAL:
907 o4(0xD3A00001); // movle r0,#1
908 o4(0xC3A00000); // movgt r0,#0
909 break;
910 case OP_GREATER:
911 o4(0xD3A00000); // movle r0,#0
912 o4(0xC3A00001); // movgt r0,#1
913 break;
914 case OP_GREATER_EQUAL:
915 o4(0xA3A00001); // movge r0,#1
916 o4(0xB3A00000); // movlt r0,#0
917 break;
918 case OP_LESS:
919 o4(0xA3A00000); // movge r0,#0
920 o4(0xB3A00001); // movlt r0,#1
921 break;
922 default:
923 error("Unknown comparison op %d", op);
924 break;
925 }
926#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700927 switch(op) {
928 case OP_EQUALS:
929 callRuntime((void*) runtime_cmp_eq_dd);
930 break;
931 case OP_NOT_EQUALS:
932 callRuntime((void*) runtime_cmp_ne_dd);
933 break;
934 case OP_LESS_EQUAL:
935 callRuntime((void*) runtime_cmp_le_dd);
936 break;
937 case OP_GREATER:
938 callRuntime((void*) runtime_cmp_gt_dd);
939 break;
940 case OP_GREATER_EQUAL:
941 callRuntime((void*) runtime_cmp_ge_dd);
942 break;
943 case OP_LESS:
944 callRuntime((void*) runtime_cmp_lt_dd);
945 break;
946 default:
947 error("Unknown comparison op %d", op);
948 break;
949 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700950#endif
Jack Palevichb7718b92009-07-09 22:00:24 -0700951 } else {
952 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -0700953#ifdef ARM_USE_VFP
954 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -0700955 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -0700956 switch(op) {
957 case OP_EQUALS:
958 o4(0x03A00001); // moveq r0,#1
959 o4(0x13A00000); // movne r0,#0
960 break;
961 case OP_NOT_EQUALS:
962 o4(0x03A00000); // moveq r0,#0
963 o4(0x13A00001); // movne r0,#1
964 break;
965 case OP_LESS_EQUAL:
966 o4(0xD3A00001); // movle r0,#1
967 o4(0xC3A00000); // movgt r0,#0
968 break;
969 case OP_GREATER:
970 o4(0xD3A00000); // movle r0,#0
971 o4(0xC3A00001); // movgt r0,#1
972 break;
973 case OP_GREATER_EQUAL:
974 o4(0xA3A00001); // movge r0,#1
975 o4(0xB3A00000); // movlt r0,#0
976 break;
977 case OP_LESS:
978 o4(0xA3A00000); // movge r0,#0
979 o4(0xB3A00001); // movlt r0,#1
980 break;
981 default:
982 error("Unknown comparison op %d", op);
983 break;
984 }
985#else
Jack Palevichb7718b92009-07-09 22:00:24 -0700986 switch(op) {
987 case OP_EQUALS:
988 callRuntime((void*) runtime_cmp_eq_ff);
989 break;
990 case OP_NOT_EQUALS:
991 callRuntime((void*) runtime_cmp_ne_ff);
992 break;
993 case OP_LESS_EQUAL:
994 callRuntime((void*) runtime_cmp_le_ff);
995 break;
996 case OP_GREATER:
997 callRuntime((void*) runtime_cmp_gt_ff);
998 break;
999 case OP_GREATER_EQUAL:
1000 callRuntime((void*) runtime_cmp_ge_ff);
1001 break;
1002 case OP_LESS:
1003 callRuntime((void*) runtime_cmp_lt_ff);
1004 break;
1005 default:
1006 error("Unknown comparison op %d", op);
1007 break;
1008 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001009#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001010 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001011 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001012 }
1013
Jack Palevich546b2242009-05-13 15:10:04 -07001014 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001015 Type* pR0Type = getR0Type();
1016 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001017 TypeTag tagR0 = pR0Type->tag;
1018 TypeTag tagTOS = pTOSType->tag;
1019 bool isFloatR0 = isFloatTag(tagR0);
1020 bool isFloatTOS = isFloatTag(tagTOS);
1021 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001022 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001023 bool isPtrR0 = isPointerTag(tagR0);
1024 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001025 if (isPtrR0 || isPtrTOS) {
1026 if (isPtrR0 && isPtrTOS) {
1027 if (op != OP_MINUS) {
1028 error("Unsupported pointer-pointer operation %d.", op);
1029 }
1030 if (! typeEqual(pR0Type, pTOSType)) {
1031 error("Incompatible pointer types for subtraction.");
1032 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001033 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001034 setR0Type(mkpInt);
1035 int size = sizeOf(pR0Type->pHead);
1036 if (size != 1) {
1037 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001038 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001039 // TODO: Optimize for power-of-two.
1040 genOp(OP_DIV);
1041 }
1042 } else {
1043 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1044 error("Unsupported pointer-scalar operation %d", op);
1045 }
Jack Palevichb6154502009-08-04 14:56:09 -07001046 Type* pPtrType = getPointerArithmeticResultType(
1047 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001048 int size = sizeOf(pPtrType->pHead);
1049 if (size != 1) {
1050 // TODO: Optimize for power-of-two.
1051 liReg(size, 2);
1052 if (isPtrR0) {
1053 o4(0x0E0010192); // mul r1,r2,r1
1054 } else {
1055 o4(0x0E0000092); // mul r0,r2,r0
1056 }
1057 }
1058 switch(op) {
1059 case OP_PLUS:
1060 o4(0xE0810000); // add r0,r1,r0
1061 break;
1062 case OP_MINUS:
1063 o4(0xE0410000); // sub r0,r1,r0
1064 break;
1065 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001066 setR0Type(pPtrType);
1067 }
1068 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001069 switch(op) {
1070 case OP_MUL:
1071 o4(0x0E0000091); // mul r0,r1,r0
1072 break;
1073 case OP_DIV:
1074 callRuntime((void*) runtime_DIV);
1075 break;
1076 case OP_MOD:
1077 callRuntime((void*) runtime_MOD);
1078 break;
1079 case OP_PLUS:
1080 o4(0xE0810000); // add r0,r1,r0
1081 break;
1082 case OP_MINUS:
1083 o4(0xE0410000); // sub r0,r1,r0
1084 break;
1085 case OP_SHIFT_LEFT:
1086 o4(0xE1A00011); // lsl r0,r1,r0
1087 break;
1088 case OP_SHIFT_RIGHT:
1089 o4(0xE1A00051); // asr r0,r1,r0
1090 break;
1091 case OP_BIT_AND:
1092 o4(0xE0010000); // and r0,r1,r0
1093 break;
1094 case OP_BIT_XOR:
1095 o4(0xE0210000); // eor r0,r1,r0
1096 break;
1097 case OP_BIT_OR:
1098 o4(0xE1810000); // orr r0,r1,r0
1099 break;
1100 case OP_BIT_NOT:
1101 o4(0xE1E00000); // mvn r0, r0
1102 break;
1103 default:
1104 error("Unimplemented op %d\n", op);
1105 break;
1106 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001107 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001108 } else {
1109 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1110 if (pResultType->tag == TY_DOUBLE) {
1111 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001112
Jack Palevichb7718b92009-07-09 22:00:24 -07001113 switch(op) {
1114 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001115#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001116 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001117#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001118 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001119#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001120 break;
1121 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001122#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001123 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001124#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001125 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001126#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001127 break;
1128 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001129#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001130 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001131#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001132 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001133#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001134 break;
1135 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001136#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001137 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001138#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001139 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001140#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001141 break;
1142 default:
1143 error("Unsupported binary floating operation %d\n", op);
1144 break;
1145 }
1146 } else {
1147 setupFloatArgs();
1148 switch(op) {
1149 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001150#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001151 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001152#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001153 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001154#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001155 break;
1156 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001157#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001158 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001159#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001160 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001161#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001162 break;
1163 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001164#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001165 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001166#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001167 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001168#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001169 break;
1170 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001171#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001172 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001173#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001174 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001175#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001176 break;
1177 default:
1178 error("Unsupported binary floating operation %d\n", op);
1179 break;
1180 }
1181 }
1182 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001183 }
Jack Palevich22305132009-05-13 10:58:45 -07001184 }
1185
Jack Palevich58c30ee2009-07-17 16:35:23 -07001186 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001187 if (op != OP_LOGICAL_NOT) {
1188 error("Unknown unary cmp %d", op);
1189 } else {
1190 Type* pR0Type = getR0Type();
1191 TypeTag tag = collapseType(pR0Type->tag);
1192 switch(tag) {
1193 case TY_INT:
1194 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001195 o4(0xE1510000); // cmp r1, r0
1196 o4(0x03A00001); // moveq r0,#1
1197 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001198 break;
1199 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001200#ifdef ARM_USE_VFP
1201 o4(0xEEF57A40); // fcmpzs s15
1202 o4(0xEEF1FA10); // fmstat
1203 o4(0x03A00001); // moveq r0,#1
1204 o4(0x13A00000); // movne r0,#0
1205#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001206 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001207#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001208 break;
1209 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001210#ifdef ARM_USE_VFP
1211 o4(0xEEB57B40); // fcmpzd d7
1212 o4(0xEEF1FA10); // fmstat
1213 o4(0x03A00001); // moveq r0,#1
1214 o4(0x13A00000); // movne r0,#0
1215#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001216 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001217#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001218 break;
1219 default:
1220 error("gUnaryCmp unsupported type");
1221 break;
1222 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001223 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001224 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001225 }
1226
1227 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001228 Type* pR0Type = getR0Type();
1229 TypeTag tag = collapseType(pR0Type->tag);
1230 switch(tag) {
1231 case TY_INT:
1232 switch(op) {
1233 case OP_MINUS:
1234 o4(0xE3A01000); // mov r1, #0
1235 o4(0xE0410000); // sub r0,r1,r0
1236 break;
1237 case OP_BIT_NOT:
1238 o4(0xE1E00000); // mvn r0, r0
1239 break;
1240 default:
1241 error("Unknown unary op %d\n", op);
1242 break;
1243 }
1244 break;
1245 case TY_FLOAT:
1246 case TY_DOUBLE:
1247 switch (op) {
1248 case OP_MINUS:
1249 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001250#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001251 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001252#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001253 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001254#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001255 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001256#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001257 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001258#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001259 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001260#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001261 }
1262 break;
1263 case OP_BIT_NOT:
1264 error("Can't apply '~' operator to a float or double.");
1265 break;
1266 default:
1267 error("Unknown unary op %d\n", op);
1268 break;
1269 }
1270 break;
1271 default:
1272 error("genUnaryOp unsupported type");
1273 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001274 }
Jack Palevich22305132009-05-13 10:58:45 -07001275 }
1276
Jack Palevich1cdef202009-05-22 12:06:27 -07001277 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001278 Type* pR0Type = getR0Type();
1279 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001280
1281#ifdef ARM_USE_VFP
1282 switch (r0ct ) {
1283 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001284 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001285 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001286 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001287 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001288 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001289 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001290 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001291 default:
1292 o4(0xE92D0001); // stmfd sp!,{r0}
1293 mStackUse += 4;
1294 }
1295#else
1296
Jack Palevichb7718b92009-07-09 22:00:24 -07001297 if (r0ct != TY_DOUBLE) {
1298 o4(0xE92D0001); // stmfd sp!,{r0}
1299 mStackUse += 4;
1300 } else {
1301 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1302 mStackUse += 8;
1303 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001304#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001305 pushType();
-b master422972c2009-06-17 19:13:52 -07001306 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001307 }
1308
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001309 virtual void over() {
1310 // We know it's only used for int-ptr ops (++/--)
1311
1312 Type* pR0Type = getR0Type();
1313 TypeTag r0ct = collapseType(pR0Type->tag);
1314
1315 Type* pTOSType = getTOSType();
1316 TypeTag tosct = collapseType(pTOSType->tag);
1317
1318 assert (r0ct == TY_INT && tosct == TY_INT);
1319
1320 o4(0xE8BD0002); // ldmfd sp!,{r1}
1321 o4(0xE92D0001); // stmfd sp!,{r0}
1322 o4(0xE92D0002); // stmfd sp!,{r1}
1323 overType();
1324 mStackUse += 4;
1325 }
1326
Jack Palevich58c30ee2009-07-17 16:35:23 -07001327 virtual void popR0() {
1328 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001329 TypeTag tosct = collapseType(pTOSType->tag);
1330#ifdef ARM_USE_VFP
1331 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001332 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001333 }
1334#endif
1335 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001336 case TY_INT:
1337 case TY_FLOAT:
1338 o4(0xE8BD0001); // ldmfd sp!,{r0}
1339 mStackUse -= 4;
1340 break;
1341 case TY_DOUBLE:
1342 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1343 mStackUse -= 8;
1344 break;
1345 default:
1346 error("Can't pop this type.");
1347 break;
1348 }
1349 popType();
1350 LOG_STACK("popR0: %d\n", mStackUse);
1351 }
1352
1353 virtual void storeR0ToTOS() {
1354 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001355 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001356 Type* pDestType = pPointerType->pHead;
1357 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001358 o4(0xE8BD0004); // ldmfd sp!,{r2}
1359 popType();
-b master422972c2009-06-17 19:13:52 -07001360 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001361 switch (pDestType->tag) {
1362 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001363 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001364 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001365 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001366 case TY_FLOAT:
1367#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001368 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001369#else
1370 o4(0xE5820000); // str r0, [r2]
1371#endif
1372 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001373 case TY_SHORT:
1374 o4(0xE1C200B0); // strh r0, [r2]
1375 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001376 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001377 o4(0xE5C20000); // strb r0, [r2]
1378 break;
1379 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001380#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001381 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001382#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001383 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001384#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001385 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001386 case TY_STRUCT:
1387 {
1388 int size = sizeOf(pDestType);
1389 if (size > 0) {
1390 liReg(size, 1);
1391 callRuntime((void*) runtime_structCopy);
1392 }
1393 }
1394 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001395 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001396 error("storeR0ToTOS: unimplemented type %d",
1397 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001398 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001399 }
Jack Palevich22305132009-05-13 10:58:45 -07001400 }
1401
Jack Palevich58c30ee2009-07-17 16:35:23 -07001402 virtual void loadR0FromR0() {
1403 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001404 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001405 Type* pNewType = pPointerType->pHead;
1406 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001407 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001408 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001409 case TY_INT:
1410 o4(0xE5900000); // ldr r0, [r0]
1411 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001412 case TY_FLOAT:
1413#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001414 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001415#else
1416 o4(0xE5900000); // ldr r0, [r0]
1417#endif
1418 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001419 case TY_SHORT:
1420 o4(0xE1D000F0); // ldrsh r0, [r0]
1421 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001422 case TY_CHAR:
1423 o4(0xE5D00000); // ldrb r0, [r0]
1424 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001425 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001426#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001427 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001428#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001429 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001430#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001431 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001432 case TY_ARRAY:
1433 pNewType = pNewType->pTail;
1434 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001435 case TY_STRUCT:
1436 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001437 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001438 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001439 break;
1440 }
Jack Palevich80e49722009-08-04 15:39:49 -07001441 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001442 }
1443
Jack Palevichb5e33312009-07-30 19:06:34 -07001444 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001445 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001446 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001447
1448 size_t immediate = 0;
1449 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001450 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001451 inRange = encode12BitImmediate(-ea, &immediate);
1452 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001453 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001454 inRange = encode12BitImmediate(ea, &immediate);
1455 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1456 }
1457 if (! inRange) {
1458 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001459 }
Jack Palevichbd894902009-05-14 19:35:31 -07001460 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001461 // Global, absolute.
1462 o4(0xE59F0000); // ldr r0, .L1
1463 o4(0xEA000000); // b .L99
1464 o4(ea); // .L1: .word 0
1465 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001466 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001467 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001468 }
1469
Jack Palevich9f51a262009-07-29 16:22:26 -07001470 virtual int leaForward(int ea, Type* pPointerType) {
1471 setR0Type(pPointerType);
1472 int result = ea;
1473 int pc = getPC();
1474 int offset = 0;
1475 if (ea) {
1476 offset = (pc - ea - 8) >> 2;
1477 if ((offset & 0xffff) != offset) {
1478 error("function forward reference out of bounds");
1479 }
1480 } else {
1481 offset = 0;
1482 }
1483 o4(0xE59F0000 | offset); // ldr r0, .L1
1484
1485 if (ea == 0) {
1486 o4(0xEA000000); // b .L99
1487 result = o4(ea); // .L1: .word 0
1488 // .L99:
1489 }
1490 return result;
1491 }
1492
Jack Palevichb6154502009-08-04 14:56:09 -07001493 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001494 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001495 if (isPointerType(pType) && isPointerType(pR0Type)) {
1496 Type* pA = pR0Type;
1497 Type* pB = pType;
1498 // Array decays to pointer
1499 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1500 pA = pA->pTail;
1501 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001502 if (! (typeEqual(pA, pB)
1503 || pB->pHead->tag == TY_VOID
1504 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1505 )) {
1506 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001507 }
Jack Palevichb6154502009-08-04 14:56:09 -07001508 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001509 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001510 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001511 TypeTag r0Tag = collapseType(pR0Type->tag);
1512 TypeTag destTag = collapseType(pType->tag);
1513 if (r0Tag == TY_INT) {
1514 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001515#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001516 o4(0xEE070A90); // fmsr s15, r0
1517 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001518
1519#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001520 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001521#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001522 } else {
1523 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001524#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001525 o4(0xEE070A90); // fmsr s15, r0
1526 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001527
1528#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001529 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001530#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001531 }
1532 } else if (r0Tag == TY_FLOAT) {
1533 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001534#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001535 o4(0xEEFD7AE7); // ftosizs s15, s15
1536 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001537#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001538 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001539#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001540 } else {
1541 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001542#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001543 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001544#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001545 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001546#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 }
1548 } else {
1549 assert (r0Tag == TY_DOUBLE);
1550 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001551#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001552 o4(0xEEFD7BC7); // ftosizd s15, d7
1553 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001554#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001555 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001556#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001557 } else {
1558 assert(destTag == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001559#ifdef ARM_USE_VFP
1560 o4(0xEEF77BC7); // fcvtsd s15, d7
1561#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001562 callRuntime((void*) runtime_double_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001563#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001564 }
1565 }
Jack Palevich8df46192009-07-07 14:48:51 -07001566 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001567 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001568 }
1569
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001570 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001571 return o4(0xE24DDF00); // Placeholder
1572 }
1573
Jack Palevich8148c5b2009-07-16 18:24:47 -07001574 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001575 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001576 Type* pR0Type = getR0Type();
1577 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001578#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001579 switch(r0ct) {
1580 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001581 if (l < 0 || l > 4096-4) {
1582 error("l out of range for stack offset: 0x%08x", l);
1583 }
1584 o4(0xE58D0000 | l); // str r0, [sp, #l]
1585 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001586 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001587 if (l < 0 || l > 1020 || (l & 3)) {
1588 error("l out of range for stack offset: 0x%08x", l);
1589 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001590 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001591 return 4;
1592 case TY_DOUBLE: {
1593 // Align to 8 byte boundary
1594 int l2 = (l + 7) & ~7;
1595 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1596 error("l out of range for stack offset: 0x%08x", l);
1597 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001598 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001599 return (l2 - l) + 8;
1600 }
1601 default:
1602 assert(false);
1603 return 0;
1604 }
1605#else
1606 switch(r0ct) {
1607 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001608 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001609 if (l < 0 || l > 4096-4) {
1610 error("l out of range for stack offset: 0x%08x", l);
1611 }
1612 o4(0xE58D0000 + l); // str r0, [sp, #l]
1613 return 4;
1614 case TY_DOUBLE: {
1615 // Align to 8 byte boundary
1616 int l2 = (l + 7) & ~7;
1617 if (l2 < 0 || l2 > 4096-8) {
1618 error("l out of range for stack offset: 0x%08x", l);
1619 }
1620 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1621 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1622 return (l2 - l) + 8;
1623 }
1624 default:
1625 assert(false);
1626 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001627 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001628#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001629 }
1630
Jack Palevichb7718b92009-07-09 22:00:24 -07001631 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001632 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001633 // Have to calculate register arg count from actual stack size,
1634 // in order to properly handle ... functions.
1635 int regArgCount = l >> 2;
1636 if (regArgCount > 4) {
1637 regArgCount = 4;
1638 }
1639 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001640 argumentStackUse -= regArgCount * 4;
1641 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1642 }
1643 mStackUse += argumentStackUse;
1644
1645 // Align stack.
1646 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1647 * STACK_ALIGNMENT);
1648 mStackAlignmentAdjustment = 0;
1649 if (missalignment > 0) {
1650 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1651 }
1652 l += mStackAlignmentAdjustment;
1653
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001654 if (l < 0 || l > 0x3FC) {
1655 error("L out of range for stack adjustment: 0x%08x", l);
1656 }
1657 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001658 mStackUse += mStackAlignmentAdjustment;
1659 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1660 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001661 }
1662
Jack Palevich8df46192009-07-07 14:48:51 -07001663 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001664 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001665 // Forward calls are always short (local)
1666 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001667 }
1668
Jack Palevich8df46192009-07-07 14:48:51 -07001669 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001670 assert(pFunc->tag == TY_FUNC);
1671 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001672 int argCount = l >> 2;
1673 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001674 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001675 if (adjustedL < 0 || adjustedL > 4096-4) {
1676 error("l out of range for stack offset: 0x%08x", l);
1677 }
1678 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1679 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001680 Type* pReturnType = pFunc->pHead;
1681 setR0Type(pReturnType);
1682#ifdef ARM_USE_VFP
1683 switch(pReturnType->tag) {
1684 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001685 o4(0xEE070A90); // fmsr s15, r0
1686 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001687 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001688 o4(0xEC410B17); // fmdrr d7, r0, r1
1689 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001690 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001691 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001692 }
1693#endif
Jack Palevich22305132009-05-13 10:58:45 -07001694 }
1695
Jack Palevichb7718b92009-07-09 22:00:24 -07001696 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001697 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001698 // Have to calculate register arg count from actual stack size,
1699 // in order to properly handle ... functions.
1700 int regArgCount = l >> 2;
1701 if (regArgCount > 4) {
1702 regArgCount = 4;
1703 }
1704 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001705 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1706 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001707 if (stackUse) {
1708 if (stackUse < 0 || stackUse > 255) {
1709 error("L out of range for stack adjustment: 0x%08x", l);
1710 }
1711 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001712 mStackUse -= stackUse * 4;
1713 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001714 }
Jack Palevich22305132009-05-13 10:58:45 -07001715 }
1716
Jack Palevicha6535612009-05-13 16:24:17 -07001717 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001718 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001719 }
1720
1721 /* output a symbol and patch all calls to it */
1722 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001723 int n;
1724 int base = getBase();
1725 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001726 while (t) {
1727 int data = * (int*) t;
1728 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1729 if (decodedOffset == 0) {
1730 n = 0;
1731 } else {
1732 n = base + decodedOffset; /* next value */
1733 }
1734 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1735 | encodeRelAddress(pc - t - 8);
1736 t = n;
1737 }
1738 }
1739
Jack Palevich9f51a262009-07-29 16:22:26 -07001740 /* output a symbol and patch all calls to it */
1741 virtual void resolveForward(int t) {
1742 if (t) {
1743 int pc = getPC();
1744 *(int *) t = pc;
1745 }
1746 }
1747
Jack Palevich1cdef202009-05-22 12:06:27 -07001748 virtual int finishCompile() {
1749#if defined(__arm__)
1750 const long base = long(getBase());
1751 const long curr = long(getPC());
1752 int err = cacheflush(base, curr, 0);
1753 return err;
1754#else
1755 return 0;
1756#endif
1757 }
1758
Jack Palevicha6535612009-05-13 16:24:17 -07001759 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001760#ifdef ENABLE_ARM_DISASSEMBLY
1761 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001762 disasm_interface_t di;
1763 di.di_readword = disassemble_readword;
1764 di.di_printaddr = disassemble_printaddr;
1765 di.di_printf = disassemble_printf;
1766
1767 int base = getBase();
1768 int pc = getPC();
1769 for(int i = base; i < pc; i += 4) {
1770 fprintf(out, "%08x: %08x ", i, *(int*) i);
1771 ::disasm(&di, i, 0);
1772 }
Jack Palevich09555c72009-05-27 12:25:55 -07001773#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001774 return 0;
1775 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001776
Jack Palevich9eed7a22009-07-06 17:24:34 -07001777 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001778 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001779 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001780 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001781 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001782 case TY_CHAR:
1783 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001784 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07001785 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001786 case TY_DOUBLE:
1787 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001788 case TY_ARRAY:
1789 return alignmentOf(pType->pHead);
1790 case TY_STRUCT:
1791 return pType->pHead->alignment & 0x7fffffff;
1792 case TY_FUNC:
1793 error("alignment of func not supported");
1794 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001795 default:
1796 return 4;
1797 }
1798 }
1799
1800 /**
1801 * Array element alignment (in bytes) for this type of data.
1802 */
1803 virtual size_t sizeOf(Type* pType){
1804 switch(pType->tag) {
1805 case TY_INT:
1806 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001807 case TY_SHORT:
1808 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001809 case TY_CHAR:
1810 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001811 case TY_FLOAT:
1812 return 4;
1813 case TY_DOUBLE:
1814 return 8;
1815 case TY_POINTER:
1816 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001817 case TY_ARRAY:
1818 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07001819 case TY_STRUCT:
1820 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07001821 default:
1822 error("Unsupported type %d", pType->tag);
1823 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001824 }
1825 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001826
Jack Palevich22305132009-05-13 10:58:45 -07001827 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001828 static FILE* disasmOut;
1829
1830 static u_int
1831 disassemble_readword(u_int address)
1832 {
1833 return(*((u_int *)address));
1834 }
1835
1836 static void
1837 disassemble_printaddr(u_int address)
1838 {
1839 fprintf(disasmOut, "0x%08x", address);
1840 }
1841
1842 static void
1843 disassemble_printf(const char *fmt, ...) {
1844 va_list ap;
1845 va_start(ap, fmt);
1846 vfprintf(disasmOut, fmt, ap);
1847 va_end(ap);
1848 }
1849
1850 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1851
1852 /** Encode a relative address that might also be
1853 * a label.
1854 */
1855 int encodeAddress(int value) {
1856 int base = getBase();
1857 if (value >= base && value <= getPC() ) {
1858 // This is a label, encode it relative to the base.
1859 value = value - base;
1860 }
1861 return encodeRelAddress(value);
1862 }
1863
1864 int encodeRelAddress(int value) {
1865 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1866 }
Jack Palevich22305132009-05-13 10:58:45 -07001867
Jack Palevichb7718b92009-07-09 22:00:24 -07001868 int calcRegArgCount(Type* pDecl) {
1869 int reg = 0;
1870 Type* pArgs = pDecl->pTail;
1871 while (pArgs && reg < 4) {
1872 Type* pArg = pArgs->pHead;
1873 if ( pArg->tag == TY_DOUBLE) {
1874 int evenReg = (reg + 1) & ~1;
1875 if (evenReg >= 4) {
1876 break;
1877 }
1878 reg = evenReg + 2;
1879 } else {
1880 reg++;
1881 }
1882 pArgs = pArgs->pTail;
1883 }
1884 return reg;
1885 }
1886
Jack Palevich58c30ee2009-07-17 16:35:23 -07001887 void setupIntPtrArgs() {
1888 o4(0xE8BD0002); // ldmfd sp!,{r1}
1889 mStackUse -= 4;
1890 popType();
1891 }
1892
Jack Palevich30321cb2009-08-20 15:34:23 -07001893 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001894 * Make sure both R0 and TOS are floats. (Could be ints)
1895 * We know that at least one of R0 and TOS is already a float
1896 */
1897 void setupFloatArgs() {
1898 Type* pR0Type = getR0Type();
1899 Type* pTOSType = getTOSType();
1900 TypeTag tagR0 = collapseType(pR0Type->tag);
1901 TypeTag tagTOS = collapseType(pTOSType->tag);
1902 if (tagR0 != TY_FLOAT) {
1903 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001904#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001905 o4(0xEE070A90); // fmsr s15, r0
1906 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001907#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001908 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001909#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001910 }
1911 if (tagTOS != TY_FLOAT) {
1912 assert(tagTOS == TY_INT);
1913 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001914#ifdef ARM_USE_VFP
1915 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07001916 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07001917#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001918 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1919 o4(0xE59D0004); // ldr r0, [sp, #4]
1920 callRuntime((void*) runtime_int_to_float);
1921 o4(0xE1A01000); // mov r1, r0
1922 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1923 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001924#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001925 } else {
1926 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07001927#ifdef ARM_USE_VFP
1928 o4(0xECBD7A01); // fldmfds sp!, {s14}
1929
1930#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001931 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07001932#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001933 }
1934 mStackUse -= 4;
1935 popType();
1936 }
1937
Jack Palevich30321cb2009-08-20 15:34:23 -07001938 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07001939 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1940 * We know that at least one of R0 and TOS are already a double.
1941 */
1942
1943 void setupDoubleArgs() {
1944 Type* pR0Type = getR0Type();
1945 Type* pTOSType = getTOSType();
1946 TypeTag tagR0 = collapseType(pR0Type->tag);
1947 TypeTag tagTOS = collapseType(pTOSType->tag);
1948 if (tagR0 != TY_DOUBLE) {
1949 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001950#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001951 o4(0xEE070A90); // fmsr s15, r0
1952 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001953
1954#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001955 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001956#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001957 } else {
1958 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07001959#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001960 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001961#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001962 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001963#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001964 }
1965 }
1966 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001967#ifdef ARM_USE_VFP
1968 if (tagTOS == TY_INT) {
1969 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001970 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001971 } else {
1972 assert(tagTOS == TY_FLOAT);
1973 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07001974 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07001975 }
1976#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001977 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1978 o4(0xE59D0008); // ldr r0, [sp, #8]
1979 if (tagTOS == TY_INT) {
1980 callRuntime((void*) runtime_int_to_double);
1981 } else {
1982 assert(tagTOS == TY_FLOAT);
1983 callRuntime((void*) runtime_float_to_double);
1984 }
1985 o4(0xE1A02000); // mov r2, r0
1986 o4(0xE1A03001); // mov r3, r1
1987 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1988 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07001989#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001990 mStackUse -= 4;
1991 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001992#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001993 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07001994#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001995 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07001996#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001997 mStackUse -= 8;
1998 }
1999 popType();
2000 }
2001
Jack Palevicha8f427f2009-07-13 18:40:08 -07002002 void liReg(int t, int reg) {
2003 assert(reg >= 0 && reg < 16);
2004 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002005 size_t encodedImmediate;
2006 if (encode12BitImmediate(t, &encodedImmediate)) {
2007 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2008 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002009 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002010 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002011 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002012 o4(0xE51F0000 | rN); // ldr rN, .L3
2013 o4(0xEA000000); // b .L99
2014 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002015 // .L99:
2016 }
2017 }
2018
Jack Palevich9221bcc2009-08-26 16:15:07 -07002019 bool encode12BitImmediate(size_t immediate, size_t* pResult) {
2020 for(size_t i = 0; i < 16; i++) {
2021 size_t rotate = i * 2;
2022 size_t mask = rotateRight(0xff, rotate);
2023 if ((immediate | mask) == mask) {
2024 size_t bits8 = rotateLeft(immediate, rotate);
2025 assert(bits8 <= 0xff);
2026 *pResult = (i << 8) | bits8;
2027 return true;
2028 }
2029 }
2030 return false;
2031 }
2032
2033 size_t rotateRight(size_t n, size_t rotate) {
2034 return (n >> rotate) | (n << (32 - rotate));
2035 }
2036
2037 size_t rotateLeft(size_t n, size_t rotate) {
2038 return (n << rotate) | (n >> (32 - rotate));
2039 }
2040
Jack Palevichb7718b92009-07-09 22:00:24 -07002041 void callRuntime(void* fn) {
2042 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002043 o4(0xEA000000); // b .L99
2044 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002045 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002046 }
2047
Jack Palevichb7718b92009-07-09 22:00:24 -07002048 // Integer math:
2049
2050 static int runtime_DIV(int b, int a) {
2051 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002052 }
2053
Jack Palevichb7718b92009-07-09 22:00:24 -07002054 static int runtime_MOD(int b, int a) {
2055 return a % b;
2056 }
2057
Jack Palevich9221bcc2009-08-26 16:15:07 -07002058 static void runtime_structCopy(void* src, size_t size, void* dest) {
2059 memcpy(dest, src, size);
2060 }
2061
Jack Palevich30321cb2009-08-20 15:34:23 -07002062#ifndef ARM_USE_VFP
2063
Jack Palevichb7718b92009-07-09 22:00:24 -07002064 // Comparison to zero
2065
2066 static int runtime_is_non_zero_f(float a) {
2067 return a != 0;
2068 }
2069
2070 static int runtime_is_non_zero_d(double a) {
2071 return a != 0;
2072 }
2073
2074 // Comparison to zero
2075
2076 static int runtime_is_zero_f(float a) {
2077 return a == 0;
2078 }
2079
2080 static int runtime_is_zero_d(double a) {
2081 return a == 0;
2082 }
2083
2084 // Type conversion
2085
2086 static int runtime_float_to_int(float a) {
2087 return (int) a;
2088 }
2089
2090 static double runtime_float_to_double(float a) {
2091 return (double) a;
2092 }
2093
2094 static int runtime_double_to_int(double a) {
2095 return (int) a;
2096 }
2097
2098 static float runtime_double_to_float(double a) {
2099 return (float) a;
2100 }
2101
2102 static float runtime_int_to_float(int a) {
2103 return (float) a;
2104 }
2105
2106 static double runtime_int_to_double(int a) {
2107 return (double) a;
2108 }
2109
2110 // Comparisons float
2111
2112 static int runtime_cmp_eq_ff(float b, float a) {
2113 return a == b;
2114 }
2115
2116 static int runtime_cmp_ne_ff(float b, float a) {
2117 return a != b;
2118 }
2119
2120 static int runtime_cmp_lt_ff(float b, float a) {
2121 return a < b;
2122 }
2123
2124 static int runtime_cmp_le_ff(float b, float a) {
2125 return a <= b;
2126 }
2127
2128 static int runtime_cmp_ge_ff(float b, float a) {
2129 return a >= b;
2130 }
2131
2132 static int runtime_cmp_gt_ff(float b, float a) {
2133 return a > b;
2134 }
2135
2136 // Comparisons double
2137
2138 static int runtime_cmp_eq_dd(double b, double a) {
2139 return a == b;
2140 }
2141
2142 static int runtime_cmp_ne_dd(double b, double a) {
2143 return a != b;
2144 }
2145
2146 static int runtime_cmp_lt_dd(double b, double a) {
2147 return a < b;
2148 }
2149
2150 static int runtime_cmp_le_dd(double b, double a) {
2151 return a <= b;
2152 }
2153
2154 static int runtime_cmp_ge_dd(double b, double a) {
2155 return a >= b;
2156 }
2157
2158 static int runtime_cmp_gt_dd(double b, double a) {
2159 return a > b;
2160 }
2161
2162 // Math float
2163
2164 static float runtime_op_add_ff(float b, float a) {
2165 return a + b;
2166 }
2167
2168 static float runtime_op_sub_ff(float b, float a) {
2169 return a - b;
2170 }
2171
2172 static float runtime_op_mul_ff(float b, float a) {
2173 return a * b;
2174 }
2175
2176 static float runtime_op_div_ff(float b, float a) {
2177 return a / b;
2178 }
2179
2180 static float runtime_op_neg_f(float a) {
2181 return -a;
2182 }
2183
2184 // Math double
2185
2186 static double runtime_op_add_dd(double b, double a) {
2187 return a + b;
2188 }
2189
2190 static double runtime_op_sub_dd(double b, double a) {
2191 return a - b;
2192 }
2193
2194 static double runtime_op_mul_dd(double b, double a) {
2195 return a * b;
2196 }
2197
2198 static double runtime_op_div_dd(double b, double a) {
2199 return a / b;
2200 }
2201
2202 static double runtime_op_neg_d(double a) {
2203 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002204 }
-b master422972c2009-06-17 19:13:52 -07002205
Jack Palevich30321cb2009-08-20 15:34:23 -07002206#endif
2207
-b master422972c2009-06-17 19:13:52 -07002208 static const int STACK_ALIGNMENT = 8;
2209 int mStackUse;
2210 // This variable holds the amount we adjusted the stack in the most
2211 // recent endFunctionCallArguments call. It's examined by the
2212 // following adjustStackAfterCall call.
2213 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002214 };
2215
Jack Palevich09555c72009-05-27 12:25:55 -07002216#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002217
2218#ifdef PROVIDE_X86_CODEGEN
2219
Jack Palevich21a15a22009-05-11 14:49:29 -07002220 class X86CodeGenerator : public CodeGenerator {
2221 public:
2222 X86CodeGenerator() {}
2223 virtual ~X86CodeGenerator() {}
2224
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002225 /* returns address to patch with local variable size
2226 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002227 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002228 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2229 return oad(0xec81, 0); /* sub $xxx, %esp */
2230 }
2231
Jack Palevichb7718b92009-07-09 22:00:24 -07002232 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002233 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002234 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002235 }
2236
Jack Palevich21a15a22009-05-11 14:49:29 -07002237 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002238 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002239 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002240 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002241 }
2242
Jack Palevich1a539db2009-07-08 13:04:41 -07002243 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002244 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002245 switch (pType->tag) {
2246 case TY_FLOAT:
2247 oad(0x05D9, address); // flds
2248 break;
2249 case TY_DOUBLE:
2250 oad(0x05DD, address); // fldl
2251 break;
2252 default:
2253 assert(false);
2254 break;
2255 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002256 }
2257
Jack Palevich9221bcc2009-08-26 16:15:07 -07002258 virtual void addStructOffsetR0(int offset, Type* pType) {
2259 if (offset) {
2260 oad(0x05, offset); // addl offset, %eax
2261 }
2262 setR0Type(pType, ET_LVALUE);
2263 }
2264
Jack Palevich22305132009-05-13 10:58:45 -07002265 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002266 return psym(0xe9, t);
2267 }
2268
2269 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002270 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002271 Type* pR0Type = getR0Type();
2272 TypeTag tagR0 = pR0Type->tag;
2273 bool isFloatR0 = isFloatTag(tagR0);
2274 if (isFloatR0) {
2275 o(0xeed9); // fldz
2276 o(0xe9da); // fucompp
2277 o(0xe0df); // fnstsw %ax
2278 o(0x9e); // sahf
2279 } else {
2280 o(0xc085); // test %eax, %eax
2281 }
2282 // Use two output statements to generate one instruction.
2283 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002284 return psym(0x84 + l, t);
2285 }
2286
Jack Palevich58c30ee2009-07-17 16:35:23 -07002287 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002288 Type* pR0Type = getR0Type();
2289 Type* pTOSType = getTOSType();
2290 TypeTag tagR0 = pR0Type->tag;
2291 TypeTag tagTOS = pTOSType->tag;
2292 bool isFloatR0 = isFloatTag(tagR0);
2293 bool isFloatTOS = isFloatTag(tagTOS);
2294 if (!isFloatR0 && !isFloatTOS) {
2295 int t = decodeOp(op);
2296 o(0x59); /* pop %ecx */
2297 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002298 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002299 o(0x0f); /* setxx %al */
2300 o(t + 0x90);
2301 o(0xc0);
2302 popType();
2303 } else {
2304 setupFloatOperands();
2305 switch (op) {
2306 case OP_EQUALS:
2307 o(0xe9da); // fucompp
2308 o(0xe0df); // fnstsw %ax
2309 o(0x9e); // sahf
2310 o(0xc0940f); // sete %al
2311 o(0xc29b0f); // setnp %dl
2312 o(0xd021); // andl %edx, %eax
2313 break;
2314 case OP_NOT_EQUALS:
2315 o(0xe9da); // fucompp
2316 o(0xe0df); // fnstsw %ax
2317 o(0x9e); // sahf
2318 o(0xc0950f); // setne %al
2319 o(0xc29a0f); // setp %dl
2320 o(0xd009); // orl %edx, %eax
2321 break;
2322 case OP_GREATER_EQUAL:
2323 o(0xe9da); // fucompp
2324 o(0xe0df); // fnstsw %ax
2325 o(0x05c4f6); // testb $5, %ah
2326 o(0xc0940f); // sete %al
2327 break;
2328 case OP_LESS:
2329 o(0xc9d9); // fxch %st(1)
2330 o(0xe9da); // fucompp
2331 o(0xe0df); // fnstsw %ax
2332 o(0x9e); // sahf
2333 o(0xc0970f); // seta %al
2334 break;
2335 case OP_LESS_EQUAL:
2336 o(0xc9d9); // fxch %st(1)
2337 o(0xe9da); // fucompp
2338 o(0xe0df); // fnstsw %ax
2339 o(0x9e); // sahf
2340 o(0xc0930f); // setea %al
2341 break;
2342 case OP_GREATER:
2343 o(0xe9da); // fucompp
2344 o(0xe0df); // fnstsw %ax
2345 o(0x45c4f6); // testb $69, %ah
2346 o(0xc0940f); // sete %al
2347 break;
2348 default:
2349 error("Unknown comparison op");
2350 }
2351 o(0xc0b60f); // movzbl %al, %eax
2352 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002353 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002354 }
2355
Jack Palevich546b2242009-05-13 15:10:04 -07002356 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002357 Type* pR0Type = getR0Type();
2358 Type* pTOSType = getTOSType();
2359 TypeTag tagR0 = pR0Type->tag;
2360 TypeTag tagTOS = pTOSType->tag;
2361 bool isFloatR0 = isFloatTag(tagR0);
2362 bool isFloatTOS = isFloatTag(tagTOS);
2363 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002364 bool isPtrR0 = isPointerTag(tagR0);
2365 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002366 if (isPtrR0 || isPtrTOS) {
2367 if (isPtrR0 && isPtrTOS) {
2368 if (op != OP_MINUS) {
2369 error("Unsupported pointer-pointer operation %d.", op);
2370 }
2371 if (! typeEqual(pR0Type, pTOSType)) {
2372 error("Incompatible pointer types for subtraction.");
2373 }
2374 o(0x59); /* pop %ecx */
2375 o(decodeOp(op));
2376 popType();
2377 setR0Type(mkpInt);
2378 int size = sizeOf(pR0Type->pHead);
2379 if (size != 1) {
2380 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002381 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002382 // TODO: Optimize for power-of-two.
2383 genOp(OP_DIV);
2384 }
2385 } else {
2386 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2387 error("Unsupported pointer-scalar operation %d", op);
2388 }
Jack Palevichb6154502009-08-04 14:56:09 -07002389 Type* pPtrType = getPointerArithmeticResultType(
2390 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002391 o(0x59); /* pop %ecx */
2392 int size = sizeOf(pPtrType->pHead);
2393 if (size != 1) {
2394 // TODO: Optimize for power-of-two.
2395 if (isPtrR0) {
2396 oad(0xC969, size); // imull $size, %ecx
2397 } else {
2398 oad(0xC069, size); // mul $size, %eax
2399 }
2400 }
2401 o(decodeOp(op));
2402 popType();
2403 setR0Type(pPtrType);
2404 }
2405 } else {
2406 o(0x59); /* pop %ecx */
2407 o(decodeOp(op));
2408 if (op == OP_MOD)
2409 o(0x92); /* xchg %edx, %eax */
2410 popType();
2411 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002412 } else {
2413 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2414 setupFloatOperands();
2415 // Both float. x87 R0 == left hand, x87 R1 == right hand
2416 switch (op) {
2417 case OP_MUL:
2418 o(0xc9de); // fmulp
2419 break;
2420 case OP_DIV:
2421 o(0xf1de); // fdivp
2422 break;
2423 case OP_PLUS:
2424 o(0xc1de); // faddp
2425 break;
2426 case OP_MINUS:
2427 o(0xe1de); // fsubp
2428 break;
2429 default:
2430 error("Unsupported binary floating operation.");
2431 break;
2432 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002433 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002434 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002435 }
2436
Jack Palevich58c30ee2009-07-17 16:35:23 -07002437 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002438 if (op != OP_LOGICAL_NOT) {
2439 error("Unknown unary cmp %d", op);
2440 } else {
2441 Type* pR0Type = getR0Type();
2442 TypeTag tag = collapseType(pR0Type->tag);
2443 switch(tag) {
2444 case TY_INT: {
2445 oad(0xb9, 0); /* movl $0, %ecx */
2446 int t = decodeOp(op);
2447 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002448 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002449 o(0x0f); /* setxx %al */
2450 o(t + 0x90);
2451 o(0xc0);
2452 }
2453 break;
2454 case TY_FLOAT:
2455 case TY_DOUBLE:
2456 o(0xeed9); // fldz
2457 o(0xe9da); // fucompp
2458 o(0xe0df); // fnstsw %ax
2459 o(0x9e); // sahf
2460 o(0xc0950f); // setne %al
2461 o(0xc29a0f); // setp %dl
2462 o(0xd009); // orl %edx, %eax
2463 o(0xc0b60f); // movzbl %al, %eax
2464 o(0x01f083); // xorl $1, %eax
2465 break;
2466 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002467 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002468 break;
2469 }
2470 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002471 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002472 }
2473
2474 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002475 Type* pR0Type = getR0Type();
2476 TypeTag tag = collapseType(pR0Type->tag);
2477 switch(tag) {
2478 case TY_INT:
2479 oad(0xb9, 0); /* movl $0, %ecx */
2480 o(decodeOp(op));
2481 break;
2482 case TY_FLOAT:
2483 case TY_DOUBLE:
2484 switch (op) {
2485 case OP_MINUS:
2486 o(0xe0d9); // fchs
2487 break;
2488 case OP_BIT_NOT:
2489 error("Can't apply '~' operator to a float or double.");
2490 break;
2491 default:
2492 error("Unknown unary op %d\n", op);
2493 break;
2494 }
2495 break;
2496 default:
2497 error("genUnaryOp unsupported type");
2498 break;
2499 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002500 }
2501
Jack Palevich1cdef202009-05-22 12:06:27 -07002502 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002503 Type* pR0Type = getR0Type();
2504 TypeTag r0ct = collapseType(pR0Type->tag);
2505 switch(r0ct) {
2506 case TY_INT:
2507 o(0x50); /* push %eax */
2508 break;
2509 case TY_FLOAT:
2510 o(0x50); /* push %eax */
2511 o(0x241cd9); // fstps 0(%esp)
2512 break;
2513 case TY_DOUBLE:
2514 o(0x50); /* push %eax */
2515 o(0x50); /* push %eax */
2516 o(0x241cdd); // fstpl 0(%esp)
2517 break;
2518 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002519 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002520 break;
2521 }
Jack Palevich8df46192009-07-07 14:48:51 -07002522 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002523 }
2524
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002525 virtual void over() {
2526 // We know it's only used for int-ptr ops (++/--)
2527
2528 Type* pR0Type = getR0Type();
2529 TypeTag r0ct = collapseType(pR0Type->tag);
2530
2531 Type* pTOSType = getTOSType();
2532 TypeTag tosct = collapseType(pTOSType->tag);
2533
2534 assert (r0ct == TY_INT && tosct == TY_INT);
2535
2536 o(0x59); /* pop %ecx */
2537 o(0x50); /* push %eax */
2538 o(0x51); /* push %ecx */
2539
2540 overType();
2541 }
2542
Jack Palevich58c30ee2009-07-17 16:35:23 -07002543 virtual void popR0() {
2544 Type* pR0Type = getR0Type();
2545 TypeTag r0ct = collapseType(pR0Type->tag);
2546 switch(r0ct) {
2547 case TY_INT:
2548 o(0x58); /* popl %eax */
2549 break;
2550 case TY_FLOAT:
2551 o(0x2404d9); // flds (%esp)
2552 o(0x58); /* popl %eax */
2553 break;
2554 case TY_DOUBLE:
2555 o(0x2404dd); // fldl (%esp)
2556 o(0x58); /* popl %eax */
2557 o(0x58); /* popl %eax */
2558 break;
2559 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002560 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002561 break;
2562 }
2563 popType();
2564 }
2565
2566 virtual void storeR0ToTOS() {
2567 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002568 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002569 Type* pTargetType = pPointerType->pHead;
2570 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002571 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002572 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002573 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002574 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002575 case TY_INT:
2576 o(0x0189); /* movl %eax/%al, (%ecx) */
2577 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002578 case TY_SHORT:
2579 o(0x018966); /* movw %ax, (%ecx) */
2580 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002581 case TY_CHAR:
2582 o(0x0188); /* movl %eax/%al, (%ecx) */
2583 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002584 case TY_FLOAT:
2585 o(0x19d9); /* fstps (%ecx) */
2586 break;
2587 case TY_DOUBLE:
2588 o(0x19dd); /* fstpl (%ecx) */
2589 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002590 case TY_STRUCT:
2591 {
2592 // TODO: use alignment information to use movsw/movsl instead of movsb
2593 int size = sizeOf(pTargetType);
2594 if (size > 0) {
2595 o(0x9c); // pushf
2596 o(0x57); // pushl %edi
2597 o(0x56); // pushl %esi
2598 o(0xcf89); // movl %ecx, %edi
2599 o(0xc689); // movl %eax, %esi
2600 oad(0xb9, size); // mov #size, %ecx
2601 o(0xfc); // cld
2602 o(0xf3); // rep
2603 o(0xa4); // movsb
2604 o(0x5e); // popl %esi
2605 o(0x5f); // popl %edi
2606 o(0x9d); // popf
2607 }
2608 }
2609 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002610 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002611 error("storeR0ToTOS: unsupported type %d",
2612 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002613 break;
2614 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002615 }
2616
Jack Palevich58c30ee2009-07-17 16:35:23 -07002617 virtual void loadR0FromR0() {
2618 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002619 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002620 Type* pNewType = pPointerType->pHead;
2621 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002622 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002623 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002624 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002625 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002626 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002627 case TY_SHORT:
2628 o(0xbf0f); /* movswl (%eax), %eax */
2629 ob(0);
2630 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002631 case TY_CHAR:
2632 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002633 ob(0); /* add zero in code */
2634 break;
2635 case TY_FLOAT:
2636 o2(0x00d9); // flds (%eax)
2637 break;
2638 case TY_DOUBLE:
2639 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002640 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002641 case TY_ARRAY:
2642 pNewType = pNewType->pTail;
2643 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002644 case TY_STRUCT:
2645 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002646 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002647 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002648 break;
2649 }
Jack Palevich80e49722009-08-04 15:39:49 -07002650 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002651 }
2652
Jack Palevichb5e33312009-07-30 19:06:34 -07002653 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002654 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002655 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002656 }
2657
Jack Palevich9f51a262009-07-29 16:22:26 -07002658 virtual int leaForward(int ea, Type* pPointerType) {
2659 oad(0xb8, ea); /* mov $xx, %eax */
2660 setR0Type(pPointerType);
2661 return getPC() - 4;
2662 }
2663
Jack Palevichb6154502009-08-04 14:56:09 -07002664 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002665 Type* pR0Type = getR0Type();
2666 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002667 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002668 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002669 return;
2670 }
Jack Palevichb6154502009-08-04 14:56:09 -07002671 if (isPointerType(pType) && isPointerType(pR0Type)) {
2672 Type* pA = pR0Type;
2673 Type* pB = pType;
2674 // Array decays to pointer
2675 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2676 pA = pA->pTail;
2677 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002678 if (! (typeEqual(pA, pB)
2679 || pB->pHead->tag == TY_VOID
2680 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2681 )) {
2682 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002683 }
Jack Palevichb6154502009-08-04 14:56:09 -07002684 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002685 // do nothing special
2686 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2687 // do nothing special, both held in same register on x87.
2688 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002689 TypeTag r0Tag = collapseType(pR0Type->tag);
2690 TypeTag destTag = collapseType(pType->tag);
2691 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2692 // Convert R0 from int to float
2693 o(0x50); // push %eax
2694 o(0x2404DB); // fildl 0(%esp)
2695 o(0x58); // pop %eax
2696 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2697 // Convert R0 from float to int. Complicated because
2698 // need to save and restore the rounding mode.
2699 o(0x50); // push %eax
2700 o(0x50); // push %eax
2701 o(0x02247cD9); // fnstcw 2(%esp)
2702 o(0x2444b70f); // movzwl 2(%esp), %eax
2703 o(0x02);
2704 o(0x0cb4); // movb $12, %ah
2705 o(0x24048966); // movw %ax, 0(%esp)
2706 o(0x242cd9); // fldcw 0(%esp)
2707 o(0x04245cdb); // fistpl 4(%esp)
2708 o(0x02246cd9); // fldcw 2(%esp)
2709 o(0x58); // pop %eax
2710 o(0x58); // pop %eax
2711 } else {
2712 error("Incompatible types old: %d new: %d",
2713 pR0Type->tag, pType->tag);
2714 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002715 }
2716 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002717 }
2718
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002719 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002720 return oad(0xec81, 0); /* sub $xxx, %esp */
2721 }
2722
Jack Palevich8148c5b2009-07-16 18:24:47 -07002723 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2724 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002725 Type* pR0Type = getR0Type();
2726 TypeTag r0ct = collapseType(pR0Type->tag);
2727 switch(r0ct) {
2728 case TY_INT:
2729 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2730 return 4;
2731 case TY_FLOAT:
2732 oad(0x249CD9, l); /* fstps xxx(%esp) */
2733 return 4;
2734 case TY_DOUBLE:
2735 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2736 return 8;
2737 default:
2738 assert(false);
2739 return 0;
2740 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002741 }
2742
Jack Palevichb7718b92009-07-09 22:00:24 -07002743 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002744 * (int*) a = l;
2745 }
2746
Jack Palevich8df46192009-07-07 14:48:51 -07002747 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002748 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002749 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002750 return psym(0xe8, symbol); /* call xxx */
2751 }
2752
Jack Palevich8df46192009-07-07 14:48:51 -07002753 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002754 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002755 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002756 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002757 oad(0x2494ff, l); /* call *xxx(%esp) */
2758 }
2759
Jack Palevichb7718b92009-07-09 22:00:24 -07002760 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002761 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002762 if (isIndirect) {
2763 l += 4;
2764 }
-b master422972c2009-06-17 19:13:52 -07002765 if (l > 0) {
2766 oad(0xc481, l); /* add $xxx, %esp */
2767 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002768 }
2769
Jack Palevicha6535612009-05-13 16:24:17 -07002770 virtual int jumpOffset() {
2771 return 5;
2772 }
2773
2774 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002775 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002776 }
2777
Jack Paleviche7b59062009-05-19 17:12:17 -07002778 /* output a symbol and patch all calls to it */
2779 virtual void gsym(int t) {
2780 int n;
2781 int pc = getPC();
2782 while (t) {
2783 n = *(int *) t; /* next value */
2784 *(int *) t = pc - t - 4;
2785 t = n;
2786 }
2787 }
2788
Jack Palevich9f51a262009-07-29 16:22:26 -07002789 /* output a symbol and patch all calls to it, using absolute address */
2790 virtual void resolveForward(int t) {
2791 int n;
2792 int pc = getPC();
2793 while (t) {
2794 n = *(int *) t; /* next value */
2795 *(int *) t = pc;
2796 t = n;
2797 }
2798 }
2799
Jack Palevich1cdef202009-05-22 12:06:27 -07002800 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002801 size_t pagesize = 4096;
2802 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2803 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2804 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2805 if (err) {
2806 error("mprotect() failed: %d", errno);
2807 }
2808 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002809 }
2810
Jack Palevich9eed7a22009-07-06 17:24:34 -07002811 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002812 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002813 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002814 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002815 switch (pType->tag) {
2816 case TY_CHAR:
2817 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002818 case TY_SHORT:
2819 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002820 case TY_ARRAY:
2821 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002822 case TY_STRUCT:
2823 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07002824 case TY_FUNC:
2825 error("alignment of func not supported");
2826 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002827 default:
2828 return 4;
2829 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002830 }
2831
2832 /**
2833 * Array element alignment (in bytes) for this type of data.
2834 */
2835 virtual size_t sizeOf(Type* pType){
2836 switch(pType->tag) {
2837 case TY_INT:
2838 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002839 case TY_SHORT:
2840 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002841 case TY_CHAR:
2842 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002843 case TY_FLOAT:
2844 return 4;
2845 case TY_DOUBLE:
2846 return 8;
2847 case TY_POINTER:
2848 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002849 case TY_ARRAY:
2850 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002851 case TY_STRUCT:
2852 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002853 default:
2854 error("Unsupported type %d", pType->tag);
2855 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002856 }
2857 }
2858
Jack Palevich21a15a22009-05-11 14:49:29 -07002859 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002860
2861 /** Output 1 to 4 bytes.
2862 *
2863 */
2864 void o(int n) {
2865 /* cannot use unsigned, so we must do a hack */
2866 while (n && n != -1) {
2867 ob(n & 0xff);
2868 n = n >> 8;
2869 }
2870 }
2871
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002872 /* Output exactly 2 bytes
2873 */
2874 void o2(int n) {
2875 ob(n & 0xff);
2876 ob(0xff & (n >> 8));
2877 }
2878
Jack Paleviche7b59062009-05-19 17:12:17 -07002879 /* psym is used to put an instruction with a data field which is a
2880 reference to a symbol. It is in fact the same as oad ! */
2881 int psym(int n, int t) {
2882 return oad(n, t);
2883 }
2884
2885 /* instruction + address */
2886 int oad(int n, int t) {
2887 o(n);
2888 int result = getPC();
2889 o4(t);
2890 return result;
2891 }
2892
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002893 static const int operatorHelper[];
2894
2895 int decodeOp(int op) {
2896 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002897 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002898 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002899 }
2900 return operatorHelper[op];
2901 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002902
Jack Palevich546b2242009-05-13 15:10:04 -07002903 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002904 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002905 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002906 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002907
2908 void setupFloatOperands() {
2909 Type* pR0Type = getR0Type();
2910 Type* pTOSType = getTOSType();
2911 TypeTag tagR0 = pR0Type->tag;
2912 TypeTag tagTOS = pTOSType->tag;
2913 bool isFloatR0 = isFloatTag(tagR0);
2914 bool isFloatTOS = isFloatTag(tagTOS);
2915 if (! isFloatR0) {
2916 // Convert R0 from int to float
2917 o(0x50); // push %eax
2918 o(0x2404DB); // fildl 0(%esp)
2919 o(0x58); // pop %eax
2920 }
2921 if (! isFloatTOS){
2922 o(0x2404DB); // fildl 0(%esp);
2923 o(0x58); // pop %eax
2924 } else {
2925 if (tagTOS == TY_FLOAT) {
2926 o(0x2404d9); // flds (%esp)
2927 o(0x58); // pop %eax
2928 } else {
2929 o(0x2404dd); // fldl (%esp)
2930 o(0x58); // pop %eax
2931 o(0x58); // pop %eax
2932 }
2933 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002934 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002935 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002936 };
2937
Jack Paleviche7b59062009-05-19 17:12:17 -07002938#endif // PROVIDE_X86_CODEGEN
2939
Jack Palevichb67b18f2009-06-11 21:12:23 -07002940#ifdef PROVIDE_TRACE_CODEGEN
2941 class TraceCodeGenerator : public CodeGenerator {
2942 private:
2943 CodeGenerator* mpBase;
2944
2945 public:
2946 TraceCodeGenerator(CodeGenerator* pBase) {
2947 mpBase = pBase;
2948 }
2949
2950 virtual ~TraceCodeGenerator() {
2951 delete mpBase;
2952 }
2953
2954 virtual void init(CodeBuf* pCodeBuf) {
2955 mpBase->init(pCodeBuf);
2956 }
2957
2958 void setErrorSink(ErrorSink* pErrorSink) {
2959 mpBase->setErrorSink(pErrorSink);
2960 }
2961
2962 /* returns address to patch with local variable size
2963 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002964 virtual int functionEntry(Type* pDecl) {
2965 int result = mpBase->functionEntry(pDecl);
2966 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002967 return result;
2968 }
2969
Jack Palevichb7718b92009-07-09 22:00:24 -07002970 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2971 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2972 localVariableAddress, localVariableSize);
2973 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002974 }
2975
2976 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002977 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002978 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002979 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002980 }
2981
Jack Palevich1a539db2009-07-08 13:04:41 -07002982 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002983 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002984 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002985 }
2986
Jack Palevich9221bcc2009-08-26 16:15:07 -07002987 virtual void addStructOffsetR0(int offset, Type* pType) {
2988 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
2989 mpBase->addStructOffsetR0(offset, pType);
2990 }
2991
Jack Palevichb67b18f2009-06-11 21:12:23 -07002992 virtual int gjmp(int t) {
2993 int result = mpBase->gjmp(t);
2994 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2995 return result;
2996 }
2997
2998 /* l = 0: je, l == 1: jne */
2999 virtual int gtst(bool l, int t) {
3000 int result = mpBase->gtst(l, t);
3001 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3002 return result;
3003 }
3004
Jack Palevich58c30ee2009-07-17 16:35:23 -07003005 virtual void gcmp(int op) {
3006 fprintf(stderr, "gcmp(%d)\n", op);
3007 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003008 }
3009
3010 virtual void genOp(int op) {
3011 fprintf(stderr, "genOp(%d)\n", op);
3012 mpBase->genOp(op);
3013 }
3014
Jack Palevich9eed7a22009-07-06 17:24:34 -07003015
Jack Palevich58c30ee2009-07-17 16:35:23 -07003016 virtual void gUnaryCmp(int op) {
3017 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3018 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003019 }
3020
3021 virtual void genUnaryOp(int op) {
3022 fprintf(stderr, "genUnaryOp(%d)\n", op);
3023 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003024 }
3025
3026 virtual void pushR0() {
3027 fprintf(stderr, "pushR0()\n");
3028 mpBase->pushR0();
3029 }
3030
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003031 virtual void over() {
3032 fprintf(stderr, "over()\n");
3033 mpBase->over();
3034 }
3035
Jack Palevich58c30ee2009-07-17 16:35:23 -07003036 virtual void popR0() {
3037 fprintf(stderr, "popR0()\n");
3038 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003039 }
3040
Jack Palevich58c30ee2009-07-17 16:35:23 -07003041 virtual void storeR0ToTOS() {
3042 fprintf(stderr, "storeR0ToTOS()\n");
3043 mpBase->storeR0ToTOS();
3044 }
3045
3046 virtual void loadR0FromR0() {
3047 fprintf(stderr, "loadR0FromR0()\n");
3048 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003049 }
3050
Jack Palevichb5e33312009-07-30 19:06:34 -07003051 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3052 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3053 pPointerType->pHead->tag, et);
3054 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003055 }
3056
Jack Palevich9f51a262009-07-29 16:22:26 -07003057 virtual int leaForward(int ea, Type* pPointerType) {
3058 fprintf(stderr, "leaForward(%d)\n", ea);
3059 return mpBase->leaForward(ea, pPointerType);
3060 }
3061
Jack Palevich30321cb2009-08-20 15:34:23 -07003062 virtual void convertR0Imp(Type* pType, bool isCast){
3063 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3064 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003065 }
3066
3067 virtual int beginFunctionCallArguments() {
3068 int result = mpBase->beginFunctionCallArguments();
3069 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3070 return result;
3071 }
3072
Jack Palevich8148c5b2009-07-16 18:24:47 -07003073 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3074 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3075 pArgType->tag);
3076 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003077 }
3078
Jack Palevichb7718b92009-07-09 22:00:24 -07003079 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003080 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003081 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003082 }
3083
Jack Palevich8df46192009-07-07 14:48:51 -07003084 virtual int callForward(int symbol, Type* pFunc) {
3085 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003086 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3087 return result;
3088 }
3089
Jack Palevich8df46192009-07-07 14:48:51 -07003090 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003091 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3092 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003093 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003094 }
3095
Jack Palevichb7718b92009-07-09 22:00:24 -07003096 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3097 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3098 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003099 }
3100
3101 virtual int jumpOffset() {
3102 return mpBase->jumpOffset();
3103 }
3104
3105 virtual int disassemble(FILE* out) {
3106 return mpBase->disassemble(out);
3107 }
3108
3109 /* output a symbol and patch all calls to it */
3110 virtual void gsym(int t) {
3111 fprintf(stderr, "gsym(%d)\n", t);
3112 mpBase->gsym(t);
3113 }
3114
Jack Palevich9f51a262009-07-29 16:22:26 -07003115 virtual void resolveForward(int t) {
3116 mpBase->resolveForward(t);
3117 }
3118
Jack Palevichb67b18f2009-06-11 21:12:23 -07003119 virtual int finishCompile() {
3120 int result = mpBase->finishCompile();
3121 fprintf(stderr, "finishCompile() = %d\n", result);
3122 return result;
3123 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003124
3125 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003126 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003127 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003128 virtual size_t alignmentOf(Type* pType){
3129 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003130 }
3131
3132 /**
3133 * Array element alignment (in bytes) for this type of data.
3134 */
3135 virtual size_t sizeOf(Type* pType){
3136 return mpBase->sizeOf(pType);
3137 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003138
3139 virtual Type* getR0Type() {
3140 return mpBase->getR0Type();
3141 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003142
3143 virtual ExpressionType getR0ExpressionType() {
3144 return mpBase->getR0ExpressionType();
3145 }
3146
3147 virtual void setR0ExpressionType(ExpressionType et) {
3148 mpBase->setR0ExpressionType(et);
3149 }
3150
3151 virtual size_t getExpressionStackDepth() {
3152 return mpBase->getExpressionStackDepth();
3153 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003154
3155 virtual void forceR0RVal() {
3156 return mpBase->forceR0RVal();
3157 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003158 };
3159
3160#endif // PROVIDE_TRACE_CODEGEN
3161
Jack Palevich569f1352009-06-29 14:29:08 -07003162 class Arena {
3163 public:
3164 // Used to record a given allocation amount.
3165 // Used:
3166 // Mark mark = arena.mark();
3167 // ... lots of arena.allocate()
3168 // arena.free(mark);
3169
3170 struct Mark {
3171 size_t chunk;
3172 size_t offset;
3173 };
3174
3175 Arena() {
3176 mCurrentChunk = 0;
3177 Chunk start(CHUNK_SIZE);
3178 mData.push_back(start);
3179 }
3180
3181 ~Arena() {
3182 for(size_t i = 0; i < mData.size(); i++) {
3183 mData[i].free();
3184 }
3185 }
3186
3187 // Alloc using the standard alignment size safe for any variable
3188 void* alloc(size_t size) {
3189 return alloc(size, 8);
3190 }
3191
3192 Mark mark(){
3193 Mark result;
3194 result.chunk = mCurrentChunk;
3195 result.offset = mData[mCurrentChunk].mOffset;
3196 return result;
3197 }
3198
3199 void freeToMark(const Mark& mark) {
3200 mCurrentChunk = mark.chunk;
3201 mData[mCurrentChunk].mOffset = mark.offset;
3202 }
3203
3204 private:
3205 // Allocate memory aligned to a given size
3206 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3207 // Memory is not zero filled.
3208
3209 void* alloc(size_t size, size_t alignment) {
3210 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3211 if (mCurrentChunk + 1 < mData.size()) {
3212 mCurrentChunk++;
3213 } else {
3214 size_t allocSize = CHUNK_SIZE;
3215 if (allocSize < size + alignment - 1) {
3216 allocSize = size + alignment - 1;
3217 }
3218 Chunk chunk(allocSize);
3219 mData.push_back(chunk);
3220 mCurrentChunk++;
3221 }
3222 }
3223 return mData[mCurrentChunk].allocate(size, alignment);
3224 }
3225
3226 static const size_t CHUNK_SIZE = 128*1024;
3227 // Note: this class does not deallocate its
3228 // memory when it's destroyed. It depends upon
3229 // its parent to deallocate the memory.
3230 struct Chunk {
3231 Chunk() {
3232 mpData = 0;
3233 mSize = 0;
3234 mOffset = 0;
3235 }
3236
3237 Chunk(size_t size) {
3238 mSize = size;
3239 mpData = (char*) malloc(size);
3240 mOffset = 0;
3241 }
3242
3243 ~Chunk() {
3244 // Doesn't deallocate memory.
3245 }
3246
3247 void* allocate(size_t size, size_t alignment) {
3248 size_t alignedOffset = aligned(mOffset, alignment);
3249 void* result = mpData + alignedOffset;
3250 mOffset = alignedOffset + size;
3251 return result;
3252 }
3253
3254 void free() {
3255 if (mpData) {
3256 ::free(mpData);
3257 mpData = 0;
3258 }
3259 }
3260
3261 size_t remainingCapacity(size_t alignment) {
3262 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3263 }
3264
3265 // Assume alignment is a power of two
3266 inline size_t aligned(size_t v, size_t alignment) {
3267 size_t mask = alignment-1;
3268 return (v + mask) & ~mask;
3269 }
3270
3271 char* mpData;
3272 size_t mSize;
3273 size_t mOffset;
3274 };
3275
3276 size_t mCurrentChunk;
3277
3278 Vector<Chunk> mData;
3279 };
3280
Jack Palevich569f1352009-06-29 14:29:08 -07003281 struct VariableInfo;
3282
3283 struct Token {
3284 int hash;
3285 size_t length;
3286 char* pText;
3287 tokenid_t id;
3288
3289 // Current values for the token
3290 char* mpMacroDefinition;
3291 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003292 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003293 };
3294
3295 class TokenTable {
3296 public:
3297 // Don't use 0..0xff, allows characters and operators to be tokens too.
3298
3299 static const int TOKEN_BASE = 0x100;
3300 TokenTable() {
3301 mpMap = hashmapCreate(128, hashFn, equalsFn);
3302 }
3303
3304 ~TokenTable() {
3305 hashmapFree(mpMap);
3306 }
3307
3308 void setArena(Arena* pArena) {
3309 mpArena = pArena;
3310 }
3311
3312 // Returns a token for a given string of characters.
3313 tokenid_t intern(const char* pText, size_t length) {
3314 Token probe;
3315 int hash = hashmapHash((void*) pText, length);
3316 {
3317 Token probe;
3318 probe.hash = hash;
3319 probe.length = length;
3320 probe.pText = (char*) pText;
3321 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3322 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003323 return pValue->id;
3324 }
3325 }
3326
3327 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3328 memset(pToken, 0, sizeof(*pToken));
3329 pToken->hash = hash;
3330 pToken->length = length;
3331 pToken->pText = (char*) mpArena->alloc(length + 1);
3332 memcpy(pToken->pText, pText, length);
3333 pToken->pText[length] = 0;
3334 pToken->id = mTokens.size() + TOKEN_BASE;
3335 mTokens.push_back(pToken);
3336 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003337 return pToken->id;
3338 }
3339
3340 // Return the Token for a given tokenid.
3341 Token& operator[](tokenid_t id) {
3342 return *mTokens[id - TOKEN_BASE];
3343 }
3344
3345 inline size_t size() {
3346 return mTokens.size();
3347 }
3348
3349 private:
3350
3351 static int hashFn(void* pKey) {
3352 Token* pToken = (Token*) pKey;
3353 return pToken->hash;
3354 }
3355
3356 static bool equalsFn(void* keyA, void* keyB) {
3357 Token* pTokenA = (Token*) keyA;
3358 Token* pTokenB = (Token*) keyB;
3359 // Don't need to compare hash values, they should always be equal
3360 return pTokenA->length == pTokenB->length
3361 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3362 }
3363
3364 Hashmap* mpMap;
3365 Vector<Token*> mTokens;
3366 Arena* mpArena;
3367 };
3368
Jack Palevich1cdef202009-05-22 12:06:27 -07003369 class InputStream {
3370 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003371 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003372 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003373 };
3374
3375 class TextInputStream : public InputStream {
3376 public:
3377 TextInputStream(const char* text, size_t textLength)
3378 : pText(text), mTextLength(textLength), mPosition(0) {
3379 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003380
Jack Palevichdc456462009-07-16 16:50:56 -07003381 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003382 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3383 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003384
Jack Palevichdc456462009-07-16 16:50:56 -07003385 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003386 const char* pText;
3387 size_t mTextLength;
3388 size_t mPosition;
3389 };
3390
Jack Palevicheedf9d22009-06-04 16:23:40 -07003391 class String {
3392 public:
3393 String() {
3394 mpBase = 0;
3395 mUsed = 0;
3396 mSize = 0;
3397 }
3398
Jack Palevich303d8ff2009-06-11 19:06:24 -07003399 String(const char* item, int len, bool adopt) {
3400 if (len < 0) {
3401 len = strlen(item);
3402 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003403 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003404 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003405 mUsed = len;
3406 mSize = len + 1;
3407 } else {
3408 mpBase = 0;
3409 mUsed = 0;
3410 mSize = 0;
3411 appendBytes(item, len);
3412 }
3413 }
3414
Jack Palevich303d8ff2009-06-11 19:06:24 -07003415 String(const String& other) {
3416 mpBase = 0;
3417 mUsed = 0;
3418 mSize = 0;
3419 appendBytes(other.getUnwrapped(), other.len());
3420 }
3421
Jack Palevicheedf9d22009-06-04 16:23:40 -07003422 ~String() {
3423 if (mpBase) {
3424 free(mpBase);
3425 }
3426 }
3427
Jack Palevicha6baa232009-06-12 11:25:59 -07003428 String& operator=(const String& other) {
3429 clear();
3430 appendBytes(other.getUnwrapped(), other.len());
3431 return *this;
3432 }
3433
Jack Palevich303d8ff2009-06-11 19:06:24 -07003434 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003435 return mpBase;
3436 }
3437
Jack Palevich303d8ff2009-06-11 19:06:24 -07003438 void clear() {
3439 mUsed = 0;
3440 if (mSize > 0) {
3441 mpBase[0] = 0;
3442 }
3443 }
3444
Jack Palevicheedf9d22009-06-04 16:23:40 -07003445 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003446 appendBytes(s, strlen(s));
3447 }
3448
3449 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003450 memcpy(ensure(n), s, n + 1);
3451 }
3452
3453 void append(char c) {
3454 * ensure(1) = c;
3455 }
3456
Jack Palevich86351982009-06-30 18:09:56 -07003457 void append(String& other) {
3458 appendBytes(other.getUnwrapped(), other.len());
3459 }
3460
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003461 char* orphan() {
3462 char* result = mpBase;
3463 mpBase = 0;
3464 mUsed = 0;
3465 mSize = 0;
3466 return result;
3467 }
3468
Jack Palevicheedf9d22009-06-04 16:23:40 -07003469 void printf(const char* fmt,...) {
3470 va_list ap;
3471 va_start(ap, fmt);
3472 vprintf(fmt, ap);
3473 va_end(ap);
3474 }
3475
3476 void vprintf(const char* fmt, va_list ap) {
3477 char* temp;
3478 int numChars = vasprintf(&temp, fmt, ap);
3479 memcpy(ensure(numChars), temp, numChars+1);
3480 free(temp);
3481 }
3482
Jack Palevich303d8ff2009-06-11 19:06:24 -07003483 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003484 return mUsed;
3485 }
3486
3487 private:
3488 char* ensure(int n) {
3489 size_t newUsed = mUsed + n;
3490 if (newUsed > mSize) {
3491 size_t newSize = mSize * 2 + 10;
3492 if (newSize < newUsed) {
3493 newSize = newUsed;
3494 }
3495 mpBase = (char*) realloc(mpBase, newSize + 1);
3496 mSize = newSize;
3497 }
3498 mpBase[newUsed] = '\0';
3499 char* result = mpBase + mUsed;
3500 mUsed = newUsed;
3501 return result;
3502 }
3503
3504 char* mpBase;
3505 size_t mUsed;
3506 size_t mSize;
3507 };
3508
Jack Palevich569f1352009-06-29 14:29:08 -07003509 void internKeywords() {
3510 // Note: order has to match TOK_ constants
3511 static const char* keywords[] = {
3512 "int",
3513 "char",
3514 "void",
3515 "if",
3516 "else",
3517 "while",
3518 "break",
3519 "return",
3520 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003521 "auto",
3522 "case",
3523 "const",
3524 "continue",
3525 "default",
3526 "do",
3527 "double",
3528 "enum",
3529 "extern",
3530 "float",
3531 "goto",
3532 "long",
3533 "register",
3534 "short",
3535 "signed",
3536 "sizeof",
3537 "static",
3538 "struct",
3539 "switch",
3540 "typedef",
3541 "union",
3542 "unsigned",
3543 "volatile",
3544 "_Bool",
3545 "_Complex",
3546 "_Imaginary",
3547 "inline",
3548 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003549
3550 // predefined tokens that can also be symbols start here:
3551 "pragma",
3552 "define",
3553 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003554 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003555
Jack Palevich569f1352009-06-29 14:29:08 -07003556 for(int i = 0; keywords[i]; i++) {
3557 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003558 }
Jack Palevich569f1352009-06-29 14:29:08 -07003559 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003560
Jack Palevich36d94142009-06-08 15:55:32 -07003561 struct InputState {
3562 InputStream* pStream;
3563 int oldCh;
3564 };
3565
Jack Palevich2db168f2009-06-11 14:29:47 -07003566 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003567 void* pAddress;
3568 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003569 tokenid_t tok;
3570 size_t level;
3571 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003572 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003573 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003574 };
3575
Jack Palevich303d8ff2009-06-11 19:06:24 -07003576 class SymbolStack {
3577 public:
3578 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003579 mpArena = 0;
3580 mpTokenTable = 0;
3581 }
3582
3583 void setArena(Arena* pArena) {
3584 mpArena = pArena;
3585 }
3586
3587 void setTokenTable(TokenTable* pTokenTable) {
3588 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003589 }
3590
3591 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003592 Mark mark;
3593 mark.mArenaMark = mpArena->mark();
3594 mark.mSymbolHead = mStack.size();
3595 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003596 }
3597
3598 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003599 // Undo any shadowing that was done:
3600 Mark mark = mLevelStack.back();
3601 mLevelStack.pop_back();
3602 while (mStack.size() > mark.mSymbolHead) {
3603 VariableInfo* pV = mStack.back();
3604 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003605 if (pV->isStructTag) {
3606 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3607 } else {
3608 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3609 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003610 }
Jack Palevich569f1352009-06-29 14:29:08 -07003611 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003612 }
3613
Jack Palevich569f1352009-06-29 14:29:08 -07003614 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3615 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3616 return pV && pV->level == level();
3617 }
3618
Jack Palevich9221bcc2009-08-26 16:15:07 -07003619 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3620 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3621 return pV && pV->level == level();
3622 }
3623
Jack Palevich569f1352009-06-29 14:29:08 -07003624 VariableInfo* add(tokenid_t tok) {
3625 Token& token = (*mpTokenTable)[tok];
3626 VariableInfo* pOldV = token.mpVariableInfo;
3627 VariableInfo* pNewV =
3628 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3629 memset(pNewV, 0, sizeof(VariableInfo));
3630 pNewV->tok = tok;
3631 pNewV->level = level();
3632 pNewV->pOldDefinition = pOldV;
3633 token.mpVariableInfo = pNewV;
3634 mStack.push_back(pNewV);
3635 return pNewV;
3636 }
3637
Jack Palevich9221bcc2009-08-26 16:15:07 -07003638 VariableInfo* addStructTag(tokenid_t tok) {
3639 Token& token = (*mpTokenTable)[tok];
3640 VariableInfo* pOldS = token.mpStructInfo;
3641 VariableInfo* pNewS =
3642 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3643 memset(pNewS, 0, sizeof(VariableInfo));
3644 pNewS->tok = tok;
3645 pNewS->level = level();
3646 pNewS->isStructTag = true;
3647 pNewS->pOldDefinition = pOldS;
3648 token.mpStructInfo = pNewS;
3649 mStack.push_back(pNewS);
3650 return pNewS;
3651 }
3652
Jack Palevich86351982009-06-30 18:09:56 -07003653 VariableInfo* add(Type* pType) {
3654 VariableInfo* pVI = add(pType->id);
3655 pVI->pType = pType;
3656 return pVI;
3657 }
3658
Jack Palevich569f1352009-06-29 14:29:08 -07003659 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3660 for (size_t i = 0; i < mStack.size(); i++) {
3661 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003662 break;
3663 }
3664 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003665 }
3666
Jack Palevich303d8ff2009-06-11 19:06:24 -07003667 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003668 inline size_t level() {
3669 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003670 }
3671
Jack Palevich569f1352009-06-29 14:29:08 -07003672 struct Mark {
3673 Arena::Mark mArenaMark;
3674 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003675 };
3676
Jack Palevich569f1352009-06-29 14:29:08 -07003677 Arena* mpArena;
3678 TokenTable* mpTokenTable;
3679 Vector<VariableInfo*> mStack;
3680 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003681 };
Jack Palevich36d94142009-06-08 15:55:32 -07003682
3683 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003684 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003685 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003686 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003687 int tokl; // token operator level
3688 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003689 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003690 intptr_t loc; // local variable index
3691 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003692 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003693 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003694 char* dptr; // Macro state: Points to macro text during macro playback.
3695 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003696 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003697 ACCSymbolLookupFn mpSymbolLookupFn;
3698 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003699
3700 // Arena for the duration of the compile
3701 Arena mGlobalArena;
3702 // Arena for data that's only needed when compiling a single function
3703 Arena mLocalArena;
3704
Jack Palevich2ff5c222009-07-23 15:11:22 -07003705 Arena* mpCurrentArena;
3706
Jack Palevich569f1352009-06-29 14:29:08 -07003707 TokenTable mTokenTable;
3708 SymbolStack mGlobals;
3709 SymbolStack mLocals;
3710
Jack Palevich9221bcc2009-08-26 16:15:07 -07003711 SymbolStack* mpCurrentSymbolStack;
3712
Jack Palevich40600de2009-07-01 15:32:35 -07003713 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003714 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003715 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003716 Type* mkpChar; // char
3717 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003718 Type* mkpFloat;
3719 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003720 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003721 Type* mkpIntPtr;
3722 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003723 Type* mkpFloatPtr;
3724 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003725 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003726
Jack Palevich36d94142009-06-08 15:55:32 -07003727 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003728 int mLineNumber;
3729 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003730
3731 CodeBuf codeBuf;
3732 CodeGenerator* pGen;
3733
Jack Palevicheedf9d22009-06-04 16:23:40 -07003734 String mErrorBuf;
3735
Jack Palevicheedf9d22009-06-04 16:23:40 -07003736 String mPragmas;
3737 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003738 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003739
Jack Palevich21a15a22009-05-11 14:49:29 -07003740 static const int ALLOC_SIZE = 99999;
3741
Jack Palevich303d8ff2009-06-11 19:06:24 -07003742 static const int TOK_DUMMY = 1;
3743 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003744 static const int TOK_NUM_FLOAT = 3;
3745 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003746 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003747 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003748
3749 // 3..255 are character and/or operators
3750
Jack Palevich2db168f2009-06-11 14:29:47 -07003751 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003752 // Order has to match string list in "internKeywords".
3753 enum {
3754 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3755 TOK_INT = TOK_KEYWORD,
3756 TOK_CHAR,
3757 TOK_VOID,
3758 TOK_IF,
3759 TOK_ELSE,
3760 TOK_WHILE,
3761 TOK_BREAK,
3762 TOK_RETURN,
3763 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003764 TOK_AUTO,
3765 TOK_CASE,
3766 TOK_CONST,
3767 TOK_CONTINUE,
3768 TOK_DEFAULT,
3769 TOK_DO,
3770 TOK_DOUBLE,
3771 TOK_ENUM,
3772 TOK_EXTERN,
3773 TOK_FLOAT,
3774 TOK_GOTO,
3775 TOK_LONG,
3776 TOK_REGISTER,
3777 TOK_SHORT,
3778 TOK_SIGNED,
3779 TOK_SIZEOF,
3780 TOK_STATIC,
3781 TOK_STRUCT,
3782 TOK_SWITCH,
3783 TOK_TYPEDEF,
3784 TOK_UNION,
3785 TOK_UNSIGNED,
3786 TOK_VOLATILE,
3787 TOK__BOOL,
3788 TOK__COMPLEX,
3789 TOK__IMAGINARY,
3790 TOK_INLINE,
3791 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003792
3793 // Symbols start after keywords
3794
3795 TOK_SYMBOL,
3796 TOK_PRAGMA = TOK_SYMBOL,
3797 TOK_DEFINE,
3798 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003799 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003800
3801 static const int LOCAL = 0x200;
3802
3803 static const int SYM_FORWARD = 0;
3804 static const int SYM_DEFINE = 1;
3805
3806 /* tokens in string heap */
3807 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003808
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003809 static const int OP_INCREMENT = 0;
3810 static const int OP_DECREMENT = 1;
3811 static const int OP_MUL = 2;
3812 static const int OP_DIV = 3;
3813 static const int OP_MOD = 4;
3814 static const int OP_PLUS = 5;
3815 static const int OP_MINUS = 6;
3816 static const int OP_SHIFT_LEFT = 7;
3817 static const int OP_SHIFT_RIGHT = 8;
3818 static const int OP_LESS_EQUAL = 9;
3819 static const int OP_GREATER_EQUAL = 10;
3820 static const int OP_LESS = 11;
3821 static const int OP_GREATER = 12;
3822 static const int OP_EQUALS = 13;
3823 static const int OP_NOT_EQUALS = 14;
3824 static const int OP_LOGICAL_AND = 15;
3825 static const int OP_LOGICAL_OR = 16;
3826 static const int OP_BIT_AND = 17;
3827 static const int OP_BIT_XOR = 18;
3828 static const int OP_BIT_OR = 19;
3829 static const int OP_BIT_NOT = 20;
3830 static const int OP_LOGICAL_NOT = 21;
3831 static const int OP_COUNT = 22;
3832
3833 /* Operators are searched from front, the two-character operators appear
3834 * before the single-character operators with the same first character.
3835 * @ is used to pad out single-character operators.
3836 */
3837 static const char* operatorChars;
3838 static const char operatorLevel[];
3839
Jack Palevich569f1352009-06-29 14:29:08 -07003840 /* Called when we detect an internal problem. Does nothing in production.
3841 *
3842 */
3843 void internalError() {
3844 * (char*) 0 = 0;
3845 }
3846
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003847 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003848 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07003849 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003850 internalError();
3851 }
Jack Palevich86351982009-06-30 18:09:56 -07003852 }
3853
Jack Palevich40600de2009-07-01 15:32:35 -07003854 bool isSymbol(tokenid_t t) {
3855 return t >= TOK_SYMBOL &&
3856 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3857 }
3858
3859 bool isSymbolOrKeyword(tokenid_t t) {
3860 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003861 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003862 }
3863
Jack Palevich86351982009-06-30 18:09:56 -07003864 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003865 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003866 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3867 if (pV && pV->tok != t) {
3868 internalError();
3869 }
3870 return pV;
3871 }
3872
3873 inline bool isDefined(tokenid_t t) {
3874 return t >= TOK_SYMBOL && VI(t) != 0;
3875 }
3876
Jack Palevich40600de2009-07-01 15:32:35 -07003877 const char* nameof(tokenid_t t) {
3878 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003879 return mTokenTable[t].pText;
3880 }
3881
Jack Palevich21a15a22009-05-11 14:49:29 -07003882 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003883 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003884 }
3885
3886 void inp() {
3887 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003888 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003889 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003890 dptr = 0;
3891 ch = dch;
3892 }
Jack Palevichdc456462009-07-16 16:50:56 -07003893 } else {
3894 if (mbBumpLine) {
3895 mLineNumber++;
3896 mbBumpLine = false;
3897 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003898 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003899 if (ch == '\n') {
3900 mbBumpLine = true;
3901 }
3902 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003903#if 0
3904 printf("ch='%c' 0x%x\n", ch, ch);
3905#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003906 }
3907
3908 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003909 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003910 }
3911
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003912 int decodeHex(int c) {
3913 if (isdigit(c)) {
3914 c -= '0';
3915 } else if (c <= 'F') {
3916 c = c - 'A' + 10;
3917 } else {
3918 c =c - 'a' + 10;
3919 }
3920 return c;
3921 }
3922
Jack Palevichb4758ff2009-06-12 12:49:14 -07003923 /* read a character constant, advances ch to after end of constant */
3924 int getq() {
3925 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003926 if (ch == '\\') {
3927 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003928 if (isoctal(ch)) {
3929 // 1 to 3 octal characters.
3930 val = 0;
3931 for(int i = 0; i < 3; i++) {
3932 if (isoctal(ch)) {
3933 val = (val << 3) + ch - '0';
3934 inp();
3935 }
3936 }
3937 return val;
3938 } else if (ch == 'x' || ch == 'X') {
3939 // N hex chars
3940 inp();
3941 if (! isxdigit(ch)) {
3942 error("'x' character escape requires at least one digit.");
3943 } else {
3944 val = 0;
3945 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003946 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003947 inp();
3948 }
3949 }
3950 } else {
3951 int val = ch;
3952 switch (ch) {
3953 case 'a':
3954 val = '\a';
3955 break;
3956 case 'b':
3957 val = '\b';
3958 break;
3959 case 'f':
3960 val = '\f';
3961 break;
3962 case 'n':
3963 val = '\n';
3964 break;
3965 case 'r':
3966 val = '\r';
3967 break;
3968 case 't':
3969 val = '\t';
3970 break;
3971 case 'v':
3972 val = '\v';
3973 break;
3974 case '\\':
3975 val = '\\';
3976 break;
3977 case '\'':
3978 val = '\'';
3979 break;
3980 case '"':
3981 val = '"';
3982 break;
3983 case '?':
3984 val = '?';
3985 break;
3986 default:
3987 error("Undefined character escape %c", ch);
3988 break;
3989 }
3990 inp();
3991 return val;
3992 }
3993 } else {
3994 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003995 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003996 return val;
3997 }
3998
3999 static bool isoctal(int ch) {
4000 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004001 }
4002
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004003 bool acceptCh(int c) {
4004 bool result = c == ch;
4005 if (result) {
4006 pdef(ch);
4007 inp();
4008 }
4009 return result;
4010 }
4011
4012 bool acceptDigitsCh() {
4013 bool result = false;
4014 while (isdigit(ch)) {
4015 result = true;
4016 pdef(ch);
4017 inp();
4018 }
4019 return result;
4020 }
4021
4022 void parseFloat() {
4023 tok = TOK_NUM_DOUBLE;
4024 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004025 if(mTokenString.len() == 0) {
4026 mTokenString.append('0');
4027 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004028 acceptCh('.');
4029 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004030 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004031 acceptCh('-') || acceptCh('+');
4032 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004033 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004034 if (ch == 'f' || ch == 'F') {
4035 tok = TOK_NUM_FLOAT;
4036 inp();
4037 } else if (ch == 'l' || ch == 'L') {
4038 inp();
4039 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004040 }
4041 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004042 char* pEnd = pText + strlen(pText);
4043 char* pEndPtr = 0;
4044 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004045 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004046 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004047 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004048 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004049 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004050 if (errno || pEndPtr != pEnd) {
4051 error("Can't parse constant: %s", pText);
4052 }
4053 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004054 }
4055
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 void next() {
4057 int l, a;
4058
Jack Palevich546b2242009-05-13 15:10:04 -07004059 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004060 if (ch == '#') {
4061 inp();
4062 next();
4063 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004064 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004065 } else if (tok == TOK_PRAGMA) {
4066 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004067 } else if (tok == TOK_LINE) {
4068 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004069 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004070 error("Unsupported preprocessor directive \"%s\"",
4071 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004072 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004073 }
4074 inp();
4075 }
4076 tokl = 0;
4077 tok = ch;
4078 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004079 if (isdigit(ch) || ch == '.') {
4080 // Start of a numeric constant. Could be integer, float, or
4081 // double, won't know until we look further.
4082 mTokenString.clear();
4083 pdef(ch);
4084 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004085 if (tok == '.' && !isdigit(ch)) {
4086 goto done;
4087 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004088 int base = 10;
4089 if (tok == '0') {
4090 if (ch == 'x' || ch == 'X') {
4091 base = 16;
4092 tok = TOK_NUM;
4093 tokc = 0;
4094 inp();
4095 while ( isxdigit(ch) ) {
4096 tokc = (tokc << 4) + decodeHex(ch);
4097 inp();
4098 }
4099 } else if (isoctal(ch)){
4100 base = 8;
4101 tok = TOK_NUM;
4102 tokc = 0;
4103 while ( isoctal(ch) ) {
4104 tokc = (tokc << 3) + (ch - '0');
4105 inp();
4106 }
4107 }
4108 } else if (isdigit(tok)){
4109 acceptDigitsCh();
4110 }
4111 if (base == 10) {
4112 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4113 parseFloat();
4114 } else {
4115 // It's an integer constant
4116 char* pText = mTokenString.getUnwrapped();
4117 char* pEnd = pText + strlen(pText);
4118 char* pEndPtr = 0;
4119 errno = 0;
4120 tokc = strtol(pText, &pEndPtr, base);
4121 if (errno || pEndPtr != pEnd) {
4122 error("Can't parse constant: %s %d %d", pText, base, errno);
4123 }
4124 tok = TOK_NUM;
4125 }
4126 }
4127 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004128 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004129 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004130 pdef(ch);
4131 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004132 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004133 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004134 if (! mbSuppressMacroExpansion) {
4135 // Is this a macro?
4136 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4137 if (pMacroDefinition) {
4138 // Yes, it is a macro
4139 dptr = pMacroDefinition;
4140 dch = ch;
4141 inp();
4142 next();
4143 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004144 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004145 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004146 inp();
4147 if (tok == '\'') {
4148 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004149 tokc = getq();
4150 if (ch != '\'') {
4151 error("Expected a ' character, got %c", ch);
4152 } else {
4153 inp();
4154 }
Jack Palevich546b2242009-05-13 15:10:04 -07004155 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004156 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004157 while (ch && ch != EOF) {
4158 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004159 inp();
4160 inp();
4161 if (ch == '/')
4162 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004163 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004164 if (ch == EOF) {
4165 error("End of file inside comment.");
4166 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004167 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004168 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004169 } else if ((tok == '/') & (ch == '/')) {
4170 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004171 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004172 inp();
4173 }
4174 inp();
4175 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004176 } else if ((tok == '-') & (ch == '>')) {
4177 inp();
4178 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004179 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004180 const char* t = operatorChars;
4181 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004182 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004183 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004184 tokl = operatorLevel[opIndex];
4185 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004186 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004187#if 0
4188 printf("%c%c -> tokl=%d tokc=0x%x\n",
4189 l, a, tokl, tokc);
4190#endif
4191 if (a == ch) {
4192 inp();
4193 tok = TOK_DUMMY; /* dummy token for double tokens */
4194 }
Jack Palevich0c017742009-07-31 12:00:39 -07004195 /* check for op=, valid for * / % + - << >> & ^ | */
4196 if (ch == '=' &&
4197 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004198 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004199 inp();
4200 tok = TOK_OP_ASSIGNMENT;
4201 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004202 break;
4203 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004204 opIndex++;
4205 }
4206 if (l == 0) {
4207 tokl = 0;
4208 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004209 }
4210 }
4211 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004212
4213 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004214#if 0
4215 {
Jack Palevich569f1352009-06-29 14:29:08 -07004216 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004217 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004218 fprintf(stderr, "%s\n", buf.getUnwrapped());
4219 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004220#endif
4221 }
4222
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004223 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004224 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004225 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004226 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004227 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004228 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004229 if (ch == '(') {
4230 delete pName;
4231 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004232 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004233 }
4234 while (isspace(ch)) {
4235 inp();
4236 }
Jack Palevich569f1352009-06-29 14:29:08 -07004237 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004238 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004239 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004240 // Check for '//' comments.
4241 if (appendToValue && ch == '/') {
4242 inp();
4243 if (ch == '/') {
4244 appendToValue = false;
4245 } else {
4246 value.append('/');
4247 }
4248 }
4249 if (appendToValue && ch != EOF) {
4250 value.append(ch);
4251 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004252 inp();
4253 }
Jack Palevich569f1352009-06-29 14:29:08 -07004254 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4255 memcpy(pDefn, value.getUnwrapped(), value.len());
4256 pDefn[value.len()] = 0;
4257 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004258 }
4259
Jack Palevicheedf9d22009-06-04 16:23:40 -07004260 void doPragma() {
4261 // # pragma name(val)
4262 int state = 0;
4263 while(ch != EOF && ch != '\n' && state < 10) {
4264 switch(state) {
4265 case 0:
4266 if (isspace(ch)) {
4267 inp();
4268 } else {
4269 state++;
4270 }
4271 break;
4272 case 1:
4273 if (isalnum(ch)) {
4274 mPragmas.append(ch);
4275 inp();
4276 } else if (ch == '(') {
4277 mPragmas.append(0);
4278 inp();
4279 state++;
4280 } else {
4281 state = 11;
4282 }
4283 break;
4284 case 2:
4285 if (isalnum(ch)) {
4286 mPragmas.append(ch);
4287 inp();
4288 } else if (ch == ')') {
4289 mPragmas.append(0);
4290 inp();
4291 state = 10;
4292 } else {
4293 state = 11;
4294 }
4295 break;
4296 }
4297 }
4298 if(state != 10) {
4299 error("Unexpected pragma syntax");
4300 }
4301 mPragmaStringCount += 2;
4302 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004303
Jack Palevichdc456462009-07-16 16:50:56 -07004304 void doLine() {
4305 // # line number { "filename "}
4306 next();
4307 if (tok != TOK_NUM) {
4308 error("Expected a line-number");
4309 } else {
4310 mLineNumber = tokc-1; // The end-of-line will increment it.
4311 }
4312 while(ch != EOF && ch != '\n') {
4313 inp();
4314 }
4315 }
4316
Jack Palevichac0e95e2009-05-29 13:53:44 -07004317 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004318 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004319 mErrorBuf.vprintf(fmt, ap);
4320 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004321 }
4322
Jack Palevich8b0624c2009-05-20 12:12:06 -07004323 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004324 if (tok != c) {
4325 error("'%c' expected", c);
4326 }
4327 next();
4328 }
4329
Jack Palevich86351982009-06-30 18:09:56 -07004330 bool accept(intptr_t c) {
4331 if (tok == c) {
4332 next();
4333 return true;
4334 }
4335 return false;
4336 }
4337
Jack Palevich40600de2009-07-01 15:32:35 -07004338 bool acceptStringLiteral() {
4339 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004340 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004341 // This while loop merges multiple adjacent string constants.
4342 while (tok == '"') {
4343 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004344 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004345 }
4346 if (ch != '"') {
4347 error("Unterminated string constant.");
4348 }
4349 inp();
4350 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004351 }
Jack Palevich40600de2009-07-01 15:32:35 -07004352 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004353 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004354 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004355 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004356
4357 return true;
4358 }
4359 return false;
4360 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004361
Jack Palevichb1544ca2009-07-16 15:09:20 -07004362 void linkGlobal(tokenid_t t, bool isFunction) {
4363 VariableInfo* pVI = VI(t);
4364 void* n = NULL;
4365 if (mpSymbolLookupFn) {
4366 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4367 }
4368 if (pVI->pType == NULL) {
4369 if (isFunction) {
4370 pVI->pType = mkpIntFn;
4371 } else {
4372 pVI->pType = mkpInt;
4373 }
4374 }
4375 pVI->pAddress = n;
4376 }
4377
Jack Palevich29daf572009-07-30 19:38:55 -07004378 void unaryOrAssignment() {
4379 unary();
4380 if (accept('=')) {
4381 checkLVal();
4382 pGen->pushR0();
4383 expr();
4384 pGen->forceR0RVal();
4385 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004386 } else if (tok == TOK_OP_ASSIGNMENT) {
4387 int t = tokc;
4388 next();
4389 checkLVal();
4390 pGen->pushR0();
4391 pGen->forceR0RVal();
4392 pGen->pushR0();
4393 expr();
4394 pGen->forceR0RVal();
4395 pGen->genOp(t);
4396 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004397 }
4398 }
4399
Jack Palevich40600de2009-07-01 15:32:35 -07004400 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004401 */
Jack Palevich29daf572009-07-30 19:38:55 -07004402 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004403 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004404 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004405 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004406 if (acceptStringLiteral()) {
4407 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004408 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004409 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004410 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004411 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004412 t = tok;
4413 next();
4414 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004415 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004416 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004417 // Align to 4-byte boundary
4418 glo = (char*) (((intptr_t) glo + 3) & -4);
4419 * (float*) glo = (float) ad;
4420 pGen->loadFloat((int) glo, mkpFloat);
4421 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004422 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004423 // Align to 8-byte boundary
4424 glo = (char*) (((intptr_t) glo + 7) & -8);
4425 * (double*) glo = ad;
4426 pGen->loadFloat((int) glo, mkpDouble);
4427 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004428 } else if (c == 2) {
4429 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004430 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004431 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004432 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004433 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004434 else if (t == '+') {
4435 // ignore unary plus.
4436 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004437 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004438 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004439 } else if (c == 11) {
4440 // pre increment / pre decrement
4441 unary();
4442 doIncDec(a == OP_INCREMENT, 0);
4443 }
4444 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004445 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004446 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004447 if (pCast) {
4448 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004449 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004450 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004451 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004452 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004453 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004454 skip(')');
4455 }
4456 } else if (t == '*') {
4457 /* This is a pointer dereference.
4458 */
Jack Palevich29daf572009-07-30 19:38:55 -07004459 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004460 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004461 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004462 unary();
4463 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004464 } else if (t == EOF ) {
4465 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004466 } else if (t == ';') {
4467 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004468 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004469 // Don't have to do anything special here, the error
4470 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004471 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004472 if (!isDefined(t)) {
4473 mGlobals.add(t);
4474 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004475 }
Jack Palevich8df46192009-07-07 14:48:51 -07004476 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004477 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004478 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004479 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004480 linkGlobal(t, tok == '(');
4481 n = (intptr_t) pVI->pAddress;
4482 if (!n && tok != '(') {
4483 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004484 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004485 }
Jack Palevich29daf572009-07-30 19:38:55 -07004486 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004487 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004488 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004489 linkGlobal(t, false);
4490 n = (intptr_t) pVI->pAddress;
4491 if (!n) {
4492 error("Undeclared variable %s\n", nameof(t));
4493 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004494 }
Jack Palevich5b659092009-07-31 14:55:07 -07004495 }
4496 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004497 Type* pVal;
4498 ExpressionType et;
4499 if (pVI->pType->tag == TY_ARRAY) {
4500 pVal = pVI->pType;
4501 et = ET_RVALUE;
4502 } else {
4503 pVal = createPtrType(pVI->pType);
4504 et = ET_LVALUE;
4505 }
Jack Palevich5b659092009-07-31 14:55:07 -07004506 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004507 int tag = pVal->pHead->tag;
4508 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004509 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004510 }
Jack Palevich5b659092009-07-31 14:55:07 -07004511 pGen->leaR0(n, pVal, et);
4512 } else {
4513 pVI->pForward = (void*) pGen->leaForward(
4514 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004515 }
4516 }
4517 }
4518
Jack Palevich5b659092009-07-31 14:55:07 -07004519 /* Now handle postfix operators */
4520 for(;;) {
4521 if (tokl == 11) {
4522 // post inc / post dec
4523 doIncDec(tokc == OP_INCREMENT, true);
4524 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004525 } else if (accept('[')) {
4526 // Array reference
4527 pGen->forceR0RVal();
4528 pGen->pushR0();
4529 commaExpr();
4530 pGen->forceR0RVal();
4531 pGen->genOp(OP_PLUS);
4532 doPointer();
4533 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004534 } else if (accept('.')) {
4535 // struct element
4536 pGen->forceR0RVal();
4537 Type* pStruct = pGen->getR0Type();
4538 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004539 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004540 } else {
4541 error("expected a struct value to the left of '.'");
4542 }
4543 } else if (accept(TOK_OP_ARROW)) {
4544 pGen->forceR0RVal();
4545 Type* pPtr = pGen->getR0Type();
4546 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4547 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004548 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004549 } else {
4550 error("Expected a pointer to a struct to the left of '->'");
4551 }
Jack Palevich5b659092009-07-31 14:55:07 -07004552 } else if (accept('(')) {
4553 /* function call */
4554 Type* pDecl = NULL;
4555 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004556 Type* pFn = pGen->getR0Type();
4557 assert(pFn->tag == TY_POINTER);
4558 assert(pFn->pHead->tag == TY_FUNC);
4559 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004560 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004561 Type* pArgList = pDecl->pTail;
4562 bool varArgs = pArgList == NULL;
4563 /* push args and invert order */
4564 a = pGen->beginFunctionCallArguments();
4565 int l = 0;
4566 int argCount = 0;
4567 while (tok != ')' && tok != EOF) {
4568 if (! varArgs && !pArgList) {
4569 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004570 }
Jack Palevich5b659092009-07-31 14:55:07 -07004571 expr();
4572 pGen->forceR0RVal();
4573 Type* pTargetType;
4574 if (pArgList) {
4575 pTargetType = pArgList->pHead;
4576 pArgList = pArgList->pTail;
4577 } else {
4578 // This is a ... function, just pass arguments in their
4579 // natural type.
4580 pTargetType = pGen->getR0Type();
4581 if (pTargetType->tag == TY_FLOAT) {
4582 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004583 } else if (pTargetType->tag == TY_ARRAY) {
4584 // Pass arrays by pointer.
4585 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004586 }
4587 }
4588 if (pTargetType->tag == TY_VOID) {
4589 error("Can't pass void value for argument %d",
4590 argCount + 1);
4591 } else {
4592 l += pGen->storeR0ToArg(l, pTargetType);
4593 }
4594 if (accept(',')) {
4595 // fine
4596 } else if ( tok != ')') {
4597 error("Expected ',' or ')'");
4598 }
4599 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004600 }
Jack Palevich5b659092009-07-31 14:55:07 -07004601 if (! varArgs && pArgList) {
4602 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004603 }
Jack Palevich5b659092009-07-31 14:55:07 -07004604 pGen->endFunctionCallArguments(pDecl, a, l);
4605 skip(')');
4606 pGen->callIndirect(l, pDecl);
4607 pGen->adjustStackAfterCall(pDecl, l, true);
4608 } else {
4609 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004610 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004611 }
4612 }
4613
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004614 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004615 Type* pStructElement = lookupStructMember(pStruct, tok);
4616 if (pStructElement) {
4617 next();
4618 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4619 } else {
4620 String buf;
4621 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004622 error("Expected a struct member to the right of '%s', got %s",
4623 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004624 }
4625 }
4626
Jack Palevichaaac9282009-07-31 14:34:34 -07004627 void doIncDec(int isInc, int isPost) {
4628 // R0 already has the lval
4629 checkLVal();
4630 int lit = isInc ? 1 : -1;
4631 pGen->pushR0();
4632 pGen->loadR0FromR0();
4633 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004634 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4635 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004636 error("++/-- illegal for this type. %d", tag);
4637 }
4638 if (isPost) {
4639 pGen->over();
4640 pGen->pushR0();
4641 pGen->li(lit);
4642 pGen->genOp(OP_PLUS);
4643 pGen->storeR0ToTOS();
4644 pGen->popR0();
4645 } else {
4646 pGen->pushR0();
4647 pGen->li(lit);
4648 pGen->genOp(OP_PLUS);
4649 pGen->over();
4650 pGen->storeR0ToTOS();
4651 pGen->popR0();
4652 }
4653 }
4654
Jack Palevich47cbea92009-07-31 15:25:53 -07004655 void doPointer() {
4656 pGen->forceR0RVal();
4657 Type* pR0Type = pGen->getR0Type();
4658 if (pR0Type->tag != TY_POINTER) {
4659 error("Expected a pointer type.");
4660 } else {
4661 if (pR0Type->pHead->tag != TY_FUNC) {
4662 pGen->setR0ExpressionType(ET_LVALUE);
4663 }
4664 }
4665 }
4666
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004667 void doAddressOf() {
4668 Type* pR0 = pGen->getR0Type();
4669 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4670 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4671 error("Expected an lvalue");
4672 }
4673 Type* pR0Type = pGen->getR0Type();
4674 pGen->setR0ExpressionType(ET_RVALUE);
4675 }
4676
Jack Palevich40600de2009-07-01 15:32:35 -07004677 /* Recursive descent parser for binary operations.
4678 */
4679 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004680 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004681 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004682 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004683 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004684 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004685 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004686 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004687 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 t = tokc;
4689 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004690 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004691 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004692 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004693 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004694 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004695 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004696 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004697 // Check for syntax error.
4698 if (pGen->getR0Type() == NULL) {
4699 // We failed to parse a right-hand argument.
4700 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004701 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004702 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004703 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004704 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004705 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004706 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004707 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004708 }
4709 }
4710 }
4711 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004712 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004713 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004714 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004715 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004716 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004717 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004718 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004719 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004720 }
4721 }
4722 }
4723
Jack Palevich43aaee32009-07-31 14:01:37 -07004724 void commaExpr() {
4725 for(;;) {
4726 expr();
4727 if (!accept(',')) {
4728 break;
4729 }
4730 }
4731 }
4732
Jack Palevich21a15a22009-05-11 14:49:29 -07004733 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004734 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004735 }
4736
4737 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004738 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004739 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004740 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004741 }
4742
Jack Palevicha6baa232009-06-12 11:25:59 -07004743 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004744 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004745
Jack Palevich95727a02009-07-06 12:07:15 -07004746 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004747 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004748 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004749 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004750 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004751 next();
4752 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004753 a = test_expr();
4754 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004755 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004756 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004757 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004758 n = pGen->gjmp(0); /* jmp */
4759 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004760 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004761 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004762 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004763 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004764 }
Jack Palevich546b2242009-05-13 15:10:04 -07004765 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004766 t = tok;
4767 next();
4768 skip('(');
4769 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004770 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004771 a = test_expr();
4772 } else {
4773 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004774 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004775 skip(';');
4776 n = codeBuf.getPC();
4777 a = 0;
4778 if (tok != ';')
4779 a = test_expr();
4780 skip(';');
4781 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004782 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004783 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004784 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004785 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004786 n = t + 4;
4787 }
4788 }
4789 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004790 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004791 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004792 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004793 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004794 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004795 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004796 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004797 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004798 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004799 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004800 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004801 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004802 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004803 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004804 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004805 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004806 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004807 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004808 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004809 if (pReturnType->tag == TY_VOID) {
4810 error("Must not return a value from a void function");
4811 } else {
4812 pGen->convertR0(pReturnType);
4813 }
4814 } else {
4815 if (pReturnType->tag != TY_VOID) {
4816 error("Must specify a value here");
4817 }
Jack Palevich8df46192009-07-07 14:48:51 -07004818 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004819 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004820 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004821 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004822 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004823 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004824 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004825 }
4826 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004827
Jack Palevicha8f427f2009-07-13 18:40:08 -07004828 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004829 if (a == b) {
4830 return true;
4831 }
4832 if (a == NULL || b == NULL) {
4833 return false;
4834 }
4835 TypeTag at = a->tag;
4836 if (at != b->tag) {
4837 return false;
4838 }
4839 if (at == TY_POINTER) {
4840 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004841 } else if (at == TY_ARRAY) {
4842 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004843 } else if (at == TY_FUNC || at == TY_PARAM) {
4844 return typeEqual(a->pHead, b->pHead)
4845 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004846 } else if (at == TY_STRUCT) {
4847 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07004848 }
4849 return true;
4850 }
4851
Jack Palevich2ff5c222009-07-23 15:11:22 -07004852 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004853 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004854 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004855 memset(pType, 0, sizeof(*pType));
4856 pType->tag = tag;
4857 pType->pHead = pHead;
4858 pType->pTail = pTail;
4859 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004860 }
4861
Jack Palevich2ff5c222009-07-23 15:11:22 -07004862 Type* createPtrType(Type* pType) {
4863 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004864 }
4865
4866 /**
4867 * Try to print a type in declaration order
4868 */
Jack Palevich86351982009-06-30 18:09:56 -07004869 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004870 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004871 if (pType == NULL) {
4872 buffer.appendCStr("null");
4873 return;
4874 }
Jack Palevich3f226492009-07-02 14:46:19 -07004875 decodeTypeImp(buffer, pType);
4876 }
4877
4878 void decodeTypeImp(String& buffer, Type* pType) {
4879 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004880 decodeId(buffer, pType->id);
4881 decodeTypeImpPostfix(buffer, pType);
4882 }
Jack Palevich3f226492009-07-02 14:46:19 -07004883
Jack Palevich9221bcc2009-08-26 16:15:07 -07004884 void decodeId(String& buffer, tokenid_t id) {
4885 if (id) {
4886 String temp;
4887 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004888 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004889 }
Jack Palevich3f226492009-07-02 14:46:19 -07004890 }
4891
4892 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4893 TypeTag tag = pType->tag;
4894
Jack Palevich9221bcc2009-08-26 16:15:07 -07004895 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07004896 switch (tag) {
4897 case TY_INT:
4898 buffer.appendCStr("int");
4899 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004900 case TY_SHORT:
4901 buffer.appendCStr("short");
4902 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004903 case TY_CHAR:
4904 buffer.appendCStr("char");
4905 break;
4906 case TY_VOID:
4907 buffer.appendCStr("void");
4908 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004909 case TY_FLOAT:
4910 buffer.appendCStr("float");
4911 break;
4912 case TY_DOUBLE:
4913 buffer.appendCStr("double");
4914 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004915 case TY_STRUCT:
4916 {
4917 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4918 buffer.appendCStr(isStruct ? "struct" : "union");
4919 if (pType->pHead && pType->pHead->structTag) {
4920 buffer.append(' ');
4921 decodeId(buffer, pType->pHead->structTag);
4922 }
4923 }
4924 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004925 default:
4926 break;
4927 }
Jack Palevich86351982009-06-30 18:09:56 -07004928 buffer.append(' ');
4929 }
Jack Palevich3f226492009-07-02 14:46:19 -07004930
4931 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004932 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004933 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004934 case TY_SHORT:
4935 break;
Jack Palevich86351982009-06-30 18:09:56 -07004936 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004937 break;
4938 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004939 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004940 case TY_FLOAT:
4941 break;
4942 case TY_DOUBLE:
4943 break;
Jack Palevich86351982009-06-30 18:09:56 -07004944 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004945 decodeTypeImpPrefix(buffer, pType->pHead);
4946 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4947 buffer.append('(');
4948 }
4949 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004950 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004951 case TY_ARRAY:
4952 decodeTypeImpPrefix(buffer, pType->pHead);
4953 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004954 case TY_STRUCT:
4955 break;
Jack Palevich86351982009-06-30 18:09:56 -07004956 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004957 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004958 break;
4959 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004960 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004961 break;
4962 default:
4963 String temp;
4964 temp.printf("Unknown tag %d", pType->tag);
4965 buffer.append(temp);
4966 break;
4967 }
Jack Palevich3f226492009-07-02 14:46:19 -07004968 }
4969
4970 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4971 TypeTag tag = pType->tag;
4972
4973 switch(tag) {
4974 case TY_POINTER:
4975 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4976 buffer.append(')');
4977 }
4978 decodeTypeImpPostfix(buffer, pType->pHead);
4979 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004980 case TY_ARRAY:
4981 {
4982 String temp;
4983 temp.printf("[%d]", pType->length);
4984 buffer.append(temp);
4985 }
4986 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07004987 case TY_STRUCT:
4988 if (pType->pHead->length >= 0) {
4989 buffer.appendCStr(" {");
4990 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4991 decodeTypeImp(buffer, pArg->pHead);
4992 buffer.appendCStr(";");
4993 }
4994 buffer.append('}');
4995 }
4996 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004997 case TY_FUNC:
4998 buffer.append('(');
4999 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5000 decodeTypeImp(buffer, pArg);
5001 if (pArg->pTail) {
5002 buffer.appendCStr(", ");
5003 }
5004 }
5005 buffer.append(')');
5006 break;
5007 default:
5008 break;
Jack Palevich86351982009-06-30 18:09:56 -07005009 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005010 }
5011
Jack Palevich86351982009-06-30 18:09:56 -07005012 void printType(Type* pType) {
5013 String buffer;
5014 decodeType(buffer, pType);
5015 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005016 }
5017
Jack Palevich2ff5c222009-07-23 15:11:22 -07005018 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005019 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005020 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005021 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005022 } else if (tok == TOK_SHORT) {
5023 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005024 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005025 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005026 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005027 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005028 } else if (tok == TOK_FLOAT) {
5029 pType = mkpFloat;
5030 } else if (tok == TOK_DOUBLE) {
5031 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005032 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5033 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005034 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005035 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005036 }
5037 next();
Jack Palevich86351982009-06-30 18:09:56 -07005038 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005039 }
5040
Jack Palevich9221bcc2009-08-26 16:15:07 -07005041 Type* acceptStruct() {
5042 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5043 bool isStruct = tok == TOK_STRUCT;
5044 next();
5045 tokenid_t structTag = acceptSymbol();
5046 bool isDeclaration = accept('{');
5047 bool fail = false;
5048
5049 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5050 if (structTag) {
5051 Token* pToken = &mTokenTable[structTag];
5052 VariableInfo* pStructInfo = pToken->mpStructInfo;
5053 bool needToDeclare = !pStructInfo;
5054 if (pStructInfo) {
5055 if (isDeclaration) {
5056 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5057 if (pStructInfo->pType->pHead->length == -1) {
5058 // we're filling in a forward declaration.
5059 needToDeclare = false;
5060 } else {
5061 error("A struct with the same name is already defined at this level.");
5062 fail = true;
5063 }
5064 } else {
5065 needToDeclare = true;
5066 }
5067 }
5068 if (!fail) {
5069 assert(pStructInfo->isStructTag);
5070 pStructType->pHead = pStructInfo->pType;
5071 pStructType->pTail = pStructType->pHead->pTail;
5072 }
5073 }
5074
5075 if (needToDeclare) {
5076 // This is a new struct name
5077 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5078 pStructType = createType(TY_STRUCT, NULL, NULL);
5079 pStructType->structTag = structTag;
5080 pStructType->pHead = pStructType;
5081 if (! isDeclaration) {
5082 // A forward declaration
5083 pStructType->length = -1;
5084 }
5085 pToken->mpStructInfo->pType = pStructType;
5086 }
5087 } else {
5088 // An anonymous struct
5089 pStructType->pHead = pStructType;
5090 }
5091
5092 if (isDeclaration) {
5093 size_t offset = 0;
5094 size_t structSize = 0;
5095 size_t structAlignment = 0;
5096 Type** pParamHolder = & pStructType->pHead->pTail;
5097 while (tok != '}' && tok != EOF) {
5098 Type* pPrimitiveType = expectPrimitiveType();
5099 if (pPrimitiveType) {
5100 while (tok != ';' && tok != EOF) {
5101 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5102 if (!pItem) {
5103 break;
5104 }
5105 if (lookupStructMember(pStructType, pItem->id)) {
5106 String buf;
5107 decodeToken(buf, pItem->id, false);
5108 error("Duplicate struct member %s", buf.getUnwrapped());
5109 }
5110 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5111 size_t alignment = pGen->alignmentOf(pItem);
5112 if (alignment > structAlignment) {
5113 structAlignment = alignment;
5114 }
5115 size_t alignmentMask = alignment - 1;
5116 offset = (offset + alignmentMask) & ~alignmentMask;
5117 pStructElement->length = offset;
5118 size_t size = pGen->sizeOf(pItem);
5119 if (isStruct) {
5120 offset += size;
5121 structSize = offset;
5122 } else {
5123 if (size >= structSize) {
5124 structSize = size;
5125 }
5126 }
5127 *pParamHolder = pStructElement;
5128 pParamHolder = &pStructElement->pTail;
5129 accept(',');
5130 }
5131 skip(';');
5132 } else {
5133 // Some sort of syntax error, skip token and keep trying
5134 next();
5135 }
5136 }
5137 if (!fail) {
5138 pStructType->pHead->length = structSize;
5139 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5140 }
5141 skip('}');
5142 }
5143 if (fail) {
5144 pStructType = NULL;
5145 }
5146 return pStructType;
5147 }
5148
5149 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5150 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5151 if (pStructElement->pHead->id == memberId) {
5152 return pStructElement;
5153 }
5154 }
5155 return NULL;
5156 }
5157
Jack Palevich2ff5c222009-07-23 15:11:22 -07005158 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005159 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005160 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005161 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005162 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005163 if (declName) {
5164 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005165 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005166 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005167 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005168 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005169 } else if (nameRequired) {
5170 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005171 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005172#if 0
5173 fprintf(stderr, "Parsed a declaration: ");
5174 printType(pType);
5175#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005176 if (reportFailure) {
5177 return NULL;
5178 }
Jack Palevich86351982009-06-30 18:09:56 -07005179 return pType;
5180 }
5181
Jack Palevich2ff5c222009-07-23 15:11:22 -07005182 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005183 bool nameRequired = pBaseType->tag != TY_STRUCT;
5184 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005185 if (! pType) {
5186 error("Expected a declaration");
5187 }
5188 return pType;
5189 }
5190
Jack Palevich3f226492009-07-02 14:46:19 -07005191 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005192 Type* acceptCastTypeDeclaration() {
5193 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005194 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005195 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005196 }
Jack Palevich86351982009-06-30 18:09:56 -07005197 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005198 }
5199
Jack Palevich2ff5c222009-07-23 15:11:22 -07005200 Type* expectCastTypeDeclaration() {
5201 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005202 if (! pType) {
5203 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005204 }
Jack Palevich3f226492009-07-02 14:46:19 -07005205 return pType;
5206 }
5207
5208 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005209 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005210 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005211 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005212 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005213 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005214 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005215 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005216 return pType;
5217 }
5218
5219 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005220 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005221 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005222 // direct-dcl :
5223 // name
5224 // (dcl)
5225 // direct-dcl()
5226 // direct-dcl[]
5227 Type* pNewHead = NULL;
5228 if (accept('(')) {
5229 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005230 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005231 skip(')');
5232 } else if ((declName = acceptSymbol()) != 0) {
5233 if (nameAllowed == false && declName) {
5234 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005235 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005236 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005237 } else if (nameRequired && ! declName) {
5238 String temp;
5239 decodeToken(temp, tok, true);
5240 error("Expected name. Got %s", temp.getUnwrapped());
5241 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005242 }
Jack Palevichb6154502009-08-04 14:56:09 -07005243 for(;;) {
5244 if (accept('(')) {
5245 // Function declaration
5246 Type* pTail = acceptArgs(nameAllowed);
5247 pType = createType(TY_FUNC, pType, pTail);
5248 skip(')');
5249 } if (accept('[')) {
5250 if (tok != ']') {
5251 if (tok != TOK_NUM || tokc <= 0) {
5252 error("Expected positive integer constant");
5253 } else {
5254 Type* pDecayType = createPtrType(pType);
5255 pType = createType(TY_ARRAY, pType, pDecayType);
5256 pType->length = tokc;
5257 }
5258 next();
5259 }
5260 skip(']');
5261 } else {
5262 break;
5263 }
Jack Palevich86351982009-06-30 18:09:56 -07005264 }
Jack Palevich3f226492009-07-02 14:46:19 -07005265
5266 if (pNewHead) {
5267 Type* pA = pNewHead;
5268 while (pA->pHead) {
5269 pA = pA->pHead;
5270 }
5271 pA->pHead = pType;
5272 pType = pNewHead;
5273 }
Jack Palevich86351982009-06-30 18:09:56 -07005274 return pType;
5275 }
5276
Jack Palevich2ff5c222009-07-23 15:11:22 -07005277 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005278 Type* pHead = NULL;
5279 Type* pTail = NULL;
5280 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005281 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005282 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005283 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005284 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005285 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005286 if (!pHead) {
5287 pHead = pParam;
5288 pTail = pParam;
5289 } else {
5290 pTail->pTail = pParam;
5291 pTail = pParam;
5292 }
5293 }
5294 }
5295 if (! accept(',')) {
5296 break;
5297 }
5298 }
5299 return pHead;
5300 }
5301
Jack Palevich2ff5c222009-07-23 15:11:22 -07005302 Type* expectPrimitiveType() {
5303 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005304 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005305 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005306 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005307 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005308 }
Jack Palevich86351982009-06-30 18:09:56 -07005309 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005310 }
5311
Jack Palevichb5e33312009-07-30 19:06:34 -07005312 void checkLVal() {
5313 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005314 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005315 }
5316 }
5317
Jack Palevich86351982009-06-30 18:09:56 -07005318 void addGlobalSymbol(Type* pDecl) {
5319 tokenid_t t = pDecl->id;
5320 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005321 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005322 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005323 }
Jack Palevich86351982009-06-30 18:09:56 -07005324 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005325 }
5326
Jack Palevich86351982009-06-30 18:09:56 -07005327 void reportDuplicate(tokenid_t t) {
5328 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005329 }
5330
Jack Palevich86351982009-06-30 18:09:56 -07005331 void addLocalSymbol(Type* pDecl) {
5332 tokenid_t t = pDecl->id;
5333 if (mLocals.isDefinedAtCurrentLevel(t)) {
5334 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005335 }
Jack Palevich86351982009-06-30 18:09:56 -07005336 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005337 }
5338
Jack Palevich61de31f2009-09-08 11:06:40 -07005339 bool checkUndeclaredStruct(Type* pBaseType) {
5340 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5341 String temp;
5342 decodeToken(temp, pBaseType->structTag, false);
5343 error("Undeclared struct %s", temp.getUnwrapped());
5344 return true;
5345 }
5346 return false;
5347 }
5348
Jack Palevich95727a02009-07-06 12:07:15 -07005349 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005350 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005351
Jack Palevich95727a02009-07-06 12:07:15 -07005352 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005353 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005354 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005355 if (!pDecl) {
5356 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005357 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005358 if (!pDecl->id) {
5359 break;
5360 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005361 if (checkUndeclaredStruct(pDecl)) {
5362 break;
5363 }
Jack Palevich86351982009-06-30 18:09:56 -07005364 int variableAddress = 0;
5365 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005366 size_t alignment = pGen->alignmentOf(pDecl);
5367 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005368 size_t alignmentMask = ~ (alignment - 1);
5369 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005370 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005371 loc = (loc + alignment - 1) & alignmentMask;
5372 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5373 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005374 variableAddress = -loc;
5375 VI(pDecl->id)->pAddress = (void*) variableAddress;
5376 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005377 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005378 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005379 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005380 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005381 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005382 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005383 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005384 if (tok == ',')
5385 next();
5386 }
5387 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005388 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005389 }
5390 }
5391
Jack Palevichf1728be2009-06-12 13:53:51 -07005392 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005393 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005394 }
5395
Jack Palevich37c54bd2009-07-14 18:35:36 -07005396 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005397 if (token == EOF ) {
5398 buffer.printf("EOF");
5399 } else if (token == TOK_NUM) {
5400 buffer.printf("numeric constant");
5401 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005402 if (token < 32) {
5403 buffer.printf("'\\x%02x'", token);
5404 } else {
5405 buffer.printf("'%c'", token);
5406 }
Jack Palevich569f1352009-06-29 14:29:08 -07005407 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005408 if (quote) {
5409 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5410 buffer.printf("keyword \"%s\"", nameof(token));
5411 } else {
5412 buffer.printf("symbol \"%s\"", nameof(token));
5413 }
5414 } else {
5415 buffer.printf("%s", nameof(token));
5416 }
Jack Palevich569f1352009-06-29 14:29:08 -07005417 }
5418 }
5419
Jack Palevich9221bcc2009-08-26 16:15:07 -07005420 void printToken(tokenid_t token) {
5421 String buffer;
5422 decodeToken(buffer, token, true);
5423 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5424 }
5425
Jack Palevich40600de2009-07-01 15:32:35 -07005426 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005427 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005428 if (!result) {
5429 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005430 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005431 error("Expected symbol. Got %s", temp.getUnwrapped());
5432 }
5433 return result;
5434 }
5435
Jack Palevich86351982009-06-30 18:09:56 -07005436 tokenid_t acceptSymbol() {
5437 tokenid_t result = 0;
5438 if (tok >= TOK_SYMBOL) {
5439 result = tok;
5440 next();
Jack Palevich86351982009-06-30 18:09:56 -07005441 }
5442 return result;
5443 }
5444
Jack Palevichb7c81e92009-06-04 19:56:13 -07005445 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005446 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005447 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005448 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005449 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005450 break;
5451 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005452 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005453 if (!pDecl) {
5454 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005455 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005456 if (!pDecl->id) {
5457 skip(';');
5458 continue;
5459 }
5460
Jack Palevich61de31f2009-09-08 11:06:40 -07005461 if (checkUndeclaredStruct(pDecl)) {
5462 skip(';');
5463 continue;
5464 }
5465
Jack Palevich86351982009-06-30 18:09:56 -07005466 if (! isDefined(pDecl->id)) {
5467 addGlobalSymbol(pDecl);
5468 }
5469 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005470 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005471 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005472 }
Jack Palevich86351982009-06-30 18:09:56 -07005473 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005474 // it's a variable declaration
5475 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005476 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005477 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005478 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005479 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005480 }
Jack Palevich86351982009-06-30 18:09:56 -07005481 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005482 if (tok == TOK_NUM) {
5483 if (name) {
5484 * (int*) name->pAddress = tokc;
5485 }
5486 next();
5487 } else {
5488 error("Expected an integer constant");
5489 }
5490 }
Jack Palevich86351982009-06-30 18:09:56 -07005491 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005492 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005493 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005494 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005495 if (!pDecl) {
5496 break;
5497 }
5498 if (! isDefined(pDecl->id)) {
5499 addGlobalSymbol(pDecl);
5500 }
5501 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005502 }
5503 skip(';');
5504 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005505 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005506 if (accept(';')) {
5507 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005508 } else if (tok != '{') {
5509 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005510 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005511 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005512 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005513 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005514 /* patch forward references */
5515 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005516 /* put function address */
5517 name->pAddress = (void*) codeBuf.getPC();
5518 }
5519 // Calculate stack offsets for parameters
5520 mLocals.pushLevel();
5521 intptr_t a = 8;
5522 int argCount = 0;
5523 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5524 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005525 if (pArg->id) {
5526 addLocalSymbol(pArg);
5527 }
Jack Palevich95727a02009-07-06 12:07:15 -07005528 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005529 Type* pPassingType = passingType(pArg);
5530 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005531 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005532 if (pArg->id) {
5533 VI(pArg->id)->pAddress = (void*) a;
5534 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005535 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005536 argCount++;
5537 }
5538 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005539 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005540 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005541 block(0, true);
5542 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005543 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005544 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005545 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005546 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005547 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005548 }
5549 }
5550 }
5551
Jack Palevich9221bcc2009-08-26 16:15:07 -07005552 Type* passingType(Type* pType) {
5553 switch (pType->tag) {
5554 case TY_CHAR:
5555 case TY_SHORT:
5556 return mkpInt;
5557 default:
5558 return pType;
5559 }
5560 }
5561
Jack Palevich9cbd2262009-07-08 16:48:41 -07005562 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5563 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5564 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005565 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005566 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005567 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005568 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005569 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005570 char* result = (char*) base;
5571 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005572 return result;
5573 }
5574
Jack Palevich21a15a22009-05-11 14:49:29 -07005575 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005576 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005577 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005578 pGlobalBase = 0;
5579 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005580 if (pGen) {
5581 delete pGen;
5582 pGen = 0;
5583 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005584 if (file) {
5585 delete file;
5586 file = 0;
5587 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005588 }
5589
Jack Palevich8c246a92009-07-14 21:14:10 -07005590 // One-time initialization, when class is constructed.
5591 void init() {
5592 mpSymbolLookupFn = 0;
5593 mpSymbolLookupContext = 0;
5594 }
5595
Jack Palevich21a15a22009-05-11 14:49:29 -07005596 void clear() {
5597 tok = 0;
5598 tokc = 0;
5599 tokl = 0;
5600 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005601 rsym = 0;
5602 loc = 0;
5603 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005604 dptr = 0;
5605 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005606 file = 0;
5607 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005608 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005609 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005610 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005611 mLineNumber = 1;
5612 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005613 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005614 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005615
Jack Palevich22305132009-05-13 10:58:45 -07005616 void setArchitecture(const char* architecture) {
5617 delete pGen;
5618 pGen = 0;
5619
5620 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005621#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005622 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005623 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005624 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005625#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005626#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005627 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005628 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005629 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005630#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005631 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005632 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005633 }
5634 }
5635
5636 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005637#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005638 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07005639#elif defined(DEFAULT_X86_CODEGEN)
5640 pGen = new X86CodeGenerator();
5641#endif
5642 }
5643 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005644 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005645 } else {
5646 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005647 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005648 }
5649 }
5650
Jack Palevich77ae76e2009-05-10 19:59:24 -07005651public:
Jack Palevich22305132009-05-13 10:58:45 -07005652 struct args {
5653 args() {
5654 architecture = 0;
5655 }
5656 const char* architecture;
5657 };
5658
Jack Paleviche7b59062009-05-19 17:12:17 -07005659 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005660 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005661 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005662 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005663
Jack Paleviche7b59062009-05-19 17:12:17 -07005664 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005665 cleanup();
5666 }
5667
Jack Palevich8c246a92009-07-14 21:14:10 -07005668 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5669 mpSymbolLookupFn = pFn;
5670 mpSymbolLookupContext = pContext;
5671 }
5672
Jack Palevich1cdef202009-05-22 12:06:27 -07005673 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005674 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005675
Jack Palevich2ff5c222009-07-23 15:11:22 -07005676 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005677 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005678 cleanup();
5679 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005680 mTokenTable.setArena(&mGlobalArena);
5681 mGlobals.setArena(&mGlobalArena);
5682 mGlobals.setTokenTable(&mTokenTable);
5683 mLocals.setArena(&mLocalArena);
5684 mLocals.setTokenTable(&mTokenTable);
5685
5686 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005687 codeBuf.init(ALLOC_SIZE);
5688 setArchitecture(NULL);
5689 if (!pGen) {
5690 return -1;
5691 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005692#ifdef PROVIDE_TRACE_CODEGEN
5693 pGen = new TraceCodeGenerator(pGen);
5694#endif
5695 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005696 pGen->init(&codeBuf);
5697 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005698 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5699 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005700 inp();
5701 next();
5702 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005703 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005704 result = pGen->finishCompile();
5705 if (result == 0) {
5706 if (mErrorBuf.len()) {
5707 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005708 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005709 }
Jack Palevichce105a92009-07-16 14:30:33 -07005710 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005711 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005712 }
5713
Jack Palevich86351982009-06-30 18:09:56 -07005714 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005715 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005716 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005717 mkpChar = createType(TY_CHAR, NULL, NULL);
5718 mkpVoid = createType(TY_VOID, NULL, NULL);
5719 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5720 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5721 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5722 mkpIntPtr = createPtrType(mkpInt);
5723 mkpCharPtr = createPtrType(mkpChar);
5724 mkpFloatPtr = createPtrType(mkpFloat);
5725 mkpDoublePtr = createPtrType(mkpDouble);
5726 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005727 }
5728
Jack Palevicha6baa232009-06-12 11:25:59 -07005729 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005730 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005731 }
5732
Jack Palevich569f1352009-06-29 14:29:08 -07005733 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005734 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005735 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005736 }
5737
Jack Palevich569f1352009-06-29 14:29:08 -07005738 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005739 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005740 error("Undefined forward reference: %s",
5741 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005742 }
5743 return true;
5744 }
5745
Jack Palevich21a15a22009-05-11 14:49:29 -07005746 int dump(FILE* out) {
5747 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5748 return 0;
5749 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005750
Jack Palevicha6535612009-05-13 16:24:17 -07005751 int disassemble(FILE* out) {
5752 return pGen->disassemble(out);
5753 }
5754
Jack Palevich1cdef202009-05-22 12:06:27 -07005755 /* Look through the symbol table to find a symbol.
5756 * If found, return its value.
5757 */
5758 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005759 if (mCompileResult == 0) {
5760 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5761 VariableInfo* pVariableInfo = VI(tok);
5762 if (pVariableInfo) {
5763 return pVariableInfo->pAddress;
5764 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005765 }
5766 return NULL;
5767 }
5768
Jack Palevicheedf9d22009-06-04 16:23:40 -07005769 void getPragmas(ACCsizei* actualStringCount,
5770 ACCsizei maxStringCount, ACCchar** strings) {
5771 int stringCount = mPragmaStringCount;
5772 if (actualStringCount) {
5773 *actualStringCount = stringCount;
5774 }
5775 if (stringCount > maxStringCount) {
5776 stringCount = maxStringCount;
5777 }
5778 if (strings) {
5779 char* pPragmas = mPragmas.getUnwrapped();
5780 while (stringCount-- > 0) {
5781 *strings++ = pPragmas;
5782 pPragmas += strlen(pPragmas) + 1;
5783 }
5784 }
5785 }
5786
Jack Palevichac0e95e2009-05-29 13:53:44 -07005787 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005788 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005789 }
5790
Jack Palevich77ae76e2009-05-10 19:59:24 -07005791};
5792
Jack Paleviche7b59062009-05-19 17:12:17 -07005793const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005794 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5795
Jack Paleviche7b59062009-05-19 17:12:17 -07005796const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005797 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5798 5, 5, /* ==, != */
5799 9, 10, /* &&, || */
5800 6, 7, 8, /* & ^ | */
5801 2, 2 /* ~ ! */
5802 };
5803
Jack Palevich8b0624c2009-05-20 12:12:06 -07005804#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005805FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005806#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005807
Jack Palevich8b0624c2009-05-20 12:12:06 -07005808#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005809const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005810 0x1, // ++
5811 0xff, // --
5812 0xc1af0f, // *
5813 0xf9f79991, // /
5814 0xf9f79991, // % (With manual assist to swap results)
5815 0xc801, // +
5816 0xd8f7c829, // -
5817 0xe0d391, // <<
5818 0xf8d391, // >>
5819 0xe, // <=
5820 0xd, // >=
5821 0xc, // <
5822 0xf, // >
5823 0x4, // ==
5824 0x5, // !=
5825 0x0, // &&
5826 0x1, // ||
5827 0xc821, // &
5828 0xc831, // ^
5829 0xc809, // |
5830 0xd0f7, // ~
5831 0x4 // !
5832};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005833#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005834
Jack Palevich1cdef202009-05-22 12:06:27 -07005835struct ACCscript {
5836 ACCscript() {
5837 text = 0;
5838 textLength = 0;
5839 accError = ACC_NO_ERROR;
5840 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005841
Jack Palevich1cdef202009-05-22 12:06:27 -07005842 ~ACCscript() {
5843 delete text;
5844 }
Jack Palevich546b2242009-05-13 15:10:04 -07005845
Jack Palevich8c246a92009-07-14 21:14:10 -07005846 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5847 compiler.registerSymbolCallback(pFn, pContext);
5848 }
5849
Jack Palevich1cdef202009-05-22 12:06:27 -07005850 void setError(ACCenum error) {
5851 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5852 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005853 }
5854 }
5855
Jack Palevich1cdef202009-05-22 12:06:27 -07005856 ACCenum getError() {
5857 ACCenum result = accError;
5858 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005859 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005860 }
5861
Jack Palevich1cdef202009-05-22 12:06:27 -07005862 Compiler compiler;
5863 char* text;
5864 int textLength;
5865 ACCenum accError;
5866};
5867
5868
5869extern "C"
5870ACCscript* accCreateScript() {
5871 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005872}
Jack Palevich1cdef202009-05-22 12:06:27 -07005873
5874extern "C"
5875ACCenum accGetError( ACCscript* script ) {
5876 return script->getError();
5877}
5878
5879extern "C"
5880void accDeleteScript(ACCscript* script) {
5881 delete script;
5882}
5883
5884extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005885void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5886 ACCvoid* pContext) {
5887 script->registerSymbolCallback(pFn, pContext);
5888}
5889
5890extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005891void accScriptSource(ACCscript* script,
5892 ACCsizei count,
5893 const ACCchar ** string,
5894 const ACCint * length) {
5895 int totalLength = 0;
5896 for(int i = 0; i < count; i++) {
5897 int len = -1;
5898 const ACCchar* s = string[i];
5899 if (length) {
5900 len = length[i];
5901 }
5902 if (len < 0) {
5903 len = strlen(s);
5904 }
5905 totalLength += len;
5906 }
5907 delete script->text;
5908 char* text = new char[totalLength + 1];
5909 script->text = text;
5910 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005911 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005912 for(int i = 0; i < count; i++) {
5913 int len = -1;
5914 const ACCchar* s = string[i];
5915 if (length) {
5916 len = length[i];
5917 }
5918 if (len < 0) {
5919 len = strlen(s);
5920 }
Jack Palevich09555c72009-05-27 12:25:55 -07005921 memcpy(dest, s, len);
5922 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005923 }
5924 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07005925
5926#ifdef DEBUG_SAVE_INPUT_TO_FILE
5927 int counter;
5928 char path[PATH_MAX];
5929 for (counter = 0; counter < 4096; counter++) {
5930 sprintf(path, DEBUG_DUMP_PATTERN, counter);
5931 if(access(path, F_OK) != 0) {
5932 break;
5933 }
5934 }
5935 if (counter < 4096) {
5936 FILE* fd = fopen(path, "w");
5937 if (fd) {
5938 fwrite(text, totalLength, 1, fd);
5939 fclose(fd);
5940 }
5941 }
5942#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07005943}
5944
5945extern "C"
5946void accCompileScript(ACCscript* script) {
5947 int result = script->compiler.compile(script->text, script->textLength);
5948 if (result) {
5949 script->setError(ACC_INVALID_OPERATION);
5950 }
5951}
5952
5953extern "C"
5954void accGetScriptiv(ACCscript* script,
5955 ACCenum pname,
5956 ACCint * params) {
5957 switch (pname) {
5958 case ACC_INFO_LOG_LENGTH:
5959 *params = 0;
5960 break;
5961 }
5962}
5963
5964extern "C"
5965void accGetScriptInfoLog(ACCscript* script,
5966 ACCsizei maxLength,
5967 ACCsizei * length,
5968 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005969 char* message = script->compiler.getErrorMessage();
5970 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005971 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005972 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005973 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005974 if (infoLog && maxLength > 0) {
5975 int trimmedLength = maxLength < messageLength ?
5976 maxLength : messageLength;
5977 memcpy(infoLog, message, trimmedLength);
5978 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005979 }
5980}
5981
5982extern "C"
5983void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5984 ACCvoid ** address) {
5985 void* value = script->compiler.lookup(name);
5986 if (value) {
5987 *address = value;
5988 } else {
5989 script->setError(ACC_INVALID_VALUE);
5990 }
5991}
5992
Jack Palevicheedf9d22009-06-04 16:23:40 -07005993extern "C"
5994void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5995 ACCsizei maxStringCount, ACCchar** strings){
5996 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5997}
5998
-b master422972c2009-06-17 19:13:52 -07005999extern "C"
6000void accDisassemble(ACCscript* script) {
6001 script->compiler.disassemble(stderr);
6002}
6003
Jack Palevicheedf9d22009-06-04 16:23:40 -07006004
Jack Palevich1cdef202009-05-22 12:06:27 -07006005} // namespace acc
6006