blob: 8f33b0bdd5b98a586c38ff549376e04d7c59d953 [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 Palevich30321cb2009-08-20 15:34:23 -070042#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
43#define ARM_USE_VFP
44#endif
45
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050
-b master422972c2009-06-17 19:13:52 -070051#define LOG_STACK(...) do {} while(0)
52// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
53
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichd30a2ce2009-09-09 19:08:54 -070056// Uncomment to disable ARM peephole optimizations
57// #define DISABLE_ARM_PEEPHOLE
58
Jack Palevich61de31f2009-09-08 11:06:40 -070059// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
60// #define DEBUG_SAVE_INPUT_TO_FILE
61
Jack Palevich9116bc42009-09-08 11:46:42 -070062#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070063#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070064#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070065#else
66#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
67#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070068#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070069
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) {
Jack Palevichba48fe22009-11-27 11:51:36 +080085 clear();
Jack Palevich8df46192009-07-07 14:48:51 -070086 free(mpBase);
87 }
88 }
89
90 inline E& operator[](size_t i) {
91 return mpBase[i];
92 }
93
94 inline E& front() {
95 return mpBase[0];
96 }
97
98 inline E& back() {
99 return mpBase[mUsed - 1];
100 }
101
102 void pop_back() {
103 mUsed -= 1;
104 mpBase[mUsed].~E();
105 }
106
107 void push_back(const E& item) {
108 * ensure(1) = item;
109 }
110
Jack Palevichba48fe22009-11-27 11:51:36 +0800111 inline size_t size() {
Jack Palevich8df46192009-07-07 14:48:51 -0700112 return mUsed;
113 }
114
Jack Palevichba48fe22009-11-27 11:51:36 +0800115 void clear() {
116 if (mpBase) {
117 size_t used = mUsed;
118 for(size_t i = 0; i < used; i++) {
119 mpBase[i].~E();
120 }
121 }
122 mUsed = 0;
123 }
124
Jack Palevich8df46192009-07-07 14:48:51 -0700125private:
126 E* ensure(int n) {
127 size_t newUsed = mUsed + n;
128 if (newUsed > mSize) {
129 size_t newSize = mSize * 2 + 10;
130 if (newSize < newUsed) {
131 newSize = newUsed;
132 }
133 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
134 mSize = newSize;
135 }
136 E* result = mpBase + mUsed;
137 mUsed = newUsed;
138 return result;
139 }
140
141 E* mpBase;
142 size_t mUsed;
143 size_t mSize;
144};
145
Jack Palevichac0e95e2009-05-29 13:53:44 -0700146class ErrorSink {
147public:
148 void error(const char *fmt, ...) {
149 va_list ap;
150 va_start(ap, fmt);
151 verror(fmt, ap);
152 va_end(ap);
153 }
154
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700155 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700156 virtual void verror(const char* fmt, va_list ap) = 0;
157};
158
159class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700160 typedef int tokenid_t;
161 enum TypeTag {
Jack Palevichee1f8292009-10-28 16:10:17 -0700162 TY_UNKNOWN = -1,
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700163 TY_INT, // 0
164 TY_CHAR, // 1
165 TY_SHORT, // 2
166 TY_VOID, // 3
167 TY_FLOAT, // 4
168 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700169 TY_POINTER, // 6
170 TY_ARRAY, // 7
171 TY_STRUCT, // 8
172 TY_FUNC, // 9
173 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700174 };
175
Jack Palevichee1f8292009-10-28 16:10:17 -0700176 enum StorageClass {
177 SC_DEFAULT, // 0
178 SC_AUTO, // 1
179 SC_REGISTER, // 2
180 SC_STATIC, // 3
181 SC_EXTERN, // 4
182 SC_TYPEDEF // 5
183 };
184
Jack Palevich8df46192009-07-07 14:48:51 -0700185 struct Type {
186 TypeTag tag;
Jack Palevichee1f8292009-10-28 16:10:17 -0700187 StorageClass storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700188 tokenid_t id; // For function arguments, global vars, local vars, struct elements
189 tokenid_t structTag; // For structs the name of the struct
190 int length; // length of array, offset of struct element. -1 means struct is forward defined
191 int alignment; // for structs only
192 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700193 Type* pTail;
194 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700195
Jack Palevichba929a42009-07-17 10:20:32 -0700196 enum ExpressionType {
197 ET_RVALUE,
198 ET_LVALUE
199 };
200
201 struct ExpressionValue {
202 ExpressionValue() {
203 et = ET_RVALUE;
204 pType = NULL;
205 }
206 ExpressionType et;
207 Type* pType;
208 };
209
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700210 class ICodeBuf {
211 public:
212 virtual ~ICodeBuf() {}
213 virtual void init(int size) = 0;
214 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
215 virtual void o4(int n) = 0;
216 virtual void ob(int n) = 0;
217 virtual void* getBase() = 0;
218 virtual intptr_t getSize() = 0;
219 virtual intptr_t getPC() = 0;
220 // Call this before trying to modify code in the buffer.
221 virtual void flush() = 0;
222 };
223
224 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700225 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700226 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700227 ErrorSink* mErrorSink;
228 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700229 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 void release() {
232 if (pProgramBase != 0) {
233 free(pProgramBase);
234 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700235 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700236 }
237
Jack Palevich0a280a02009-06-11 10:53:51 -0700238 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700239 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700240 bool overflow = newSize > mSize;
241 if (overflow && !mOverflowed) {
242 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700243 if (mErrorSink) {
244 mErrorSink->error("Code too large: %d bytes", newSize);
245 }
246 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700247 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700248 }
249
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 public:
251 CodeBuf() {
252 pProgramBase = 0;
253 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700254 mErrorSink = 0;
255 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700256 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700257 }
258
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700259 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 release();
261 }
262
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700263 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700264 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700265 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700266 pProgramBase = (char*) calloc(1, size);
267 ind = pProgramBase;
268 }
269
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700270 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700271 mErrorSink = pErrorSink;
272 }
273
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700274 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700275 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700276 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700277 }
Jack Palevich546b2242009-05-13 15:10:04 -0700278 * (int*) ind = n;
279 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700280 }
281
Jack Palevich21a15a22009-05-11 14:49:29 -0700282 /*
283 * Output a byte. Handles all values, 0..ff.
284 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700285 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700286 if(check(1)) {
287 return;
288 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700289 *ind++ = n;
290 }
291
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700292 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700293 return (void*) pProgramBase;
294 }
295
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700296 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700297 return ind - pProgramBase;
298 }
299
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700300 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700301 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700302 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700303
304 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700305 };
306
Jack Palevich1cdef202009-05-22 12:06:27 -0700307 /**
308 * A code generator creates an in-memory program, generating the code on
309 * the fly. There is one code generator implementation for each supported
310 * architecture.
311 *
312 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700313 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700314 * FP - a frame pointer for accessing function arguments and local
315 * variables.
316 * SP - a stack pointer for storing intermediate results while evaluating
317 * expressions. The stack pointer grows downwards.
318 *
319 * The function calling convention is that all arguments are placed on the
320 * stack such that the first argument has the lowest address.
321 * After the call, the result is in R0. The caller is responsible for
322 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700323 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 * FP and SP registers are saved.
325 */
326
Jack Palevich21a15a22009-05-11 14:49:29 -0700327 class CodeGenerator {
328 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700329 CodeGenerator() {
330 mErrorSink = 0;
331 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700332 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700333 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700334 virtual ~CodeGenerator() {}
335
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700336 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700337 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700338 pCodeBuf->setErrorSink(mErrorSink);
339 }
340
Jack Palevichb67b18f2009-06-11 21:12:23 -0700341 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700342 mErrorSink = pErrorSink;
343 if (pCodeBuf) {
344 pCodeBuf->setErrorSink(mErrorSink);
345 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700346 }
347
Jack Palevich58c30ee2009-07-17 16:35:23 -0700348 /* Give the code generator some utility types so it can
349 * use its own types as needed for the results of some
350 * operations like gcmp.
351 */
352
Jack Palevicha8f427f2009-07-13 18:40:08 -0700353 void setTypes(Type* pInt) {
354 mkpInt = pInt;
355 }
356
Jack Palevich1cdef202009-05-22 12:06:27 -0700357 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700358 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700359 * Save the old value of the FP.
360 * Set the new value of the FP.
361 * Convert from the native platform calling convention to
362 * our stack-based calling convention. This may require
363 * pushing arguments from registers to the stack.
364 * Allocate "N" bytes of stack space. N isn't known yet, so
365 * just emit the instructions for adjusting the stack, and return
366 * the address to patch up. The patching will be done in
367 * functionExit().
368 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700369 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700370 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700371
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 /* Emit a function epilog.
373 * Restore the old SP and FP register values.
374 * Return to the calling function.
375 * argCount - the number of arguments to the function.
376 * localVariableAddress - returned from functionEntry()
377 * localVariableSize - the size in bytes of the local variables.
378 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700379 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700380 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700381
Jack Palevich1cdef202009-05-22 12:06:27 -0700382 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700383 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700384
Jack Palevich1a539db2009-07-08 13:04:41 -0700385 /* Load floating point value from global address. */
386 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700387
Jack Palevich9221bcc2009-08-26 16:15:07 -0700388 /* Add the struct offset in bytes to R0, change the type to pType */
389 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
390
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 /* Jump to a target, and return the address of the word that
392 * holds the target data, in case it needs to be fixed up later.
393 */
Jack Palevich22305132009-05-13 10:58:45 -0700394 virtual int gjmp(int t) = 0;
395
Jack Palevich1cdef202009-05-22 12:06:27 -0700396 /* Test R0 and jump to a target if the test succeeds.
397 * l = 0: je, l == 1: jne
398 * Return the address of the word that holds the targed data, in
399 * case it needs to be fixed up later.
400 */
Jack Palevich22305132009-05-13 10:58:45 -0700401 virtual int gtst(bool l, int t) = 0;
402
Jack Palevich9eed7a22009-07-06 17:24:34 -0700403 /* Compare TOS against R0, and store the boolean result in R0.
404 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700405 * op specifies the comparison.
406 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700407 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700408
Jack Palevich9eed7a22009-07-06 17:24:34 -0700409 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700411 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700412 */
Jack Palevich546b2242009-05-13 15:10:04 -0700413 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700414
Jack Palevich9eed7a22009-07-06 17:24:34 -0700415 /* Compare 0 against R0, and store the boolean result in R0.
416 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700417 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700418 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700419
420 /* Perform the arithmetic op specified by op. 0 is the
421 * left argument, R0 is the right argument.
422 */
423 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700424
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700425 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700426 */
427 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700428
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700429 /* Turn R0, TOS into R0 TOS R0 */
430
431 virtual void over() = 0;
432
433 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700434 */
435 virtual void popR0() = 0;
436
Jack Palevich9eed7a22009-07-06 17:24:34 -0700437 /* Store R0 to the address stored in TOS.
438 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700440 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700441
Jack Palevich1cdef202009-05-22 12:06:27 -0700442 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700443 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700444 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700445
Jack Palevich1cdef202009-05-22 12:06:27 -0700446 /* Load the absolute address of a variable to R0.
447 * If ea <= LOCAL, then this is a local variable, or an
448 * argument, addressed relative to FP.
449 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700450 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700451 * et is ET_RVALUE for things like string constants, ET_LVALUE for
452 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700453 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700454 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700455
Jack Palevich9f51a262009-07-29 16:22:26 -0700456 /* Load the pc-relative address of a forward-referenced variable to R0.
457 * Return the address of the 4-byte constant so that it can be filled
458 * in later.
459 */
460 virtual int leaForward(int ea, Type* pPointerType) = 0;
461
Jack Palevich8df46192009-07-07 14:48:51 -0700462 /**
463 * Convert R0 to the given type.
464 */
Jack Palevichb6154502009-08-04 14:56:09 -0700465
466 void convertR0(Type* pType) {
467 convertR0Imp(pType, false);
468 }
469
470 void castR0(Type* pType) {
471 convertR0Imp(pType, true);
472 }
473
474 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700475
Jack Palevich1cdef202009-05-22 12:06:27 -0700476 /* Emit code to adjust the stack for a function call. Return the
477 * label for the address of the instruction that adjusts the
478 * stack size. This will be passed as argument "a" to
479 * endFunctionCallArguments.
480 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700481 virtual int beginFunctionCallArguments() = 0;
482
Jack Palevich1cdef202009-05-22 12:06:27 -0700483 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700484 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700485 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700486 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700487
Jack Palevich1cdef202009-05-22 12:06:27 -0700488 /* Patch the function call preamble.
489 * a is the address returned from beginFunctionCallArguments
490 * l is the number of bytes the arguments took on the stack.
491 * Typically you would also emit code to convert the argument
492 * list into whatever the native function calling convention is.
493 * On ARM for example you would pop the first 5 arguments into
494 * R0..R4
495 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700496 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700497
Jack Palevich1cdef202009-05-22 12:06:27 -0700498 /* Emit a call to an unknown function. The argument "symbol" needs to
499 * be stored in the location where the address should go. It forms
500 * a chain. The address will be patched later.
501 * Return the address of the word that has to be patched.
502 */
Jack Palevich8df46192009-07-07 14:48:51 -0700503 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700504
Jack Palevich1cdef202009-05-22 12:06:27 -0700505 /* Call a function pointer. L is the number of bytes the arguments
506 * take on the stack. The address of the function is stored at
507 * location SP + l.
508 */
Jack Palevich8df46192009-07-07 14:48:51 -0700509 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700510
Jack Palevich1cdef202009-05-22 12:06:27 -0700511 /* Adjust SP after returning from a function call. l is the
512 * number of bytes of arguments stored on the stack. isIndirect
513 * is true if this was an indirect call. (In which case the
514 * address of the function is stored at location SP + l.)
515 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700516 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700517
Jack Palevich1cdef202009-05-22 12:06:27 -0700518 /* Generate a symbol at the current PC. t is the head of a
519 * linked list of addresses to patch.
520 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700521 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700522
Jack Palevich9f51a262009-07-29 16:22:26 -0700523 /* Resolve a forward reference function at the current PC.
524 * t is the head of a
525 * linked list of addresses to patch.
526 * (Like gsym, but using absolute address, not PC relative address.)
527 */
528 virtual void resolveForward(int t) = 0;
529
Jack Palevich1cdef202009-05-22 12:06:27 -0700530 /*
531 * Do any cleanup work required at the end of a compile.
532 * For example, an instruction cache might need to be
533 * invalidated.
534 * Return non-zero if there is an error.
535 */
536 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700537
Jack Palevicha6535612009-05-13 16:24:17 -0700538 /**
539 * Adjust relative branches by this amount.
540 */
541 virtual int jumpOffset() = 0;
542
Jack Palevich9eed7a22009-07-06 17:24:34 -0700543 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700544 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700545 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700546 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700547
548 /**
549 * Array element alignment (in bytes) for this type of data.
550 */
551 virtual size_t sizeOf(Type* type) = 0;
552
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700553 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700554 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700555 }
556
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700557 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700558 return mExpressionStack.back().et;
559 }
560
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700561 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700562 mExpressionStack.back().et = et;
563 }
564
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700565 virtual size_t getExpressionStackDepth() {
566 return mExpressionStack.size();
567 }
568
Jack Palevichb5e33312009-07-30 19:06:34 -0700569 virtual void forceR0RVal() {
570 if (getR0ExpressionType() == ET_LVALUE) {
571 loadR0FromR0();
572 }
573 }
574
Jack Palevich21a15a22009-05-11 14:49:29 -0700575 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700576 /*
577 * Output a byte. Handles all values, 0..ff.
578 */
579 void ob(int n) {
580 pCodeBuf->ob(n);
581 }
582
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700583 void o4(int data) {
584 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700585 }
586
Jack Palevich8b0624c2009-05-20 12:12:06 -0700587 intptr_t getBase() {
588 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700589 }
590
Jack Palevich8b0624c2009-05-20 12:12:06 -0700591 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700592 return pCodeBuf->getPC();
593 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700594
595 intptr_t getSize() {
596 return pCodeBuf->getSize();
597 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700598
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700599 void flush() {
600 pCodeBuf->flush();
601 }
602
Jack Palevichac0e95e2009-05-29 13:53:44 -0700603 void error(const char* fmt,...) {
604 va_list ap;
605 va_start(ap, fmt);
606 mErrorSink->verror(fmt, ap);
607 va_end(ap);
608 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700609
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700610 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700611 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700612 error("code generator assertion failed at line %s:%d.", __FILE__, line);
613 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700614 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700615 }
616 }
Jack Palevich8df46192009-07-07 14:48:51 -0700617
618 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700619 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700620 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700621 mExpressionStack.back().et = ET_RVALUE;
622 }
623
624 void setR0Type(Type* pType, ExpressionType et) {
625 assert(pType != NULL);
626 mExpressionStack.back().pType = pType;
627 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700628 }
629
Jack Palevich8df46192009-07-07 14:48:51 -0700630 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700631 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700632 }
633
634 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700635 if (mExpressionStack.size()) {
636 mExpressionStack.push_back(mExpressionStack.back());
637 } else {
638 mExpressionStack.push_back(ExpressionValue());
639 }
640
Jack Palevich8df46192009-07-07 14:48:51 -0700641 }
642
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700643 void overType() {
644 size_t size = mExpressionStack.size();
645 if (size >= 2) {
646 mExpressionStack.push_back(mExpressionStack.back());
647 mExpressionStack[size-1] = mExpressionStack[size-2];
648 mExpressionStack[size-2] = mExpressionStack[size];
649 }
650 }
651
Jack Palevich8df46192009-07-07 14:48:51 -0700652 void popType() {
653 mExpressionStack.pop_back();
654 }
655
656 bool bitsSame(Type* pA, Type* pB) {
657 return collapseType(pA->tag) == collapseType(pB->tag);
658 }
659
660 TypeTag collapseType(TypeTag tag) {
661 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700662 TY_INT,
663 TY_INT,
664 TY_INT,
665 TY_VOID,
666 TY_FLOAT,
667 TY_DOUBLE,
668 TY_INT,
669 TY_INT,
670 TY_VOID,
671 TY_VOID,
672 TY_VOID
673 };
Jack Palevich8df46192009-07-07 14:48:51 -0700674 return collapsedTag[tag];
675 }
676
Jack Palevich1a539db2009-07-08 13:04:41 -0700677 TypeTag collapseTypeR0() {
678 return collapseType(getR0Type()->tag);
679 }
680
Jack Palevichb6154502009-08-04 14:56:09 -0700681 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700682 return isFloatTag(pType->tag);
683 }
684
Jack Palevichb6154502009-08-04 14:56:09 -0700685 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700686 return tag == TY_FLOAT || tag == TY_DOUBLE;
687 }
688
Jack Palevichb6154502009-08-04 14:56:09 -0700689 static bool isPointerType(Type* pType) {
690 return isPointerTag(pType->tag);
691 }
692
693 static bool isPointerTag(TypeTag tag) {
694 return tag == TY_POINTER || tag == TY_ARRAY;
695 }
696
697 Type* getPointerArithmeticResultType(Type* a, Type* b) {
698 TypeTag aTag = a->tag;
699 TypeTag bTag = b->tag;
700 if (aTag == TY_POINTER) {
701 return a;
702 }
703 if (bTag == TY_POINTER) {
704 return b;
705 }
706 if (aTag == TY_ARRAY) {
707 return a->pTail;
708 }
709 if (bTag == TY_ARRAY) {
710 return b->pTail;
711 }
712 return NULL;
713 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700714 Type* mkpInt;
715
Jack Palevich21a15a22009-05-11 14:49:29 -0700716 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700717 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700718 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700719 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700720 };
721
Jack Paleviche7b59062009-05-19 17:12:17 -0700722#ifdef PROVIDE_ARM_CODEGEN
723
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700724 static size_t rotateRight(size_t n, size_t rotate) {
725 return (n >> rotate) | (n << (32 - rotate));
726 }
727
728 static size_t rotateLeft(size_t n, size_t rotate) {
729 return (n << rotate) | (n >> (32 - rotate));
730 }
731
732 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
733 for(size_t i = 0; i < 16; i++) {
734 size_t rotate = i * 2;
735 size_t mask = rotateRight(0xff, rotate);
736 if ((immediate | mask) == mask) {
737 size_t bits8 = rotateLeft(immediate, rotate);
738 // assert(bits8 <= 0xff);
739 *pResult = (i << 8) | bits8;
740 return true;
741 }
742 }
743 return false;
744 }
745
746 static size_t decode12BitImmediate(size_t immediate) {
747 size_t data = immediate & 0xff;
748 size_t rotate = 2 * ((immediate >> 8) & 0xf);
749 return rotateRight(data, rotate);
750 }
751
Jack Palevich53f06582009-09-10 14:01:58 -0700752 static bool isPowerOfTwo(size_t n) {
753 return (n != 0) & ((n & (n-1)) == 0);
754 }
755
756 static size_t log2(size_t n) {
757 int result = 0;
758 while (n >>= 1) {
759 result++;
760 }
761 return result;
762 }
763
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700764 class ARMCodeBuf : public ICodeBuf {
765 ICodeBuf* mpBase;
766 ErrorSink* mErrorSink;
767
768 class CircularQueue {
769 static const int SIZE = 16; // Must be power of 2
770 static const int MASK = SIZE-1;
771 unsigned int mBuf[SIZE];
772 int mHead;
773 int mCount;
774
775 public:
776 CircularQueue() {
777 mHead = 0;
778 mCount = 0;
779 }
780
781 void pushBack(unsigned int data) {
782 mBuf[(mHead + mCount) & MASK] = data;
783 mCount += 1;
784 }
785
786 unsigned int popFront() {
787 unsigned int result = mBuf[mHead];
788 mHead = (mHead + 1) & MASK;
789 mCount -= 1;
790 return result;
791 }
792
793 void popBack(int n) {
794 mCount -= n;
795 }
796
797 inline int count() {
798 return mCount;
799 }
800
801 bool empty() {
802 return mCount == 0;
803 }
804
805 bool full() {
806 return mCount == SIZE;
807 }
808
809 // The valid indexes are 1 - count() to 0
810 unsigned int operator[](int i) {
811 return mBuf[(mHead + mCount + i) & MASK];
812 }
813 };
814
815 CircularQueue mQ;
816
817 void error(const char* fmt,...) {
818 va_list ap;
819 va_start(ap, fmt);
820 mErrorSink->verror(fmt, ap);
821 va_end(ap);
822 }
823
824 void flush() {
825 while (!mQ.empty()) {
826 mpBase->o4(mQ.popFront());
827 }
828 mpBase->flush();
829 }
830
831 public:
832 ARMCodeBuf(ICodeBuf* pBase) {
833 mpBase = pBase;
834 }
835
836 virtual ~ARMCodeBuf() {
837 delete mpBase;
838 }
839
840 void init(int size) {
841 mpBase->init(size);
842 }
843
844 void setErrorSink(ErrorSink* pErrorSink) {
845 mErrorSink = pErrorSink;
846 mpBase->setErrorSink(pErrorSink);
847 }
848
849 void o4(int n) {
850 if (mQ.full()) {
851 mpBase->o4(mQ.popFront());
852 }
853 mQ.pushBack(n);
854
855#ifndef DISABLE_ARM_PEEPHOLE
856 // Peephole check
857 bool didPeep;
858 do {
Jack Palevich53f06582009-09-10 14:01:58 -0700859 static const unsigned int opMask = 0x01e00000;
860 static const unsigned int immediateMask = 0x00000fff;
861 static const unsigned int BMask = 0x00400000;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700862 didPeep = false;
863 if (mQ.count() >= 4) {
864
865 // Operand by a small constant
866 // push;mov #imm;pop;op ==> op #imm
867
Jack Palevich1c60e462009-09-18 15:03:03 -0700868 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
869 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
870 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
871 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700872 unsigned int movConst = mQ[-3];
873 unsigned int op = mQ[-1];
874 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
875 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
876 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
877 mQ.popBack(4);
878 mQ.pushBack(combined);
879 didPeep = true;
880 } else {
881 mQ.popBack(4);
882 didPeep = true;
883 }
884 }
885 }
886
887 // Load local variable
Jack Palevich53f06582009-09-10 14:01:58 -0700888 // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm]
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700889 if (mQ.count() >= 2) {
Jack Palevich53f06582009-09-10 14:01:58 -0700890 if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
891 const unsigned int encodedImmediate = mQ[-2] & immediateMask;
892 const unsigned int ld = mQ[-1];
893 if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
894 unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
895 mQ.popBack(2);
896 mQ.pushBack(combined);
897 didPeep = true;
Jack Palevich1c60e462009-09-18 15:03:03 -0700898 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
Jack Palevich53f06582009-09-10 14:01:58 -0700899 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
900 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700901 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
Jack Palevich53f06582009-09-10 14:01:58 -0700902 mQ.popBack(2);
903 mQ.pushBack(combined);
904 didPeep = true;
905 }
906 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700907 }
908 }
909
910 // Constant array lookup
911
912 if (mQ.count() >= 6 &&
913 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
914 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
915 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
916 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
917 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
918 mQ[-1] == 0xe0810000) { // add r0, r1, r0
919 unsigned int mov1 = mQ[-5];
920 unsigned int mov2 = mQ[-3];
921 unsigned int const1 = decode12BitImmediate(mov1);
922 unsigned int const2 = decode12BitImmediate(mov2);
923 unsigned int comboConst = const1 * const2;
924 size_t immediate = 0;
925 if (encode12BitImmediate(comboConst, &immediate)) {
926 mQ.popBack(6);
927 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
928 if (comboConst) {
929 mQ.pushBack(add);
930 }
931 didPeep = true;
932 }
933 }
934
Jack Palevich53f06582009-09-10 14:01:58 -0700935 // Pointer arithmetic with a stride that is a power of two
936
937 if (mQ.count() >= 3 &&
Jack Palevich1c60e462009-09-18 15:03:03 -0700938 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
939 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
Jack Palevich53f06582009-09-10 14:01:58 -0700940 mQ[-1] == 0xe0810000) { // add r0, r1, r0
941 int stride = decode12BitImmediate(mQ[-3]);
942 if (isPowerOfTwo(stride)) {
943 mQ.popBack(3);
944 unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
945 mQ.pushBack(add);
946 didPeep = true;
947 }
948 }
949
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700950 } while (didPeep);
951#endif
952 }
953
954 void ob(int n) {
955 error("ob() not supported.");
956 }
957
958 void* getBase() {
959 flush();
960 return mpBase->getBase();
961 }
962
963 intptr_t getSize() {
964 flush();
965 return mpBase->getSize();
966 }
967
968 intptr_t getPC() {
969 flush();
970 return mpBase->getPC();
971 }
972 };
973
Jack Palevich22305132009-05-13 10:58:45 -0700974 class ARMCodeGenerator : public CodeGenerator {
975 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700976 ARMCodeGenerator() {
977#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700978 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700979#else
Jack Palevichd5315572009-09-09 13:19:34 -0700980 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700981#endif
982 }
-b master422972c2009-06-17 19:13:52 -0700983
Jack Palevich22305132009-05-13 10:58:45 -0700984 virtual ~ARMCodeGenerator() {}
985
986 /* returns address to patch with local variable size
987 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700988 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700989 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700990 // sp -> arg4 arg5 ...
991 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700992 int regArgCount = calcRegArgCount(pDecl);
993 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700994 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700995 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700996 }
997 // sp -> arg0 arg1 ...
998 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700999 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -07001000 // sp, fp -> oldfp, retadr, arg0 arg1 ....
1001 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -07001002 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001003 int pc = getPC();
1004 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -07001005 // We don't know how many local variables we are going to use,
1006 // but we will round the allocation up to a multiple of
1007 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001008 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001009 }
1010
Jack Palevichb7718b92009-07-09 22:00:24 -07001011 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -07001012 // Round local variable size up to a multiple of stack alignment
1013 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
1014 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -07001015 // Patch local variable allocation code:
1016 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -07001017 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -07001018 }
Jack Palevich69796b62009-05-14 15:42:26 -07001019 *(char*) (localVariableAddress) = localVariableSize;
1020
Jack Palevich30321cb2009-08-20 15:34:23 -07001021#ifdef ARM_USE_VFP
1022 {
Jack Palevichc0f25332009-08-25 12:23:43 -07001023 Type* pReturnType = pDecl->pHead;
1024 switch(pReturnType->tag) {
1025 case TY_FLOAT:
1026 o4(0xEE170A90); // fmrs r0, s15
1027 break;
1028 case TY_DOUBLE:
1029 o4(0xEC510B17); // fmrrd r0, r1, d7
1030 break;
1031 default:
1032 break;
1033 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001034 }
1035#endif
1036
Jack Palevich69796b62009-05-14 15:42:26 -07001037 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
1038 o4(0xE1A0E00B); // mov lr, fp
1039 o4(0xE59BB000); // ldr fp, [fp]
1040 o4(0xE28ED004); // add sp, lr, #4
1041 // sp -> retadr, arg0, ...
1042 o4(0xE8BD4000); // ldmfd sp!, {lr}
1043 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -07001044
1045 // We store the PC into the lr so we can adjust the sp before
1046 // returning. We need to pull off the registers we pushed
1047 // earlier. We don't need to actually store them anywhere,
1048 // just adjust the stack.
1049 int regArgCount = calcRegArgCount(pDecl);
1050 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -07001051 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
1052 }
1053 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -07001054 }
1055
1056 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001057 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001058 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001059 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001060 }
1061
Jack Palevich1a539db2009-07-08 13:04:41 -07001062 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001063 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001064 // Global, absolute address
1065 o4(0xE59F0000); // ldr r0, .L1
1066 o4(0xEA000000); // b .L99
1067 o4(address); // .L1: .word ea
1068 // .L99:
1069
1070 switch (pType->tag) {
1071 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001072#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001073 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001074#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001075 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001076#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001077 break;
1078 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001079#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001080 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001081#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001082 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001083#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001084 break;
1085 default:
1086 assert(false);
1087 break;
1088 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001089 }
1090
Jack Palevich9221bcc2009-08-26 16:15:07 -07001091
1092 virtual void addStructOffsetR0(int offset, Type* pType) {
1093 if (offset) {
1094 size_t immediate = 0;
1095 if (encode12BitImmediate(offset, &immediate)) {
1096 o4(0xE2800000 | immediate); // add r0, r0, #offset
1097 } else {
1098 error("structure offset out of range: %d", offset);
1099 }
1100 }
1101 setR0Type(pType, ET_LVALUE);
1102 }
1103
Jack Palevich22305132009-05-13 10:58:45 -07001104 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001105 int pc = getPC();
1106 o4(0xEA000000 | encodeAddress(t)); // b .L33
1107 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001108 }
1109
1110 /* l = 0: je, l == 1: jne */
1111 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001112 Type* pR0Type = getR0Type();
1113 TypeTag tagR0 = pR0Type->tag;
1114 switch(tagR0) {
1115 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001116#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001117 o4(0xEEF57A40); // fcmpzs s15
1118 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001119#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001120 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001121 o4(0xE3500000); // cmp r0,#0
1122#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001123 break;
1124 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001125#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001126 o4(0xEEB57B40); // fcmpzd d7
1127 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001128#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001129 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001130 o4(0xE3500000); // cmp r0,#0
1131#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001132 break;
1133 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001134 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001135 break;
1136 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001137 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001138 int pc = getPC();
1139 o4(branch | encodeAddress(t));
1140 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001141 }
1142
Jack Palevich58c30ee2009-07-17 16:35:23 -07001143 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001144 Type* pR0Type = getR0Type();
1145 Type* pTOSType = getTOSType();
1146 TypeTag tagR0 = collapseType(pR0Type->tag);
1147 TypeTag tagTOS = collapseType(pTOSType->tag);
1148 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001149 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001150 o4(0xE1510000); // cmp r1, r1
1151 switch(op) {
1152 case OP_EQUALS:
1153 o4(0x03A00001); // moveq r0,#1
1154 o4(0x13A00000); // movne r0,#0
1155 break;
1156 case OP_NOT_EQUALS:
1157 o4(0x03A00000); // moveq r0,#0
1158 o4(0x13A00001); // movne r0,#1
1159 break;
1160 case OP_LESS_EQUAL:
1161 o4(0xD3A00001); // movle r0,#1
1162 o4(0xC3A00000); // movgt r0,#0
1163 break;
1164 case OP_GREATER:
1165 o4(0xD3A00000); // movle r0,#0
1166 o4(0xC3A00001); // movgt r0,#1
1167 break;
1168 case OP_GREATER_EQUAL:
1169 o4(0xA3A00001); // movge r0,#1
1170 o4(0xB3A00000); // movlt r0,#0
1171 break;
1172 case OP_LESS:
1173 o4(0xA3A00000); // movge r0,#0
1174 o4(0xB3A00001); // movlt r0,#1
1175 break;
1176 default:
1177 error("Unknown comparison op %d", op);
1178 break;
1179 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001180 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1181 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001182#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001183 o4(0xEEB46BC7); // fcmped d6, d7
1184 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001185 switch(op) {
1186 case OP_EQUALS:
1187 o4(0x03A00001); // moveq r0,#1
1188 o4(0x13A00000); // movne r0,#0
1189 break;
1190 case OP_NOT_EQUALS:
1191 o4(0x03A00000); // moveq r0,#0
1192 o4(0x13A00001); // movne r0,#1
1193 break;
1194 case OP_LESS_EQUAL:
1195 o4(0xD3A00001); // movle r0,#1
1196 o4(0xC3A00000); // movgt r0,#0
1197 break;
1198 case OP_GREATER:
1199 o4(0xD3A00000); // movle r0,#0
1200 o4(0xC3A00001); // movgt r0,#1
1201 break;
1202 case OP_GREATER_EQUAL:
1203 o4(0xA3A00001); // movge r0,#1
1204 o4(0xB3A00000); // movlt r0,#0
1205 break;
1206 case OP_LESS:
1207 o4(0xA3A00000); // movge r0,#0
1208 o4(0xB3A00001); // movlt r0,#1
1209 break;
1210 default:
1211 error("Unknown comparison op %d", op);
1212 break;
1213 }
1214#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001215 switch(op) {
1216 case OP_EQUALS:
1217 callRuntime((void*) runtime_cmp_eq_dd);
1218 break;
1219 case OP_NOT_EQUALS:
1220 callRuntime((void*) runtime_cmp_ne_dd);
1221 break;
1222 case OP_LESS_EQUAL:
1223 callRuntime((void*) runtime_cmp_le_dd);
1224 break;
1225 case OP_GREATER:
1226 callRuntime((void*) runtime_cmp_gt_dd);
1227 break;
1228 case OP_GREATER_EQUAL:
1229 callRuntime((void*) runtime_cmp_ge_dd);
1230 break;
1231 case OP_LESS:
1232 callRuntime((void*) runtime_cmp_lt_dd);
1233 break;
1234 default:
1235 error("Unknown comparison op %d", op);
1236 break;
1237 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001238#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001239 } else {
1240 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001241#ifdef ARM_USE_VFP
1242 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001243 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001244 switch(op) {
1245 case OP_EQUALS:
1246 o4(0x03A00001); // moveq r0,#1
1247 o4(0x13A00000); // movne r0,#0
1248 break;
1249 case OP_NOT_EQUALS:
1250 o4(0x03A00000); // moveq r0,#0
1251 o4(0x13A00001); // movne r0,#1
1252 break;
1253 case OP_LESS_EQUAL:
1254 o4(0xD3A00001); // movle r0,#1
1255 o4(0xC3A00000); // movgt r0,#0
1256 break;
1257 case OP_GREATER:
1258 o4(0xD3A00000); // movle r0,#0
1259 o4(0xC3A00001); // movgt r0,#1
1260 break;
1261 case OP_GREATER_EQUAL:
1262 o4(0xA3A00001); // movge r0,#1
1263 o4(0xB3A00000); // movlt r0,#0
1264 break;
1265 case OP_LESS:
1266 o4(0xA3A00000); // movge r0,#0
1267 o4(0xB3A00001); // movlt r0,#1
1268 break;
1269 default:
1270 error("Unknown comparison op %d", op);
1271 break;
1272 }
1273#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001274 switch(op) {
1275 case OP_EQUALS:
1276 callRuntime((void*) runtime_cmp_eq_ff);
1277 break;
1278 case OP_NOT_EQUALS:
1279 callRuntime((void*) runtime_cmp_ne_ff);
1280 break;
1281 case OP_LESS_EQUAL:
1282 callRuntime((void*) runtime_cmp_le_ff);
1283 break;
1284 case OP_GREATER:
1285 callRuntime((void*) runtime_cmp_gt_ff);
1286 break;
1287 case OP_GREATER_EQUAL:
1288 callRuntime((void*) runtime_cmp_ge_ff);
1289 break;
1290 case OP_LESS:
1291 callRuntime((void*) runtime_cmp_lt_ff);
1292 break;
1293 default:
1294 error("Unknown comparison op %d", op);
1295 break;
1296 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001297#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001298 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001299 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001300 }
1301
Jack Palevich546b2242009-05-13 15:10:04 -07001302 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001303 Type* pR0Type = getR0Type();
1304 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001305 TypeTag tagR0 = pR0Type->tag;
1306 TypeTag tagTOS = pTOSType->tag;
1307 bool isFloatR0 = isFloatTag(tagR0);
1308 bool isFloatTOS = isFloatTag(tagTOS);
1309 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001310 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001311 bool isPtrR0 = isPointerTag(tagR0);
1312 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001313 if (isPtrR0 || isPtrTOS) {
1314 if (isPtrR0 && isPtrTOS) {
1315 if (op != OP_MINUS) {
1316 error("Unsupported pointer-pointer operation %d.", op);
1317 }
1318 if (! typeEqual(pR0Type, pTOSType)) {
1319 error("Incompatible pointer types for subtraction.");
1320 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001321 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001322 setR0Type(mkpInt);
1323 int size = sizeOf(pR0Type->pHead);
1324 if (size != 1) {
1325 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001326 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001327 // TODO: Optimize for power-of-two.
1328 genOp(OP_DIV);
1329 }
1330 } else {
1331 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1332 error("Unsupported pointer-scalar operation %d", op);
1333 }
Jack Palevichb6154502009-08-04 14:56:09 -07001334 Type* pPtrType = getPointerArithmeticResultType(
1335 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001336 int size = sizeOf(pPtrType->pHead);
1337 if (size != 1) {
1338 // TODO: Optimize for power-of-two.
1339 liReg(size, 2);
1340 if (isPtrR0) {
1341 o4(0x0E0010192); // mul r1,r2,r1
1342 } else {
1343 o4(0x0E0000092); // mul r0,r2,r0
1344 }
1345 }
1346 switch(op) {
1347 case OP_PLUS:
1348 o4(0xE0810000); // add r0,r1,r0
1349 break;
1350 case OP_MINUS:
1351 o4(0xE0410000); // sub r0,r1,r0
1352 break;
1353 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001354 setR0Type(pPtrType);
1355 }
1356 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001357 switch(op) {
1358 case OP_MUL:
1359 o4(0x0E0000091); // mul r0,r1,r0
1360 break;
1361 case OP_DIV:
1362 callRuntime((void*) runtime_DIV);
1363 break;
1364 case OP_MOD:
1365 callRuntime((void*) runtime_MOD);
1366 break;
1367 case OP_PLUS:
1368 o4(0xE0810000); // add r0,r1,r0
1369 break;
1370 case OP_MINUS:
1371 o4(0xE0410000); // sub r0,r1,r0
1372 break;
1373 case OP_SHIFT_LEFT:
1374 o4(0xE1A00011); // lsl r0,r1,r0
1375 break;
1376 case OP_SHIFT_RIGHT:
1377 o4(0xE1A00051); // asr r0,r1,r0
1378 break;
1379 case OP_BIT_AND:
1380 o4(0xE0010000); // and r0,r1,r0
1381 break;
1382 case OP_BIT_XOR:
1383 o4(0xE0210000); // eor r0,r1,r0
1384 break;
1385 case OP_BIT_OR:
1386 o4(0xE1810000); // orr r0,r1,r0
1387 break;
1388 case OP_BIT_NOT:
1389 o4(0xE1E00000); // mvn r0, r0
1390 break;
1391 default:
1392 error("Unimplemented op %d\n", op);
1393 break;
1394 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001395 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001396 } else {
1397 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1398 if (pResultType->tag == TY_DOUBLE) {
1399 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001400
Jack Palevichb7718b92009-07-09 22:00:24 -07001401 switch(op) {
1402 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001403#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001404 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001405#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001406 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001407#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001408 break;
1409 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001410#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001411 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001412#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001413 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001414#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001415 break;
1416 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001417#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001418 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001419#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001420 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001421#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001422 break;
1423 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001424#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001425 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001426#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001427 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001428#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001429 break;
1430 default:
1431 error("Unsupported binary floating operation %d\n", op);
1432 break;
1433 }
1434 } else {
1435 setupFloatArgs();
1436 switch(op) {
1437 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001438#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001439 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001440#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001441 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001442#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001443 break;
1444 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001445#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001446 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001447#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001448 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001449#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001450 break;
1451 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001452#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001453 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001454#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001455 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001456#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001457 break;
1458 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001459#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001460 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001461#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001462 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001463#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001464 break;
1465 default:
1466 error("Unsupported binary floating operation %d\n", op);
1467 break;
1468 }
1469 }
1470 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001471 }
Jack Palevich22305132009-05-13 10:58:45 -07001472 }
1473
Jack Palevich58c30ee2009-07-17 16:35:23 -07001474 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001475 if (op != OP_LOGICAL_NOT) {
1476 error("Unknown unary cmp %d", op);
1477 } else {
1478 Type* pR0Type = getR0Type();
1479 TypeTag tag = collapseType(pR0Type->tag);
1480 switch(tag) {
1481 case TY_INT:
1482 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001483 o4(0xE1510000); // cmp r1, r0
1484 o4(0x03A00001); // moveq r0,#1
1485 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001486 break;
1487 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001488#ifdef ARM_USE_VFP
1489 o4(0xEEF57A40); // fcmpzs s15
1490 o4(0xEEF1FA10); // fmstat
1491 o4(0x03A00001); // moveq r0,#1
1492 o4(0x13A00000); // movne r0,#0
1493#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001494 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001495#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001496 break;
1497 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001498#ifdef ARM_USE_VFP
1499 o4(0xEEB57B40); // fcmpzd d7
1500 o4(0xEEF1FA10); // fmstat
1501 o4(0x03A00001); // moveq r0,#1
1502 o4(0x13A00000); // movne r0,#0
1503#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001504 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001505#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001506 break;
1507 default:
1508 error("gUnaryCmp unsupported type");
1509 break;
1510 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001511 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001512 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001513 }
1514
1515 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001516 Type* pR0Type = getR0Type();
1517 TypeTag tag = collapseType(pR0Type->tag);
1518 switch(tag) {
1519 case TY_INT:
1520 switch(op) {
1521 case OP_MINUS:
1522 o4(0xE3A01000); // mov r1, #0
1523 o4(0xE0410000); // sub r0,r1,r0
1524 break;
1525 case OP_BIT_NOT:
1526 o4(0xE1E00000); // mvn r0, r0
1527 break;
1528 default:
1529 error("Unknown unary op %d\n", op);
1530 break;
1531 }
1532 break;
1533 case TY_FLOAT:
1534 case TY_DOUBLE:
1535 switch (op) {
1536 case OP_MINUS:
1537 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001538#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001539 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001540#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001541 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001542#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001543 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001544#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001545 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001546#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001548#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001549 }
1550 break;
1551 case OP_BIT_NOT:
1552 error("Can't apply '~' operator to a float or double.");
1553 break;
1554 default:
1555 error("Unknown unary op %d\n", op);
1556 break;
1557 }
1558 break;
1559 default:
1560 error("genUnaryOp unsupported type");
1561 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001562 }
Jack Palevich22305132009-05-13 10:58:45 -07001563 }
1564
Jack Palevich1cdef202009-05-22 12:06:27 -07001565 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001566 Type* pR0Type = getR0Type();
1567 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001568
1569#ifdef ARM_USE_VFP
1570 switch (r0ct ) {
1571 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001572 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001573 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001574 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001575 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001576 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001577 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001578 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001579 default:
1580 o4(0xE92D0001); // stmfd sp!,{r0}
1581 mStackUse += 4;
1582 }
1583#else
1584
Jack Palevichb7718b92009-07-09 22:00:24 -07001585 if (r0ct != TY_DOUBLE) {
1586 o4(0xE92D0001); // stmfd sp!,{r0}
1587 mStackUse += 4;
1588 } else {
1589 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1590 mStackUse += 8;
1591 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001592#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001593 pushType();
-b master422972c2009-06-17 19:13:52 -07001594 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001595 }
1596
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001597 virtual void over() {
1598 // We know it's only used for int-ptr ops (++/--)
1599
1600 Type* pR0Type = getR0Type();
1601 TypeTag r0ct = collapseType(pR0Type->tag);
1602
1603 Type* pTOSType = getTOSType();
1604 TypeTag tosct = collapseType(pTOSType->tag);
1605
1606 assert (r0ct == TY_INT && tosct == TY_INT);
1607
1608 o4(0xE8BD0002); // ldmfd sp!,{r1}
1609 o4(0xE92D0001); // stmfd sp!,{r0}
1610 o4(0xE92D0002); // stmfd sp!,{r1}
1611 overType();
1612 mStackUse += 4;
1613 }
1614
Jack Palevich58c30ee2009-07-17 16:35:23 -07001615 virtual void popR0() {
1616 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001617 TypeTag tosct = collapseType(pTOSType->tag);
1618#ifdef ARM_USE_VFP
1619 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001620 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001621 }
1622#endif
1623 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001624 case TY_INT:
1625 case TY_FLOAT:
1626 o4(0xE8BD0001); // ldmfd sp!,{r0}
1627 mStackUse -= 4;
1628 break;
1629 case TY_DOUBLE:
1630 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1631 mStackUse -= 8;
1632 break;
1633 default:
1634 error("Can't pop this type.");
1635 break;
1636 }
1637 popType();
1638 LOG_STACK("popR0: %d\n", mStackUse);
1639 }
1640
1641 virtual void storeR0ToTOS() {
1642 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001643 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001644 Type* pDestType = pPointerType->pHead;
1645 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001646 o4(0xE8BD0004); // ldmfd sp!,{r2}
1647 popType();
-b master422972c2009-06-17 19:13:52 -07001648 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001649 switch (pDestType->tag) {
1650 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001651 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001652 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001653 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001654 case TY_FLOAT:
1655#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001656 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001657#else
1658 o4(0xE5820000); // str r0, [r2]
1659#endif
1660 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001661 case TY_SHORT:
1662 o4(0xE1C200B0); // strh r0, [r2]
1663 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001664 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001665 o4(0xE5C20000); // strb r0, [r2]
1666 break;
1667 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001668#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001669 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001670#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001671 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001672#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001673 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001674 case TY_STRUCT:
1675 {
1676 int size = sizeOf(pDestType);
1677 if (size > 0) {
1678 liReg(size, 1);
1679 callRuntime((void*) runtime_structCopy);
1680 }
1681 }
1682 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001683 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001684 error("storeR0ToTOS: unimplemented type %d",
1685 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001686 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001687 }
Jack Palevich02effee2009-11-09 12:52:45 +08001688 setR0Type(pDestType);
Jack Palevich22305132009-05-13 10:58:45 -07001689 }
1690
Jack Palevich58c30ee2009-07-17 16:35:23 -07001691 virtual void loadR0FromR0() {
1692 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001693 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001694 Type* pNewType = pPointerType->pHead;
1695 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001696 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001697 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001698 case TY_INT:
1699 o4(0xE5900000); // ldr r0, [r0]
1700 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001701 case TY_FLOAT:
1702#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001703 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001704#else
1705 o4(0xE5900000); // ldr r0, [r0]
1706#endif
1707 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001708 case TY_SHORT:
1709 o4(0xE1D000F0); // ldrsh r0, [r0]
1710 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001711 case TY_CHAR:
1712 o4(0xE5D00000); // ldrb r0, [r0]
1713 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001714 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001715#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001716 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001717#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001718 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001719#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001720 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001721 case TY_ARRAY:
1722 pNewType = pNewType->pTail;
1723 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001724 case TY_STRUCT:
1725 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001726 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001727 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001728 break;
1729 }
Jack Palevich80e49722009-08-04 15:39:49 -07001730 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001731 }
1732
Jack Palevichb5e33312009-07-30 19:06:34 -07001733 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001734 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001735 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001736
1737 size_t immediate = 0;
1738 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001739 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001740 inRange = encode12BitImmediate(-ea, &immediate);
1741 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001742 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001743 inRange = encode12BitImmediate(ea, &immediate);
1744 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1745 }
1746 if (! inRange) {
1747 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001748 }
Jack Palevichbd894902009-05-14 19:35:31 -07001749 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001750 // Global, absolute.
1751 o4(0xE59F0000); // ldr r0, .L1
1752 o4(0xEA000000); // b .L99
1753 o4(ea); // .L1: .word 0
1754 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001755 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001756 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001757 }
1758
Jack Palevich9f51a262009-07-29 16:22:26 -07001759 virtual int leaForward(int ea, Type* pPointerType) {
1760 setR0Type(pPointerType);
1761 int result = ea;
1762 int pc = getPC();
1763 int offset = 0;
1764 if (ea) {
1765 offset = (pc - ea - 8) >> 2;
1766 if ((offset & 0xffff) != offset) {
1767 error("function forward reference out of bounds");
1768 }
1769 } else {
1770 offset = 0;
1771 }
1772 o4(0xE59F0000 | offset); // ldr r0, .L1
1773
1774 if (ea == 0) {
1775 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001776 result = getPC();
1777 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001778 // .L99:
1779 }
1780 return result;
1781 }
1782
Jack Palevichb6154502009-08-04 14:56:09 -07001783 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001784 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001785 if (isPointerType(pType) && isPointerType(pR0Type)) {
1786 Type* pA = pR0Type;
1787 Type* pB = pType;
1788 // Array decays to pointer
1789 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1790 pA = pA->pTail;
1791 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001792 if (! (typeEqual(pA, pB)
1793 || pB->pHead->tag == TY_VOID
1794 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1795 )) {
1796 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001797 }
Jack Palevichb6154502009-08-04 14:56:09 -07001798 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001799 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001800 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001801 TypeTag r0Tag = collapseType(pR0Type->tag);
1802 TypeTag destTag = collapseType(pType->tag);
1803 if (r0Tag == TY_INT) {
1804 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001805#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001806 o4(0xEE070A90); // fmsr s15, r0
1807 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001808
1809#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001810 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001811#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001812 } else {
1813 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001814#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001815 o4(0xEE070A90); // fmsr s15, r0
1816 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001817
1818#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001819 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001820#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001821 }
1822 } else if (r0Tag == TY_FLOAT) {
1823 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001824#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001825 o4(0xEEFD7AE7); // ftosizs s15, s15
1826 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001827#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001828 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001829#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001830 } else {
1831 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001832#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001833 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001834#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001835 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001836#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001837 }
1838 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001839 if (r0Tag == TY_DOUBLE) {
1840 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001841#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001842 o4(0xEEFD7BC7); // ftosizd s15, d7
1843 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001844#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001845 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001846#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001847 } else {
1848 if(destTag == TY_FLOAT) {
1849#ifdef ARM_USE_VFP
1850 o4(0xEEF77BC7); // fcvtsd s15, d7
1851#else
1852 callRuntime((void*) runtime_double_to_float);
1853#endif
1854 } else {
1855 incompatibleTypes(pR0Type, pType);
1856 }
1857 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001858 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001859 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001860 }
1861 }
Jack Palevich8df46192009-07-07 14:48:51 -07001862 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001863 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001864 }
1865
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001866 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001867 int pc = getPC();
1868 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1869 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001870 }
1871
Jack Palevich8148c5b2009-07-16 18:24:47 -07001872 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001873 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001874 Type* pR0Type = getR0Type();
1875 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001876#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001877 switch(r0ct) {
1878 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001879 if (l < 0 || l > 4096-4) {
1880 error("l out of range for stack offset: 0x%08x", l);
1881 }
1882 o4(0xE58D0000 | l); // str r0, [sp, #l]
1883 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001884 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001885 if (l < 0 || l > 1020 || (l & 3)) {
1886 error("l out of range for stack offset: 0x%08x", l);
1887 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001888 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001889 return 4;
1890 case TY_DOUBLE: {
1891 // Align to 8 byte boundary
1892 int l2 = (l + 7) & ~7;
1893 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1894 error("l out of range for stack offset: 0x%08x", l);
1895 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001896 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001897 return (l2 - l) + 8;
1898 }
1899 default:
1900 assert(false);
1901 return 0;
1902 }
1903#else
1904 switch(r0ct) {
1905 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001906 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001907 if (l < 0 || l > 4096-4) {
1908 error("l out of range for stack offset: 0x%08x", l);
1909 }
1910 o4(0xE58D0000 + l); // str r0, [sp, #l]
1911 return 4;
1912 case TY_DOUBLE: {
1913 // Align to 8 byte boundary
1914 int l2 = (l + 7) & ~7;
1915 if (l2 < 0 || l2 > 4096-8) {
1916 error("l out of range for stack offset: 0x%08x", l);
1917 }
1918 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1919 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1920 return (l2 - l) + 8;
1921 }
1922 default:
1923 assert(false);
1924 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001925 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001926#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001927 }
1928
Jack Palevichb7718b92009-07-09 22:00:24 -07001929 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001930 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001931 // Have to calculate register arg count from actual stack size,
1932 // in order to properly handle ... functions.
1933 int regArgCount = l >> 2;
1934 if (regArgCount > 4) {
1935 regArgCount = 4;
1936 }
1937 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001938 argumentStackUse -= regArgCount * 4;
1939 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1940 }
1941 mStackUse += argumentStackUse;
1942
1943 // Align stack.
1944 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1945 * STACK_ALIGNMENT);
1946 mStackAlignmentAdjustment = 0;
1947 if (missalignment > 0) {
1948 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1949 }
1950 l += mStackAlignmentAdjustment;
1951
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001952 if (l < 0 || l > 0x3FC) {
1953 error("L out of range for stack adjustment: 0x%08x", l);
1954 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001955 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001956 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001957 mStackUse += mStackAlignmentAdjustment;
1958 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1959 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001960 }
1961
Jack Palevich8df46192009-07-07 14:48:51 -07001962 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001963 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001964 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001965 int pc = getPC();
1966 o4(0xEB000000 | encodeAddress(symbol));
1967 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001968 }
1969
Jack Palevich8df46192009-07-07 14:48:51 -07001970 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001971 assert(pFunc->tag == TY_FUNC);
1972 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001973 int argCount = l >> 2;
1974 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001975 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001976 if (adjustedL < 0 || adjustedL > 4096-4) {
1977 error("l out of range for stack offset: 0x%08x", l);
1978 }
1979 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1980 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001981 Type* pReturnType = pFunc->pHead;
1982 setR0Type(pReturnType);
1983#ifdef ARM_USE_VFP
1984 switch(pReturnType->tag) {
1985 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001986 o4(0xEE070A90); // fmsr s15, r0
1987 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001988 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001989 o4(0xEC410B17); // fmdrr d7, r0, r1
1990 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001991 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001992 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001993 }
1994#endif
Jack Palevich22305132009-05-13 10:58:45 -07001995 }
1996
Jack Palevichb7718b92009-07-09 22:00:24 -07001997 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001998 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001999 // Have to calculate register arg count from actual stack size,
2000 // in order to properly handle ... functions.
2001 int regArgCount = l >> 2;
2002 if (regArgCount > 4) {
2003 regArgCount = 4;
2004 }
2005 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07002006 int stackUse = stackArgs + (isIndirect ? 1 : 0)
2007 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07002008 if (stackUse) {
2009 if (stackUse < 0 || stackUse > 255) {
2010 error("L out of range for stack adjustment: 0x%08x", l);
2011 }
2012 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07002013 mStackUse -= stackUse * 4;
2014 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002015 }
Jack Palevich22305132009-05-13 10:58:45 -07002016 }
2017
Jack Palevicha6535612009-05-13 16:24:17 -07002018 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07002019 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002020 }
2021
2022 /* output a symbol and patch all calls to it */
2023 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002024 int n;
2025 int base = getBase();
2026 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002027 while (t) {
2028 int data = * (int*) t;
2029 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2030 if (decodedOffset == 0) {
2031 n = 0;
2032 } else {
2033 n = base + decodedOffset; /* next value */
2034 }
2035 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2036 | encodeRelAddress(pc - t - 8);
2037 t = n;
2038 }
2039 }
2040
Jack Palevich9f51a262009-07-29 16:22:26 -07002041 /* output a symbol and patch all calls to it */
2042 virtual void resolveForward(int t) {
2043 if (t) {
2044 int pc = getPC();
2045 *(int *) t = pc;
2046 }
2047 }
2048
Jack Palevich1cdef202009-05-22 12:06:27 -07002049 virtual int finishCompile() {
2050#if defined(__arm__)
2051 const long base = long(getBase());
2052 const long curr = long(getPC());
2053 int err = cacheflush(base, curr, 0);
2054 return err;
2055#else
2056 return 0;
2057#endif
2058 }
2059
Jack Palevich9eed7a22009-07-06 17:24:34 -07002060 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002061 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002062 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002063 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002064 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002065 case TY_CHAR:
2066 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002067 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002068 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002069 case TY_DOUBLE:
2070 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002071 case TY_ARRAY:
2072 return alignmentOf(pType->pHead);
2073 case TY_STRUCT:
2074 return pType->pHead->alignment & 0x7fffffff;
2075 case TY_FUNC:
2076 error("alignment of func not supported");
2077 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002078 default:
2079 return 4;
2080 }
2081 }
2082
2083 /**
2084 * Array element alignment (in bytes) for this type of data.
2085 */
2086 virtual size_t sizeOf(Type* pType){
2087 switch(pType->tag) {
2088 case TY_INT:
2089 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002090 case TY_SHORT:
2091 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002092 case TY_CHAR:
2093 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002094 case TY_FLOAT:
2095 return 4;
2096 case TY_DOUBLE:
2097 return 8;
2098 case TY_POINTER:
2099 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002100 case TY_ARRAY:
2101 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002102 case TY_STRUCT:
2103 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002104 default:
2105 error("Unsupported type %d", pType->tag);
2106 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002107 }
2108 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002109
Jack Palevich22305132009-05-13 10:58:45 -07002110 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002111
2112 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2113
2114 /** Encode a relative address that might also be
2115 * a label.
2116 */
2117 int encodeAddress(int value) {
2118 int base = getBase();
2119 if (value >= base && value <= getPC() ) {
2120 // This is a label, encode it relative to the base.
2121 value = value - base;
2122 }
2123 return encodeRelAddress(value);
2124 }
2125
2126 int encodeRelAddress(int value) {
2127 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2128 }
Jack Palevich22305132009-05-13 10:58:45 -07002129
Jack Palevichb7718b92009-07-09 22:00:24 -07002130 int calcRegArgCount(Type* pDecl) {
2131 int reg = 0;
2132 Type* pArgs = pDecl->pTail;
2133 while (pArgs && reg < 4) {
2134 Type* pArg = pArgs->pHead;
2135 if ( pArg->tag == TY_DOUBLE) {
2136 int evenReg = (reg + 1) & ~1;
2137 if (evenReg >= 4) {
2138 break;
2139 }
2140 reg = evenReg + 2;
2141 } else {
2142 reg++;
2143 }
2144 pArgs = pArgs->pTail;
2145 }
2146 return reg;
2147 }
2148
Jack Palevich58c30ee2009-07-17 16:35:23 -07002149 void setupIntPtrArgs() {
2150 o4(0xE8BD0002); // ldmfd sp!,{r1}
2151 mStackUse -= 4;
2152 popType();
2153 }
2154
Jack Palevich30321cb2009-08-20 15:34:23 -07002155 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002156 * Make sure both R0 and TOS are floats. (Could be ints)
2157 * We know that at least one of R0 and TOS is already a float
2158 */
2159 void setupFloatArgs() {
2160 Type* pR0Type = getR0Type();
2161 Type* pTOSType = getTOSType();
2162 TypeTag tagR0 = collapseType(pR0Type->tag);
2163 TypeTag tagTOS = collapseType(pTOSType->tag);
2164 if (tagR0 != TY_FLOAT) {
2165 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002166#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002167 o4(0xEE070A90); // fmsr s15, r0
2168 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002169#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002170 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002171#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002172 }
2173 if (tagTOS != TY_FLOAT) {
2174 assert(tagTOS == TY_INT);
2175 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002176#ifdef ARM_USE_VFP
2177 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002178 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002179#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002180 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2181 o4(0xE59D0004); // ldr r0, [sp, #4]
2182 callRuntime((void*) runtime_int_to_float);
2183 o4(0xE1A01000); // mov r1, r0
2184 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2185 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002186#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002187 } else {
2188 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002189#ifdef ARM_USE_VFP
2190 o4(0xECBD7A01); // fldmfds sp!, {s14}
2191
2192#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002193 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002194#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002195 }
2196 mStackUse -= 4;
2197 popType();
2198 }
2199
Jack Palevich30321cb2009-08-20 15:34:23 -07002200 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002201 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2202 * We know that at least one of R0 and TOS are already a double.
2203 */
2204
2205 void setupDoubleArgs() {
2206 Type* pR0Type = getR0Type();
2207 Type* pTOSType = getTOSType();
2208 TypeTag tagR0 = collapseType(pR0Type->tag);
2209 TypeTag tagTOS = collapseType(pTOSType->tag);
2210 if (tagR0 != TY_DOUBLE) {
2211 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002212#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002213 o4(0xEE070A90); // fmsr s15, r0
2214 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002215
2216#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002217 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002218#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002219 } else {
2220 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002221#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002222 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002223#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002224 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002225#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002226 }
2227 }
2228 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002229#ifdef ARM_USE_VFP
2230 if (tagTOS == TY_INT) {
2231 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002232 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002233 } else {
2234 assert(tagTOS == TY_FLOAT);
2235 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002236 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002237 }
2238#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002239 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2240 o4(0xE59D0008); // ldr r0, [sp, #8]
2241 if (tagTOS == TY_INT) {
2242 callRuntime((void*) runtime_int_to_double);
2243 } else {
2244 assert(tagTOS == TY_FLOAT);
2245 callRuntime((void*) runtime_float_to_double);
2246 }
2247 o4(0xE1A02000); // mov r2, r0
2248 o4(0xE1A03001); // mov r3, r1
2249 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2250 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002251#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002252 mStackUse -= 4;
2253 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002254#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002255 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002256#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002257 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002258#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002259 mStackUse -= 8;
2260 }
2261 popType();
2262 }
2263
Jack Palevicha8f427f2009-07-13 18:40:08 -07002264 void liReg(int t, int reg) {
2265 assert(reg >= 0 && reg < 16);
2266 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002267 size_t encodedImmediate;
2268 if (encode12BitImmediate(t, &encodedImmediate)) {
2269 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2270 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002271 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002272 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002273 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002274 o4(0xE51F0000 | rN); // ldr rN, .L3
2275 o4(0xEA000000); // b .L99
2276 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002277 // .L99:
2278 }
2279 }
2280
Jack Palevichc408bbf2009-09-08 12:07:32 -07002281 void incompatibleTypes(Type* pR0Type, Type* pType) {
2282 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2283 }
2284
Jack Palevichb7718b92009-07-09 22:00:24 -07002285 void callRuntime(void* fn) {
2286 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002287 o4(0xEA000000); // b .L99
2288 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002289 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002290 }
2291
Jack Palevichb7718b92009-07-09 22:00:24 -07002292 // Integer math:
2293
2294 static int runtime_DIV(int b, int a) {
2295 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002296 }
2297
Jack Palevichb7718b92009-07-09 22:00:24 -07002298 static int runtime_MOD(int b, int a) {
2299 return a % b;
2300 }
2301
Jack Palevich9221bcc2009-08-26 16:15:07 -07002302 static void runtime_structCopy(void* src, size_t size, void* dest) {
2303 memcpy(dest, src, size);
2304 }
2305
Jack Palevich30321cb2009-08-20 15:34:23 -07002306#ifndef ARM_USE_VFP
2307
Jack Palevichb7718b92009-07-09 22:00:24 -07002308 // Comparison to zero
2309
2310 static int runtime_is_non_zero_f(float a) {
2311 return a != 0;
2312 }
2313
2314 static int runtime_is_non_zero_d(double a) {
2315 return a != 0;
2316 }
2317
2318 // Comparison to zero
2319
2320 static int runtime_is_zero_f(float a) {
2321 return a == 0;
2322 }
2323
2324 static int runtime_is_zero_d(double a) {
2325 return a == 0;
2326 }
2327
2328 // Type conversion
2329
2330 static int runtime_float_to_int(float a) {
2331 return (int) a;
2332 }
2333
2334 static double runtime_float_to_double(float a) {
2335 return (double) a;
2336 }
2337
2338 static int runtime_double_to_int(double a) {
2339 return (int) a;
2340 }
2341
2342 static float runtime_double_to_float(double a) {
2343 return (float) a;
2344 }
2345
2346 static float runtime_int_to_float(int a) {
2347 return (float) a;
2348 }
2349
2350 static double runtime_int_to_double(int a) {
2351 return (double) a;
2352 }
2353
2354 // Comparisons float
2355
2356 static int runtime_cmp_eq_ff(float b, float a) {
2357 return a == b;
2358 }
2359
2360 static int runtime_cmp_ne_ff(float b, float a) {
2361 return a != b;
2362 }
2363
2364 static int runtime_cmp_lt_ff(float b, float a) {
2365 return a < b;
2366 }
2367
2368 static int runtime_cmp_le_ff(float b, float a) {
2369 return a <= b;
2370 }
2371
2372 static int runtime_cmp_ge_ff(float b, float a) {
2373 return a >= b;
2374 }
2375
2376 static int runtime_cmp_gt_ff(float b, float a) {
2377 return a > b;
2378 }
2379
2380 // Comparisons double
2381
2382 static int runtime_cmp_eq_dd(double b, double a) {
2383 return a == b;
2384 }
2385
2386 static int runtime_cmp_ne_dd(double b, double a) {
2387 return a != b;
2388 }
2389
2390 static int runtime_cmp_lt_dd(double b, double a) {
2391 return a < b;
2392 }
2393
2394 static int runtime_cmp_le_dd(double b, double a) {
2395 return a <= b;
2396 }
2397
2398 static int runtime_cmp_ge_dd(double b, double a) {
2399 return a >= b;
2400 }
2401
2402 static int runtime_cmp_gt_dd(double b, double a) {
2403 return a > b;
2404 }
2405
2406 // Math float
2407
2408 static float runtime_op_add_ff(float b, float a) {
2409 return a + b;
2410 }
2411
2412 static float runtime_op_sub_ff(float b, float a) {
2413 return a - b;
2414 }
2415
2416 static float runtime_op_mul_ff(float b, float a) {
2417 return a * b;
2418 }
2419
2420 static float runtime_op_div_ff(float b, float a) {
2421 return a / b;
2422 }
2423
2424 static float runtime_op_neg_f(float a) {
2425 return -a;
2426 }
2427
2428 // Math double
2429
2430 static double runtime_op_add_dd(double b, double a) {
2431 return a + b;
2432 }
2433
2434 static double runtime_op_sub_dd(double b, double a) {
2435 return a - b;
2436 }
2437
2438 static double runtime_op_mul_dd(double b, double a) {
2439 return a * b;
2440 }
2441
2442 static double runtime_op_div_dd(double b, double a) {
2443 return a / b;
2444 }
2445
2446 static double runtime_op_neg_d(double a) {
2447 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002448 }
-b master422972c2009-06-17 19:13:52 -07002449
Jack Palevich30321cb2009-08-20 15:34:23 -07002450#endif
2451
-b master422972c2009-06-17 19:13:52 -07002452 static const int STACK_ALIGNMENT = 8;
2453 int mStackUse;
2454 // This variable holds the amount we adjusted the stack in the most
2455 // recent endFunctionCallArguments call. It's examined by the
2456 // following adjustStackAfterCall call.
2457 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002458 };
2459
Jack Palevich09555c72009-05-27 12:25:55 -07002460#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002461
2462#ifdef PROVIDE_X86_CODEGEN
2463
Jack Palevich21a15a22009-05-11 14:49:29 -07002464 class X86CodeGenerator : public CodeGenerator {
2465 public:
2466 X86CodeGenerator() {}
2467 virtual ~X86CodeGenerator() {}
2468
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002469 /* returns address to patch with local variable size
2470 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002471 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002472 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2473 return oad(0xec81, 0); /* sub $xxx, %esp */
2474 }
2475
Jack Palevichb7718b92009-07-09 22:00:24 -07002476 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002477 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002478 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002479 }
2480
Jack Palevich21a15a22009-05-11 14:49:29 -07002481 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002482 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002483 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002484 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002485 }
2486
Jack Palevich1a539db2009-07-08 13:04:41 -07002487 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002488 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002489 switch (pType->tag) {
2490 case TY_FLOAT:
2491 oad(0x05D9, address); // flds
2492 break;
2493 case TY_DOUBLE:
2494 oad(0x05DD, address); // fldl
2495 break;
2496 default:
2497 assert(false);
2498 break;
2499 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002500 }
2501
Jack Palevich9221bcc2009-08-26 16:15:07 -07002502 virtual void addStructOffsetR0(int offset, Type* pType) {
2503 if (offset) {
2504 oad(0x05, offset); // addl offset, %eax
2505 }
2506 setR0Type(pType, ET_LVALUE);
2507 }
2508
Jack Palevich22305132009-05-13 10:58:45 -07002509 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002510 return psym(0xe9, t);
2511 }
2512
2513 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002514 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002515 Type* pR0Type = getR0Type();
2516 TypeTag tagR0 = pR0Type->tag;
2517 bool isFloatR0 = isFloatTag(tagR0);
2518 if (isFloatR0) {
2519 o(0xeed9); // fldz
2520 o(0xe9da); // fucompp
2521 o(0xe0df); // fnstsw %ax
2522 o(0x9e); // sahf
2523 } else {
2524 o(0xc085); // test %eax, %eax
2525 }
2526 // Use two output statements to generate one instruction.
2527 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002528 return psym(0x84 + l, t);
2529 }
2530
Jack Palevich58c30ee2009-07-17 16:35:23 -07002531 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002532 Type* pR0Type = getR0Type();
2533 Type* pTOSType = getTOSType();
2534 TypeTag tagR0 = pR0Type->tag;
2535 TypeTag tagTOS = pTOSType->tag;
2536 bool isFloatR0 = isFloatTag(tagR0);
2537 bool isFloatTOS = isFloatTag(tagTOS);
2538 if (!isFloatR0 && !isFloatTOS) {
2539 int t = decodeOp(op);
2540 o(0x59); /* pop %ecx */
2541 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002542 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002543 o(0x0f); /* setxx %al */
2544 o(t + 0x90);
2545 o(0xc0);
2546 popType();
2547 } else {
2548 setupFloatOperands();
2549 switch (op) {
2550 case OP_EQUALS:
2551 o(0xe9da); // fucompp
2552 o(0xe0df); // fnstsw %ax
2553 o(0x9e); // sahf
2554 o(0xc0940f); // sete %al
2555 o(0xc29b0f); // setnp %dl
2556 o(0xd021); // andl %edx, %eax
2557 break;
2558 case OP_NOT_EQUALS:
2559 o(0xe9da); // fucompp
2560 o(0xe0df); // fnstsw %ax
2561 o(0x9e); // sahf
2562 o(0xc0950f); // setne %al
2563 o(0xc29a0f); // setp %dl
2564 o(0xd009); // orl %edx, %eax
2565 break;
2566 case OP_GREATER_EQUAL:
2567 o(0xe9da); // fucompp
2568 o(0xe0df); // fnstsw %ax
2569 o(0x05c4f6); // testb $5, %ah
2570 o(0xc0940f); // sete %al
2571 break;
2572 case OP_LESS:
2573 o(0xc9d9); // fxch %st(1)
2574 o(0xe9da); // fucompp
2575 o(0xe0df); // fnstsw %ax
2576 o(0x9e); // sahf
2577 o(0xc0970f); // seta %al
2578 break;
2579 case OP_LESS_EQUAL:
2580 o(0xc9d9); // fxch %st(1)
2581 o(0xe9da); // fucompp
2582 o(0xe0df); // fnstsw %ax
2583 o(0x9e); // sahf
2584 o(0xc0930f); // setea %al
2585 break;
2586 case OP_GREATER:
2587 o(0xe9da); // fucompp
2588 o(0xe0df); // fnstsw %ax
2589 o(0x45c4f6); // testb $69, %ah
2590 o(0xc0940f); // sete %al
2591 break;
2592 default:
2593 error("Unknown comparison op");
2594 }
2595 o(0xc0b60f); // movzbl %al, %eax
2596 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002597 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002598 }
2599
Jack Palevich546b2242009-05-13 15:10:04 -07002600 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002601 Type* pR0Type = getR0Type();
2602 Type* pTOSType = getTOSType();
2603 TypeTag tagR0 = pR0Type->tag;
2604 TypeTag tagTOS = pTOSType->tag;
2605 bool isFloatR0 = isFloatTag(tagR0);
2606 bool isFloatTOS = isFloatTag(tagTOS);
2607 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002608 bool isPtrR0 = isPointerTag(tagR0);
2609 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002610 if (isPtrR0 || isPtrTOS) {
2611 if (isPtrR0 && isPtrTOS) {
2612 if (op != OP_MINUS) {
2613 error("Unsupported pointer-pointer operation %d.", op);
2614 }
2615 if (! typeEqual(pR0Type, pTOSType)) {
2616 error("Incompatible pointer types for subtraction.");
2617 }
2618 o(0x59); /* pop %ecx */
2619 o(decodeOp(op));
2620 popType();
2621 setR0Type(mkpInt);
2622 int size = sizeOf(pR0Type->pHead);
2623 if (size != 1) {
2624 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002625 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002626 // TODO: Optimize for power-of-two.
2627 genOp(OP_DIV);
2628 }
2629 } else {
2630 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2631 error("Unsupported pointer-scalar operation %d", op);
2632 }
Jack Palevichb6154502009-08-04 14:56:09 -07002633 Type* pPtrType = getPointerArithmeticResultType(
2634 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002635 o(0x59); /* pop %ecx */
2636 int size = sizeOf(pPtrType->pHead);
2637 if (size != 1) {
2638 // TODO: Optimize for power-of-two.
2639 if (isPtrR0) {
2640 oad(0xC969, size); // imull $size, %ecx
2641 } else {
2642 oad(0xC069, size); // mul $size, %eax
2643 }
2644 }
2645 o(decodeOp(op));
2646 popType();
2647 setR0Type(pPtrType);
2648 }
2649 } else {
2650 o(0x59); /* pop %ecx */
2651 o(decodeOp(op));
2652 if (op == OP_MOD)
2653 o(0x92); /* xchg %edx, %eax */
2654 popType();
2655 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002656 } else {
2657 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2658 setupFloatOperands();
2659 // Both float. x87 R0 == left hand, x87 R1 == right hand
2660 switch (op) {
2661 case OP_MUL:
2662 o(0xc9de); // fmulp
2663 break;
2664 case OP_DIV:
2665 o(0xf1de); // fdivp
2666 break;
2667 case OP_PLUS:
2668 o(0xc1de); // faddp
2669 break;
2670 case OP_MINUS:
2671 o(0xe1de); // fsubp
2672 break;
2673 default:
2674 error("Unsupported binary floating operation.");
2675 break;
2676 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002677 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002678 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002679 }
2680
Jack Palevich58c30ee2009-07-17 16:35:23 -07002681 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002682 if (op != OP_LOGICAL_NOT) {
2683 error("Unknown unary cmp %d", op);
2684 } else {
2685 Type* pR0Type = getR0Type();
2686 TypeTag tag = collapseType(pR0Type->tag);
2687 switch(tag) {
2688 case TY_INT: {
2689 oad(0xb9, 0); /* movl $0, %ecx */
2690 int t = decodeOp(op);
2691 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002692 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002693 o(0x0f); /* setxx %al */
2694 o(t + 0x90);
2695 o(0xc0);
2696 }
2697 break;
2698 case TY_FLOAT:
2699 case TY_DOUBLE:
2700 o(0xeed9); // fldz
2701 o(0xe9da); // fucompp
2702 o(0xe0df); // fnstsw %ax
2703 o(0x9e); // sahf
2704 o(0xc0950f); // setne %al
2705 o(0xc29a0f); // setp %dl
2706 o(0xd009); // orl %edx, %eax
2707 o(0xc0b60f); // movzbl %al, %eax
2708 o(0x01f083); // xorl $1, %eax
2709 break;
2710 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002711 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002712 break;
2713 }
2714 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002715 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002716 }
2717
2718 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002719 Type* pR0Type = getR0Type();
2720 TypeTag tag = collapseType(pR0Type->tag);
2721 switch(tag) {
2722 case TY_INT:
2723 oad(0xb9, 0); /* movl $0, %ecx */
2724 o(decodeOp(op));
2725 break;
2726 case TY_FLOAT:
2727 case TY_DOUBLE:
2728 switch (op) {
2729 case OP_MINUS:
2730 o(0xe0d9); // fchs
2731 break;
2732 case OP_BIT_NOT:
2733 error("Can't apply '~' operator to a float or double.");
2734 break;
2735 default:
2736 error("Unknown unary op %d\n", op);
2737 break;
2738 }
2739 break;
2740 default:
2741 error("genUnaryOp unsupported type");
2742 break;
2743 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002744 }
2745
Jack Palevich1cdef202009-05-22 12:06:27 -07002746 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002747 Type* pR0Type = getR0Type();
2748 TypeTag r0ct = collapseType(pR0Type->tag);
2749 switch(r0ct) {
2750 case TY_INT:
2751 o(0x50); /* push %eax */
2752 break;
2753 case TY_FLOAT:
2754 o(0x50); /* push %eax */
2755 o(0x241cd9); // fstps 0(%esp)
2756 break;
2757 case TY_DOUBLE:
2758 o(0x50); /* push %eax */
2759 o(0x50); /* push %eax */
2760 o(0x241cdd); // fstpl 0(%esp)
2761 break;
2762 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002763 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002764 break;
2765 }
Jack Palevich8df46192009-07-07 14:48:51 -07002766 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002767 }
2768
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002769 virtual void over() {
2770 // We know it's only used for int-ptr ops (++/--)
2771
2772 Type* pR0Type = getR0Type();
2773 TypeTag r0ct = collapseType(pR0Type->tag);
2774
2775 Type* pTOSType = getTOSType();
2776 TypeTag tosct = collapseType(pTOSType->tag);
2777
2778 assert (r0ct == TY_INT && tosct == TY_INT);
2779
2780 o(0x59); /* pop %ecx */
2781 o(0x50); /* push %eax */
2782 o(0x51); /* push %ecx */
2783
2784 overType();
2785 }
2786
Jack Palevich58c30ee2009-07-17 16:35:23 -07002787 virtual void popR0() {
2788 Type* pR0Type = getR0Type();
2789 TypeTag r0ct = collapseType(pR0Type->tag);
2790 switch(r0ct) {
2791 case TY_INT:
2792 o(0x58); /* popl %eax */
2793 break;
2794 case TY_FLOAT:
2795 o(0x2404d9); // flds (%esp)
2796 o(0x58); /* popl %eax */
2797 break;
2798 case TY_DOUBLE:
2799 o(0x2404dd); // fldl (%esp)
2800 o(0x58); /* popl %eax */
2801 o(0x58); /* popl %eax */
2802 break;
2803 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002804 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002805 break;
2806 }
2807 popType();
2808 }
2809
2810 virtual void storeR0ToTOS() {
2811 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002812 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002813 Type* pTargetType = pPointerType->pHead;
2814 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002815 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002816 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002817 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002818 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002819 case TY_INT:
2820 o(0x0189); /* movl %eax/%al, (%ecx) */
2821 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002822 case TY_SHORT:
2823 o(0x018966); /* movw %ax, (%ecx) */
2824 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002825 case TY_CHAR:
2826 o(0x0188); /* movl %eax/%al, (%ecx) */
2827 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002828 case TY_FLOAT:
2829 o(0x19d9); /* fstps (%ecx) */
2830 break;
2831 case TY_DOUBLE:
2832 o(0x19dd); /* fstpl (%ecx) */
2833 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002834 case TY_STRUCT:
2835 {
2836 // TODO: use alignment information to use movsw/movsl instead of movsb
2837 int size = sizeOf(pTargetType);
2838 if (size > 0) {
2839 o(0x9c); // pushf
2840 o(0x57); // pushl %edi
2841 o(0x56); // pushl %esi
2842 o(0xcf89); // movl %ecx, %edi
2843 o(0xc689); // movl %eax, %esi
2844 oad(0xb9, size); // mov #size, %ecx
2845 o(0xfc); // cld
2846 o(0xf3); // rep
2847 o(0xa4); // movsb
2848 o(0x5e); // popl %esi
2849 o(0x5f); // popl %edi
2850 o(0x9d); // popf
2851 }
2852 }
2853 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002854 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002855 error("storeR0ToTOS: unsupported type %d",
2856 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002857 break;
2858 }
Jack Palevich02effee2009-11-09 12:52:45 +08002859 setR0Type(pTargetType);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002860 }
2861
Jack Palevich58c30ee2009-07-17 16:35:23 -07002862 virtual void loadR0FromR0() {
2863 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002864 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002865 Type* pNewType = pPointerType->pHead;
2866 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002867 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002868 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002869 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002870 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002871 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002872 case TY_SHORT:
2873 o(0xbf0f); /* movswl (%eax), %eax */
2874 ob(0);
2875 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002876 case TY_CHAR:
2877 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002878 ob(0); /* add zero in code */
2879 break;
2880 case TY_FLOAT:
2881 o2(0x00d9); // flds (%eax)
2882 break;
2883 case TY_DOUBLE:
2884 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002885 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002886 case TY_ARRAY:
2887 pNewType = pNewType->pTail;
2888 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002889 case TY_STRUCT:
2890 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002891 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002892 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002893 break;
2894 }
Jack Palevich80e49722009-08-04 15:39:49 -07002895 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002896 }
2897
Jack Palevichb5e33312009-07-30 19:06:34 -07002898 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002899 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002900 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002901 }
2902
Jack Palevich9f51a262009-07-29 16:22:26 -07002903 virtual int leaForward(int ea, Type* pPointerType) {
2904 oad(0xb8, ea); /* mov $xx, %eax */
2905 setR0Type(pPointerType);
2906 return getPC() - 4;
2907 }
2908
Jack Palevichb6154502009-08-04 14:56:09 -07002909 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002910 Type* pR0Type = getR0Type();
2911 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002912 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002913 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002914 return;
2915 }
Jack Palevichb6154502009-08-04 14:56:09 -07002916 if (isPointerType(pType) && isPointerType(pR0Type)) {
2917 Type* pA = pR0Type;
2918 Type* pB = pType;
2919 // Array decays to pointer
2920 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2921 pA = pA->pTail;
2922 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002923 if (! (typeEqual(pA, pB)
2924 || pB->pHead->tag == TY_VOID
2925 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2926 )) {
2927 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002928 }
Jack Palevichb6154502009-08-04 14:56:09 -07002929 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002930 // do nothing special
2931 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2932 // do nothing special, both held in same register on x87.
2933 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002934 TypeTag r0Tag = collapseType(pR0Type->tag);
2935 TypeTag destTag = collapseType(pType->tag);
2936 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2937 // Convert R0 from int to float
2938 o(0x50); // push %eax
2939 o(0x2404DB); // fildl 0(%esp)
2940 o(0x58); // pop %eax
2941 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2942 // Convert R0 from float to int. Complicated because
2943 // need to save and restore the rounding mode.
2944 o(0x50); // push %eax
2945 o(0x50); // push %eax
2946 o(0x02247cD9); // fnstcw 2(%esp)
2947 o(0x2444b70f); // movzwl 2(%esp), %eax
2948 o(0x02);
2949 o(0x0cb4); // movb $12, %ah
2950 o(0x24048966); // movw %ax, 0(%esp)
2951 o(0x242cd9); // fldcw 0(%esp)
2952 o(0x04245cdb); // fistpl 4(%esp)
2953 o(0x02246cd9); // fldcw 2(%esp)
2954 o(0x58); // pop %eax
2955 o(0x58); // pop %eax
2956 } else {
2957 error("Incompatible types old: %d new: %d",
2958 pR0Type->tag, pType->tag);
2959 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002960 }
2961 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002962 }
2963
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002964 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002965 return oad(0xec81, 0); /* sub $xxx, %esp */
2966 }
2967
Jack Palevich8148c5b2009-07-16 18:24:47 -07002968 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2969 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002970 Type* pR0Type = getR0Type();
2971 TypeTag r0ct = collapseType(pR0Type->tag);
2972 switch(r0ct) {
2973 case TY_INT:
2974 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2975 return 4;
2976 case TY_FLOAT:
2977 oad(0x249CD9, l); /* fstps xxx(%esp) */
2978 return 4;
2979 case TY_DOUBLE:
2980 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2981 return 8;
2982 default:
2983 assert(false);
2984 return 0;
2985 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002986 }
2987
Jack Palevichb7718b92009-07-09 22:00:24 -07002988 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002989 * (int*) a = l;
2990 }
2991
Jack Palevich8df46192009-07-07 14:48:51 -07002992 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002993 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002994 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002995 return psym(0xe8, symbol); /* call xxx */
2996 }
2997
Jack Palevich8df46192009-07-07 14:48:51 -07002998 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002999 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07003000 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07003001 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003002 oad(0x2494ff, l); /* call *xxx(%esp) */
3003 }
3004
Jack Palevichb7718b92009-07-09 22:00:24 -07003005 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003006 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07003007 if (isIndirect) {
3008 l += 4;
3009 }
-b master422972c2009-06-17 19:13:52 -07003010 if (l > 0) {
3011 oad(0xc481, l); /* add $xxx, %esp */
3012 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003013 }
3014
Jack Palevicha6535612009-05-13 16:24:17 -07003015 virtual int jumpOffset() {
3016 return 5;
3017 }
3018
Jack Paleviche7b59062009-05-19 17:12:17 -07003019 /* output a symbol and patch all calls to it */
3020 virtual void gsym(int t) {
3021 int n;
3022 int pc = getPC();
3023 while (t) {
3024 n = *(int *) t; /* next value */
3025 *(int *) t = pc - t - 4;
3026 t = n;
3027 }
3028 }
3029
Jack Palevich9f51a262009-07-29 16:22:26 -07003030 /* output a symbol and patch all calls to it, using absolute address */
3031 virtual void resolveForward(int t) {
3032 int n;
3033 int pc = getPC();
3034 while (t) {
3035 n = *(int *) t; /* next value */
3036 *(int *) t = pc;
3037 t = n;
3038 }
3039 }
3040
Jack Palevich1cdef202009-05-22 12:06:27 -07003041 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003042 size_t pagesize = 4096;
3043 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3044 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3045 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3046 if (err) {
3047 error("mprotect() failed: %d", errno);
3048 }
3049 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003050 }
3051
Jack Palevich9eed7a22009-07-06 17:24:34 -07003052 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003053 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003054 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003055 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003056 switch (pType->tag) {
3057 case TY_CHAR:
3058 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003059 case TY_SHORT:
3060 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003061 case TY_ARRAY:
3062 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003063 case TY_STRUCT:
3064 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003065 case TY_FUNC:
3066 error("alignment of func not supported");
3067 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003068 default:
3069 return 4;
3070 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003071 }
3072
3073 /**
3074 * Array element alignment (in bytes) for this type of data.
3075 */
3076 virtual size_t sizeOf(Type* pType){
3077 switch(pType->tag) {
3078 case TY_INT:
3079 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003080 case TY_SHORT:
3081 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003082 case TY_CHAR:
3083 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003084 case TY_FLOAT:
3085 return 4;
3086 case TY_DOUBLE:
3087 return 8;
3088 case TY_POINTER:
3089 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003090 case TY_ARRAY:
3091 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003092 case TY_STRUCT:
3093 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003094 default:
3095 error("Unsupported type %d", pType->tag);
3096 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003097 }
3098 }
3099
Jack Palevich21a15a22009-05-11 14:49:29 -07003100 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003101
3102 /** Output 1 to 4 bytes.
3103 *
3104 */
3105 void o(int n) {
3106 /* cannot use unsigned, so we must do a hack */
3107 while (n && n != -1) {
3108 ob(n & 0xff);
3109 n = n >> 8;
3110 }
3111 }
3112
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003113 /* Output exactly 2 bytes
3114 */
3115 void o2(int n) {
3116 ob(n & 0xff);
3117 ob(0xff & (n >> 8));
3118 }
3119
Jack Paleviche7b59062009-05-19 17:12:17 -07003120 /* psym is used to put an instruction with a data field which is a
3121 reference to a symbol. It is in fact the same as oad ! */
3122 int psym(int n, int t) {
3123 return oad(n, t);
3124 }
3125
3126 /* instruction + address */
3127 int oad(int n, int t) {
3128 o(n);
3129 int result = getPC();
3130 o4(t);
3131 return result;
3132 }
3133
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003134 static const int operatorHelper[];
3135
3136 int decodeOp(int op) {
3137 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003138 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003139 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003140 }
3141 return operatorHelper[op];
3142 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003143
Jack Palevich546b2242009-05-13 15:10:04 -07003144 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003145 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003146 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003147 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003148
3149 void setupFloatOperands() {
3150 Type* pR0Type = getR0Type();
3151 Type* pTOSType = getTOSType();
3152 TypeTag tagR0 = pR0Type->tag;
3153 TypeTag tagTOS = pTOSType->tag;
3154 bool isFloatR0 = isFloatTag(tagR0);
3155 bool isFloatTOS = isFloatTag(tagTOS);
3156 if (! isFloatR0) {
3157 // Convert R0 from int to float
3158 o(0x50); // push %eax
3159 o(0x2404DB); // fildl 0(%esp)
3160 o(0x58); // pop %eax
3161 }
3162 if (! isFloatTOS){
3163 o(0x2404DB); // fildl 0(%esp);
3164 o(0x58); // pop %eax
3165 } else {
3166 if (tagTOS == TY_FLOAT) {
3167 o(0x2404d9); // flds (%esp)
3168 o(0x58); // pop %eax
3169 } else {
3170 o(0x2404dd); // fldl (%esp)
3171 o(0x58); // pop %eax
3172 o(0x58); // pop %eax
3173 }
3174 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003175 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003176 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003177 };
3178
Jack Paleviche7b59062009-05-19 17:12:17 -07003179#endif // PROVIDE_X86_CODEGEN
3180
Jack Palevichb67b18f2009-06-11 21:12:23 -07003181#ifdef PROVIDE_TRACE_CODEGEN
3182 class TraceCodeGenerator : public CodeGenerator {
3183 private:
3184 CodeGenerator* mpBase;
3185
3186 public:
3187 TraceCodeGenerator(CodeGenerator* pBase) {
3188 mpBase = pBase;
3189 }
3190
3191 virtual ~TraceCodeGenerator() {
3192 delete mpBase;
3193 }
3194
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003195 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003196 mpBase->init(pCodeBuf);
3197 }
3198
3199 void setErrorSink(ErrorSink* pErrorSink) {
3200 mpBase->setErrorSink(pErrorSink);
3201 }
3202
3203 /* returns address to patch with local variable size
3204 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003205 virtual int functionEntry(Type* pDecl) {
3206 int result = mpBase->functionEntry(pDecl);
3207 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003208 return result;
3209 }
3210
Jack Palevichb7718b92009-07-09 22:00:24 -07003211 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3212 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3213 localVariableAddress, localVariableSize);
3214 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003215 }
3216
3217 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003218 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003219 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003220 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003221 }
3222
Jack Palevich1a539db2009-07-08 13:04:41 -07003223 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003224 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003225 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003226 }
3227
Jack Palevich9221bcc2009-08-26 16:15:07 -07003228 virtual void addStructOffsetR0(int offset, Type* pType) {
3229 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3230 mpBase->addStructOffsetR0(offset, pType);
3231 }
3232
Jack Palevichb67b18f2009-06-11 21:12:23 -07003233 virtual int gjmp(int t) {
3234 int result = mpBase->gjmp(t);
3235 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3236 return result;
3237 }
3238
3239 /* l = 0: je, l == 1: jne */
3240 virtual int gtst(bool l, int t) {
3241 int result = mpBase->gtst(l, t);
3242 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3243 return result;
3244 }
3245
Jack Palevich58c30ee2009-07-17 16:35:23 -07003246 virtual void gcmp(int op) {
3247 fprintf(stderr, "gcmp(%d)\n", op);
3248 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003249 }
3250
3251 virtual void genOp(int op) {
3252 fprintf(stderr, "genOp(%d)\n", op);
3253 mpBase->genOp(op);
3254 }
3255
Jack Palevich9eed7a22009-07-06 17:24:34 -07003256
Jack Palevich58c30ee2009-07-17 16:35:23 -07003257 virtual void gUnaryCmp(int op) {
3258 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3259 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003260 }
3261
3262 virtual void genUnaryOp(int op) {
3263 fprintf(stderr, "genUnaryOp(%d)\n", op);
3264 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003265 }
3266
3267 virtual void pushR0() {
3268 fprintf(stderr, "pushR0()\n");
3269 mpBase->pushR0();
3270 }
3271
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003272 virtual void over() {
3273 fprintf(stderr, "over()\n");
3274 mpBase->over();
3275 }
3276
Jack Palevich58c30ee2009-07-17 16:35:23 -07003277 virtual void popR0() {
3278 fprintf(stderr, "popR0()\n");
3279 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003280 }
3281
Jack Palevich58c30ee2009-07-17 16:35:23 -07003282 virtual void storeR0ToTOS() {
3283 fprintf(stderr, "storeR0ToTOS()\n");
3284 mpBase->storeR0ToTOS();
3285 }
3286
3287 virtual void loadR0FromR0() {
3288 fprintf(stderr, "loadR0FromR0()\n");
3289 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003290 }
3291
Jack Palevichb5e33312009-07-30 19:06:34 -07003292 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3293 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3294 pPointerType->pHead->tag, et);
3295 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003296 }
3297
Jack Palevich9f51a262009-07-29 16:22:26 -07003298 virtual int leaForward(int ea, Type* pPointerType) {
3299 fprintf(stderr, "leaForward(%d)\n", ea);
3300 return mpBase->leaForward(ea, pPointerType);
3301 }
3302
Jack Palevich30321cb2009-08-20 15:34:23 -07003303 virtual void convertR0Imp(Type* pType, bool isCast){
3304 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3305 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003306 }
3307
3308 virtual int beginFunctionCallArguments() {
3309 int result = mpBase->beginFunctionCallArguments();
3310 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3311 return result;
3312 }
3313
Jack Palevich8148c5b2009-07-16 18:24:47 -07003314 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3315 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3316 pArgType->tag);
3317 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003318 }
3319
Jack Palevichb7718b92009-07-09 22:00:24 -07003320 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003321 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003322 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003323 }
3324
Jack Palevich8df46192009-07-07 14:48:51 -07003325 virtual int callForward(int symbol, Type* pFunc) {
3326 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003327 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3328 return result;
3329 }
3330
Jack Palevich8df46192009-07-07 14:48:51 -07003331 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003332 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3333 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003334 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003335 }
3336
Jack Palevichb7718b92009-07-09 22:00:24 -07003337 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3338 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3339 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003340 }
3341
3342 virtual int jumpOffset() {
3343 return mpBase->jumpOffset();
3344 }
3345
Jack Palevichb67b18f2009-06-11 21:12:23 -07003346 /* output a symbol and patch all calls to it */
3347 virtual void gsym(int t) {
3348 fprintf(stderr, "gsym(%d)\n", t);
3349 mpBase->gsym(t);
3350 }
3351
Jack Palevich9f51a262009-07-29 16:22:26 -07003352 virtual void resolveForward(int t) {
3353 mpBase->resolveForward(t);
3354 }
3355
Jack Palevichb67b18f2009-06-11 21:12:23 -07003356 virtual int finishCompile() {
3357 int result = mpBase->finishCompile();
3358 fprintf(stderr, "finishCompile() = %d\n", result);
3359 return result;
3360 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003361
3362 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003363 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003364 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003365 virtual size_t alignmentOf(Type* pType){
3366 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003367 }
3368
3369 /**
3370 * Array element alignment (in bytes) for this type of data.
3371 */
3372 virtual size_t sizeOf(Type* pType){
3373 return mpBase->sizeOf(pType);
3374 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003375
3376 virtual Type* getR0Type() {
3377 return mpBase->getR0Type();
3378 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003379
3380 virtual ExpressionType getR0ExpressionType() {
3381 return mpBase->getR0ExpressionType();
3382 }
3383
3384 virtual void setR0ExpressionType(ExpressionType et) {
3385 mpBase->setR0ExpressionType(et);
3386 }
3387
3388 virtual size_t getExpressionStackDepth() {
3389 return mpBase->getExpressionStackDepth();
3390 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003391
3392 virtual void forceR0RVal() {
3393 return mpBase->forceR0RVal();
3394 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003395 };
3396
3397#endif // PROVIDE_TRACE_CODEGEN
3398
Jack Palevich569f1352009-06-29 14:29:08 -07003399 class Arena {
3400 public:
3401 // Used to record a given allocation amount.
3402 // Used:
3403 // Mark mark = arena.mark();
3404 // ... lots of arena.allocate()
3405 // arena.free(mark);
3406
3407 struct Mark {
3408 size_t chunk;
3409 size_t offset;
3410 };
3411
3412 Arena() {
3413 mCurrentChunk = 0;
3414 Chunk start(CHUNK_SIZE);
3415 mData.push_back(start);
3416 }
3417
3418 ~Arena() {
3419 for(size_t i = 0; i < mData.size(); i++) {
3420 mData[i].free();
3421 }
3422 }
3423
3424 // Alloc using the standard alignment size safe for any variable
3425 void* alloc(size_t size) {
3426 return alloc(size, 8);
3427 }
3428
3429 Mark mark(){
3430 Mark result;
3431 result.chunk = mCurrentChunk;
3432 result.offset = mData[mCurrentChunk].mOffset;
3433 return result;
3434 }
3435
3436 void freeToMark(const Mark& mark) {
3437 mCurrentChunk = mark.chunk;
3438 mData[mCurrentChunk].mOffset = mark.offset;
3439 }
3440
3441 private:
3442 // Allocate memory aligned to a given size
3443 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3444 // Memory is not zero filled.
3445
3446 void* alloc(size_t size, size_t alignment) {
3447 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3448 if (mCurrentChunk + 1 < mData.size()) {
3449 mCurrentChunk++;
3450 } else {
3451 size_t allocSize = CHUNK_SIZE;
3452 if (allocSize < size + alignment - 1) {
3453 allocSize = size + alignment - 1;
3454 }
3455 Chunk chunk(allocSize);
3456 mData.push_back(chunk);
3457 mCurrentChunk++;
3458 }
3459 }
3460 return mData[mCurrentChunk].allocate(size, alignment);
3461 }
3462
3463 static const size_t CHUNK_SIZE = 128*1024;
3464 // Note: this class does not deallocate its
3465 // memory when it's destroyed. It depends upon
3466 // its parent to deallocate the memory.
3467 struct Chunk {
3468 Chunk() {
3469 mpData = 0;
3470 mSize = 0;
3471 mOffset = 0;
3472 }
3473
3474 Chunk(size_t size) {
3475 mSize = size;
3476 mpData = (char*) malloc(size);
3477 mOffset = 0;
3478 }
3479
3480 ~Chunk() {
3481 // Doesn't deallocate memory.
3482 }
3483
3484 void* allocate(size_t size, size_t alignment) {
3485 size_t alignedOffset = aligned(mOffset, alignment);
3486 void* result = mpData + alignedOffset;
3487 mOffset = alignedOffset + size;
3488 return result;
3489 }
3490
3491 void free() {
3492 if (mpData) {
3493 ::free(mpData);
3494 mpData = 0;
3495 }
3496 }
3497
3498 size_t remainingCapacity(size_t alignment) {
3499 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3500 }
3501
3502 // Assume alignment is a power of two
3503 inline size_t aligned(size_t v, size_t alignment) {
3504 size_t mask = alignment-1;
3505 return (v + mask) & ~mask;
3506 }
3507
3508 char* mpData;
3509 size_t mSize;
3510 size_t mOffset;
3511 };
3512
3513 size_t mCurrentChunk;
3514
3515 Vector<Chunk> mData;
3516 };
3517
Jack Palevich569f1352009-06-29 14:29:08 -07003518 struct VariableInfo;
3519
3520 struct Token {
3521 int hash;
3522 size_t length;
3523 char* pText;
3524 tokenid_t id;
3525
3526 // Current values for the token
3527 char* mpMacroDefinition;
3528 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003529 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003530 };
3531
3532 class TokenTable {
3533 public:
3534 // Don't use 0..0xff, allows characters and operators to be tokens too.
3535
3536 static const int TOKEN_BASE = 0x100;
3537 TokenTable() {
3538 mpMap = hashmapCreate(128, hashFn, equalsFn);
3539 }
3540
3541 ~TokenTable() {
3542 hashmapFree(mpMap);
3543 }
3544
3545 void setArena(Arena* pArena) {
3546 mpArena = pArena;
3547 }
3548
3549 // Returns a token for a given string of characters.
3550 tokenid_t intern(const char* pText, size_t length) {
3551 Token probe;
3552 int hash = hashmapHash((void*) pText, length);
3553 {
3554 Token probe;
3555 probe.hash = hash;
3556 probe.length = length;
3557 probe.pText = (char*) pText;
3558 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3559 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003560 return pValue->id;
3561 }
3562 }
3563
3564 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3565 memset(pToken, 0, sizeof(*pToken));
3566 pToken->hash = hash;
3567 pToken->length = length;
3568 pToken->pText = (char*) mpArena->alloc(length + 1);
3569 memcpy(pToken->pText, pText, length);
3570 pToken->pText[length] = 0;
3571 pToken->id = mTokens.size() + TOKEN_BASE;
3572 mTokens.push_back(pToken);
3573 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003574 return pToken->id;
3575 }
3576
3577 // Return the Token for a given tokenid.
3578 Token& operator[](tokenid_t id) {
3579 return *mTokens[id - TOKEN_BASE];
3580 }
3581
3582 inline size_t size() {
3583 return mTokens.size();
3584 }
3585
3586 private:
3587
3588 static int hashFn(void* pKey) {
3589 Token* pToken = (Token*) pKey;
3590 return pToken->hash;
3591 }
3592
3593 static bool equalsFn(void* keyA, void* keyB) {
3594 Token* pTokenA = (Token*) keyA;
3595 Token* pTokenB = (Token*) keyB;
3596 // Don't need to compare hash values, they should always be equal
3597 return pTokenA->length == pTokenB->length
3598 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3599 }
3600
3601 Hashmap* mpMap;
3602 Vector<Token*> mTokens;
3603 Arena* mpArena;
3604 };
3605
Jack Palevich1cdef202009-05-22 12:06:27 -07003606 class InputStream {
3607 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003608 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003609 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003610 };
3611
3612 class TextInputStream : public InputStream {
3613 public:
3614 TextInputStream(const char* text, size_t textLength)
3615 : pText(text), mTextLength(textLength), mPosition(0) {
3616 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003617
Jack Palevichdc456462009-07-16 16:50:56 -07003618 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003619 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3620 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003621
Jack Palevichdc456462009-07-16 16:50:56 -07003622 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003623 const char* pText;
3624 size_t mTextLength;
3625 size_t mPosition;
3626 };
3627
Jack Palevicheedf9d22009-06-04 16:23:40 -07003628 class String {
3629 public:
3630 String() {
3631 mpBase = 0;
3632 mUsed = 0;
3633 mSize = 0;
3634 }
3635
Jack Palevich303d8ff2009-06-11 19:06:24 -07003636 String(const char* item, int len, bool adopt) {
3637 if (len < 0) {
3638 len = strlen(item);
3639 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003640 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003641 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003642 mUsed = len;
3643 mSize = len + 1;
3644 } else {
3645 mpBase = 0;
3646 mUsed = 0;
3647 mSize = 0;
3648 appendBytes(item, len);
3649 }
3650 }
3651
Jack Palevich303d8ff2009-06-11 19:06:24 -07003652 String(const String& other) {
3653 mpBase = 0;
3654 mUsed = 0;
3655 mSize = 0;
3656 appendBytes(other.getUnwrapped(), other.len());
3657 }
3658
Jack Palevicheedf9d22009-06-04 16:23:40 -07003659 ~String() {
3660 if (mpBase) {
3661 free(mpBase);
3662 }
3663 }
3664
Jack Palevicha6baa232009-06-12 11:25:59 -07003665 String& operator=(const String& other) {
3666 clear();
3667 appendBytes(other.getUnwrapped(), other.len());
3668 return *this;
3669 }
3670
Jack Palevich303d8ff2009-06-11 19:06:24 -07003671 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003672 return mpBase;
3673 }
3674
Jack Palevich303d8ff2009-06-11 19:06:24 -07003675 void clear() {
3676 mUsed = 0;
3677 if (mSize > 0) {
3678 mpBase[0] = 0;
3679 }
3680 }
3681
Jack Palevicheedf9d22009-06-04 16:23:40 -07003682 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003683 appendBytes(s, strlen(s));
3684 }
3685
3686 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003687 memcpy(ensure(n), s, n + 1);
3688 }
3689
3690 void append(char c) {
3691 * ensure(1) = c;
3692 }
3693
Jack Palevich86351982009-06-30 18:09:56 -07003694 void append(String& other) {
3695 appendBytes(other.getUnwrapped(), other.len());
3696 }
3697
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003698 char* orphan() {
3699 char* result = mpBase;
3700 mpBase = 0;
3701 mUsed = 0;
3702 mSize = 0;
3703 return result;
3704 }
3705
Jack Palevicheedf9d22009-06-04 16:23:40 -07003706 void printf(const char* fmt,...) {
3707 va_list ap;
3708 va_start(ap, fmt);
3709 vprintf(fmt, ap);
3710 va_end(ap);
3711 }
3712
3713 void vprintf(const char* fmt, va_list ap) {
3714 char* temp;
3715 int numChars = vasprintf(&temp, fmt, ap);
3716 memcpy(ensure(numChars), temp, numChars+1);
3717 free(temp);
3718 }
3719
Jack Palevich303d8ff2009-06-11 19:06:24 -07003720 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003721 return mUsed;
3722 }
3723
3724 private:
3725 char* ensure(int n) {
3726 size_t newUsed = mUsed + n;
3727 if (newUsed > mSize) {
3728 size_t newSize = mSize * 2 + 10;
3729 if (newSize < newUsed) {
3730 newSize = newUsed;
3731 }
3732 mpBase = (char*) realloc(mpBase, newSize + 1);
3733 mSize = newSize;
3734 }
3735 mpBase[newUsed] = '\0';
3736 char* result = mpBase + mUsed;
3737 mUsed = newUsed;
3738 return result;
3739 }
3740
3741 char* mpBase;
3742 size_t mUsed;
3743 size_t mSize;
3744 };
3745
Jack Palevich569f1352009-06-29 14:29:08 -07003746 void internKeywords() {
3747 // Note: order has to match TOK_ constants
3748 static const char* keywords[] = {
3749 "int",
3750 "char",
3751 "void",
3752 "if",
3753 "else",
3754 "while",
3755 "break",
3756 "return",
3757 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003758 "auto",
3759 "case",
3760 "const",
3761 "continue",
3762 "default",
3763 "do",
3764 "double",
3765 "enum",
3766 "extern",
3767 "float",
3768 "goto",
3769 "long",
3770 "register",
3771 "short",
3772 "signed",
3773 "sizeof",
3774 "static",
3775 "struct",
3776 "switch",
3777 "typedef",
3778 "union",
3779 "unsigned",
3780 "volatile",
3781 "_Bool",
3782 "_Complex",
3783 "_Imaginary",
3784 "inline",
3785 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003786
3787 // predefined tokens that can also be symbols start here:
3788 "pragma",
3789 "define",
3790 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003791 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003792
Jack Palevich569f1352009-06-29 14:29:08 -07003793 for(int i = 0; keywords[i]; i++) {
3794 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003795 }
Jack Palevich569f1352009-06-29 14:29:08 -07003796 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003797
Jack Palevich36d94142009-06-08 15:55:32 -07003798 struct InputState {
3799 InputStream* pStream;
3800 int oldCh;
3801 };
3802
Jack Palevich2db168f2009-06-11 14:29:47 -07003803 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003804 void* pAddress;
3805 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003806 tokenid_t tok;
3807 size_t level;
3808 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003809 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003810 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003811 };
3812
Jack Palevich303d8ff2009-06-11 19:06:24 -07003813 class SymbolStack {
3814 public:
3815 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003816 mpArena = 0;
3817 mpTokenTable = 0;
3818 }
3819
3820 void setArena(Arena* pArena) {
3821 mpArena = pArena;
3822 }
3823
3824 void setTokenTable(TokenTable* pTokenTable) {
3825 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003826 }
3827
3828 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003829 Mark mark;
3830 mark.mArenaMark = mpArena->mark();
3831 mark.mSymbolHead = mStack.size();
3832 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003833 }
3834
3835 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003836 // Undo any shadowing that was done:
3837 Mark mark = mLevelStack.back();
3838 mLevelStack.pop_back();
3839 while (mStack.size() > mark.mSymbolHead) {
3840 VariableInfo* pV = mStack.back();
3841 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003842 if (pV->isStructTag) {
3843 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3844 } else {
3845 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3846 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003847 }
Jack Palevich569f1352009-06-29 14:29:08 -07003848 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003849 }
3850
Jack Palevich569f1352009-06-29 14:29:08 -07003851 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3852 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3853 return pV && pV->level == level();
3854 }
3855
Jack Palevich9221bcc2009-08-26 16:15:07 -07003856 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3857 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3858 return pV && pV->level == level();
3859 }
3860
Jack Palevich569f1352009-06-29 14:29:08 -07003861 VariableInfo* add(tokenid_t tok) {
3862 Token& token = (*mpTokenTable)[tok];
3863 VariableInfo* pOldV = token.mpVariableInfo;
3864 VariableInfo* pNewV =
3865 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3866 memset(pNewV, 0, sizeof(VariableInfo));
3867 pNewV->tok = tok;
3868 pNewV->level = level();
3869 pNewV->pOldDefinition = pOldV;
3870 token.mpVariableInfo = pNewV;
3871 mStack.push_back(pNewV);
3872 return pNewV;
3873 }
3874
Jack Palevich9221bcc2009-08-26 16:15:07 -07003875 VariableInfo* addStructTag(tokenid_t tok) {
3876 Token& token = (*mpTokenTable)[tok];
3877 VariableInfo* pOldS = token.mpStructInfo;
3878 VariableInfo* pNewS =
3879 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3880 memset(pNewS, 0, sizeof(VariableInfo));
3881 pNewS->tok = tok;
3882 pNewS->level = level();
3883 pNewS->isStructTag = true;
3884 pNewS->pOldDefinition = pOldS;
3885 token.mpStructInfo = pNewS;
3886 mStack.push_back(pNewS);
3887 return pNewS;
3888 }
3889
Jack Palevich86351982009-06-30 18:09:56 -07003890 VariableInfo* add(Type* pType) {
3891 VariableInfo* pVI = add(pType->id);
3892 pVI->pType = pType;
3893 return pVI;
3894 }
3895
Jack Palevich569f1352009-06-29 14:29:08 -07003896 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3897 for (size_t i = 0; i < mStack.size(); i++) {
3898 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003899 break;
3900 }
3901 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003902 }
3903
Jack Palevich303d8ff2009-06-11 19:06:24 -07003904 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003905 inline size_t level() {
3906 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003907 }
3908
Jack Palevich569f1352009-06-29 14:29:08 -07003909 struct Mark {
3910 Arena::Mark mArenaMark;
3911 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003912 };
3913
Jack Palevich569f1352009-06-29 14:29:08 -07003914 Arena* mpArena;
3915 TokenTable* mpTokenTable;
3916 Vector<VariableInfo*> mStack;
3917 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003918 };
Jack Palevich36d94142009-06-08 15:55:32 -07003919
Jack Palevich188a5a72009-10-27 17:23:20 -07003920 struct MacroState {
3921 tokenid_t name; // Name of the current macro we are expanding
3922 char* dptr; // point to macro text during macro playback
3923 int dch; // Saves old value of ch during a macro playback
3924 };
3925
3926#define MACRO_NESTING_MAX 32
3927 MacroState macroState[MACRO_NESTING_MAX];
3928 int macroLevel; // -1 means not playing any macro.
3929
Jack Palevich36d94142009-06-08 15:55:32 -07003930 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003931 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003932 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003933 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003934 int tokl; // token operator level
3935 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003936 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003937 intptr_t loc; // local variable index
3938 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003939 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003940 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003941 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003942 ACCSymbolLookupFn mpSymbolLookupFn;
3943 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003944
3945 // Arena for the duration of the compile
3946 Arena mGlobalArena;
3947 // Arena for data that's only needed when compiling a single function
3948 Arena mLocalArena;
3949
Jack Palevich2ff5c222009-07-23 15:11:22 -07003950 Arena* mpCurrentArena;
3951
Jack Palevich569f1352009-06-29 14:29:08 -07003952 TokenTable mTokenTable;
3953 SymbolStack mGlobals;
3954 SymbolStack mLocals;
3955
Jack Palevich9221bcc2009-08-26 16:15:07 -07003956 SymbolStack* mpCurrentSymbolStack;
3957
Jack Palevich40600de2009-07-01 15:32:35 -07003958 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003959 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003960 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003961 Type* mkpChar; // char
3962 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003963 Type* mkpFloat;
3964 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003965 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003966 Type* mkpIntPtr;
3967 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003968 Type* mkpFloatPtr;
3969 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003970 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003971
Jack Palevich36d94142009-06-08 15:55:32 -07003972 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003973 int mLineNumber;
3974 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003975
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003976 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003977 CodeGenerator* pGen;
3978
Jack Palevicheedf9d22009-06-04 16:23:40 -07003979 String mErrorBuf;
3980
Jack Palevicheedf9d22009-06-04 16:23:40 -07003981 String mPragmas;
3982 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003983 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003984
Jack Palevich21a15a22009-05-11 14:49:29 -07003985 static const int ALLOC_SIZE = 99999;
3986
Jack Palevich303d8ff2009-06-11 19:06:24 -07003987 static const int TOK_DUMMY = 1;
3988 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003989 static const int TOK_NUM_FLOAT = 3;
3990 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003991 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003992 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003993
3994 // 3..255 are character and/or operators
3995
Jack Palevich2db168f2009-06-11 14:29:47 -07003996 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003997 // Order has to match string list in "internKeywords".
3998 enum {
3999 TOK_KEYWORD = TokenTable::TOKEN_BASE,
4000 TOK_INT = TOK_KEYWORD,
4001 TOK_CHAR,
4002 TOK_VOID,
4003 TOK_IF,
4004 TOK_ELSE,
4005 TOK_WHILE,
4006 TOK_BREAK,
4007 TOK_RETURN,
4008 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07004009 TOK_AUTO,
4010 TOK_CASE,
4011 TOK_CONST,
4012 TOK_CONTINUE,
4013 TOK_DEFAULT,
4014 TOK_DO,
4015 TOK_DOUBLE,
4016 TOK_ENUM,
4017 TOK_EXTERN,
4018 TOK_FLOAT,
4019 TOK_GOTO,
4020 TOK_LONG,
4021 TOK_REGISTER,
4022 TOK_SHORT,
4023 TOK_SIGNED,
4024 TOK_SIZEOF,
4025 TOK_STATIC,
4026 TOK_STRUCT,
4027 TOK_SWITCH,
4028 TOK_TYPEDEF,
4029 TOK_UNION,
4030 TOK_UNSIGNED,
4031 TOK_VOLATILE,
4032 TOK__BOOL,
4033 TOK__COMPLEX,
4034 TOK__IMAGINARY,
4035 TOK_INLINE,
4036 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004037
4038 // Symbols start after keywords
4039
4040 TOK_SYMBOL,
4041 TOK_PRAGMA = TOK_SYMBOL,
4042 TOK_DEFINE,
4043 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004044 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004045
4046 static const int LOCAL = 0x200;
4047
Jack Palevich21a15a22009-05-11 14:49:29 -07004048 /* tokens in string heap */
4049 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004050
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004051 static const int OP_INCREMENT = 0;
4052 static const int OP_DECREMENT = 1;
4053 static const int OP_MUL = 2;
4054 static const int OP_DIV = 3;
4055 static const int OP_MOD = 4;
4056 static const int OP_PLUS = 5;
4057 static const int OP_MINUS = 6;
4058 static const int OP_SHIFT_LEFT = 7;
4059 static const int OP_SHIFT_RIGHT = 8;
4060 static const int OP_LESS_EQUAL = 9;
4061 static const int OP_GREATER_EQUAL = 10;
4062 static const int OP_LESS = 11;
4063 static const int OP_GREATER = 12;
4064 static const int OP_EQUALS = 13;
4065 static const int OP_NOT_EQUALS = 14;
4066 static const int OP_LOGICAL_AND = 15;
4067 static const int OP_LOGICAL_OR = 16;
4068 static const int OP_BIT_AND = 17;
4069 static const int OP_BIT_XOR = 18;
4070 static const int OP_BIT_OR = 19;
4071 static const int OP_BIT_NOT = 20;
4072 static const int OP_LOGICAL_NOT = 21;
4073 static const int OP_COUNT = 22;
4074
4075 /* Operators are searched from front, the two-character operators appear
4076 * before the single-character operators with the same first character.
4077 * @ is used to pad out single-character operators.
4078 */
4079 static const char* operatorChars;
4080 static const char operatorLevel[];
4081
Jack Palevich569f1352009-06-29 14:29:08 -07004082 /* Called when we detect an internal problem. Does nothing in production.
4083 *
4084 */
4085 void internalError() {
4086 * (char*) 0 = 0;
4087 }
4088
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004089 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004090 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004091 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004092 internalError();
4093 }
Jack Palevich86351982009-06-30 18:09:56 -07004094 }
4095
Jack Palevich40600de2009-07-01 15:32:35 -07004096 bool isSymbol(tokenid_t t) {
4097 return t >= TOK_SYMBOL &&
4098 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4099 }
4100
4101 bool isSymbolOrKeyword(tokenid_t t) {
4102 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004103 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004104 }
4105
Jack Palevich86351982009-06-30 18:09:56 -07004106 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004107 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004108 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4109 if (pV && pV->tok != t) {
4110 internalError();
4111 }
4112 return pV;
4113 }
4114
4115 inline bool isDefined(tokenid_t t) {
4116 return t >= TOK_SYMBOL && VI(t) != 0;
4117 }
4118
Jack Palevich40600de2009-07-01 15:32:35 -07004119 const char* nameof(tokenid_t t) {
4120 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004121 return mTokenTable[t].pText;
4122 }
4123
Jack Palevich21a15a22009-05-11 14:49:29 -07004124 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004125 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004126 }
4127
4128 void inp() {
Jack Palevich188a5a72009-10-27 17:23:20 -07004129 // Close any totally empty macros. We leave them on the stack until now
4130 // so that we know which macros are being expanded when checking if the
4131 // last token in the macro is a macro that's already being expanded.
4132 while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
4133 macroLevel--;
4134 }
4135 if (macroLevel >= 0) {
4136 ch = *macroState[macroLevel].dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004137 if (ch == 0) {
Jack Palevich188a5a72009-10-27 17:23:20 -07004138 ch = macroState[macroLevel].dch;
4139 macroState[macroLevel].dptr = NULL; // This macro's done
Jack Palevich21a15a22009-05-11 14:49:29 -07004140 }
Jack Palevichdc456462009-07-16 16:50:56 -07004141 } else {
4142 if (mbBumpLine) {
4143 mLineNumber++;
4144 mbBumpLine = false;
4145 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004146 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004147 if (ch == '\n') {
4148 mbBumpLine = true;
4149 }
4150 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004151#if 0
4152 printf("ch='%c' 0x%x\n", ch, ch);
4153#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 }
4155
4156 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004157 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004158 }
4159
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004160 int decodeHex(int c) {
4161 if (isdigit(c)) {
4162 c -= '0';
4163 } else if (c <= 'F') {
4164 c = c - 'A' + 10;
4165 } else {
4166 c =c - 'a' + 10;
4167 }
4168 return c;
4169 }
4170
Jack Palevichb4758ff2009-06-12 12:49:14 -07004171 /* read a character constant, advances ch to after end of constant */
4172 int getq() {
4173 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004174 if (ch == '\\') {
4175 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004176 if (isoctal(ch)) {
4177 // 1 to 3 octal characters.
4178 val = 0;
4179 for(int i = 0; i < 3; i++) {
4180 if (isoctal(ch)) {
4181 val = (val << 3) + ch - '0';
4182 inp();
4183 }
4184 }
4185 return val;
4186 } else if (ch == 'x' || ch == 'X') {
4187 // N hex chars
4188 inp();
4189 if (! isxdigit(ch)) {
4190 error("'x' character escape requires at least one digit.");
4191 } else {
4192 val = 0;
4193 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004194 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004195 inp();
4196 }
4197 }
4198 } else {
4199 int val = ch;
4200 switch (ch) {
4201 case 'a':
4202 val = '\a';
4203 break;
4204 case 'b':
4205 val = '\b';
4206 break;
4207 case 'f':
4208 val = '\f';
4209 break;
4210 case 'n':
4211 val = '\n';
4212 break;
4213 case 'r':
4214 val = '\r';
4215 break;
4216 case 't':
4217 val = '\t';
4218 break;
4219 case 'v':
4220 val = '\v';
4221 break;
4222 case '\\':
4223 val = '\\';
4224 break;
4225 case '\'':
4226 val = '\'';
4227 break;
4228 case '"':
4229 val = '"';
4230 break;
4231 case '?':
4232 val = '?';
4233 break;
4234 default:
4235 error("Undefined character escape %c", ch);
4236 break;
4237 }
4238 inp();
4239 return val;
4240 }
4241 } else {
4242 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004243 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004244 return val;
4245 }
4246
4247 static bool isoctal(int ch) {
4248 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004249 }
4250
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004251 bool acceptCh(int c) {
4252 bool result = c == ch;
4253 if (result) {
4254 pdef(ch);
4255 inp();
4256 }
4257 return result;
4258 }
4259
4260 bool acceptDigitsCh() {
4261 bool result = false;
4262 while (isdigit(ch)) {
4263 result = true;
4264 pdef(ch);
4265 inp();
4266 }
4267 return result;
4268 }
4269
4270 void parseFloat() {
4271 tok = TOK_NUM_DOUBLE;
4272 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004273 if(mTokenString.len() == 0) {
4274 mTokenString.append('0');
4275 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004276 acceptCh('.');
4277 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004278 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004279 acceptCh('-') || acceptCh('+');
4280 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004281 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004282 if (ch == 'f' || ch == 'F') {
4283 tok = TOK_NUM_FLOAT;
4284 inp();
4285 } else if (ch == 'l' || ch == 'L') {
4286 inp();
4287 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004288 }
4289 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004290 char* pEnd = pText + strlen(pText);
4291 char* pEndPtr = 0;
4292 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004293 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004294 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004295 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004296 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004297 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004298 if (errno || pEndPtr != pEnd) {
4299 error("Can't parse constant: %s", pText);
4300 }
4301 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004302 }
4303
Jack Palevich188a5a72009-10-27 17:23:20 -07004304 bool currentlyBeingExpanded(tokenid_t id) {
4305 for (int i = 0; i <= macroLevel; i++) {
4306 if (macroState[macroLevel].name == id) {
4307 return true;
4308 }
4309 }
4310 return false;
4311 }
4312
Jack Palevich21a15a22009-05-11 14:49:29 -07004313 void next() {
4314 int l, a;
4315
Jack Palevich546b2242009-05-13 15:10:04 -07004316 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004317 if (ch == '#') {
4318 inp();
4319 next();
4320 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004321 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004322 } else if (tok == TOK_PRAGMA) {
4323 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004324 } else if (tok == TOK_LINE) {
4325 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004326 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004327 error("Unsupported preprocessor directive \"%s\"",
4328 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004329 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004330 }
4331 inp();
4332 }
4333 tokl = 0;
4334 tok = ch;
4335 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004336 if (isdigit(ch) || ch == '.') {
4337 // Start of a numeric constant. Could be integer, float, or
4338 // double, won't know until we look further.
4339 mTokenString.clear();
4340 pdef(ch);
4341 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004342 if (tok == '.' && !isdigit(ch)) {
4343 goto done;
4344 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004345 int base = 10;
4346 if (tok == '0') {
4347 if (ch == 'x' || ch == 'X') {
4348 base = 16;
4349 tok = TOK_NUM;
4350 tokc = 0;
4351 inp();
4352 while ( isxdigit(ch) ) {
4353 tokc = (tokc << 4) + decodeHex(ch);
4354 inp();
4355 }
4356 } else if (isoctal(ch)){
4357 base = 8;
4358 tok = TOK_NUM;
4359 tokc = 0;
4360 while ( isoctal(ch) ) {
4361 tokc = (tokc << 3) + (ch - '0');
4362 inp();
4363 }
4364 }
4365 } else if (isdigit(tok)){
4366 acceptDigitsCh();
4367 }
4368 if (base == 10) {
4369 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4370 parseFloat();
4371 } else {
4372 // It's an integer constant
4373 char* pText = mTokenString.getUnwrapped();
4374 char* pEnd = pText + strlen(pText);
4375 char* pEndPtr = 0;
4376 errno = 0;
4377 tokc = strtol(pText, &pEndPtr, base);
4378 if (errno || pEndPtr != pEnd) {
4379 error("Can't parse constant: %s %d %d", pText, base, errno);
4380 }
4381 tok = TOK_NUM;
4382 }
4383 }
4384 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004385 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004386 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004387 pdef(ch);
4388 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004389 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004390 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004391 if (! mbSuppressMacroExpansion) {
4392 // Is this a macro?
4393 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
Jack Palevich188a5a72009-10-27 17:23:20 -07004394 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
Jack Palevich815d8b82009-08-18 18:25:56 -07004395 // Yes, it is a macro
Jack Palevich188a5a72009-10-27 17:23:20 -07004396#if 0
4397 printf("Expanding macro %s -> %s",
4398 mTokenString.getUnwrapped(), pMacroDefinition);
4399#endif
4400 if (macroLevel >= MACRO_NESTING_MAX-1) {
4401 error("Too many levels of macro recursion.");
4402 } else {
4403 macroLevel++;
4404 macroState[macroLevel].name = tok;
4405 macroState[macroLevel].dptr = pMacroDefinition;
4406 macroState[macroLevel].dch = ch;
4407 inp();
4408 next();
4409 }
Jack Palevich815d8b82009-08-18 18:25:56 -07004410 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004411 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004412 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004413 inp();
4414 if (tok == '\'') {
4415 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004416 tokc = getq();
4417 if (ch != '\'') {
4418 error("Expected a ' character, got %c", ch);
4419 } else {
4420 inp();
4421 }
Jack Palevich546b2242009-05-13 15:10:04 -07004422 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004423 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004424 while (ch && ch != EOF) {
4425 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004426 inp();
4427 inp();
4428 if (ch == '/')
4429 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004430 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004431 if (ch == EOF) {
4432 error("End of file inside comment.");
4433 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004434 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004435 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004436 } else if ((tok == '/') & (ch == '/')) {
4437 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004438 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004439 inp();
4440 }
4441 inp();
4442 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004443 } else if ((tok == '-') & (ch == '>')) {
4444 inp();
4445 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004446 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004447 const char* t = operatorChars;
4448 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004449 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004450 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004451 tokl = operatorLevel[opIndex];
4452 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004453 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004454#if 0
4455 printf("%c%c -> tokl=%d tokc=0x%x\n",
4456 l, a, tokl, tokc);
4457#endif
4458 if (a == ch) {
4459 inp();
4460 tok = TOK_DUMMY; /* dummy token for double tokens */
4461 }
Jack Palevich0c017742009-07-31 12:00:39 -07004462 /* check for op=, valid for * / % + - << >> & ^ | */
4463 if (ch == '=' &&
4464 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004465 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004466 inp();
4467 tok = TOK_OP_ASSIGNMENT;
4468 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004469 break;
4470 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004471 opIndex++;
4472 }
4473 if (l == 0) {
4474 tokl = 0;
4475 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004476 }
4477 }
4478 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004479
4480 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004481#if 0
4482 {
Jack Palevich569f1352009-06-29 14:29:08 -07004483 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004484 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004485 fprintf(stderr, "%s\n", buf.getUnwrapped());
4486 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004487#endif
4488 }
4489
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004490 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004491 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004492 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004493 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004494 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004495 if (ch == '(') {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004496 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004497 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004498 }
4499 while (isspace(ch)) {
4500 inp();
4501 }
Jack Palevich569f1352009-06-29 14:29:08 -07004502 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004503 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004504 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004505 // Check for '//' comments.
4506 if (appendToValue && ch == '/') {
4507 inp();
4508 if (ch == '/') {
4509 appendToValue = false;
4510 } else {
4511 value.append('/');
4512 }
4513 }
4514 if (appendToValue && ch != EOF) {
4515 value.append(ch);
4516 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004517 inp();
4518 }
Jack Palevich569f1352009-06-29 14:29:08 -07004519 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4520 memcpy(pDefn, value.getUnwrapped(), value.len());
4521 pDefn[value.len()] = 0;
4522 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich188a5a72009-10-27 17:23:20 -07004523#if 0
4524 {
4525 String buf;
4526 decodeToken(buf, name, true);
4527 fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
4528 }
4529#endif
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004530 }
4531
Jack Palevicheedf9d22009-06-04 16:23:40 -07004532 void doPragma() {
4533 // # pragma name(val)
4534 int state = 0;
4535 while(ch != EOF && ch != '\n' && state < 10) {
4536 switch(state) {
4537 case 0:
4538 if (isspace(ch)) {
4539 inp();
4540 } else {
4541 state++;
4542 }
4543 break;
4544 case 1:
4545 if (isalnum(ch)) {
4546 mPragmas.append(ch);
4547 inp();
4548 } else if (ch == '(') {
4549 mPragmas.append(0);
4550 inp();
4551 state++;
4552 } else {
4553 state = 11;
4554 }
4555 break;
4556 case 2:
4557 if (isalnum(ch)) {
4558 mPragmas.append(ch);
4559 inp();
4560 } else if (ch == ')') {
4561 mPragmas.append(0);
4562 inp();
4563 state = 10;
4564 } else {
4565 state = 11;
4566 }
4567 break;
4568 }
4569 }
4570 if(state != 10) {
4571 error("Unexpected pragma syntax");
4572 }
4573 mPragmaStringCount += 2;
4574 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004575
Jack Palevichdc456462009-07-16 16:50:56 -07004576 void doLine() {
4577 // # line number { "filename "}
4578 next();
4579 if (tok != TOK_NUM) {
4580 error("Expected a line-number");
4581 } else {
4582 mLineNumber = tokc-1; // The end-of-line will increment it.
4583 }
4584 while(ch != EOF && ch != '\n') {
4585 inp();
4586 }
4587 }
4588
Jack Palevichac0e95e2009-05-29 13:53:44 -07004589 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004590 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004591 mErrorBuf.vprintf(fmt, ap);
4592 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004593 }
4594
Jack Palevich8b0624c2009-05-20 12:12:06 -07004595 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004596 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004597 error("'%c' expected", c);
4598 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004599 }
4600
Jack Palevich86351982009-06-30 18:09:56 -07004601 bool accept(intptr_t c) {
4602 if (tok == c) {
4603 next();
4604 return true;
4605 }
4606 return false;
4607 }
4608
Jack Palevich40600de2009-07-01 15:32:35 -07004609 bool acceptStringLiteral() {
4610 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004611 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004612 // This while loop merges multiple adjacent string constants.
4613 while (tok == '"') {
4614 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004615 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004616 }
4617 if (ch != '"') {
4618 error("Unterminated string constant.");
4619 }
4620 inp();
4621 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004622 }
Jack Palevich40600de2009-07-01 15:32:35 -07004623 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004624 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004625 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004626 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004627
4628 return true;
4629 }
4630 return false;
4631 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004632
Jack Palevichb1544ca2009-07-16 15:09:20 -07004633 void linkGlobal(tokenid_t t, bool isFunction) {
4634 VariableInfo* pVI = VI(t);
4635 void* n = NULL;
4636 if (mpSymbolLookupFn) {
4637 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4638 }
4639 if (pVI->pType == NULL) {
4640 if (isFunction) {
4641 pVI->pType = mkpIntFn;
4642 } else {
4643 pVI->pType = mkpInt;
4644 }
4645 }
4646 pVI->pAddress = n;
4647 }
4648
Jack Palevich29daf572009-07-30 19:38:55 -07004649 void unaryOrAssignment() {
4650 unary();
4651 if (accept('=')) {
4652 checkLVal();
4653 pGen->pushR0();
4654 expr();
4655 pGen->forceR0RVal();
4656 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004657 } else if (tok == TOK_OP_ASSIGNMENT) {
4658 int t = tokc;
4659 next();
4660 checkLVal();
4661 pGen->pushR0();
4662 pGen->forceR0RVal();
4663 pGen->pushR0();
4664 expr();
4665 pGen->forceR0RVal();
4666 pGen->genOp(t);
4667 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004668 }
4669 }
4670
Jack Palevich40600de2009-07-01 15:32:35 -07004671 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004672 */
Jack Palevich29daf572009-07-30 19:38:55 -07004673 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004674 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004675 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004676 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004677 if (acceptStringLiteral()) {
4678 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004679 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004680 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004681 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004682 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004683 t = tok;
4684 next();
4685 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004686 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004687 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004688 // Align to 4-byte boundary
4689 glo = (char*) (((intptr_t) glo + 3) & -4);
4690 * (float*) glo = (float) ad;
4691 pGen->loadFloat((int) glo, mkpFloat);
4692 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004693 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004694 // Align to 8-byte boundary
4695 glo = (char*) (((intptr_t) glo + 7) & -8);
4696 * (double*) glo = ad;
4697 pGen->loadFloat((int) glo, mkpDouble);
4698 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004699 } else if (c == 2) {
4700 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004701 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004702 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004703 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004704 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004705 else if (t == '+') {
4706 // ignore unary plus.
4707 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004708 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004709 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004710 } else if (c == 11) {
4711 // pre increment / pre decrement
4712 unary();
4713 doIncDec(a == OP_INCREMENT, 0);
4714 }
4715 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004716 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004717 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004718 if (pCast) {
4719 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004720 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004721 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004722 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004723 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004724 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004725 skip(')');
4726 }
4727 } else if (t == '*') {
4728 /* This is a pointer dereference.
4729 */
Jack Palevich29daf572009-07-30 19:38:55 -07004730 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004731 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004732 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004733 unary();
4734 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004735 } else if (t == EOF ) {
4736 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004737 } else if (t == ';') {
4738 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004739 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004740 // Don't have to do anything special here, the error
4741 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004742 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004743 if (!isDefined(t)) {
4744 mGlobals.add(t);
4745 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004746 }
Jack Palevich8df46192009-07-07 14:48:51 -07004747 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004748 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004749 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004750 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004751 linkGlobal(t, tok == '(');
4752 n = (intptr_t) pVI->pAddress;
4753 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004754 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004755 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004756 }
Jack Palevich29daf572009-07-30 19:38:55 -07004757 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004758 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004759 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004760 linkGlobal(t, false);
4761 n = (intptr_t) pVI->pAddress;
4762 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004763 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004764 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004765 }
Jack Palevich5b659092009-07-31 14:55:07 -07004766 }
4767 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004768 Type* pVal;
4769 ExpressionType et;
4770 if (pVI->pType->tag == TY_ARRAY) {
4771 pVal = pVI->pType;
4772 et = ET_RVALUE;
4773 } else {
4774 pVal = createPtrType(pVI->pType);
4775 et = ET_LVALUE;
4776 }
Jack Palevich5b659092009-07-31 14:55:07 -07004777 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004778 int tag = pVal->pHead->tag;
4779 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004780 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004781 }
Jack Palevich5b659092009-07-31 14:55:07 -07004782 pGen->leaR0(n, pVal, et);
4783 } else {
4784 pVI->pForward = (void*) pGen->leaForward(
4785 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004786 }
4787 }
4788 }
4789
Jack Palevich5b659092009-07-31 14:55:07 -07004790 /* Now handle postfix operators */
4791 for(;;) {
4792 if (tokl == 11) {
4793 // post inc / post dec
4794 doIncDec(tokc == OP_INCREMENT, true);
4795 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004796 } else if (accept('[')) {
4797 // Array reference
4798 pGen->forceR0RVal();
4799 pGen->pushR0();
4800 commaExpr();
4801 pGen->forceR0RVal();
4802 pGen->genOp(OP_PLUS);
4803 doPointer();
4804 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004805 } else if (accept('.')) {
4806 // struct element
4807 pGen->forceR0RVal();
4808 Type* pStruct = pGen->getR0Type();
4809 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004810 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004811 } else {
4812 error("expected a struct value to the left of '.'");
4813 }
4814 } else if (accept(TOK_OP_ARROW)) {
4815 pGen->forceR0RVal();
4816 Type* pPtr = pGen->getR0Type();
4817 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4818 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004819 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004820 } else {
4821 error("Expected a pointer to a struct to the left of '->'");
4822 }
Jack Palevich5b659092009-07-31 14:55:07 -07004823 } else if (accept('(')) {
4824 /* function call */
4825 Type* pDecl = NULL;
4826 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004827 Type* pFn = pGen->getR0Type();
Jack Palevich188a5a72009-10-27 17:23:20 -07004828 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
4829 pDecl = pFn->pHead;
4830 pGen->pushR0();
4831 Type* pArgList = pDecl->pTail;
4832 bool varArgs = pArgList == NULL;
4833 /* push args and invert order */
4834 a = pGen->beginFunctionCallArguments();
4835 int l = 0;
4836 int argCount = 0;
4837 while (tok != ')' && tok != EOF) {
4838 if (! varArgs && !pArgList) {
4839 error("Unexpected argument.");
Jack Palevich5b659092009-07-31 14:55:07 -07004840 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004841 expr();
4842 pGen->forceR0RVal();
4843 Type* pTargetType;
4844 if (pArgList) {
4845 pTargetType = pArgList->pHead;
4846 pArgList = pArgList->pTail;
4847 } else {
4848 // This is a ... function, just pass arguments in their
4849 // natural type.
4850 pTargetType = pGen->getR0Type();
4851 if (pTargetType->tag == TY_FLOAT) {
4852 pTargetType = mkpDouble;
4853 } else if (pTargetType->tag == TY_ARRAY) {
4854 // Pass arrays by pointer.
4855 pTargetType = pTargetType->pTail;
4856 }
4857 }
4858 if (pTargetType->tag == TY_VOID) {
4859 error("Can't pass void value for argument %d",
4860 argCount + 1);
4861 } else {
4862 l += pGen->storeR0ToArg(l, pTargetType);
4863 }
4864 if (accept(',')) {
4865 // fine
4866 } else if ( tok != ')') {
4867 error("Expected ',' or ')'");
4868 }
4869 argCount += 1;
Jack Palevich5b659092009-07-31 14:55:07 -07004870 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004871 if (! varArgs && pArgList) {
4872 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich5b659092009-07-31 14:55:07 -07004873 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004874 pGen->endFunctionCallArguments(pDecl, a, l);
4875 skip(')');
4876 pGen->callIndirect(l, pDecl);
4877 pGen->adjustStackAfterCall(pDecl, l, true);
4878 } else {
4879 error("Expected a function value to left of '('.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004880 }
Jack Palevich5b659092009-07-31 14:55:07 -07004881 } else {
4882 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004883 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004884 }
4885 }
4886
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004887 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004888 Type* pStructElement = lookupStructMember(pStruct, tok);
4889 if (pStructElement) {
4890 next();
4891 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4892 } else {
4893 String buf;
4894 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004895 error("Expected a struct member to the right of '%s', got %s",
4896 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004897 }
4898 }
4899
Jack Palevichaaac9282009-07-31 14:34:34 -07004900 void doIncDec(int isInc, int isPost) {
4901 // R0 already has the lval
4902 checkLVal();
4903 int lit = isInc ? 1 : -1;
4904 pGen->pushR0();
4905 pGen->loadR0FromR0();
4906 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004907 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4908 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004909 error("++/-- illegal for this type. %d", tag);
4910 }
4911 if (isPost) {
4912 pGen->over();
4913 pGen->pushR0();
4914 pGen->li(lit);
4915 pGen->genOp(OP_PLUS);
4916 pGen->storeR0ToTOS();
4917 pGen->popR0();
4918 } else {
4919 pGen->pushR0();
4920 pGen->li(lit);
4921 pGen->genOp(OP_PLUS);
4922 pGen->over();
4923 pGen->storeR0ToTOS();
4924 pGen->popR0();
4925 }
4926 }
4927
Jack Palevich47cbea92009-07-31 15:25:53 -07004928 void doPointer() {
4929 pGen->forceR0RVal();
4930 Type* pR0Type = pGen->getR0Type();
4931 if (pR0Type->tag != TY_POINTER) {
4932 error("Expected a pointer type.");
4933 } else {
4934 if (pR0Type->pHead->tag != TY_FUNC) {
4935 pGen->setR0ExpressionType(ET_LVALUE);
4936 }
4937 }
4938 }
4939
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004940 void doAddressOf() {
4941 Type* pR0 = pGen->getR0Type();
4942 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4943 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4944 error("Expected an lvalue");
4945 }
4946 Type* pR0Type = pGen->getR0Type();
4947 pGen->setR0ExpressionType(ET_RVALUE);
4948 }
4949
Jack Palevich40600de2009-07-01 15:32:35 -07004950 /* Recursive descent parser for binary operations.
4951 */
4952 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004953 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004954 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004955 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004956 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004957 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004958 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004959 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004960 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004961 t = tokc;
4962 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004963 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004964 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004965 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004966 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004967 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004968 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004969 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004970 // Check for syntax error.
4971 if (pGen->getR0Type() == NULL) {
4972 // We failed to parse a right-hand argument.
4973 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004974 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004975 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004976 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004977 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004978 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004979 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004980 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004981 }
4982 }
4983 }
4984 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004985 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004986 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004987 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004988 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004989 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004990 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004991 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004992 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004993 }
4994 }
4995 }
4996
Jack Palevich43aaee32009-07-31 14:01:37 -07004997 void commaExpr() {
4998 for(;;) {
4999 expr();
5000 if (!accept(',')) {
5001 break;
5002 }
5003 }
5004 }
5005
Jack Palevich21a15a22009-05-11 14:49:29 -07005006 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07005007 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07005008 }
5009
5010 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07005011 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005012 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005013 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07005014 }
5015
Jack Palevich46f2bd22009-10-29 17:56:56 -07005016 void block(intptr_t* breakLabel, intptr_t continueAddress, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07005017 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07005018
Jack Palevich95727a02009-07-06 12:07:15 -07005019 Type* pBaseType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005020 if ((pBaseType = acceptPrimitiveType(true))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07005021 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07005022 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005023 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005024 next();
5025 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07005026 a = test_expr();
5027 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005028 block(breakLabel, continueAddress, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07005029 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005030 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005031 n = pGen->gjmp(0); /* jmp */
5032 pGen->gsym(a);
Jack Palevichc951c592009-10-29 15:04:27 -07005033 block(breakLabel, continueAddress, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005034 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07005035 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005036 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005037 }
Jack Palevich546b2242009-05-13 15:10:04 -07005038 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07005039 t = tok;
5040 next();
5041 skip('(');
5042 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005043 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07005044 a = test_expr();
5045 } else {
5046 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005047 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005048 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005049 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07005050 a = 0;
5051 if (tok != ';')
5052 a = test_expr();
5053 skip(';');
5054 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005055 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005056 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005057 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005058 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005059 n = t + 4;
5060 }
5061 }
5062 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005063 block(&a, n, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005064 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005065 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005066 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005067 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005068 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005069 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005070 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005071 while (tok != '}' && tok != EOF)
Jack Palevichc951c592009-10-29 15:04:27 -07005072 block(breakLabel, continueAddress, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005073 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005074 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005075 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005076 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005077 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005078 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005079 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005080 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005081 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005082 if (pReturnType->tag == TY_VOID) {
5083 error("Must not return a value from a void function");
5084 } else {
5085 pGen->convertR0(pReturnType);
5086 }
5087 } else {
5088 if (pReturnType->tag != TY_VOID) {
5089 error("Must specify a value here");
5090 }
Jack Palevich8df46192009-07-07 14:48:51 -07005091 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005092 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005093 } else if (accept(TOK_BREAK)) {
Jack Palevichc951c592009-10-29 15:04:27 -07005094 if (breakLabel) {
5095 *breakLabel = pGen->gjmp(*breakLabel);
5096 } else {
5097 error("break statement must be within a for, do, while, or switch statement");
5098 }
5099 } else if (accept(TOK_CONTINUE)) {
5100 if (continueAddress) {
5101 pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset());
5102 } else {
5103 error("continue statement must be within a for, do, or while statement");
5104 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005105 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005106 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005107 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005108 }
5109 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005110
Jack Palevicha8f427f2009-07-13 18:40:08 -07005111 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005112 if (a == b) {
5113 return true;
5114 }
5115 if (a == NULL || b == NULL) {
5116 return false;
5117 }
5118 TypeTag at = a->tag;
5119 if (at != b->tag) {
5120 return false;
5121 }
5122 if (at == TY_POINTER) {
5123 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005124 } else if (at == TY_ARRAY) {
5125 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005126 } else if (at == TY_FUNC || at == TY_PARAM) {
5127 return typeEqual(a->pHead, b->pHead)
5128 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005129 } else if (at == TY_STRUCT) {
5130 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005131 }
5132 return true;
5133 }
5134
Jack Palevich2ff5c222009-07-23 15:11:22 -07005135 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005136 assert(tag >= TY_UNKNOWN && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005137 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005138 memset(pType, 0, sizeof(*pType));
Jack Palevichee1f8292009-10-28 16:10:17 -07005139 pType->storageClass = SC_DEFAULT;
Jack Palevich86351982009-06-30 18:09:56 -07005140 pType->tag = tag;
5141 pType->pHead = pHead;
5142 pType->pTail = pTail;
5143 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005144 }
5145
Jack Palevich2ff5c222009-07-23 15:11:22 -07005146 Type* createPtrType(Type* pType) {
5147 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005148 }
5149
5150 /**
5151 * Try to print a type in declaration order
5152 */
Jack Palevich86351982009-06-30 18:09:56 -07005153 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005154 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005155 if (pType == NULL) {
5156 buffer.appendCStr("null");
5157 return;
5158 }
Jack Palevich3f226492009-07-02 14:46:19 -07005159 decodeTypeImp(buffer, pType);
5160 }
5161
5162 void decodeTypeImp(String& buffer, Type* pType) {
5163 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005164 decodeId(buffer, pType->id);
5165 decodeTypeImpPostfix(buffer, pType);
5166 }
Jack Palevich3f226492009-07-02 14:46:19 -07005167
Jack Palevich9221bcc2009-08-26 16:15:07 -07005168 void decodeId(String& buffer, tokenid_t id) {
5169 if (id) {
5170 String temp;
5171 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005172 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005173 }
Jack Palevich3f226492009-07-02 14:46:19 -07005174 }
5175
5176 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5177 TypeTag tag = pType->tag;
5178
Jack Palevich9221bcc2009-08-26 16:15:07 -07005179 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005180 switch (tag) {
5181 case TY_INT:
5182 buffer.appendCStr("int");
5183 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005184 case TY_SHORT:
5185 buffer.appendCStr("short");
5186 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005187 case TY_CHAR:
5188 buffer.appendCStr("char");
5189 break;
5190 case TY_VOID:
5191 buffer.appendCStr("void");
5192 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005193 case TY_FLOAT:
5194 buffer.appendCStr("float");
5195 break;
5196 case TY_DOUBLE:
5197 buffer.appendCStr("double");
5198 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005199 case TY_STRUCT:
5200 {
5201 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5202 buffer.appendCStr(isStruct ? "struct" : "union");
5203 if (pType->pHead && pType->pHead->structTag) {
5204 buffer.append(' ');
5205 decodeId(buffer, pType->pHead->structTag);
5206 }
5207 }
5208 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005209 default:
5210 break;
5211 }
Jack Palevich86351982009-06-30 18:09:56 -07005212 buffer.append(' ');
5213 }
Jack Palevich3f226492009-07-02 14:46:19 -07005214
5215 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005216 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005217 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005218 case TY_SHORT:
5219 break;
Jack Palevich86351982009-06-30 18:09:56 -07005220 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005221 break;
5222 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005223 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005224 case TY_FLOAT:
5225 break;
5226 case TY_DOUBLE:
5227 break;
Jack Palevich86351982009-06-30 18:09:56 -07005228 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005229 decodeTypeImpPrefix(buffer, pType->pHead);
5230 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5231 buffer.append('(');
5232 }
5233 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005234 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005235 case TY_ARRAY:
5236 decodeTypeImpPrefix(buffer, pType->pHead);
5237 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005238 case TY_STRUCT:
5239 break;
Jack Palevich86351982009-06-30 18:09:56 -07005240 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005241 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005242 break;
5243 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005244 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005245 break;
5246 default:
5247 String temp;
5248 temp.printf("Unknown tag %d", pType->tag);
5249 buffer.append(temp);
5250 break;
5251 }
Jack Palevich3f226492009-07-02 14:46:19 -07005252 }
5253
5254 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5255 TypeTag tag = pType->tag;
5256
5257 switch(tag) {
5258 case TY_POINTER:
5259 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5260 buffer.append(')');
5261 }
5262 decodeTypeImpPostfix(buffer, pType->pHead);
5263 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005264 case TY_ARRAY:
5265 {
5266 String temp;
5267 temp.printf("[%d]", pType->length);
5268 buffer.append(temp);
5269 }
5270 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005271 case TY_STRUCT:
5272 if (pType->pHead->length >= 0) {
5273 buffer.appendCStr(" {");
5274 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5275 decodeTypeImp(buffer, pArg->pHead);
5276 buffer.appendCStr(";");
5277 }
5278 buffer.append('}');
5279 }
5280 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005281 case TY_FUNC:
5282 buffer.append('(');
5283 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5284 decodeTypeImp(buffer, pArg);
5285 if (pArg->pTail) {
5286 buffer.appendCStr(", ");
5287 }
5288 }
5289 buffer.append(')');
5290 break;
5291 default:
5292 break;
Jack Palevich86351982009-06-30 18:09:56 -07005293 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005294 }
5295
Jack Palevich86351982009-06-30 18:09:56 -07005296 void printType(Type* pType) {
5297 String buffer;
5298 decodeType(buffer, pType);
5299 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005300 }
5301
Jack Palevichee1f8292009-10-28 16:10:17 -07005302 void insertTypeSpecifier(Type** ppType, TypeTag tag) {
5303 if (! *ppType) {
5304 *ppType = createType(tag, NULL, NULL);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005305 } else {
Jack Palevichee1f8292009-10-28 16:10:17 -07005306 if ((*ppType)->tag != TY_UNKNOWN) {
5307 error("Only one type specifier allowed.");
5308 } else {
5309 (*ppType)->tag = tag;
5310 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005311 }
Jack Palevichee1f8292009-10-28 16:10:17 -07005312 }
5313
5314 void insertStorageClass(Type** ppType, StorageClass storageClass) {
5315 if (! *ppType) {
5316 *ppType = createType(TY_UNKNOWN, NULL, NULL);
5317 }
5318 if ((*ppType)->storageClass != SC_DEFAULT) {
5319 error("Only one storage class allowed.");
5320 } else {
5321 (*ppType)->storageClass = storageClass;
5322 }
5323 }
5324
5325 Type* acceptPrimitiveType(bool allowStorageClass) {
5326 Type* pType = NULL;
5327 for (bool keepGoing = true; keepGoing;) {
5328 switch(tok) {
5329 case TOK_AUTO:
5330 insertStorageClass(&pType, SC_AUTO);
5331 break;
5332 case TOK_REGISTER:
5333 insertStorageClass(&pType, SC_REGISTER);
5334 break;
5335 case TOK_STATIC:
5336 insertStorageClass(&pType, SC_STATIC);
5337 break;
5338 case TOK_EXTERN:
5339 insertStorageClass(&pType, SC_EXTERN);
5340 break;
5341 case TOK_TYPEDEF:
5342 insertStorageClass(&pType, SC_TYPEDEF);
5343 break;
5344 case TOK_INT:
5345 insertTypeSpecifier(&pType, TY_INT);
5346 break;
5347 case TOK_SHORT:
5348 insertTypeSpecifier(&pType, TY_SHORT);
5349 break;
5350 case TOK_CHAR:
5351 insertTypeSpecifier(&pType, TY_CHAR);
5352 break;
5353 case TOK_VOID:
5354 insertTypeSpecifier(&pType, TY_VOID);
5355 break;
5356 case TOK_FLOAT:
5357 insertTypeSpecifier(&pType, TY_FLOAT);
5358 break;
5359 case TOK_DOUBLE:
5360 insertTypeSpecifier(&pType, TY_DOUBLE);
5361 break;
5362 case TOK_STRUCT:
5363 case TOK_UNION:
5364 {
5365 insertTypeSpecifier(&pType, TY_STRUCT);
5366 bool isStruct = (tok == TOK_STRUCT);
5367 next();
5368 pType = acceptStruct(pType, isStruct);
5369 keepGoing = false;
5370 }
5371 break;
5372 default:
5373 // Is it a typedef?
5374 if (isSymbol(tok)) {
5375 VariableInfo* pV = VI(tok);
5376 if (pV && pV->pType->storageClass == SC_TYPEDEF) {
5377 if (! pType) {
5378 pType = createType(TY_UNKNOWN, NULL, NULL);
5379 }
5380 StorageClass storageClass = pType->storageClass;
5381 *pType = *pV->pType;
5382 pType->storageClass = storageClass;
5383 } else {
5384 keepGoing = false;
5385 }
5386 } else {
5387 keepGoing = false;
5388 }
5389 }
5390 if (keepGoing) {
5391 next();
5392 }
5393 }
5394 if (pType) {
5395 if (pType->tag == TY_UNKNOWN) {
5396 pType->tag = TY_INT;
5397 }
5398 if (allowStorageClass) {
5399 switch(pType->storageClass) {
5400 case SC_AUTO: error("auto not supported."); break;
5401 case SC_REGISTER: error("register not supported."); break;
5402 case SC_STATIC: error("static not supported."); break;
5403 case SC_EXTERN: error("extern not supported."); break;
5404 default: break;
5405 }
5406 } else {
5407 if (pType->storageClass != SC_DEFAULT) {
5408 error("An explicit storage class is not allowed in this type declaration");
5409 }
5410 }
5411 }
Jack Palevich86351982009-06-30 18:09:56 -07005412 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005413 }
5414
Jack Palevichee1f8292009-10-28 16:10:17 -07005415 Type* acceptStruct(Type* pStructType, bool isStruct) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005416 tokenid_t structTag = acceptSymbol();
5417 bool isDeclaration = accept('{');
5418 bool fail = false;
5419
Jack Palevich9221bcc2009-08-26 16:15:07 -07005420 if (structTag) {
5421 Token* pToken = &mTokenTable[structTag];
5422 VariableInfo* pStructInfo = pToken->mpStructInfo;
5423 bool needToDeclare = !pStructInfo;
5424 if (pStructInfo) {
5425 if (isDeclaration) {
5426 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5427 if (pStructInfo->pType->pHead->length == -1) {
5428 // we're filling in a forward declaration.
5429 needToDeclare = false;
5430 } else {
5431 error("A struct with the same name is already defined at this level.");
5432 fail = true;
5433 }
5434 } else {
5435 needToDeclare = true;
5436 }
5437 }
5438 if (!fail) {
5439 assert(pStructInfo->isStructTag);
5440 pStructType->pHead = pStructInfo->pType;
5441 pStructType->pTail = pStructType->pHead->pTail;
5442 }
5443 }
5444
5445 if (needToDeclare) {
5446 // This is a new struct name
5447 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
Jack Palevichee1f8292009-10-28 16:10:17 -07005448 StorageClass storageClass = pStructType->storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005449 pStructType = createType(TY_STRUCT, NULL, NULL);
5450 pStructType->structTag = structTag;
5451 pStructType->pHead = pStructType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005452 pStructType->storageClass = storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005453 if (! isDeclaration) {
5454 // A forward declaration
5455 pStructType->length = -1;
5456 }
5457 pToken->mpStructInfo->pType = pStructType;
5458 }
5459 } else {
5460 // An anonymous struct
5461 pStructType->pHead = pStructType;
5462 }
5463
5464 if (isDeclaration) {
5465 size_t offset = 0;
5466 size_t structSize = 0;
5467 size_t structAlignment = 0;
5468 Type** pParamHolder = & pStructType->pHead->pTail;
5469 while (tok != '}' && tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005470 Type* pPrimitiveType = expectPrimitiveType(false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005471 if (pPrimitiveType) {
5472 while (tok != ';' && tok != EOF) {
5473 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5474 if (!pItem) {
5475 break;
5476 }
5477 if (lookupStructMember(pStructType, pItem->id)) {
5478 String buf;
5479 decodeToken(buf, pItem->id, false);
5480 error("Duplicate struct member %s", buf.getUnwrapped());
5481 }
5482 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5483 size_t alignment = pGen->alignmentOf(pItem);
5484 if (alignment > structAlignment) {
5485 structAlignment = alignment;
5486 }
5487 size_t alignmentMask = alignment - 1;
5488 offset = (offset + alignmentMask) & ~alignmentMask;
5489 pStructElement->length = offset;
5490 size_t size = pGen->sizeOf(pItem);
5491 if (isStruct) {
5492 offset += size;
5493 structSize = offset;
5494 } else {
5495 if (size >= structSize) {
5496 structSize = size;
5497 }
5498 }
5499 *pParamHolder = pStructElement;
5500 pParamHolder = &pStructElement->pTail;
5501 accept(',');
5502 }
5503 skip(';');
5504 } else {
5505 // Some sort of syntax error, skip token and keep trying
5506 next();
5507 }
5508 }
5509 if (!fail) {
5510 pStructType->pHead->length = structSize;
5511 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5512 }
5513 skip('}');
5514 }
5515 if (fail) {
5516 pStructType = NULL;
5517 }
5518 return pStructType;
5519 }
5520
5521 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5522 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5523 if (pStructElement->pHead->id == memberId) {
5524 return pStructElement;
5525 }
5526 }
5527 return NULL;
5528 }
5529
Jack Palevich2ff5c222009-07-23 15:11:22 -07005530 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005531 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005532 bool reportFailure = false;
Jack Palevichee1f8292009-10-28 16:10:17 -07005533 StorageClass storageClass = pType->storageClass;
Jack Palevich3f226492009-07-02 14:46:19 -07005534 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005535 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005536 if (declName) {
5537 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005538 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005539 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005540 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005541 pType->id = declName;
Jack Palevichee1f8292009-10-28 16:10:17 -07005542 pType->storageClass = storageClass;
Jack Palevichb6154502009-08-04 14:56:09 -07005543 } else if (nameRequired) {
5544 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005545 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005546#if 0
5547 fprintf(stderr, "Parsed a declaration: ");
5548 printType(pType);
5549#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005550 if (reportFailure) {
5551 return NULL;
5552 }
Jack Palevich86351982009-06-30 18:09:56 -07005553 return pType;
5554 }
5555
Jack Palevich2ff5c222009-07-23 15:11:22 -07005556 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005557 bool nameRequired = pBaseType->tag != TY_STRUCT;
5558 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005559 if (! pType) {
5560 error("Expected a declaration");
5561 }
5562 return pType;
5563 }
5564
Jack Palevich3f226492009-07-02 14:46:19 -07005565 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005566 Type* acceptCastTypeDeclaration() {
Jack Palevichee1f8292009-10-28 16:10:17 -07005567 Type* pType = acceptPrimitiveType(false);
Jack Palevich3f226492009-07-02 14:46:19 -07005568 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005569 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005570 }
Jack Palevich86351982009-06-30 18:09:56 -07005571 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005572 }
5573
Jack Palevich2ff5c222009-07-23 15:11:22 -07005574 Type* expectCastTypeDeclaration() {
5575 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005576 if (! pType) {
5577 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005578 }
Jack Palevich3f226492009-07-02 14:46:19 -07005579 return pType;
5580 }
5581
5582 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005583 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005584 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005585 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005586 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005587 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005588 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005589 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005590 return pType;
5591 }
5592
5593 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005594 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005595 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005596 // direct-dcl :
5597 // name
5598 // (dcl)
5599 // direct-dcl()
5600 // direct-dcl[]
5601 Type* pNewHead = NULL;
5602 if (accept('(')) {
5603 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005604 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005605 skip(')');
5606 } else if ((declName = acceptSymbol()) != 0) {
5607 if (nameAllowed == false && declName) {
5608 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005609 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005610 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005611 } else if (nameRequired && ! declName) {
5612 String temp;
5613 decodeToken(temp, tok, true);
5614 error("Expected name. Got %s", temp.getUnwrapped());
5615 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005616 }
Jack Palevichb6154502009-08-04 14:56:09 -07005617 for(;;) {
5618 if (accept('(')) {
5619 // Function declaration
5620 Type* pTail = acceptArgs(nameAllowed);
5621 pType = createType(TY_FUNC, pType, pTail);
5622 skip(')');
5623 } if (accept('[')) {
5624 if (tok != ']') {
5625 if (tok != TOK_NUM || tokc <= 0) {
5626 error("Expected positive integer constant");
5627 } else {
5628 Type* pDecayType = createPtrType(pType);
5629 pType = createType(TY_ARRAY, pType, pDecayType);
5630 pType->length = tokc;
5631 }
5632 next();
5633 }
5634 skip(']');
5635 } else {
5636 break;
5637 }
Jack Palevich86351982009-06-30 18:09:56 -07005638 }
Jack Palevich3f226492009-07-02 14:46:19 -07005639
5640 if (pNewHead) {
5641 Type* pA = pNewHead;
5642 while (pA->pHead) {
5643 pA = pA->pHead;
5644 }
5645 pA->pHead = pType;
5646 pType = pNewHead;
5647 }
Jack Palevich86351982009-06-30 18:09:56 -07005648 return pType;
5649 }
5650
Jack Palevich2ff5c222009-07-23 15:11:22 -07005651 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005652 Type* pHead = NULL;
5653 Type* pTail = NULL;
5654 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005655 Type* pBaseArg = acceptPrimitiveType(false);
Jack Palevich86351982009-06-30 18:09:56 -07005656 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005657 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005658 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005659 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005660 if (!pHead) {
5661 pHead = pParam;
5662 pTail = pParam;
5663 } else {
5664 pTail->pTail = pParam;
5665 pTail = pParam;
5666 }
5667 }
5668 }
5669 if (! accept(',')) {
5670 break;
5671 }
5672 }
5673 return pHead;
5674 }
5675
Jack Palevichee1f8292009-10-28 16:10:17 -07005676 Type* expectPrimitiveType(bool allowStorageClass) {
5677 Type* pType = acceptPrimitiveType(allowStorageClass);
Jack Palevich86351982009-06-30 18:09:56 -07005678 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005679 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005680 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005681 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005682 }
Jack Palevich86351982009-06-30 18:09:56 -07005683 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005684 }
5685
Jack Palevichb5e33312009-07-30 19:06:34 -07005686 void checkLVal() {
5687 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005688 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005689 }
5690 }
5691
Jack Palevich86351982009-06-30 18:09:56 -07005692 void addGlobalSymbol(Type* pDecl) {
5693 tokenid_t t = pDecl->id;
5694 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005695 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005696 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005697 }
Jack Palevich86351982009-06-30 18:09:56 -07005698 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005699 }
5700
Jack Palevich86351982009-06-30 18:09:56 -07005701 void reportDuplicate(tokenid_t t) {
5702 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005703 }
5704
Jack Palevich86351982009-06-30 18:09:56 -07005705 void addLocalSymbol(Type* pDecl) {
5706 tokenid_t t = pDecl->id;
5707 if (mLocals.isDefinedAtCurrentLevel(t)) {
5708 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005709 }
Jack Palevich86351982009-06-30 18:09:56 -07005710 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005711 }
5712
Jack Palevich61de31f2009-09-08 11:06:40 -07005713 bool checkUndeclaredStruct(Type* pBaseType) {
5714 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5715 String temp;
5716 decodeToken(temp, pBaseType->structTag, false);
5717 error("Undeclared struct %s", temp.getUnwrapped());
5718 return true;
5719 }
5720 return false;
5721 }
5722
Jack Palevich95727a02009-07-06 12:07:15 -07005723 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005724 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005725
Jack Palevich95727a02009-07-06 12:07:15 -07005726 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005727 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005728 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005729 if (!pDecl) {
5730 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005731 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005732 if (!pDecl->id) {
5733 break;
5734 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005735 if (checkUndeclaredStruct(pDecl)) {
5736 break;
5737 }
Jack Palevich86351982009-06-30 18:09:56 -07005738 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005739 if (pDecl->tag == TY_FUNC) {
5740 if (tok == '{') {
5741 error("Nested functions are not allowed. Did you forget a '}' ?");
5742 break;
5743 }
5744 // Else it's a forward declaration of a function.
Jack Palevichee1f8292009-10-28 16:10:17 -07005745 } else if (pDecl->storageClass != SC_TYPEDEF) {
Jack Palevich1c60e462009-09-18 15:03:03 -07005746 int variableAddress = 0;
5747 size_t alignment = pGen->alignmentOf(pDecl);
5748 assert(alignment > 0);
5749 size_t alignmentMask = ~ (alignment - 1);
5750 size_t sizeOf = pGen->sizeOf(pDecl);
5751 assert(sizeOf > 0);
5752 loc = (loc + alignment - 1) & alignmentMask;
5753 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5754 loc = loc + alignedSize;
5755 variableAddress = -loc;
5756 VI(pDecl->id)->pAddress = (void*) variableAddress;
5757 if (accept('=')) {
5758 /* assignment */
5759 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5760 pGen->pushR0();
5761 expr();
5762 pGen->forceR0RVal();
5763 pGen->storeR0ToTOS();
5764 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005765 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005766 if (tok == ',')
5767 next();
5768 }
5769 skip(';');
Jack Palevichee1f8292009-10-28 16:10:17 -07005770 pBaseType = acceptPrimitiveType(true);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005771 }
5772 }
5773
Jack Palevichf1728be2009-06-12 13:53:51 -07005774 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005775 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005776 }
5777
Jack Palevich37c54bd2009-07-14 18:35:36 -07005778 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005779 if (token == EOF ) {
5780 buffer.printf("EOF");
5781 } else if (token == TOK_NUM) {
Jack Palevich188a5a72009-10-27 17:23:20 -07005782 buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
5783 } else if (token == TOK_NUM_FLOAT) {
5784 buffer.printf("numeric constant float %g", tokd);
5785 } else if (token == TOK_NUM_DOUBLE) {
5786 buffer.printf("numeric constant double %g", tokd);
5787 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005788 if (token < 32) {
5789 buffer.printf("'\\x%02x'", token);
5790 } else {
5791 buffer.printf("'%c'", token);
5792 }
Jack Palevich569f1352009-06-29 14:29:08 -07005793 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005794 if (quote) {
5795 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5796 buffer.printf("keyword \"%s\"", nameof(token));
5797 } else {
5798 buffer.printf("symbol \"%s\"", nameof(token));
5799 }
5800 } else {
5801 buffer.printf("%s", nameof(token));
5802 }
Jack Palevich569f1352009-06-29 14:29:08 -07005803 }
5804 }
5805
Jack Palevich9221bcc2009-08-26 16:15:07 -07005806 void printToken(tokenid_t token) {
5807 String buffer;
5808 decodeToken(buffer, token, true);
5809 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5810 }
5811
Jack Palevich40600de2009-07-01 15:32:35 -07005812 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005813 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005814 if (!result) {
5815 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005816 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005817 error("Expected symbol. Got %s", temp.getUnwrapped());
5818 }
5819 return result;
5820 }
5821
Jack Palevich86351982009-06-30 18:09:56 -07005822 tokenid_t acceptSymbol() {
5823 tokenid_t result = 0;
5824 if (tok >= TOK_SYMBOL) {
5825 result = tok;
5826 next();
Jack Palevich86351982009-06-30 18:09:56 -07005827 }
5828 return result;
5829 }
5830
Jack Palevichb7c81e92009-06-04 19:56:13 -07005831 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005832 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005833 while (tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005834 Type* pBaseType = expectPrimitiveType(true);
Jack Palevich86351982009-06-30 18:09:56 -07005835 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005836 break;
5837 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005838 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005839 if (!pDecl) {
5840 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005841 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005842 if (!pDecl->id) {
5843 skip(';');
5844 continue;
5845 }
5846
Jack Palevich61de31f2009-09-08 11:06:40 -07005847 if (checkUndeclaredStruct(pDecl)) {
5848 skip(';');
5849 continue;
5850 }
Jack Palevich86351982009-06-30 18:09:56 -07005851 if (! isDefined(pDecl->id)) {
5852 addGlobalSymbol(pDecl);
5853 }
5854 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005855 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005856 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005857 }
Jack Palevich86351982009-06-30 18:09:56 -07005858 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005859 // it's a variable declaration
5860 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005861 if (pDecl->storageClass == SC_TYPEDEF) {
5862 // Do not allocate storage.
5863 } else {
5864 if (name && !name->pAddress) {
5865 name->pAddress = (int*) allocGlobalSpace(
5866 pGen->alignmentOf(name->pType),
5867 pGen->sizeOf(name->pType));
5868 }
5869 if (accept('=')) {
5870 if (tok == TOK_NUM) {
5871 if (name) {
5872 * (int*) name->pAddress = tokc;
5873 }
5874 next();
5875 } else {
5876 error("Expected an integer constant");
Jack Palevichd7461a72009-06-12 14:26:58 -07005877 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005878 }
5879 }
Jack Palevich86351982009-06-30 18:09:56 -07005880 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005881 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005882 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005883 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005884 if (!pDecl) {
5885 break;
5886 }
5887 if (! isDefined(pDecl->id)) {
5888 addGlobalSymbol(pDecl);
5889 }
5890 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005891 }
5892 skip(';');
5893 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005894 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005895 if (accept(';')) {
5896 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005897 } else if (tok != '{') {
5898 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005899 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005900 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005901 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005902 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005903 /* patch forward references */
5904 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005905 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005906 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005907 }
5908 // Calculate stack offsets for parameters
5909 mLocals.pushLevel();
5910 intptr_t a = 8;
5911 int argCount = 0;
5912 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5913 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005914 if (pArg->id) {
5915 addLocalSymbol(pArg);
5916 }
Jack Palevich95727a02009-07-06 12:07:15 -07005917 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005918 Type* pPassingType = passingType(pArg);
5919 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005920 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005921 if (pArg->id) {
5922 VI(pArg->id)->pAddress = (void*) a;
5923 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005924 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005925 argCount++;
5926 }
5927 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005928 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005929 a = pGen->functionEntry(pDecl);
Jack Palevichc951c592009-10-29 15:04:27 -07005930 block(0, 0, true);
Jack Palevich95727a02009-07-06 12:07:15 -07005931 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005932 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005933 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005934 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005935 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005936 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005937 }
5938 }
5939 }
5940
Jack Palevich9221bcc2009-08-26 16:15:07 -07005941 Type* passingType(Type* pType) {
5942 switch (pType->tag) {
5943 case TY_CHAR:
5944 case TY_SHORT:
5945 return mkpInt;
5946 default:
5947 return pType;
5948 }
5949 }
5950
Jack Palevich9cbd2262009-07-08 16:48:41 -07005951 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5952 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5953 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005954 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005955 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005956 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005957 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005958 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005959 char* result = (char*) base;
5960 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005961 return result;
5962 }
5963
Jack Palevich21a15a22009-05-11 14:49:29 -07005964 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005965 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005966 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005967 pGlobalBase = 0;
5968 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005969 if (pGen) {
5970 delete pGen;
5971 pGen = 0;
5972 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005973 if (pCodeBuf) {
5974 delete pCodeBuf;
5975 pCodeBuf = 0;
5976 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005977 if (file) {
5978 delete file;
5979 file = 0;
5980 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005981 }
5982
Jack Palevich8c246a92009-07-14 21:14:10 -07005983 // One-time initialization, when class is constructed.
5984 void init() {
5985 mpSymbolLookupFn = 0;
5986 mpSymbolLookupContext = 0;
5987 }
5988
Jack Palevich21a15a22009-05-11 14:49:29 -07005989 void clear() {
5990 tok = 0;
5991 tokc = 0;
5992 tokl = 0;
5993 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005994 rsym = 0;
5995 loc = 0;
5996 glo = 0;
Jack Palevich188a5a72009-10-27 17:23:20 -07005997 macroLevel = -1;
Jack Palevich21a15a22009-05-11 14:49:29 -07005998 file = 0;
5999 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006000 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07006001 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07006002 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07006003 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07006004 mLineNumber = 1;
6005 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07006006 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07006007 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006008
Jack Palevich22305132009-05-13 10:58:45 -07006009 void setArchitecture(const char* architecture) {
6010 delete pGen;
6011 pGen = 0;
6012
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006013 delete pCodeBuf;
6014 pCodeBuf = new CodeBuf();
6015
Jack Palevich22305132009-05-13 10:58:45 -07006016 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006017#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006018 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006019 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006020 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07006021 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006022#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07006023#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006024 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006025 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07006026 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006027#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07006028 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006029 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07006030 }
6031 }
6032
6033 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006034#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07006035 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006036 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07006037#elif defined(DEFAULT_X86_CODEGEN)
6038 pGen = new X86CodeGenerator();
6039#endif
6040 }
6041 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006042 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07006043 } else {
6044 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07006045 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07006046 }
6047 }
6048
Jack Palevich77ae76e2009-05-10 19:59:24 -07006049public:
Jack Palevich22305132009-05-13 10:58:45 -07006050 struct args {
6051 args() {
6052 architecture = 0;
6053 }
6054 const char* architecture;
6055 };
6056
Jack Paleviche7b59062009-05-19 17:12:17 -07006057 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07006058 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07006059 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006060 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006061
Jack Paleviche7b59062009-05-19 17:12:17 -07006062 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07006063 cleanup();
6064 }
6065
Jack Palevich8c246a92009-07-14 21:14:10 -07006066 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6067 mpSymbolLookupFn = pFn;
6068 mpSymbolLookupContext = pContext;
6069 }
6070
Jack Palevich1cdef202009-05-22 12:06:27 -07006071 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006072 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07006073
Jack Palevich2ff5c222009-07-23 15:11:22 -07006074 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07006075 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07006076 cleanup();
6077 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07006078 mTokenTable.setArena(&mGlobalArena);
6079 mGlobals.setArena(&mGlobalArena);
6080 mGlobals.setTokenTable(&mTokenTable);
6081 mLocals.setArena(&mLocalArena);
6082 mLocals.setTokenTable(&mTokenTable);
6083
6084 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07006085 setArchitecture(NULL);
6086 if (!pGen) {
6087 return -1;
6088 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07006089#ifdef PROVIDE_TRACE_CODEGEN
6090 pGen = new TraceCodeGenerator(pGen);
6091#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006092 pGen->setErrorSink(this);
6093
6094 if (pCodeBuf) {
6095 pCodeBuf->init(ALLOC_SIZE);
6096 }
6097 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07006098 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07006099 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
6100 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07006101 inp();
6102 next();
6103 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07006104 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07006105 result = pGen->finishCompile();
6106 if (result == 0) {
6107 if (mErrorBuf.len()) {
6108 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006109 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07006110 }
Jack Palevichce105a92009-07-16 14:30:33 -07006111 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006112 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07006113 }
6114
Jack Palevich86351982009-06-30 18:09:56 -07006115 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07006116 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07006117 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07006118 mkpChar = createType(TY_CHAR, NULL, NULL);
6119 mkpVoid = createType(TY_VOID, NULL, NULL);
6120 mkpFloat = createType(TY_FLOAT, NULL, NULL);
6121 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
6122 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
6123 mkpIntPtr = createPtrType(mkpInt);
6124 mkpCharPtr = createPtrType(mkpChar);
6125 mkpFloatPtr = createPtrType(mkpFloat);
6126 mkpDoublePtr = createPtrType(mkpDouble);
6127 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07006128 }
6129
Jack Palevicha6baa232009-06-12 11:25:59 -07006130 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07006131 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07006132 }
6133
Jack Palevich569f1352009-06-29 14:29:08 -07006134 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006135 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07006136 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07006137 }
6138
Jack Palevich569f1352009-06-29 14:29:08 -07006139 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006140 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07006141 error("Undefined forward reference: %s",
6142 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07006143 }
6144 return true;
6145 }
6146
Jack Palevich1cdef202009-05-22 12:06:27 -07006147 /* Look through the symbol table to find a symbol.
6148 * If found, return its value.
6149 */
6150 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07006151 if (mCompileResult == 0) {
6152 tokenid_t tok = mTokenTable.intern(name, strlen(name));
6153 VariableInfo* pVariableInfo = VI(tok);
6154 if (pVariableInfo) {
6155 return pVariableInfo->pAddress;
6156 }
Jack Palevich1cdef202009-05-22 12:06:27 -07006157 }
6158 return NULL;
6159 }
6160
Jack Palevicheedf9d22009-06-04 16:23:40 -07006161 void getPragmas(ACCsizei* actualStringCount,
6162 ACCsizei maxStringCount, ACCchar** strings) {
6163 int stringCount = mPragmaStringCount;
6164 if (actualStringCount) {
6165 *actualStringCount = stringCount;
6166 }
6167 if (stringCount > maxStringCount) {
6168 stringCount = maxStringCount;
6169 }
6170 if (strings) {
6171 char* pPragmas = mPragmas.getUnwrapped();
6172 while (stringCount-- > 0) {
6173 *strings++ = pPragmas;
6174 pPragmas += strlen(pPragmas) + 1;
6175 }
6176 }
6177 }
6178
Jack Palevichd5315572009-09-09 13:19:34 -07006179 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006180 *base = pCodeBuf->getBase();
6181 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006182 }
6183
Jack Palevichac0e95e2009-05-29 13:53:44 -07006184 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006185 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006186 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006187};
6188
Jack Paleviche7b59062009-05-19 17:12:17 -07006189const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006190 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6191
Jack Paleviche7b59062009-05-19 17:12:17 -07006192const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006193 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6194 5, 5, /* ==, != */
6195 9, 10, /* &&, || */
6196 6, 7, 8, /* & ^ | */
6197 2, 2 /* ~ ! */
6198 };
6199
Jack Palevich8b0624c2009-05-20 12:12:06 -07006200#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006201const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006202 0x1, // ++
6203 0xff, // --
6204 0xc1af0f, // *
6205 0xf9f79991, // /
6206 0xf9f79991, // % (With manual assist to swap results)
6207 0xc801, // +
6208 0xd8f7c829, // -
6209 0xe0d391, // <<
6210 0xf8d391, // >>
6211 0xe, // <=
6212 0xd, // >=
6213 0xc, // <
6214 0xf, // >
6215 0x4, // ==
6216 0x5, // !=
6217 0x0, // &&
6218 0x1, // ||
6219 0xc821, // &
6220 0xc831, // ^
6221 0xc809, // |
6222 0xd0f7, // ~
6223 0x4 // !
6224};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006225#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006226
Jack Palevich1cdef202009-05-22 12:06:27 -07006227struct ACCscript {
6228 ACCscript() {
6229 text = 0;
6230 textLength = 0;
6231 accError = ACC_NO_ERROR;
6232 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006233
Jack Palevich1cdef202009-05-22 12:06:27 -07006234 ~ACCscript() {
6235 delete text;
6236 }
Jack Palevich546b2242009-05-13 15:10:04 -07006237
Jack Palevich8c246a92009-07-14 21:14:10 -07006238 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6239 compiler.registerSymbolCallback(pFn, pContext);
6240 }
6241
Jack Palevich1cdef202009-05-22 12:06:27 -07006242 void setError(ACCenum error) {
6243 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6244 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006245 }
6246 }
6247
Jack Palevich1cdef202009-05-22 12:06:27 -07006248 ACCenum getError() {
6249 ACCenum result = accError;
6250 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006251 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006252 }
6253
Jack Palevich1cdef202009-05-22 12:06:27 -07006254 Compiler compiler;
6255 char* text;
6256 int textLength;
6257 ACCenum accError;
6258};
6259
6260
6261extern "C"
6262ACCscript* accCreateScript() {
6263 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006264}
Jack Palevich1cdef202009-05-22 12:06:27 -07006265
6266extern "C"
6267ACCenum accGetError( ACCscript* script ) {
6268 return script->getError();
6269}
6270
6271extern "C"
6272void accDeleteScript(ACCscript* script) {
6273 delete script;
6274}
6275
6276extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006277void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6278 ACCvoid* pContext) {
6279 script->registerSymbolCallback(pFn, pContext);
6280}
6281
6282extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006283void accScriptSource(ACCscript* script,
6284 ACCsizei count,
6285 const ACCchar ** string,
6286 const ACCint * length) {
6287 int totalLength = 0;
6288 for(int i = 0; i < count; i++) {
6289 int len = -1;
6290 const ACCchar* s = string[i];
6291 if (length) {
6292 len = length[i];
6293 }
6294 if (len < 0) {
6295 len = strlen(s);
6296 }
6297 totalLength += len;
6298 }
6299 delete script->text;
6300 char* text = new char[totalLength + 1];
6301 script->text = text;
6302 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006303 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006304 for(int i = 0; i < count; i++) {
6305 int len = -1;
6306 const ACCchar* s = string[i];
6307 if (length) {
6308 len = length[i];
6309 }
6310 if (len < 0) {
6311 len = strlen(s);
6312 }
Jack Palevich09555c72009-05-27 12:25:55 -07006313 memcpy(dest, s, len);
6314 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006315 }
6316 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006317
6318#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006319 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006320 int counter;
6321 char path[PATH_MAX];
6322 for (counter = 0; counter < 4096; counter++) {
6323 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6324 if(access(path, F_OK) != 0) {
6325 break;
6326 }
6327 }
6328 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006329 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006330 FILE* fd = fopen(path, "w");
6331 if (fd) {
6332 fwrite(text, totalLength, 1, fd);
6333 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006334 LOGD("Saved input to file %s", path);
6335 } else {
6336 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006337 }
6338 }
6339#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006340}
6341
6342extern "C"
6343void accCompileScript(ACCscript* script) {
6344 int result = script->compiler.compile(script->text, script->textLength);
6345 if (result) {
6346 script->setError(ACC_INVALID_OPERATION);
6347 }
6348}
6349
6350extern "C"
6351void accGetScriptiv(ACCscript* script,
6352 ACCenum pname,
6353 ACCint * params) {
6354 switch (pname) {
6355 case ACC_INFO_LOG_LENGTH:
6356 *params = 0;
6357 break;
6358 }
6359}
6360
6361extern "C"
6362void accGetScriptInfoLog(ACCscript* script,
6363 ACCsizei maxLength,
6364 ACCsizei * length,
6365 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006366 char* message = script->compiler.getErrorMessage();
6367 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006368 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006369 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006370 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006371 if (infoLog && maxLength > 0) {
6372 int trimmedLength = maxLength < messageLength ?
6373 maxLength : messageLength;
6374 memcpy(infoLog, message, trimmedLength);
6375 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006376 }
6377}
6378
6379extern "C"
6380void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6381 ACCvoid ** address) {
6382 void* value = script->compiler.lookup(name);
6383 if (value) {
6384 *address = value;
6385 } else {
6386 script->setError(ACC_INVALID_VALUE);
6387 }
6388}
6389
Jack Palevicheedf9d22009-06-04 16:23:40 -07006390extern "C"
6391void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6392 ACCsizei maxStringCount, ACCchar** strings){
6393 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6394}
6395
-b master422972c2009-06-17 19:13:52 -07006396extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006397void accGetProgramBinary(ACCscript* script,
6398 ACCvoid** base, ACCsizei* length) {
6399 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006400}
6401
Jack Palevicheedf9d22009-06-04 16:23:40 -07006402
Jack Palevich1cdef202009-05-22 12:06:27 -07006403} // namespace acc
6404