blob: 6e13f9ae1422582649b2cacc22c4bdf671c6d679 [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#include <sys/mman.h>
Jack Palevich546b2242009-05-13 15:10:04 -070027
Nick Kralevich88f29fe2010-04-26 16:45:12 -070028#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
29#define MAP_ANONYMOUS MAP_ANON
30#endif
31
Jack Paleviche7b59062009-05-19 17:12:17 -070032#if defined(__arm__)
33#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070034#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070035#elif defined(__i386__)
36#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070037#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070038#elif defined(__x86_64__)
39#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070040#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
42
Jack Palevich30321cb2009-08-20 15:34:23 -070043#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
44#define ARM_USE_VFP
45#endif
46
Jack Palevich1cdef202009-05-22 12:06:27 -070047#include <acc/acc.h>
48
Jack Palevich09555c72009-05-27 12:25:55 -070049#define LOG_API(...) do {} while(0)
50// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070051
-b master422972c2009-06-17 19:13:52 -070052#define LOG_STACK(...) do {} while(0)
53// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
54
Jack Palevichb67b18f2009-06-11 21:12:23 -070055// #define PROVIDE_TRACE_CODEGEN
56
Jack Palevichd30a2ce2009-09-09 19:08:54 -070057// Uncomment to disable ARM peephole optimizations
58// #define DISABLE_ARM_PEEPHOLE
59
Jack Palevich61de31f2009-09-08 11:06:40 -070060// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
61// #define DEBUG_SAVE_INPUT_TO_FILE
62
Jack Palevich9116bc42009-09-08 11:46:42 -070063#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070064#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070065#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070066#else
67#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
68#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070069#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070070
Jack Palevich7f5b1a22009-08-17 16:54:56 -070071#define assert(b) assertImpl(b, __LINE__)
72
Jack Palevichbbf8ab52009-05-11 11:54:30 -070073namespace acc {
74
Jack Palevich8df46192009-07-07 14:48:51 -070075// Subset of STL vector.
76template<class E> class Vector {
77 public:
78 Vector() {
79 mpBase = 0;
80 mUsed = 0;
81 mSize = 0;
82 }
83
84 ~Vector() {
85 if (mpBase) {
Jack Palevichba48fe22009-11-27 11:51:36 +080086 clear();
Jack Palevich8df46192009-07-07 14:48:51 -070087 free(mpBase);
88 }
89 }
90
91 inline E& operator[](size_t i) {
92 return mpBase[i];
93 }
94
95 inline E& front() {
96 return mpBase[0];
97 }
98
99 inline E& back() {
100 return mpBase[mUsed - 1];
101 }
102
103 void pop_back() {
104 mUsed -= 1;
105 mpBase[mUsed].~E();
106 }
107
108 void push_back(const E& item) {
109 * ensure(1) = item;
110 }
111
Jack Palevichba48fe22009-11-27 11:51:36 +0800112 inline size_t size() {
Jack Palevich8df46192009-07-07 14:48:51 -0700113 return mUsed;
114 }
115
Jack Palevichba48fe22009-11-27 11:51:36 +0800116 void clear() {
117 if (mpBase) {
118 size_t used = mUsed;
119 for(size_t i = 0; i < used; i++) {
120 mpBase[i].~E();
121 }
122 }
123 mUsed = 0;
124 }
125
Jack Palevich8df46192009-07-07 14:48:51 -0700126private:
127 E* ensure(int n) {
128 size_t newUsed = mUsed + n;
129 if (newUsed > mSize) {
130 size_t newSize = mSize * 2 + 10;
131 if (newSize < newUsed) {
132 newSize = newUsed;
133 }
134 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
135 mSize = newSize;
136 }
137 E* result = mpBase + mUsed;
138 mUsed = newUsed;
139 return result;
140 }
141
142 E* mpBase;
143 size_t mUsed;
144 size_t mSize;
145};
146
Jack Palevichac0e95e2009-05-29 13:53:44 -0700147class ErrorSink {
148public:
149 void error(const char *fmt, ...) {
150 va_list ap;
151 va_start(ap, fmt);
152 verror(fmt, ap);
153 va_end(ap);
154 }
155
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700156 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700157 virtual void verror(const char* fmt, va_list ap) = 0;
158};
159
160class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700161 typedef int tokenid_t;
162 enum TypeTag {
Jack Palevichee1f8292009-10-28 16:10:17 -0700163 TY_UNKNOWN = -1,
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700164 TY_INT, // 0
165 TY_CHAR, // 1
166 TY_SHORT, // 2
167 TY_VOID, // 3
168 TY_FLOAT, // 4
169 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700170 TY_POINTER, // 6
171 TY_ARRAY, // 7
172 TY_STRUCT, // 8
173 TY_FUNC, // 9
174 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700175 };
176
Jack Palevichee1f8292009-10-28 16:10:17 -0700177 enum StorageClass {
178 SC_DEFAULT, // 0
179 SC_AUTO, // 1
180 SC_REGISTER, // 2
181 SC_STATIC, // 3
182 SC_EXTERN, // 4
183 SC_TYPEDEF // 5
184 };
185
Jack Palevich8df46192009-07-07 14:48:51 -0700186 struct Type {
187 TypeTag tag;
Jack Palevichee1f8292009-10-28 16:10:17 -0700188 StorageClass storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700189 tokenid_t id; // For function arguments, global vars, local vars, struct elements
190 tokenid_t structTag; // For structs the name of the struct
191 int length; // length of array, offset of struct element. -1 means struct is forward defined
192 int alignment; // for structs only
193 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700194 Type* pTail;
195 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700196
Jack Palevichba929a42009-07-17 10:20:32 -0700197 enum ExpressionType {
198 ET_RVALUE,
199 ET_LVALUE
200 };
201
202 struct ExpressionValue {
203 ExpressionValue() {
204 et = ET_RVALUE;
205 pType = NULL;
206 }
207 ExpressionType et;
208 Type* pType;
209 };
210
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700211 class ICodeBuf {
212 public:
213 virtual ~ICodeBuf() {}
214 virtual void init(int size) = 0;
215 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
216 virtual void o4(int n) = 0;
217 virtual void ob(int n) = 0;
218 virtual void* getBase() = 0;
219 virtual intptr_t getSize() = 0;
220 virtual intptr_t getPC() = 0;
221 // Call this before trying to modify code in the buffer.
222 virtual void flush() = 0;
223 };
224
225 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700226 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700227 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700228 ErrorSink* mErrorSink;
229 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700230 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700231
Jack Palevich21a15a22009-05-11 14:49:29 -0700232 void release() {
233 if (pProgramBase != 0) {
Nick Kralevich093ba252010-04-23 09:53:09 -0700234 munmap(pProgramBase, mSize);
Jack Palevich21a15a22009-05-11 14:49:29 -0700235 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700236 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700237 }
238
Jack Palevich0a280a02009-06-11 10:53:51 -0700239 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700240 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700241 bool overflow = newSize > mSize;
242 if (overflow && !mOverflowed) {
243 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700244 if (mErrorSink) {
245 mErrorSink->error("Code too large: %d bytes", newSize);
246 }
247 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700248 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700249 }
250
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 public:
252 CodeBuf() {
253 pProgramBase = 0;
254 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700255 mErrorSink = 0;
256 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700257 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 }
259
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700260 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 release();
262 }
263
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700264 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700265 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700266 mSize = size;
Nick Kralevich093ba252010-04-23 09:53:09 -0700267 pProgramBase = (char*) mmap(NULL, size,
268 PROT_EXEC | PROT_READ | PROT_WRITE,
269 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 ind = pProgramBase;
271 }
272
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700273 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700274 mErrorSink = pErrorSink;
275 }
276
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700277 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700278 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700279 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700280 }
Jack Palevich546b2242009-05-13 15:10:04 -0700281 * (int*) ind = n;
282 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700283 }
284
Jack Palevich21a15a22009-05-11 14:49:29 -0700285 /*
286 * Output a byte. Handles all values, 0..ff.
287 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700288 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700289 if(check(1)) {
290 return;
291 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700292 *ind++ = n;
293 }
294
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700295 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700296 return (void*) pProgramBase;
297 }
298
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700299 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700300 return ind - pProgramBase;
301 }
302
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700303 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700304 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700305 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700306
307 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700308 };
309
Jack Palevich1cdef202009-05-22 12:06:27 -0700310 /**
311 * A code generator creates an in-memory program, generating the code on
312 * the fly. There is one code generator implementation for each supported
313 * architecture.
314 *
315 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700316 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700317 * FP - a frame pointer for accessing function arguments and local
318 * variables.
319 * SP - a stack pointer for storing intermediate results while evaluating
320 * expressions. The stack pointer grows downwards.
321 *
322 * The function calling convention is that all arguments are placed on the
323 * stack such that the first argument has the lowest address.
324 * After the call, the result is in R0. The caller is responsible for
325 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700326 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700327 * FP and SP registers are saved.
328 */
329
Jack Palevich21a15a22009-05-11 14:49:29 -0700330 class CodeGenerator {
331 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700332 CodeGenerator() {
333 mErrorSink = 0;
334 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700335 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700336 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700337 virtual ~CodeGenerator() {}
338
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700339 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700340 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700341 pCodeBuf->setErrorSink(mErrorSink);
342 }
343
Jack Palevichb67b18f2009-06-11 21:12:23 -0700344 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700345 mErrorSink = pErrorSink;
346 if (pCodeBuf) {
347 pCodeBuf->setErrorSink(mErrorSink);
348 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700349 }
350
Jack Palevich58c30ee2009-07-17 16:35:23 -0700351 /* Give the code generator some utility types so it can
352 * use its own types as needed for the results of some
353 * operations like gcmp.
354 */
355
Jack Palevicha8f427f2009-07-13 18:40:08 -0700356 void setTypes(Type* pInt) {
357 mkpInt = pInt;
358 }
359
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700361 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700362 * Save the old value of the FP.
363 * Set the new value of the FP.
364 * Convert from the native platform calling convention to
365 * our stack-based calling convention. This may require
366 * pushing arguments from registers to the stack.
367 * Allocate "N" bytes of stack space. N isn't known yet, so
368 * just emit the instructions for adjusting the stack, and return
369 * the address to patch up. The patching will be done in
370 * functionExit().
371 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700372 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700373 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700374
Jack Palevich1cdef202009-05-22 12:06:27 -0700375 /* Emit a function epilog.
376 * Restore the old SP and FP register values.
377 * Return to the calling function.
378 * argCount - the number of arguments to the function.
379 * localVariableAddress - returned from functionEntry()
380 * localVariableSize - the size in bytes of the local variables.
381 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700382 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700384
Jack Palevich1cdef202009-05-22 12:06:27 -0700385 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700386 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700387
Jack Palevich1a539db2009-07-08 13:04:41 -0700388 /* Load floating point value from global address. */
389 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700390
Jack Palevich9221bcc2009-08-26 16:15:07 -0700391 /* Add the struct offset in bytes to R0, change the type to pType */
392 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
393
Jack Palevich1cdef202009-05-22 12:06:27 -0700394 /* Jump to a target, and return the address of the word that
395 * holds the target data, in case it needs to be fixed up later.
396 */
Jack Palevich22305132009-05-13 10:58:45 -0700397 virtual int gjmp(int t) = 0;
398
Jack Palevich1cdef202009-05-22 12:06:27 -0700399 /* Test R0 and jump to a target if the test succeeds.
400 * l = 0: je, l == 1: jne
401 * Return the address of the word that holds the targed data, in
402 * case it needs to be fixed up later.
403 */
Jack Palevich22305132009-05-13 10:58:45 -0700404 virtual int gtst(bool l, int t) = 0;
405
Jack Palevich9eed7a22009-07-06 17:24:34 -0700406 /* Compare TOS against R0, and store the boolean result in R0.
407 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700408 * op specifies the comparison.
409 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700410 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700411
Jack Palevich9eed7a22009-07-06 17:24:34 -0700412 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700413 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700414 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700415 */
Jack Palevich546b2242009-05-13 15:10:04 -0700416 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700417
Jack Palevich9eed7a22009-07-06 17:24:34 -0700418 /* Compare 0 against R0, and store the boolean result in R0.
419 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700421 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700422
423 /* Perform the arithmetic op specified by op. 0 is the
424 * left argument, R0 is the right argument.
425 */
426 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700428 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 */
430 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700431
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700432 /* Turn R0, TOS into R0 TOS R0 */
433
434 virtual void over() = 0;
435
436 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700437 */
438 virtual void popR0() = 0;
439
Jack Palevich9eed7a22009-07-06 17:24:34 -0700440 /* Store R0 to the address stored in TOS.
441 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700442 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700443 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700444
Jack Palevich1cdef202009-05-22 12:06:27 -0700445 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700446 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700447 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700448
Jack Palevich1cdef202009-05-22 12:06:27 -0700449 /* Load the absolute address of a variable to R0.
450 * If ea <= LOCAL, then this is a local variable, or an
451 * argument, addressed relative to FP.
452 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700453 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700454 * et is ET_RVALUE for things like string constants, ET_LVALUE for
455 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700456 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700457 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700458
Jack Palevich9f51a262009-07-29 16:22:26 -0700459 /* Load the pc-relative address of a forward-referenced variable to R0.
460 * Return the address of the 4-byte constant so that it can be filled
461 * in later.
462 */
463 virtual int leaForward(int ea, Type* pPointerType) = 0;
464
Jack Palevich8df46192009-07-07 14:48:51 -0700465 /**
466 * Convert R0 to the given type.
467 */
Jack Palevichb6154502009-08-04 14:56:09 -0700468
469 void convertR0(Type* pType) {
470 convertR0Imp(pType, false);
471 }
472
473 void castR0(Type* pType) {
474 convertR0Imp(pType, true);
475 }
476
477 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700478
Jack Palevich1cdef202009-05-22 12:06:27 -0700479 /* Emit code to adjust the stack for a function call. Return the
480 * label for the address of the instruction that adjusts the
481 * stack size. This will be passed as argument "a" to
482 * endFunctionCallArguments.
483 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700484 virtual int beginFunctionCallArguments() = 0;
485
Jack Palevich1cdef202009-05-22 12:06:27 -0700486 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700487 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700488 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700489 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700490
Jack Palevich1cdef202009-05-22 12:06:27 -0700491 /* Patch the function call preamble.
492 * a is the address returned from beginFunctionCallArguments
493 * l is the number of bytes the arguments took on the stack.
494 * Typically you would also emit code to convert the argument
495 * list into whatever the native function calling convention is.
496 * On ARM for example you would pop the first 5 arguments into
497 * R0..R4
498 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700499 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700500
Jack Palevich1cdef202009-05-22 12:06:27 -0700501 /* Emit a call to an unknown function. The argument "symbol" needs to
502 * be stored in the location where the address should go. It forms
503 * a chain. The address will be patched later.
504 * Return the address of the word that has to be patched.
505 */
Jack Palevich8df46192009-07-07 14:48:51 -0700506 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700507
Jack Palevich1cdef202009-05-22 12:06:27 -0700508 /* Call a function pointer. L is the number of bytes the arguments
509 * take on the stack. The address of the function is stored at
510 * location SP + l.
511 */
Jack Palevich8df46192009-07-07 14:48:51 -0700512 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700513
Jack Palevich1cdef202009-05-22 12:06:27 -0700514 /* Adjust SP after returning from a function call. l is the
515 * number of bytes of arguments stored on the stack. isIndirect
516 * is true if this was an indirect call. (In which case the
517 * address of the function is stored at location SP + l.)
518 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700519 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700520
Jack Palevich1cdef202009-05-22 12:06:27 -0700521 /* Generate a symbol at the current PC. t is the head of a
522 * linked list of addresses to patch.
523 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700524 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700525
Jack Palevich9f51a262009-07-29 16:22:26 -0700526 /* Resolve a forward reference function at the current PC.
527 * t is the head of a
528 * linked list of addresses to patch.
529 * (Like gsym, but using absolute address, not PC relative address.)
530 */
531 virtual void resolveForward(int t) = 0;
532
Jack Palevich1cdef202009-05-22 12:06:27 -0700533 /*
534 * Do any cleanup work required at the end of a compile.
535 * For example, an instruction cache might need to be
536 * invalidated.
537 * Return non-zero if there is an error.
538 */
539 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700540
Jack Palevicha6535612009-05-13 16:24:17 -0700541 /**
542 * Adjust relative branches by this amount.
543 */
544 virtual int jumpOffset() = 0;
545
Jack Palevich9eed7a22009-07-06 17:24:34 -0700546 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700547 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700548 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700549 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700550
551 /**
552 * Array element alignment (in bytes) for this type of data.
553 */
554 virtual size_t sizeOf(Type* type) = 0;
555
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700556 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700557 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700558 }
559
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700560 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700561 return mExpressionStack.back().et;
562 }
563
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700564 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700565 mExpressionStack.back().et = et;
566 }
567
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700568 virtual size_t getExpressionStackDepth() {
569 return mExpressionStack.size();
570 }
571
Jack Palevichb5e33312009-07-30 19:06:34 -0700572 virtual void forceR0RVal() {
573 if (getR0ExpressionType() == ET_LVALUE) {
574 loadR0FromR0();
575 }
576 }
577
Jack Palevich21a15a22009-05-11 14:49:29 -0700578 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700579 /*
580 * Output a byte. Handles all values, 0..ff.
581 */
582 void ob(int n) {
583 pCodeBuf->ob(n);
584 }
585
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700586 void o4(int data) {
587 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700588 }
589
Jack Palevich8b0624c2009-05-20 12:12:06 -0700590 intptr_t getBase() {
591 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700592 }
593
Jack Palevich8b0624c2009-05-20 12:12:06 -0700594 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700595 return pCodeBuf->getPC();
596 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700597
598 intptr_t getSize() {
599 return pCodeBuf->getSize();
600 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700601
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700602 void flush() {
603 pCodeBuf->flush();
604 }
605
Jack Palevichac0e95e2009-05-29 13:53:44 -0700606 void error(const char* fmt,...) {
607 va_list ap;
608 va_start(ap, fmt);
609 mErrorSink->verror(fmt, ap);
610 va_end(ap);
611 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700612
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700613 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700614 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700615 error("code generator assertion failed at line %s:%d.", __FILE__, line);
616 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700617 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700618 }
619 }
Jack Palevich8df46192009-07-07 14:48:51 -0700620
621 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700622 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700623 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700624 mExpressionStack.back().et = ET_RVALUE;
625 }
626
627 void setR0Type(Type* pType, ExpressionType et) {
628 assert(pType != NULL);
629 mExpressionStack.back().pType = pType;
630 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700631 }
632
Jack Palevich8df46192009-07-07 14:48:51 -0700633 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700634 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700635 }
636
637 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700638 if (mExpressionStack.size()) {
639 mExpressionStack.push_back(mExpressionStack.back());
640 } else {
641 mExpressionStack.push_back(ExpressionValue());
642 }
643
Jack Palevich8df46192009-07-07 14:48:51 -0700644 }
645
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700646 void overType() {
647 size_t size = mExpressionStack.size();
648 if (size >= 2) {
649 mExpressionStack.push_back(mExpressionStack.back());
650 mExpressionStack[size-1] = mExpressionStack[size-2];
651 mExpressionStack[size-2] = mExpressionStack[size];
652 }
653 }
654
Jack Palevich8df46192009-07-07 14:48:51 -0700655 void popType() {
656 mExpressionStack.pop_back();
657 }
658
659 bool bitsSame(Type* pA, Type* pB) {
660 return collapseType(pA->tag) == collapseType(pB->tag);
661 }
662
663 TypeTag collapseType(TypeTag tag) {
664 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700665 TY_INT,
666 TY_INT,
667 TY_INT,
668 TY_VOID,
669 TY_FLOAT,
670 TY_DOUBLE,
671 TY_INT,
672 TY_INT,
673 TY_VOID,
674 TY_VOID,
675 TY_VOID
676 };
Jack Palevich8df46192009-07-07 14:48:51 -0700677 return collapsedTag[tag];
678 }
679
Jack Palevich1a539db2009-07-08 13:04:41 -0700680 TypeTag collapseTypeR0() {
681 return collapseType(getR0Type()->tag);
682 }
683
Jack Palevichb6154502009-08-04 14:56:09 -0700684 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700685 return isFloatTag(pType->tag);
686 }
687
Jack Palevichb6154502009-08-04 14:56:09 -0700688 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700689 return tag == TY_FLOAT || tag == TY_DOUBLE;
690 }
691
Jack Palevichb6154502009-08-04 14:56:09 -0700692 static bool isPointerType(Type* pType) {
693 return isPointerTag(pType->tag);
694 }
695
696 static bool isPointerTag(TypeTag tag) {
697 return tag == TY_POINTER || tag == TY_ARRAY;
698 }
699
700 Type* getPointerArithmeticResultType(Type* a, Type* b) {
701 TypeTag aTag = a->tag;
702 TypeTag bTag = b->tag;
703 if (aTag == TY_POINTER) {
704 return a;
705 }
706 if (bTag == TY_POINTER) {
707 return b;
708 }
709 if (aTag == TY_ARRAY) {
710 return a->pTail;
711 }
712 if (bTag == TY_ARRAY) {
713 return b->pTail;
714 }
715 return NULL;
716 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700717 Type* mkpInt;
718
Jack Palevich21a15a22009-05-11 14:49:29 -0700719 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700720 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700721 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700722 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700723 };
724
Jack Paleviche7b59062009-05-19 17:12:17 -0700725#ifdef PROVIDE_ARM_CODEGEN
726
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700727 static size_t rotateRight(size_t n, size_t rotate) {
728 return (n >> rotate) | (n << (32 - rotate));
729 }
730
731 static size_t rotateLeft(size_t n, size_t rotate) {
732 return (n << rotate) | (n >> (32 - rotate));
733 }
734
735 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
736 for(size_t i = 0; i < 16; i++) {
737 size_t rotate = i * 2;
738 size_t mask = rotateRight(0xff, rotate);
739 if ((immediate | mask) == mask) {
740 size_t bits8 = rotateLeft(immediate, rotate);
741 // assert(bits8 <= 0xff);
742 *pResult = (i << 8) | bits8;
743 return true;
744 }
745 }
746 return false;
747 }
748
749 static size_t decode12BitImmediate(size_t immediate) {
750 size_t data = immediate & 0xff;
751 size_t rotate = 2 * ((immediate >> 8) & 0xf);
752 return rotateRight(data, rotate);
753 }
754
Jack Palevich53f06582009-09-10 14:01:58 -0700755 static bool isPowerOfTwo(size_t n) {
756 return (n != 0) & ((n & (n-1)) == 0);
757 }
758
759 static size_t log2(size_t n) {
760 int result = 0;
761 while (n >>= 1) {
762 result++;
763 }
764 return result;
765 }
766
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700767 class ARMCodeBuf : public ICodeBuf {
768 ICodeBuf* mpBase;
769 ErrorSink* mErrorSink;
770
771 class CircularQueue {
772 static const int SIZE = 16; // Must be power of 2
773 static const int MASK = SIZE-1;
774 unsigned int mBuf[SIZE];
775 int mHead;
776 int mCount;
777
778 public:
779 CircularQueue() {
780 mHead = 0;
781 mCount = 0;
782 }
783
784 void pushBack(unsigned int data) {
785 mBuf[(mHead + mCount) & MASK] = data;
786 mCount += 1;
787 }
788
789 unsigned int popFront() {
790 unsigned int result = mBuf[mHead];
791 mHead = (mHead + 1) & MASK;
792 mCount -= 1;
793 return result;
794 }
795
796 void popBack(int n) {
797 mCount -= n;
798 }
799
800 inline int count() {
801 return mCount;
802 }
803
804 bool empty() {
805 return mCount == 0;
806 }
807
808 bool full() {
809 return mCount == SIZE;
810 }
811
812 // The valid indexes are 1 - count() to 0
813 unsigned int operator[](int i) {
814 return mBuf[(mHead + mCount + i) & MASK];
815 }
816 };
817
818 CircularQueue mQ;
819
820 void error(const char* fmt,...) {
821 va_list ap;
822 va_start(ap, fmt);
823 mErrorSink->verror(fmt, ap);
824 va_end(ap);
825 }
826
827 void flush() {
828 while (!mQ.empty()) {
829 mpBase->o4(mQ.popFront());
830 }
831 mpBase->flush();
832 }
833
834 public:
835 ARMCodeBuf(ICodeBuf* pBase) {
836 mpBase = pBase;
837 }
838
839 virtual ~ARMCodeBuf() {
840 delete mpBase;
841 }
842
843 void init(int size) {
844 mpBase->init(size);
845 }
846
847 void setErrorSink(ErrorSink* pErrorSink) {
848 mErrorSink = pErrorSink;
849 mpBase->setErrorSink(pErrorSink);
850 }
851
852 void o4(int n) {
853 if (mQ.full()) {
854 mpBase->o4(mQ.popFront());
855 }
856 mQ.pushBack(n);
857
858#ifndef DISABLE_ARM_PEEPHOLE
859 // Peephole check
860 bool didPeep;
861 do {
Jack Palevich53f06582009-09-10 14:01:58 -0700862 static const unsigned int opMask = 0x01e00000;
863 static const unsigned int immediateMask = 0x00000fff;
864 static const unsigned int BMask = 0x00400000;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700865 didPeep = false;
866 if (mQ.count() >= 4) {
867
868 // Operand by a small constant
869 // push;mov #imm;pop;op ==> op #imm
870
Jack Palevich1c60e462009-09-18 15:03:03 -0700871 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
872 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
873 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
874 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700875 unsigned int movConst = mQ[-3];
876 unsigned int op = mQ[-1];
877 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
878 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
879 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
880 mQ.popBack(4);
881 mQ.pushBack(combined);
882 didPeep = true;
883 } else {
884 mQ.popBack(4);
885 didPeep = true;
886 }
887 }
888 }
889
890 // Load local variable
Jack Palevich53f06582009-09-10 14:01:58 -0700891 // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm]
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700892 if (mQ.count() >= 2) {
Jack Palevich53f06582009-09-10 14:01:58 -0700893 if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
894 const unsigned int encodedImmediate = mQ[-2] & immediateMask;
895 const unsigned int ld = mQ[-1];
896 if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
897 unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
898 mQ.popBack(2);
899 mQ.pushBack(combined);
900 didPeep = true;
Jack Palevich1c60e462009-09-18 15:03:03 -0700901 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
Jack Palevich53f06582009-09-10 14:01:58 -0700902 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
903 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700904 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
Jack Palevich53f06582009-09-10 14:01:58 -0700905 mQ.popBack(2);
906 mQ.pushBack(combined);
907 didPeep = true;
908 }
909 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700910 }
911 }
912
913 // Constant array lookup
914
915 if (mQ.count() >= 6 &&
916 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
917 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
918 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
919 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
920 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
921 mQ[-1] == 0xe0810000) { // add r0, r1, r0
922 unsigned int mov1 = mQ[-5];
923 unsigned int mov2 = mQ[-3];
924 unsigned int const1 = decode12BitImmediate(mov1);
925 unsigned int const2 = decode12BitImmediate(mov2);
926 unsigned int comboConst = const1 * const2;
927 size_t immediate = 0;
928 if (encode12BitImmediate(comboConst, &immediate)) {
929 mQ.popBack(6);
930 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
931 if (comboConst) {
932 mQ.pushBack(add);
933 }
934 didPeep = true;
935 }
936 }
937
Jack Palevich53f06582009-09-10 14:01:58 -0700938 // Pointer arithmetic with a stride that is a power of two
939
940 if (mQ.count() >= 3 &&
Jack Palevich1c60e462009-09-18 15:03:03 -0700941 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
942 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
Jack Palevich53f06582009-09-10 14:01:58 -0700943 mQ[-1] == 0xe0810000) { // add r0, r1, r0
944 int stride = decode12BitImmediate(mQ[-3]);
945 if (isPowerOfTwo(stride)) {
946 mQ.popBack(3);
947 unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
948 mQ.pushBack(add);
949 didPeep = true;
950 }
951 }
952
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700953 } while (didPeep);
954#endif
955 }
956
957 void ob(int n) {
958 error("ob() not supported.");
959 }
960
961 void* getBase() {
962 flush();
963 return mpBase->getBase();
964 }
965
966 intptr_t getSize() {
967 flush();
968 return mpBase->getSize();
969 }
970
971 intptr_t getPC() {
972 flush();
973 return mpBase->getPC();
974 }
975 };
976
Jack Palevich22305132009-05-13 10:58:45 -0700977 class ARMCodeGenerator : public CodeGenerator {
978 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700979 ARMCodeGenerator() {
980#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700981 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700982#else
Jack Palevichd5315572009-09-09 13:19:34 -0700983 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700984#endif
985 }
-b master422972c2009-06-17 19:13:52 -0700986
Jack Palevich22305132009-05-13 10:58:45 -0700987 virtual ~ARMCodeGenerator() {}
988
989 /* returns address to patch with local variable size
990 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700991 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700992 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700993 // sp -> arg4 arg5 ...
994 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700995 int regArgCount = calcRegArgCount(pDecl);
996 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700997 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700998 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700999 }
1000 // sp -> arg0 arg1 ...
1001 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -07001002 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -07001003 // sp, fp -> oldfp, retadr, arg0 arg1 ....
1004 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -07001005 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001006 int pc = getPC();
1007 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -07001008 // We don't know how many local variables we are going to use,
1009 // but we will round the allocation up to a multiple of
1010 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001011 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001012 }
1013
Jack Palevichb7718b92009-07-09 22:00:24 -07001014 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -07001015 // Round local variable size up to a multiple of stack alignment
1016 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
1017 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -07001018 // Patch local variable allocation code:
1019 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -07001020 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -07001021 }
Jack Palevich69796b62009-05-14 15:42:26 -07001022 *(char*) (localVariableAddress) = localVariableSize;
1023
Jack Palevich30321cb2009-08-20 15:34:23 -07001024#ifdef ARM_USE_VFP
1025 {
Jack Palevichc0f25332009-08-25 12:23:43 -07001026 Type* pReturnType = pDecl->pHead;
1027 switch(pReturnType->tag) {
1028 case TY_FLOAT:
1029 o4(0xEE170A90); // fmrs r0, s15
1030 break;
1031 case TY_DOUBLE:
1032 o4(0xEC510B17); // fmrrd r0, r1, d7
1033 break;
1034 default:
1035 break;
1036 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001037 }
1038#endif
1039
Jack Palevich69796b62009-05-14 15:42:26 -07001040 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
1041 o4(0xE1A0E00B); // mov lr, fp
1042 o4(0xE59BB000); // ldr fp, [fp]
1043 o4(0xE28ED004); // add sp, lr, #4
1044 // sp -> retadr, arg0, ...
1045 o4(0xE8BD4000); // ldmfd sp!, {lr}
1046 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -07001047
1048 // We store the PC into the lr so we can adjust the sp before
1049 // returning. We need to pull off the registers we pushed
1050 // earlier. We don't need to actually store them anywhere,
1051 // just adjust the stack.
1052 int regArgCount = calcRegArgCount(pDecl);
1053 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -07001054 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
1055 }
1056 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -07001057 }
1058
1059 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001060 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001061 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001062 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001063 }
1064
Jack Palevich1a539db2009-07-08 13:04:41 -07001065 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001066 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001067 // Global, absolute address
1068 o4(0xE59F0000); // ldr r0, .L1
1069 o4(0xEA000000); // b .L99
1070 o4(address); // .L1: .word ea
1071 // .L99:
1072
1073 switch (pType->tag) {
1074 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001075#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001076 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001077#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001078 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001079#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001080 break;
1081 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001082#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001083 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001084#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001085 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001086#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001087 break;
1088 default:
1089 assert(false);
1090 break;
1091 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001092 }
1093
Jack Palevich9221bcc2009-08-26 16:15:07 -07001094
1095 virtual void addStructOffsetR0(int offset, Type* pType) {
1096 if (offset) {
1097 size_t immediate = 0;
1098 if (encode12BitImmediate(offset, &immediate)) {
1099 o4(0xE2800000 | immediate); // add r0, r0, #offset
1100 } else {
1101 error("structure offset out of range: %d", offset);
1102 }
1103 }
1104 setR0Type(pType, ET_LVALUE);
1105 }
1106
Jack Palevich22305132009-05-13 10:58:45 -07001107 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001108 int pc = getPC();
1109 o4(0xEA000000 | encodeAddress(t)); // b .L33
1110 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001111 }
1112
1113 /* l = 0: je, l == 1: jne */
1114 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001115 Type* pR0Type = getR0Type();
1116 TypeTag tagR0 = pR0Type->tag;
1117 switch(tagR0) {
1118 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001119#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001120 o4(0xEEF57A40); // fcmpzs s15
1121 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001122#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001123 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001124 o4(0xE3500000); // cmp r0,#0
1125#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001126 break;
1127 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001128#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001129 o4(0xEEB57B40); // fcmpzd d7
1130 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001131#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001132 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001133 o4(0xE3500000); // cmp r0,#0
1134#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001135 break;
1136 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001137 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001138 break;
1139 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001140 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001141 int pc = getPC();
1142 o4(branch | encodeAddress(t));
1143 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001144 }
1145
Jack Palevich58c30ee2009-07-17 16:35:23 -07001146 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001147 Type* pR0Type = getR0Type();
1148 Type* pTOSType = getTOSType();
1149 TypeTag tagR0 = collapseType(pR0Type->tag);
1150 TypeTag tagTOS = collapseType(pTOSType->tag);
1151 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001152 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001153 o4(0xE1510000); // cmp r1, r1
1154 switch(op) {
1155 case OP_EQUALS:
1156 o4(0x03A00001); // moveq r0,#1
1157 o4(0x13A00000); // movne r0,#0
1158 break;
1159 case OP_NOT_EQUALS:
1160 o4(0x03A00000); // moveq r0,#0
1161 o4(0x13A00001); // movne r0,#1
1162 break;
1163 case OP_LESS_EQUAL:
1164 o4(0xD3A00001); // movle r0,#1
1165 o4(0xC3A00000); // movgt r0,#0
1166 break;
1167 case OP_GREATER:
1168 o4(0xD3A00000); // movle r0,#0
1169 o4(0xC3A00001); // movgt r0,#1
1170 break;
1171 case OP_GREATER_EQUAL:
1172 o4(0xA3A00001); // movge r0,#1
1173 o4(0xB3A00000); // movlt r0,#0
1174 break;
1175 case OP_LESS:
1176 o4(0xA3A00000); // movge r0,#0
1177 o4(0xB3A00001); // movlt r0,#1
1178 break;
1179 default:
1180 error("Unknown comparison op %d", op);
1181 break;
1182 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001183 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1184 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001185#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001186 o4(0xEEB46BC7); // fcmped d6, d7
1187 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001188 switch(op) {
1189 case OP_EQUALS:
1190 o4(0x03A00001); // moveq r0,#1
1191 o4(0x13A00000); // movne r0,#0
1192 break;
1193 case OP_NOT_EQUALS:
1194 o4(0x03A00000); // moveq r0,#0
1195 o4(0x13A00001); // movne r0,#1
1196 break;
1197 case OP_LESS_EQUAL:
1198 o4(0xD3A00001); // movle r0,#1
1199 o4(0xC3A00000); // movgt r0,#0
1200 break;
1201 case OP_GREATER:
1202 o4(0xD3A00000); // movle r0,#0
1203 o4(0xC3A00001); // movgt r0,#1
1204 break;
1205 case OP_GREATER_EQUAL:
1206 o4(0xA3A00001); // movge r0,#1
1207 o4(0xB3A00000); // movlt r0,#0
1208 break;
1209 case OP_LESS:
1210 o4(0xA3A00000); // movge r0,#0
1211 o4(0xB3A00001); // movlt r0,#1
1212 break;
1213 default:
1214 error("Unknown comparison op %d", op);
1215 break;
1216 }
1217#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001218 switch(op) {
1219 case OP_EQUALS:
1220 callRuntime((void*) runtime_cmp_eq_dd);
1221 break;
1222 case OP_NOT_EQUALS:
1223 callRuntime((void*) runtime_cmp_ne_dd);
1224 break;
1225 case OP_LESS_EQUAL:
1226 callRuntime((void*) runtime_cmp_le_dd);
1227 break;
1228 case OP_GREATER:
1229 callRuntime((void*) runtime_cmp_gt_dd);
1230 break;
1231 case OP_GREATER_EQUAL:
1232 callRuntime((void*) runtime_cmp_ge_dd);
1233 break;
1234 case OP_LESS:
1235 callRuntime((void*) runtime_cmp_lt_dd);
1236 break;
1237 default:
1238 error("Unknown comparison op %d", op);
1239 break;
1240 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001241#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001242 } else {
1243 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001244#ifdef ARM_USE_VFP
1245 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001246 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001247 switch(op) {
1248 case OP_EQUALS:
1249 o4(0x03A00001); // moveq r0,#1
1250 o4(0x13A00000); // movne r0,#0
1251 break;
1252 case OP_NOT_EQUALS:
1253 o4(0x03A00000); // moveq r0,#0
1254 o4(0x13A00001); // movne r0,#1
1255 break;
1256 case OP_LESS_EQUAL:
1257 o4(0xD3A00001); // movle r0,#1
1258 o4(0xC3A00000); // movgt r0,#0
1259 break;
1260 case OP_GREATER:
1261 o4(0xD3A00000); // movle r0,#0
1262 o4(0xC3A00001); // movgt r0,#1
1263 break;
1264 case OP_GREATER_EQUAL:
1265 o4(0xA3A00001); // movge r0,#1
1266 o4(0xB3A00000); // movlt r0,#0
1267 break;
1268 case OP_LESS:
1269 o4(0xA3A00000); // movge r0,#0
1270 o4(0xB3A00001); // movlt r0,#1
1271 break;
1272 default:
1273 error("Unknown comparison op %d", op);
1274 break;
1275 }
1276#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001277 switch(op) {
1278 case OP_EQUALS:
1279 callRuntime((void*) runtime_cmp_eq_ff);
1280 break;
1281 case OP_NOT_EQUALS:
1282 callRuntime((void*) runtime_cmp_ne_ff);
1283 break;
1284 case OP_LESS_EQUAL:
1285 callRuntime((void*) runtime_cmp_le_ff);
1286 break;
1287 case OP_GREATER:
1288 callRuntime((void*) runtime_cmp_gt_ff);
1289 break;
1290 case OP_GREATER_EQUAL:
1291 callRuntime((void*) runtime_cmp_ge_ff);
1292 break;
1293 case OP_LESS:
1294 callRuntime((void*) runtime_cmp_lt_ff);
1295 break;
1296 default:
1297 error("Unknown comparison op %d", op);
1298 break;
1299 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001300#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001301 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001302 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001303 }
1304
Jack Palevich546b2242009-05-13 15:10:04 -07001305 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001306 Type* pR0Type = getR0Type();
1307 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001308 TypeTag tagR0 = pR0Type->tag;
1309 TypeTag tagTOS = pTOSType->tag;
1310 bool isFloatR0 = isFloatTag(tagR0);
1311 bool isFloatTOS = isFloatTag(tagTOS);
1312 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001313 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001314 bool isPtrR0 = isPointerTag(tagR0);
1315 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001316 if (isPtrR0 || isPtrTOS) {
1317 if (isPtrR0 && isPtrTOS) {
1318 if (op != OP_MINUS) {
1319 error("Unsupported pointer-pointer operation %d.", op);
1320 }
1321 if (! typeEqual(pR0Type, pTOSType)) {
1322 error("Incompatible pointer types for subtraction.");
1323 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001324 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001325 setR0Type(mkpInt);
1326 int size = sizeOf(pR0Type->pHead);
1327 if (size != 1) {
1328 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001329 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001330 // TODO: Optimize for power-of-two.
1331 genOp(OP_DIV);
1332 }
1333 } else {
1334 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1335 error("Unsupported pointer-scalar operation %d", op);
1336 }
Jack Palevichb6154502009-08-04 14:56:09 -07001337 Type* pPtrType = getPointerArithmeticResultType(
1338 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001339 int size = sizeOf(pPtrType->pHead);
1340 if (size != 1) {
1341 // TODO: Optimize for power-of-two.
1342 liReg(size, 2);
1343 if (isPtrR0) {
1344 o4(0x0E0010192); // mul r1,r2,r1
1345 } else {
1346 o4(0x0E0000092); // mul r0,r2,r0
1347 }
1348 }
1349 switch(op) {
1350 case OP_PLUS:
1351 o4(0xE0810000); // add r0,r1,r0
1352 break;
1353 case OP_MINUS:
1354 o4(0xE0410000); // sub r0,r1,r0
1355 break;
1356 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001357 setR0Type(pPtrType);
1358 }
1359 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001360 switch(op) {
1361 case OP_MUL:
1362 o4(0x0E0000091); // mul r0,r1,r0
1363 break;
1364 case OP_DIV:
1365 callRuntime((void*) runtime_DIV);
1366 break;
1367 case OP_MOD:
1368 callRuntime((void*) runtime_MOD);
1369 break;
1370 case OP_PLUS:
1371 o4(0xE0810000); // add r0,r1,r0
1372 break;
1373 case OP_MINUS:
1374 o4(0xE0410000); // sub r0,r1,r0
1375 break;
1376 case OP_SHIFT_LEFT:
1377 o4(0xE1A00011); // lsl r0,r1,r0
1378 break;
1379 case OP_SHIFT_RIGHT:
1380 o4(0xE1A00051); // asr r0,r1,r0
1381 break;
1382 case OP_BIT_AND:
1383 o4(0xE0010000); // and r0,r1,r0
1384 break;
1385 case OP_BIT_XOR:
1386 o4(0xE0210000); // eor r0,r1,r0
1387 break;
1388 case OP_BIT_OR:
1389 o4(0xE1810000); // orr r0,r1,r0
1390 break;
1391 case OP_BIT_NOT:
1392 o4(0xE1E00000); // mvn r0, r0
1393 break;
1394 default:
1395 error("Unimplemented op %d\n", op);
1396 break;
1397 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001398 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001399 } else {
1400 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1401 if (pResultType->tag == TY_DOUBLE) {
1402 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001403
Jack Palevichb7718b92009-07-09 22:00:24 -07001404 switch(op) {
1405 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001406#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001407 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001408#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001409 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001410#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001411 break;
1412 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001413#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001414 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001415#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001416 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001417#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001418 break;
1419 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001420#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001421 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001422#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001423 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001424#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001425 break;
1426 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001427#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001428 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001429#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001430 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001431#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001432 break;
1433 default:
1434 error("Unsupported binary floating operation %d\n", op);
1435 break;
1436 }
1437 } else {
1438 setupFloatArgs();
1439 switch(op) {
1440 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001441#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001442 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001443#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001444 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001445#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001446 break;
1447 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001448#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001449 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001450#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001451 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001452#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001453 break;
1454 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001455#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001456 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001457#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001458 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001459#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001460 break;
1461 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001462#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001463 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001464#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001465 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001466#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001467 break;
1468 default:
1469 error("Unsupported binary floating operation %d\n", op);
1470 break;
1471 }
1472 }
1473 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001474 }
Jack Palevich22305132009-05-13 10:58:45 -07001475 }
1476
Jack Palevich58c30ee2009-07-17 16:35:23 -07001477 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001478 if (op != OP_LOGICAL_NOT) {
1479 error("Unknown unary cmp %d", op);
1480 } else {
1481 Type* pR0Type = getR0Type();
1482 TypeTag tag = collapseType(pR0Type->tag);
1483 switch(tag) {
1484 case TY_INT:
1485 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001486 o4(0xE1510000); // cmp r1, r0
1487 o4(0x03A00001); // moveq r0,#1
1488 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001489 break;
1490 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001491#ifdef ARM_USE_VFP
1492 o4(0xEEF57A40); // fcmpzs s15
1493 o4(0xEEF1FA10); // fmstat
1494 o4(0x03A00001); // moveq r0,#1
1495 o4(0x13A00000); // movne r0,#0
1496#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001497 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001498#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001499 break;
1500 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001501#ifdef ARM_USE_VFP
1502 o4(0xEEB57B40); // fcmpzd d7
1503 o4(0xEEF1FA10); // fmstat
1504 o4(0x03A00001); // moveq r0,#1
1505 o4(0x13A00000); // movne r0,#0
1506#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001507 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001508#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001509 break;
1510 default:
1511 error("gUnaryCmp unsupported type");
1512 break;
1513 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001514 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001515 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001516 }
1517
1518 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001519 Type* pR0Type = getR0Type();
1520 TypeTag tag = collapseType(pR0Type->tag);
1521 switch(tag) {
1522 case TY_INT:
1523 switch(op) {
1524 case OP_MINUS:
1525 o4(0xE3A01000); // mov r1, #0
1526 o4(0xE0410000); // sub r0,r1,r0
1527 break;
1528 case OP_BIT_NOT:
1529 o4(0xE1E00000); // mvn r0, r0
1530 break;
1531 default:
1532 error("Unknown unary op %d\n", op);
1533 break;
1534 }
1535 break;
1536 case TY_FLOAT:
1537 case TY_DOUBLE:
1538 switch (op) {
1539 case OP_MINUS:
1540 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001541#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001542 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001543#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001544 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001545#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001546 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001547#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001548 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001549#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001550 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001551#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001552 }
1553 break;
1554 case OP_BIT_NOT:
1555 error("Can't apply '~' operator to a float or double.");
1556 break;
1557 default:
1558 error("Unknown unary op %d\n", op);
1559 break;
1560 }
1561 break;
1562 default:
1563 error("genUnaryOp unsupported type");
1564 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001565 }
Jack Palevich22305132009-05-13 10:58:45 -07001566 }
1567
Jack Palevich1cdef202009-05-22 12:06:27 -07001568 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001569 Type* pR0Type = getR0Type();
1570 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001571
1572#ifdef ARM_USE_VFP
1573 switch (r0ct ) {
1574 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001575 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001576 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001577 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001578 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001579 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001580 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001581 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001582 default:
1583 o4(0xE92D0001); // stmfd sp!,{r0}
1584 mStackUse += 4;
1585 }
1586#else
1587
Jack Palevichb7718b92009-07-09 22:00:24 -07001588 if (r0ct != TY_DOUBLE) {
1589 o4(0xE92D0001); // stmfd sp!,{r0}
1590 mStackUse += 4;
1591 } else {
1592 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1593 mStackUse += 8;
1594 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001595#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001596 pushType();
-b master422972c2009-06-17 19:13:52 -07001597 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001598 }
1599
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001600 virtual void over() {
1601 // We know it's only used for int-ptr ops (++/--)
1602
1603 Type* pR0Type = getR0Type();
1604 TypeTag r0ct = collapseType(pR0Type->tag);
1605
1606 Type* pTOSType = getTOSType();
1607 TypeTag tosct = collapseType(pTOSType->tag);
1608
1609 assert (r0ct == TY_INT && tosct == TY_INT);
1610
1611 o4(0xE8BD0002); // ldmfd sp!,{r1}
1612 o4(0xE92D0001); // stmfd sp!,{r0}
1613 o4(0xE92D0002); // stmfd sp!,{r1}
1614 overType();
1615 mStackUse += 4;
1616 }
1617
Jack Palevich58c30ee2009-07-17 16:35:23 -07001618 virtual void popR0() {
1619 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001620 TypeTag tosct = collapseType(pTOSType->tag);
1621#ifdef ARM_USE_VFP
1622 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001623 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001624 }
1625#endif
1626 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001627 case TY_INT:
1628 case TY_FLOAT:
1629 o4(0xE8BD0001); // ldmfd sp!,{r0}
1630 mStackUse -= 4;
1631 break;
1632 case TY_DOUBLE:
1633 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1634 mStackUse -= 8;
1635 break;
1636 default:
1637 error("Can't pop this type.");
1638 break;
1639 }
1640 popType();
1641 LOG_STACK("popR0: %d\n", mStackUse);
1642 }
1643
1644 virtual void storeR0ToTOS() {
1645 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001646 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001647 Type* pDestType = pPointerType->pHead;
1648 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001649 o4(0xE8BD0004); // ldmfd sp!,{r2}
1650 popType();
-b master422972c2009-06-17 19:13:52 -07001651 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001652 switch (pDestType->tag) {
1653 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001654 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001655 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001656 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001657 case TY_FLOAT:
1658#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001659 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001660#else
1661 o4(0xE5820000); // str r0, [r2]
1662#endif
1663 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001664 case TY_SHORT:
1665 o4(0xE1C200B0); // strh r0, [r2]
1666 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001667 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001668 o4(0xE5C20000); // strb r0, [r2]
1669 break;
1670 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001671#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001672 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001673#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001674 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001675#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001676 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001677 case TY_STRUCT:
1678 {
1679 int size = sizeOf(pDestType);
1680 if (size > 0) {
1681 liReg(size, 1);
1682 callRuntime((void*) runtime_structCopy);
1683 }
1684 }
1685 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001686 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001687 error("storeR0ToTOS: unimplemented type %d",
1688 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001689 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001690 }
Jack Palevich02effee2009-11-09 12:52:45 +08001691 setR0Type(pDestType);
Jack Palevich22305132009-05-13 10:58:45 -07001692 }
1693
Jack Palevich58c30ee2009-07-17 16:35:23 -07001694 virtual void loadR0FromR0() {
1695 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001696 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001697 Type* pNewType = pPointerType->pHead;
1698 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001699 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001700 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001701 case TY_INT:
1702 o4(0xE5900000); // ldr r0, [r0]
1703 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001704 case TY_FLOAT:
1705#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001706 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001707#else
1708 o4(0xE5900000); // ldr r0, [r0]
1709#endif
1710 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001711 case TY_SHORT:
1712 o4(0xE1D000F0); // ldrsh r0, [r0]
1713 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001714 case TY_CHAR:
1715 o4(0xE5D00000); // ldrb r0, [r0]
1716 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001717 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001718#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001719 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001720#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001721 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001722#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001723 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001724 case TY_ARRAY:
1725 pNewType = pNewType->pTail;
1726 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001727 case TY_STRUCT:
1728 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001729 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001730 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001731 break;
1732 }
Jack Palevich80e49722009-08-04 15:39:49 -07001733 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001734 }
1735
Jack Palevichb5e33312009-07-30 19:06:34 -07001736 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001737 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001738 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001739
1740 size_t immediate = 0;
1741 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001742 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001743 inRange = encode12BitImmediate(-ea, &immediate);
1744 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001745 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001746 inRange = encode12BitImmediate(ea, &immediate);
1747 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1748 }
1749 if (! inRange) {
1750 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001751 }
Jack Palevichbd894902009-05-14 19:35:31 -07001752 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001753 // Global, absolute.
1754 o4(0xE59F0000); // ldr r0, .L1
1755 o4(0xEA000000); // b .L99
1756 o4(ea); // .L1: .word 0
1757 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001758 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001759 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001760 }
1761
Jack Palevich9f51a262009-07-29 16:22:26 -07001762 virtual int leaForward(int ea, Type* pPointerType) {
1763 setR0Type(pPointerType);
1764 int result = ea;
1765 int pc = getPC();
1766 int offset = 0;
1767 if (ea) {
1768 offset = (pc - ea - 8) >> 2;
1769 if ((offset & 0xffff) != offset) {
1770 error("function forward reference out of bounds");
1771 }
1772 } else {
1773 offset = 0;
1774 }
1775 o4(0xE59F0000 | offset); // ldr r0, .L1
1776
1777 if (ea == 0) {
1778 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001779 result = getPC();
1780 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001781 // .L99:
1782 }
1783 return result;
1784 }
1785
Jack Palevichb6154502009-08-04 14:56:09 -07001786 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001787 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001788 if (isPointerType(pType) && isPointerType(pR0Type)) {
1789 Type* pA = pR0Type;
1790 Type* pB = pType;
1791 // Array decays to pointer
1792 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1793 pA = pA->pTail;
1794 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001795 if (! (typeEqual(pA, pB)
1796 || pB->pHead->tag == TY_VOID
1797 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1798 )) {
1799 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001800 }
Jack Palevichb6154502009-08-04 14:56:09 -07001801 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001802 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001803 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001804 TypeTag r0Tag = collapseType(pR0Type->tag);
1805 TypeTag destTag = collapseType(pType->tag);
1806 if (r0Tag == TY_INT) {
1807 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001808#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001809 o4(0xEE070A90); // fmsr s15, r0
1810 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001811
1812#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001813 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001814#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001815 } else {
1816 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001817#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001818 o4(0xEE070A90); // fmsr s15, r0
1819 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001820
1821#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001822 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001823#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001824 }
1825 } else if (r0Tag == TY_FLOAT) {
1826 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001827#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001828 o4(0xEEFD7AE7); // ftosizs s15, s15
1829 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001830#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001831 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001832#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001833 } else {
1834 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001835#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001836 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001837#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001838 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001839#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001840 }
1841 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001842 if (r0Tag == TY_DOUBLE) {
1843 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001844#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001845 o4(0xEEFD7BC7); // ftosizd s15, d7
1846 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001847#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001848 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001849#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001850 } else {
1851 if(destTag == TY_FLOAT) {
1852#ifdef ARM_USE_VFP
1853 o4(0xEEF77BC7); // fcvtsd s15, d7
1854#else
1855 callRuntime((void*) runtime_double_to_float);
1856#endif
1857 } else {
1858 incompatibleTypes(pR0Type, pType);
1859 }
1860 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001861 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001862 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001863 }
1864 }
Jack Palevich8df46192009-07-07 14:48:51 -07001865 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001866 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001867 }
1868
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001869 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001870 int pc = getPC();
1871 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1872 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001873 }
1874
Jack Palevich8148c5b2009-07-16 18:24:47 -07001875 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001876 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001877 Type* pR0Type = getR0Type();
1878 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001879#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001880 switch(r0ct) {
1881 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001882 if (l < 0 || l > 4096-4) {
1883 error("l out of range for stack offset: 0x%08x", l);
1884 }
1885 o4(0xE58D0000 | l); // str r0, [sp, #l]
1886 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001887 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001888 if (l < 0 || l > 1020 || (l & 3)) {
1889 error("l out of range for stack offset: 0x%08x", l);
1890 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001891 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001892 return 4;
1893 case TY_DOUBLE: {
1894 // Align to 8 byte boundary
1895 int l2 = (l + 7) & ~7;
1896 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1897 error("l out of range for stack offset: 0x%08x", l);
1898 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001899 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001900 return (l2 - l) + 8;
1901 }
1902 default:
1903 assert(false);
1904 return 0;
1905 }
1906#else
1907 switch(r0ct) {
1908 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001909 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001910 if (l < 0 || l > 4096-4) {
1911 error("l out of range for stack offset: 0x%08x", l);
1912 }
1913 o4(0xE58D0000 + l); // str r0, [sp, #l]
1914 return 4;
1915 case TY_DOUBLE: {
1916 // Align to 8 byte boundary
1917 int l2 = (l + 7) & ~7;
1918 if (l2 < 0 || l2 > 4096-8) {
1919 error("l out of range for stack offset: 0x%08x", l);
1920 }
1921 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1922 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1923 return (l2 - l) + 8;
1924 }
1925 default:
1926 assert(false);
1927 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001928 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001929#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001930 }
1931
Jack Palevichb7718b92009-07-09 22:00:24 -07001932 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001933 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001934 // Have to calculate register arg count from actual stack size,
1935 // in order to properly handle ... functions.
1936 int regArgCount = l >> 2;
1937 if (regArgCount > 4) {
1938 regArgCount = 4;
1939 }
1940 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001941 argumentStackUse -= regArgCount * 4;
1942 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1943 }
1944 mStackUse += argumentStackUse;
1945
1946 // Align stack.
1947 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1948 * STACK_ALIGNMENT);
1949 mStackAlignmentAdjustment = 0;
1950 if (missalignment > 0) {
1951 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1952 }
1953 l += mStackAlignmentAdjustment;
1954
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001955 if (l < 0 || l > 0x3FC) {
1956 error("L out of range for stack adjustment: 0x%08x", l);
1957 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001958 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001959 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001960 mStackUse += mStackAlignmentAdjustment;
1961 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1962 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001963 }
1964
Jack Palevich8df46192009-07-07 14:48:51 -07001965 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001966 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001967 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001968 int pc = getPC();
1969 o4(0xEB000000 | encodeAddress(symbol));
1970 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001971 }
1972
Jack Palevich8df46192009-07-07 14:48:51 -07001973 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001974 assert(pFunc->tag == TY_FUNC);
1975 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001976 int argCount = l >> 2;
1977 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001978 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001979 if (adjustedL < 0 || adjustedL > 4096-4) {
1980 error("l out of range for stack offset: 0x%08x", l);
1981 }
1982 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1983 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001984 Type* pReturnType = pFunc->pHead;
1985 setR0Type(pReturnType);
1986#ifdef ARM_USE_VFP
1987 switch(pReturnType->tag) {
1988 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001989 o4(0xEE070A90); // fmsr s15, r0
1990 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001991 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001992 o4(0xEC410B17); // fmdrr d7, r0, r1
1993 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001994 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001995 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001996 }
1997#endif
Jack Palevich22305132009-05-13 10:58:45 -07001998 }
1999
Jack Palevichb7718b92009-07-09 22:00:24 -07002000 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002001 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07002002 // Have to calculate register arg count from actual stack size,
2003 // in order to properly handle ... functions.
2004 int regArgCount = l >> 2;
2005 if (regArgCount > 4) {
2006 regArgCount = 4;
2007 }
2008 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07002009 int stackUse = stackArgs + (isIndirect ? 1 : 0)
2010 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07002011 if (stackUse) {
2012 if (stackUse < 0 || stackUse > 255) {
2013 error("L out of range for stack adjustment: 0x%08x", l);
2014 }
2015 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07002016 mStackUse -= stackUse * 4;
2017 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002018 }
Jack Palevich22305132009-05-13 10:58:45 -07002019 }
2020
Jack Palevicha6535612009-05-13 16:24:17 -07002021 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07002022 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002023 }
2024
2025 /* output a symbol and patch all calls to it */
2026 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002027 int n;
2028 int base = getBase();
2029 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002030 while (t) {
2031 int data = * (int*) t;
2032 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2033 if (decodedOffset == 0) {
2034 n = 0;
2035 } else {
2036 n = base + decodedOffset; /* next value */
2037 }
2038 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2039 | encodeRelAddress(pc - t - 8);
2040 t = n;
2041 }
2042 }
2043
Jack Palevich9f51a262009-07-29 16:22:26 -07002044 /* output a symbol and patch all calls to it */
2045 virtual void resolveForward(int t) {
2046 if (t) {
2047 int pc = getPC();
2048 *(int *) t = pc;
2049 }
2050 }
2051
Jack Palevich1cdef202009-05-22 12:06:27 -07002052 virtual int finishCompile() {
2053#if defined(__arm__)
2054 const long base = long(getBase());
2055 const long curr = long(getPC());
2056 int err = cacheflush(base, curr, 0);
2057 return err;
2058#else
2059 return 0;
2060#endif
2061 }
2062
Jack Palevich9eed7a22009-07-06 17:24:34 -07002063 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002064 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002065 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002066 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002067 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002068 case TY_CHAR:
2069 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002070 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002071 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002072 case TY_DOUBLE:
2073 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002074 case TY_ARRAY:
2075 return alignmentOf(pType->pHead);
2076 case TY_STRUCT:
2077 return pType->pHead->alignment & 0x7fffffff;
2078 case TY_FUNC:
2079 error("alignment of func not supported");
2080 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002081 default:
2082 return 4;
2083 }
2084 }
2085
2086 /**
2087 * Array element alignment (in bytes) for this type of data.
2088 */
2089 virtual size_t sizeOf(Type* pType){
2090 switch(pType->tag) {
2091 case TY_INT:
2092 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002093 case TY_SHORT:
2094 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002095 case TY_CHAR:
2096 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002097 case TY_FLOAT:
2098 return 4;
2099 case TY_DOUBLE:
2100 return 8;
2101 case TY_POINTER:
2102 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002103 case TY_ARRAY:
2104 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002105 case TY_STRUCT:
2106 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002107 default:
2108 error("Unsupported type %d", pType->tag);
2109 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002110 }
2111 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002112
Jack Palevich22305132009-05-13 10:58:45 -07002113 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002114
2115 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2116
2117 /** Encode a relative address that might also be
2118 * a label.
2119 */
2120 int encodeAddress(int value) {
2121 int base = getBase();
2122 if (value >= base && value <= getPC() ) {
2123 // This is a label, encode it relative to the base.
2124 value = value - base;
2125 }
2126 return encodeRelAddress(value);
2127 }
2128
2129 int encodeRelAddress(int value) {
2130 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2131 }
Jack Palevich22305132009-05-13 10:58:45 -07002132
Jack Palevichb7718b92009-07-09 22:00:24 -07002133 int calcRegArgCount(Type* pDecl) {
2134 int reg = 0;
2135 Type* pArgs = pDecl->pTail;
2136 while (pArgs && reg < 4) {
2137 Type* pArg = pArgs->pHead;
2138 if ( pArg->tag == TY_DOUBLE) {
2139 int evenReg = (reg + 1) & ~1;
2140 if (evenReg >= 4) {
2141 break;
2142 }
2143 reg = evenReg + 2;
2144 } else {
2145 reg++;
2146 }
2147 pArgs = pArgs->pTail;
2148 }
2149 return reg;
2150 }
2151
Jack Palevich58c30ee2009-07-17 16:35:23 -07002152 void setupIntPtrArgs() {
2153 o4(0xE8BD0002); // ldmfd sp!,{r1}
2154 mStackUse -= 4;
2155 popType();
2156 }
2157
Jack Palevich30321cb2009-08-20 15:34:23 -07002158 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002159 * Make sure both R0 and TOS are floats. (Could be ints)
2160 * We know that at least one of R0 and TOS is already a float
2161 */
2162 void setupFloatArgs() {
2163 Type* pR0Type = getR0Type();
2164 Type* pTOSType = getTOSType();
2165 TypeTag tagR0 = collapseType(pR0Type->tag);
2166 TypeTag tagTOS = collapseType(pTOSType->tag);
2167 if (tagR0 != TY_FLOAT) {
2168 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002169#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002170 o4(0xEE070A90); // fmsr s15, r0
2171 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002172#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002173 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002174#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002175 }
2176 if (tagTOS != TY_FLOAT) {
2177 assert(tagTOS == TY_INT);
2178 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002179#ifdef ARM_USE_VFP
2180 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002181 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002182#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002183 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2184 o4(0xE59D0004); // ldr r0, [sp, #4]
2185 callRuntime((void*) runtime_int_to_float);
2186 o4(0xE1A01000); // mov r1, r0
2187 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2188 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002189#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002190 } else {
2191 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002192#ifdef ARM_USE_VFP
2193 o4(0xECBD7A01); // fldmfds sp!, {s14}
2194
2195#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002196 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002197#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002198 }
2199 mStackUse -= 4;
2200 popType();
2201 }
2202
Jack Palevich30321cb2009-08-20 15:34:23 -07002203 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002204 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2205 * We know that at least one of R0 and TOS are already a double.
2206 */
2207
2208 void setupDoubleArgs() {
2209 Type* pR0Type = getR0Type();
2210 Type* pTOSType = getTOSType();
2211 TypeTag tagR0 = collapseType(pR0Type->tag);
2212 TypeTag tagTOS = collapseType(pTOSType->tag);
2213 if (tagR0 != TY_DOUBLE) {
2214 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002215#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002216 o4(0xEE070A90); // fmsr s15, r0
2217 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002218
2219#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002220 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002221#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002222 } else {
2223 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002224#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002225 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002226#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002227 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002228#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002229 }
2230 }
2231 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002232#ifdef ARM_USE_VFP
2233 if (tagTOS == TY_INT) {
2234 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002235 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002236 } else {
2237 assert(tagTOS == TY_FLOAT);
2238 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002239 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002240 }
2241#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002242 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2243 o4(0xE59D0008); // ldr r0, [sp, #8]
2244 if (tagTOS == TY_INT) {
2245 callRuntime((void*) runtime_int_to_double);
2246 } else {
2247 assert(tagTOS == TY_FLOAT);
2248 callRuntime((void*) runtime_float_to_double);
2249 }
2250 o4(0xE1A02000); // mov r2, r0
2251 o4(0xE1A03001); // mov r3, r1
2252 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2253 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002254#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002255 mStackUse -= 4;
2256 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002257#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002258 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002259#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002260 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002261#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002262 mStackUse -= 8;
2263 }
2264 popType();
2265 }
2266
Jack Palevicha8f427f2009-07-13 18:40:08 -07002267 void liReg(int t, int reg) {
2268 assert(reg >= 0 && reg < 16);
2269 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002270 size_t encodedImmediate;
2271 if (encode12BitImmediate(t, &encodedImmediate)) {
2272 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2273 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002274 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002275 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002276 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002277 o4(0xE51F0000 | rN); // ldr rN, .L3
2278 o4(0xEA000000); // b .L99
2279 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002280 // .L99:
2281 }
2282 }
2283
Jack Palevichc408bbf2009-09-08 12:07:32 -07002284 void incompatibleTypes(Type* pR0Type, Type* pType) {
2285 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2286 }
2287
Jack Palevichb7718b92009-07-09 22:00:24 -07002288 void callRuntime(void* fn) {
2289 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002290 o4(0xEA000000); // b .L99
2291 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002292 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002293 }
2294
Jack Palevichb7718b92009-07-09 22:00:24 -07002295 // Integer math:
2296
2297 static int runtime_DIV(int b, int a) {
2298 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002299 }
2300
Jack Palevichb7718b92009-07-09 22:00:24 -07002301 static int runtime_MOD(int b, int a) {
2302 return a % b;
2303 }
2304
Jack Palevich9221bcc2009-08-26 16:15:07 -07002305 static void runtime_structCopy(void* src, size_t size, void* dest) {
2306 memcpy(dest, src, size);
2307 }
2308
Jack Palevich30321cb2009-08-20 15:34:23 -07002309#ifndef ARM_USE_VFP
2310
Jack Palevichb7718b92009-07-09 22:00:24 -07002311 // Comparison to zero
2312
2313 static int runtime_is_non_zero_f(float a) {
2314 return a != 0;
2315 }
2316
2317 static int runtime_is_non_zero_d(double a) {
2318 return a != 0;
2319 }
2320
2321 // Comparison to zero
2322
2323 static int runtime_is_zero_f(float a) {
2324 return a == 0;
2325 }
2326
2327 static int runtime_is_zero_d(double a) {
2328 return a == 0;
2329 }
2330
2331 // Type conversion
2332
2333 static int runtime_float_to_int(float a) {
2334 return (int) a;
2335 }
2336
2337 static double runtime_float_to_double(float a) {
2338 return (double) a;
2339 }
2340
2341 static int runtime_double_to_int(double a) {
2342 return (int) a;
2343 }
2344
2345 static float runtime_double_to_float(double a) {
2346 return (float) a;
2347 }
2348
2349 static float runtime_int_to_float(int a) {
2350 return (float) a;
2351 }
2352
2353 static double runtime_int_to_double(int a) {
2354 return (double) a;
2355 }
2356
2357 // Comparisons float
2358
2359 static int runtime_cmp_eq_ff(float b, float a) {
2360 return a == b;
2361 }
2362
2363 static int runtime_cmp_ne_ff(float b, float a) {
2364 return a != b;
2365 }
2366
2367 static int runtime_cmp_lt_ff(float b, float a) {
2368 return a < b;
2369 }
2370
2371 static int runtime_cmp_le_ff(float b, float a) {
2372 return a <= b;
2373 }
2374
2375 static int runtime_cmp_ge_ff(float b, float a) {
2376 return a >= b;
2377 }
2378
2379 static int runtime_cmp_gt_ff(float b, float a) {
2380 return a > b;
2381 }
2382
2383 // Comparisons double
2384
2385 static int runtime_cmp_eq_dd(double b, double a) {
2386 return a == b;
2387 }
2388
2389 static int runtime_cmp_ne_dd(double b, double a) {
2390 return a != b;
2391 }
2392
2393 static int runtime_cmp_lt_dd(double b, double a) {
2394 return a < b;
2395 }
2396
2397 static int runtime_cmp_le_dd(double b, double a) {
2398 return a <= b;
2399 }
2400
2401 static int runtime_cmp_ge_dd(double b, double a) {
2402 return a >= b;
2403 }
2404
2405 static int runtime_cmp_gt_dd(double b, double a) {
2406 return a > b;
2407 }
2408
2409 // Math float
2410
2411 static float runtime_op_add_ff(float b, float a) {
2412 return a + b;
2413 }
2414
2415 static float runtime_op_sub_ff(float b, float a) {
2416 return a - b;
2417 }
2418
2419 static float runtime_op_mul_ff(float b, float a) {
2420 return a * b;
2421 }
2422
2423 static float runtime_op_div_ff(float b, float a) {
2424 return a / b;
2425 }
2426
2427 static float runtime_op_neg_f(float a) {
2428 return -a;
2429 }
2430
2431 // Math double
2432
2433 static double runtime_op_add_dd(double b, double a) {
2434 return a + b;
2435 }
2436
2437 static double runtime_op_sub_dd(double b, double a) {
2438 return a - b;
2439 }
2440
2441 static double runtime_op_mul_dd(double b, double a) {
2442 return a * b;
2443 }
2444
2445 static double runtime_op_div_dd(double b, double a) {
2446 return a / b;
2447 }
2448
2449 static double runtime_op_neg_d(double a) {
2450 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002451 }
-b master422972c2009-06-17 19:13:52 -07002452
Jack Palevich30321cb2009-08-20 15:34:23 -07002453#endif
2454
-b master422972c2009-06-17 19:13:52 -07002455 static const int STACK_ALIGNMENT = 8;
2456 int mStackUse;
2457 // This variable holds the amount we adjusted the stack in the most
2458 // recent endFunctionCallArguments call. It's examined by the
2459 // following adjustStackAfterCall call.
2460 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002461 };
2462
Jack Palevich09555c72009-05-27 12:25:55 -07002463#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002464
2465#ifdef PROVIDE_X86_CODEGEN
2466
Jack Palevich21a15a22009-05-11 14:49:29 -07002467 class X86CodeGenerator : public CodeGenerator {
2468 public:
2469 X86CodeGenerator() {}
2470 virtual ~X86CodeGenerator() {}
2471
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002472 /* returns address to patch with local variable size
2473 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002474 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002475 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2476 return oad(0xec81, 0); /* sub $xxx, %esp */
2477 }
2478
Jack Palevichb7718b92009-07-09 22:00:24 -07002479 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002480 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002481 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002482 }
2483
Jack Palevich21a15a22009-05-11 14:49:29 -07002484 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002485 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002486 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002487 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002488 }
2489
Jack Palevich1a539db2009-07-08 13:04:41 -07002490 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002491 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002492 switch (pType->tag) {
2493 case TY_FLOAT:
2494 oad(0x05D9, address); // flds
2495 break;
2496 case TY_DOUBLE:
2497 oad(0x05DD, address); // fldl
2498 break;
2499 default:
2500 assert(false);
2501 break;
2502 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002503 }
2504
Jack Palevich9221bcc2009-08-26 16:15:07 -07002505 virtual void addStructOffsetR0(int offset, Type* pType) {
2506 if (offset) {
2507 oad(0x05, offset); // addl offset, %eax
2508 }
2509 setR0Type(pType, ET_LVALUE);
2510 }
2511
Jack Palevich22305132009-05-13 10:58:45 -07002512 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002513 return psym(0xe9, t);
2514 }
2515
2516 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002517 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002518 Type* pR0Type = getR0Type();
2519 TypeTag tagR0 = pR0Type->tag;
2520 bool isFloatR0 = isFloatTag(tagR0);
2521 if (isFloatR0) {
2522 o(0xeed9); // fldz
2523 o(0xe9da); // fucompp
2524 o(0xe0df); // fnstsw %ax
2525 o(0x9e); // sahf
2526 } else {
2527 o(0xc085); // test %eax, %eax
2528 }
2529 // Use two output statements to generate one instruction.
2530 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002531 return psym(0x84 + l, t);
2532 }
2533
Jack Palevich58c30ee2009-07-17 16:35:23 -07002534 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002535 Type* pR0Type = getR0Type();
2536 Type* pTOSType = getTOSType();
2537 TypeTag tagR0 = pR0Type->tag;
2538 TypeTag tagTOS = pTOSType->tag;
2539 bool isFloatR0 = isFloatTag(tagR0);
2540 bool isFloatTOS = isFloatTag(tagTOS);
2541 if (!isFloatR0 && !isFloatTOS) {
2542 int t = decodeOp(op);
2543 o(0x59); /* pop %ecx */
2544 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002545 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002546 o(0x0f); /* setxx %al */
2547 o(t + 0x90);
2548 o(0xc0);
2549 popType();
2550 } else {
2551 setupFloatOperands();
2552 switch (op) {
2553 case OP_EQUALS:
2554 o(0xe9da); // fucompp
2555 o(0xe0df); // fnstsw %ax
2556 o(0x9e); // sahf
2557 o(0xc0940f); // sete %al
2558 o(0xc29b0f); // setnp %dl
2559 o(0xd021); // andl %edx, %eax
2560 break;
2561 case OP_NOT_EQUALS:
2562 o(0xe9da); // fucompp
2563 o(0xe0df); // fnstsw %ax
2564 o(0x9e); // sahf
2565 o(0xc0950f); // setne %al
2566 o(0xc29a0f); // setp %dl
2567 o(0xd009); // orl %edx, %eax
2568 break;
2569 case OP_GREATER_EQUAL:
2570 o(0xe9da); // fucompp
2571 o(0xe0df); // fnstsw %ax
2572 o(0x05c4f6); // testb $5, %ah
2573 o(0xc0940f); // sete %al
2574 break;
2575 case OP_LESS:
2576 o(0xc9d9); // fxch %st(1)
2577 o(0xe9da); // fucompp
2578 o(0xe0df); // fnstsw %ax
2579 o(0x9e); // sahf
2580 o(0xc0970f); // seta %al
2581 break;
2582 case OP_LESS_EQUAL:
2583 o(0xc9d9); // fxch %st(1)
2584 o(0xe9da); // fucompp
2585 o(0xe0df); // fnstsw %ax
2586 o(0x9e); // sahf
2587 o(0xc0930f); // setea %al
2588 break;
2589 case OP_GREATER:
2590 o(0xe9da); // fucompp
2591 o(0xe0df); // fnstsw %ax
2592 o(0x45c4f6); // testb $69, %ah
2593 o(0xc0940f); // sete %al
2594 break;
2595 default:
2596 error("Unknown comparison op");
2597 }
2598 o(0xc0b60f); // movzbl %al, %eax
2599 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002600 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002601 }
2602
Jack Palevich546b2242009-05-13 15:10:04 -07002603 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002604 Type* pR0Type = getR0Type();
2605 Type* pTOSType = getTOSType();
2606 TypeTag tagR0 = pR0Type->tag;
2607 TypeTag tagTOS = pTOSType->tag;
2608 bool isFloatR0 = isFloatTag(tagR0);
2609 bool isFloatTOS = isFloatTag(tagTOS);
2610 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002611 bool isPtrR0 = isPointerTag(tagR0);
2612 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002613 if (isPtrR0 || isPtrTOS) {
2614 if (isPtrR0 && isPtrTOS) {
2615 if (op != OP_MINUS) {
2616 error("Unsupported pointer-pointer operation %d.", op);
2617 }
2618 if (! typeEqual(pR0Type, pTOSType)) {
2619 error("Incompatible pointer types for subtraction.");
2620 }
2621 o(0x59); /* pop %ecx */
2622 o(decodeOp(op));
2623 popType();
2624 setR0Type(mkpInt);
2625 int size = sizeOf(pR0Type->pHead);
2626 if (size != 1) {
2627 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002628 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002629 // TODO: Optimize for power-of-two.
2630 genOp(OP_DIV);
2631 }
2632 } else {
2633 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2634 error("Unsupported pointer-scalar operation %d", op);
2635 }
Jack Palevichb6154502009-08-04 14:56:09 -07002636 Type* pPtrType = getPointerArithmeticResultType(
2637 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002638 o(0x59); /* pop %ecx */
2639 int size = sizeOf(pPtrType->pHead);
2640 if (size != 1) {
2641 // TODO: Optimize for power-of-two.
2642 if (isPtrR0) {
2643 oad(0xC969, size); // imull $size, %ecx
2644 } else {
2645 oad(0xC069, size); // mul $size, %eax
2646 }
2647 }
2648 o(decodeOp(op));
2649 popType();
2650 setR0Type(pPtrType);
2651 }
2652 } else {
2653 o(0x59); /* pop %ecx */
2654 o(decodeOp(op));
2655 if (op == OP_MOD)
2656 o(0x92); /* xchg %edx, %eax */
2657 popType();
2658 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002659 } else {
2660 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2661 setupFloatOperands();
2662 // Both float. x87 R0 == left hand, x87 R1 == right hand
2663 switch (op) {
2664 case OP_MUL:
2665 o(0xc9de); // fmulp
2666 break;
2667 case OP_DIV:
2668 o(0xf1de); // fdivp
2669 break;
2670 case OP_PLUS:
2671 o(0xc1de); // faddp
2672 break;
2673 case OP_MINUS:
2674 o(0xe1de); // fsubp
2675 break;
2676 default:
2677 error("Unsupported binary floating operation.");
2678 break;
2679 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002680 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002681 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002682 }
2683
Jack Palevich58c30ee2009-07-17 16:35:23 -07002684 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002685 if (op != OP_LOGICAL_NOT) {
2686 error("Unknown unary cmp %d", op);
2687 } else {
2688 Type* pR0Type = getR0Type();
2689 TypeTag tag = collapseType(pR0Type->tag);
2690 switch(tag) {
2691 case TY_INT: {
2692 oad(0xb9, 0); /* movl $0, %ecx */
2693 int t = decodeOp(op);
2694 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002695 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002696 o(0x0f); /* setxx %al */
2697 o(t + 0x90);
2698 o(0xc0);
2699 }
2700 break;
2701 case TY_FLOAT:
2702 case TY_DOUBLE:
2703 o(0xeed9); // fldz
2704 o(0xe9da); // fucompp
2705 o(0xe0df); // fnstsw %ax
2706 o(0x9e); // sahf
2707 o(0xc0950f); // setne %al
2708 o(0xc29a0f); // setp %dl
2709 o(0xd009); // orl %edx, %eax
2710 o(0xc0b60f); // movzbl %al, %eax
2711 o(0x01f083); // xorl $1, %eax
2712 break;
2713 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002714 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002715 break;
2716 }
2717 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002718 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002719 }
2720
2721 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002722 Type* pR0Type = getR0Type();
2723 TypeTag tag = collapseType(pR0Type->tag);
2724 switch(tag) {
2725 case TY_INT:
2726 oad(0xb9, 0); /* movl $0, %ecx */
2727 o(decodeOp(op));
2728 break;
2729 case TY_FLOAT:
2730 case TY_DOUBLE:
2731 switch (op) {
2732 case OP_MINUS:
2733 o(0xe0d9); // fchs
2734 break;
2735 case OP_BIT_NOT:
2736 error("Can't apply '~' operator to a float or double.");
2737 break;
2738 default:
2739 error("Unknown unary op %d\n", op);
2740 break;
2741 }
2742 break;
2743 default:
2744 error("genUnaryOp unsupported type");
2745 break;
2746 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002747 }
2748
Jack Palevich1cdef202009-05-22 12:06:27 -07002749 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002750 Type* pR0Type = getR0Type();
2751 TypeTag r0ct = collapseType(pR0Type->tag);
2752 switch(r0ct) {
2753 case TY_INT:
2754 o(0x50); /* push %eax */
2755 break;
2756 case TY_FLOAT:
2757 o(0x50); /* push %eax */
2758 o(0x241cd9); // fstps 0(%esp)
2759 break;
2760 case TY_DOUBLE:
2761 o(0x50); /* push %eax */
2762 o(0x50); /* push %eax */
2763 o(0x241cdd); // fstpl 0(%esp)
2764 break;
2765 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002766 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002767 break;
2768 }
Jack Palevich8df46192009-07-07 14:48:51 -07002769 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002770 }
2771
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002772 virtual void over() {
2773 // We know it's only used for int-ptr ops (++/--)
2774
2775 Type* pR0Type = getR0Type();
2776 TypeTag r0ct = collapseType(pR0Type->tag);
2777
2778 Type* pTOSType = getTOSType();
2779 TypeTag tosct = collapseType(pTOSType->tag);
2780
2781 assert (r0ct == TY_INT && tosct == TY_INT);
2782
2783 o(0x59); /* pop %ecx */
2784 o(0x50); /* push %eax */
2785 o(0x51); /* push %ecx */
2786
2787 overType();
2788 }
2789
Jack Palevich58c30ee2009-07-17 16:35:23 -07002790 virtual void popR0() {
2791 Type* pR0Type = getR0Type();
2792 TypeTag r0ct = collapseType(pR0Type->tag);
2793 switch(r0ct) {
2794 case TY_INT:
2795 o(0x58); /* popl %eax */
2796 break;
2797 case TY_FLOAT:
2798 o(0x2404d9); // flds (%esp)
2799 o(0x58); /* popl %eax */
2800 break;
2801 case TY_DOUBLE:
2802 o(0x2404dd); // fldl (%esp)
2803 o(0x58); /* popl %eax */
2804 o(0x58); /* popl %eax */
2805 break;
2806 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002807 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002808 break;
2809 }
2810 popType();
2811 }
2812
2813 virtual void storeR0ToTOS() {
2814 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002815 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002816 Type* pTargetType = pPointerType->pHead;
2817 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002818 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002819 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002820 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002821 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002822 case TY_INT:
2823 o(0x0189); /* movl %eax/%al, (%ecx) */
2824 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002825 case TY_SHORT:
2826 o(0x018966); /* movw %ax, (%ecx) */
2827 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002828 case TY_CHAR:
2829 o(0x0188); /* movl %eax/%al, (%ecx) */
2830 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002831 case TY_FLOAT:
2832 o(0x19d9); /* fstps (%ecx) */
2833 break;
2834 case TY_DOUBLE:
2835 o(0x19dd); /* fstpl (%ecx) */
2836 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002837 case TY_STRUCT:
2838 {
2839 // TODO: use alignment information to use movsw/movsl instead of movsb
2840 int size = sizeOf(pTargetType);
2841 if (size > 0) {
2842 o(0x9c); // pushf
2843 o(0x57); // pushl %edi
2844 o(0x56); // pushl %esi
2845 o(0xcf89); // movl %ecx, %edi
2846 o(0xc689); // movl %eax, %esi
2847 oad(0xb9, size); // mov #size, %ecx
2848 o(0xfc); // cld
2849 o(0xf3); // rep
2850 o(0xa4); // movsb
2851 o(0x5e); // popl %esi
2852 o(0x5f); // popl %edi
2853 o(0x9d); // popf
2854 }
2855 }
2856 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002857 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002858 error("storeR0ToTOS: unsupported type %d",
2859 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002860 break;
2861 }
Jack Palevich02effee2009-11-09 12:52:45 +08002862 setR0Type(pTargetType);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002863 }
2864
Jack Palevich58c30ee2009-07-17 16:35:23 -07002865 virtual void loadR0FromR0() {
2866 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002867 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002868 Type* pNewType = pPointerType->pHead;
2869 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002870 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002871 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002872 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002873 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002874 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002875 case TY_SHORT:
2876 o(0xbf0f); /* movswl (%eax), %eax */
2877 ob(0);
2878 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002879 case TY_CHAR:
2880 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002881 ob(0); /* add zero in code */
2882 break;
2883 case TY_FLOAT:
2884 o2(0x00d9); // flds (%eax)
2885 break;
2886 case TY_DOUBLE:
2887 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002888 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002889 case TY_ARRAY:
2890 pNewType = pNewType->pTail;
2891 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002892 case TY_STRUCT:
2893 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002894 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002895 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002896 break;
2897 }
Jack Palevich80e49722009-08-04 15:39:49 -07002898 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002899 }
2900
Jack Palevichb5e33312009-07-30 19:06:34 -07002901 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002902 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002903 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002904 }
2905
Jack Palevich9f51a262009-07-29 16:22:26 -07002906 virtual int leaForward(int ea, Type* pPointerType) {
2907 oad(0xb8, ea); /* mov $xx, %eax */
2908 setR0Type(pPointerType);
2909 return getPC() - 4;
2910 }
2911
Jack Palevichb6154502009-08-04 14:56:09 -07002912 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002913 Type* pR0Type = getR0Type();
2914 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002915 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002916 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002917 return;
2918 }
Jack Palevichb6154502009-08-04 14:56:09 -07002919 if (isPointerType(pType) && isPointerType(pR0Type)) {
2920 Type* pA = pR0Type;
2921 Type* pB = pType;
2922 // Array decays to pointer
2923 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2924 pA = pA->pTail;
2925 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002926 if (! (typeEqual(pA, pB)
2927 || pB->pHead->tag == TY_VOID
2928 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2929 )) {
2930 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002931 }
Jack Palevichb6154502009-08-04 14:56:09 -07002932 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002933 // do nothing special
2934 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2935 // do nothing special, both held in same register on x87.
2936 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002937 TypeTag r0Tag = collapseType(pR0Type->tag);
2938 TypeTag destTag = collapseType(pType->tag);
2939 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2940 // Convert R0 from int to float
2941 o(0x50); // push %eax
2942 o(0x2404DB); // fildl 0(%esp)
2943 o(0x58); // pop %eax
2944 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2945 // Convert R0 from float to int. Complicated because
2946 // need to save and restore the rounding mode.
2947 o(0x50); // push %eax
2948 o(0x50); // push %eax
2949 o(0x02247cD9); // fnstcw 2(%esp)
2950 o(0x2444b70f); // movzwl 2(%esp), %eax
2951 o(0x02);
2952 o(0x0cb4); // movb $12, %ah
2953 o(0x24048966); // movw %ax, 0(%esp)
2954 o(0x242cd9); // fldcw 0(%esp)
2955 o(0x04245cdb); // fistpl 4(%esp)
2956 o(0x02246cd9); // fldcw 2(%esp)
2957 o(0x58); // pop %eax
2958 o(0x58); // pop %eax
2959 } else {
2960 error("Incompatible types old: %d new: %d",
2961 pR0Type->tag, pType->tag);
2962 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002963 }
2964 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002965 }
2966
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002967 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002968 return oad(0xec81, 0); /* sub $xxx, %esp */
2969 }
2970
Jack Palevich8148c5b2009-07-16 18:24:47 -07002971 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2972 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002973 Type* pR0Type = getR0Type();
2974 TypeTag r0ct = collapseType(pR0Type->tag);
2975 switch(r0ct) {
2976 case TY_INT:
2977 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2978 return 4;
2979 case TY_FLOAT:
2980 oad(0x249CD9, l); /* fstps xxx(%esp) */
2981 return 4;
2982 case TY_DOUBLE:
2983 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2984 return 8;
2985 default:
2986 assert(false);
2987 return 0;
2988 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002989 }
2990
Jack Palevichb7718b92009-07-09 22:00:24 -07002991 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002992 * (int*) a = l;
2993 }
2994
Jack Palevich8df46192009-07-07 14:48:51 -07002995 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002996 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002997 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002998 return psym(0xe8, symbol); /* call xxx */
2999 }
3000
Jack Palevich8df46192009-07-07 14:48:51 -07003001 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003002 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07003003 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07003004 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003005 oad(0x2494ff, l); /* call *xxx(%esp) */
3006 }
3007
Jack Palevichb7718b92009-07-09 22:00:24 -07003008 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003009 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07003010 if (isIndirect) {
3011 l += 4;
3012 }
-b master422972c2009-06-17 19:13:52 -07003013 if (l > 0) {
3014 oad(0xc481, l); /* add $xxx, %esp */
3015 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003016 }
3017
Jack Palevicha6535612009-05-13 16:24:17 -07003018 virtual int jumpOffset() {
3019 return 5;
3020 }
3021
Jack Paleviche7b59062009-05-19 17:12:17 -07003022 /* output a symbol and patch all calls to it */
3023 virtual void gsym(int t) {
3024 int n;
3025 int pc = getPC();
3026 while (t) {
3027 n = *(int *) t; /* next value */
3028 *(int *) t = pc - t - 4;
3029 t = n;
3030 }
3031 }
3032
Jack Palevich9f51a262009-07-29 16:22:26 -07003033 /* output a symbol and patch all calls to it, using absolute address */
3034 virtual void resolveForward(int t) {
3035 int n;
3036 int pc = getPC();
3037 while (t) {
3038 n = *(int *) t; /* next value */
3039 *(int *) t = pc;
3040 t = n;
3041 }
3042 }
3043
Jack Palevich1cdef202009-05-22 12:06:27 -07003044 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003045 size_t pagesize = 4096;
3046 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3047 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3048 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3049 if (err) {
3050 error("mprotect() failed: %d", errno);
3051 }
3052 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003053 }
3054
Jack Palevich9eed7a22009-07-06 17:24:34 -07003055 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003056 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003057 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003058 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003059 switch (pType->tag) {
3060 case TY_CHAR:
3061 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003062 case TY_SHORT:
3063 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003064 case TY_ARRAY:
3065 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003066 case TY_STRUCT:
3067 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003068 case TY_FUNC:
3069 error("alignment of func not supported");
3070 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003071 default:
3072 return 4;
3073 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003074 }
3075
3076 /**
3077 * Array element alignment (in bytes) for this type of data.
3078 */
3079 virtual size_t sizeOf(Type* pType){
3080 switch(pType->tag) {
3081 case TY_INT:
3082 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003083 case TY_SHORT:
3084 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003085 case TY_CHAR:
3086 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003087 case TY_FLOAT:
3088 return 4;
3089 case TY_DOUBLE:
3090 return 8;
3091 case TY_POINTER:
3092 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003093 case TY_ARRAY:
3094 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003095 case TY_STRUCT:
3096 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003097 default:
3098 error("Unsupported type %d", pType->tag);
3099 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003100 }
3101 }
3102
Jack Palevich21a15a22009-05-11 14:49:29 -07003103 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003104
3105 /** Output 1 to 4 bytes.
3106 *
3107 */
3108 void o(int n) {
3109 /* cannot use unsigned, so we must do a hack */
3110 while (n && n != -1) {
3111 ob(n & 0xff);
3112 n = n >> 8;
3113 }
3114 }
3115
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003116 /* Output exactly 2 bytes
3117 */
3118 void o2(int n) {
3119 ob(n & 0xff);
3120 ob(0xff & (n >> 8));
3121 }
3122
Jack Paleviche7b59062009-05-19 17:12:17 -07003123 /* psym is used to put an instruction with a data field which is a
3124 reference to a symbol. It is in fact the same as oad ! */
3125 int psym(int n, int t) {
3126 return oad(n, t);
3127 }
3128
3129 /* instruction + address */
3130 int oad(int n, int t) {
3131 o(n);
3132 int result = getPC();
3133 o4(t);
3134 return result;
3135 }
3136
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003137 static const int operatorHelper[];
3138
3139 int decodeOp(int op) {
3140 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003141 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003142 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003143 }
3144 return operatorHelper[op];
3145 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003146
Jack Palevich546b2242009-05-13 15:10:04 -07003147 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003148 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003149 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003150 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003151
3152 void setupFloatOperands() {
3153 Type* pR0Type = getR0Type();
3154 Type* pTOSType = getTOSType();
3155 TypeTag tagR0 = pR0Type->tag;
3156 TypeTag tagTOS = pTOSType->tag;
3157 bool isFloatR0 = isFloatTag(tagR0);
3158 bool isFloatTOS = isFloatTag(tagTOS);
3159 if (! isFloatR0) {
3160 // Convert R0 from int to float
3161 o(0x50); // push %eax
3162 o(0x2404DB); // fildl 0(%esp)
3163 o(0x58); // pop %eax
3164 }
3165 if (! isFloatTOS){
3166 o(0x2404DB); // fildl 0(%esp);
3167 o(0x58); // pop %eax
3168 } else {
3169 if (tagTOS == TY_FLOAT) {
3170 o(0x2404d9); // flds (%esp)
3171 o(0x58); // pop %eax
3172 } else {
3173 o(0x2404dd); // fldl (%esp)
3174 o(0x58); // pop %eax
3175 o(0x58); // pop %eax
3176 }
3177 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003178 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003179 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003180 };
3181
Jack Paleviche7b59062009-05-19 17:12:17 -07003182#endif // PROVIDE_X86_CODEGEN
3183
Jack Palevichb67b18f2009-06-11 21:12:23 -07003184#ifdef PROVIDE_TRACE_CODEGEN
3185 class TraceCodeGenerator : public CodeGenerator {
3186 private:
3187 CodeGenerator* mpBase;
3188
3189 public:
3190 TraceCodeGenerator(CodeGenerator* pBase) {
3191 mpBase = pBase;
3192 }
3193
3194 virtual ~TraceCodeGenerator() {
3195 delete mpBase;
3196 }
3197
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003198 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003199 mpBase->init(pCodeBuf);
3200 }
3201
3202 void setErrorSink(ErrorSink* pErrorSink) {
3203 mpBase->setErrorSink(pErrorSink);
3204 }
3205
3206 /* returns address to patch with local variable size
3207 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003208 virtual int functionEntry(Type* pDecl) {
3209 int result = mpBase->functionEntry(pDecl);
3210 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003211 return result;
3212 }
3213
Jack Palevichb7718b92009-07-09 22:00:24 -07003214 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3215 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3216 localVariableAddress, localVariableSize);
3217 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003218 }
3219
3220 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003221 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003222 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003223 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003224 }
3225
Jack Palevich1a539db2009-07-08 13:04:41 -07003226 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003227 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003228 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003229 }
3230
Jack Palevich9221bcc2009-08-26 16:15:07 -07003231 virtual void addStructOffsetR0(int offset, Type* pType) {
3232 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3233 mpBase->addStructOffsetR0(offset, pType);
3234 }
3235
Jack Palevichb67b18f2009-06-11 21:12:23 -07003236 virtual int gjmp(int t) {
3237 int result = mpBase->gjmp(t);
3238 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3239 return result;
3240 }
3241
3242 /* l = 0: je, l == 1: jne */
3243 virtual int gtst(bool l, int t) {
3244 int result = mpBase->gtst(l, t);
3245 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3246 return result;
3247 }
3248
Jack Palevich58c30ee2009-07-17 16:35:23 -07003249 virtual void gcmp(int op) {
3250 fprintf(stderr, "gcmp(%d)\n", op);
3251 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003252 }
3253
3254 virtual void genOp(int op) {
3255 fprintf(stderr, "genOp(%d)\n", op);
3256 mpBase->genOp(op);
3257 }
3258
Jack Palevich9eed7a22009-07-06 17:24:34 -07003259
Jack Palevich58c30ee2009-07-17 16:35:23 -07003260 virtual void gUnaryCmp(int op) {
3261 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3262 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003263 }
3264
3265 virtual void genUnaryOp(int op) {
3266 fprintf(stderr, "genUnaryOp(%d)\n", op);
3267 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003268 }
3269
3270 virtual void pushR0() {
3271 fprintf(stderr, "pushR0()\n");
3272 mpBase->pushR0();
3273 }
3274
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003275 virtual void over() {
3276 fprintf(stderr, "over()\n");
3277 mpBase->over();
3278 }
3279
Jack Palevich58c30ee2009-07-17 16:35:23 -07003280 virtual void popR0() {
3281 fprintf(stderr, "popR0()\n");
3282 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003283 }
3284
Jack Palevich58c30ee2009-07-17 16:35:23 -07003285 virtual void storeR0ToTOS() {
3286 fprintf(stderr, "storeR0ToTOS()\n");
3287 mpBase->storeR0ToTOS();
3288 }
3289
3290 virtual void loadR0FromR0() {
3291 fprintf(stderr, "loadR0FromR0()\n");
3292 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003293 }
3294
Jack Palevichb5e33312009-07-30 19:06:34 -07003295 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3296 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3297 pPointerType->pHead->tag, et);
3298 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003299 }
3300
Jack Palevich9f51a262009-07-29 16:22:26 -07003301 virtual int leaForward(int ea, Type* pPointerType) {
3302 fprintf(stderr, "leaForward(%d)\n", ea);
3303 return mpBase->leaForward(ea, pPointerType);
3304 }
3305
Jack Palevich30321cb2009-08-20 15:34:23 -07003306 virtual void convertR0Imp(Type* pType, bool isCast){
3307 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3308 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003309 }
3310
3311 virtual int beginFunctionCallArguments() {
3312 int result = mpBase->beginFunctionCallArguments();
3313 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3314 return result;
3315 }
3316
Jack Palevich8148c5b2009-07-16 18:24:47 -07003317 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3318 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3319 pArgType->tag);
3320 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003321 }
3322
Jack Palevichb7718b92009-07-09 22:00:24 -07003323 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003324 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003325 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003326 }
3327
Jack Palevich8df46192009-07-07 14:48:51 -07003328 virtual int callForward(int symbol, Type* pFunc) {
3329 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003330 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3331 return result;
3332 }
3333
Jack Palevich8df46192009-07-07 14:48:51 -07003334 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003335 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3336 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003337 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003338 }
3339
Jack Palevichb7718b92009-07-09 22:00:24 -07003340 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3341 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3342 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003343 }
3344
3345 virtual int jumpOffset() {
3346 return mpBase->jumpOffset();
3347 }
3348
Jack Palevichb67b18f2009-06-11 21:12:23 -07003349 /* output a symbol and patch all calls to it */
3350 virtual void gsym(int t) {
3351 fprintf(stderr, "gsym(%d)\n", t);
3352 mpBase->gsym(t);
3353 }
3354
Jack Palevich9f51a262009-07-29 16:22:26 -07003355 virtual void resolveForward(int t) {
3356 mpBase->resolveForward(t);
3357 }
3358
Jack Palevichb67b18f2009-06-11 21:12:23 -07003359 virtual int finishCompile() {
3360 int result = mpBase->finishCompile();
3361 fprintf(stderr, "finishCompile() = %d\n", result);
3362 return result;
3363 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003364
3365 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003366 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003367 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003368 virtual size_t alignmentOf(Type* pType){
3369 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003370 }
3371
3372 /**
3373 * Array element alignment (in bytes) for this type of data.
3374 */
3375 virtual size_t sizeOf(Type* pType){
3376 return mpBase->sizeOf(pType);
3377 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003378
3379 virtual Type* getR0Type() {
3380 return mpBase->getR0Type();
3381 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003382
3383 virtual ExpressionType getR0ExpressionType() {
3384 return mpBase->getR0ExpressionType();
3385 }
3386
3387 virtual void setR0ExpressionType(ExpressionType et) {
3388 mpBase->setR0ExpressionType(et);
3389 }
3390
3391 virtual size_t getExpressionStackDepth() {
3392 return mpBase->getExpressionStackDepth();
3393 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003394
3395 virtual void forceR0RVal() {
3396 return mpBase->forceR0RVal();
3397 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003398 };
3399
3400#endif // PROVIDE_TRACE_CODEGEN
3401
Jack Palevich569f1352009-06-29 14:29:08 -07003402 class Arena {
3403 public:
3404 // Used to record a given allocation amount.
3405 // Used:
3406 // Mark mark = arena.mark();
3407 // ... lots of arena.allocate()
3408 // arena.free(mark);
3409
3410 struct Mark {
3411 size_t chunk;
3412 size_t offset;
3413 };
3414
3415 Arena() {
3416 mCurrentChunk = 0;
3417 Chunk start(CHUNK_SIZE);
3418 mData.push_back(start);
3419 }
3420
3421 ~Arena() {
3422 for(size_t i = 0; i < mData.size(); i++) {
3423 mData[i].free();
3424 }
3425 }
3426
3427 // Alloc using the standard alignment size safe for any variable
3428 void* alloc(size_t size) {
3429 return alloc(size, 8);
3430 }
3431
3432 Mark mark(){
3433 Mark result;
3434 result.chunk = mCurrentChunk;
3435 result.offset = mData[mCurrentChunk].mOffset;
3436 return result;
3437 }
3438
3439 void freeToMark(const Mark& mark) {
3440 mCurrentChunk = mark.chunk;
3441 mData[mCurrentChunk].mOffset = mark.offset;
3442 }
3443
3444 private:
3445 // Allocate memory aligned to a given size
3446 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3447 // Memory is not zero filled.
3448
3449 void* alloc(size_t size, size_t alignment) {
3450 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3451 if (mCurrentChunk + 1 < mData.size()) {
3452 mCurrentChunk++;
3453 } else {
3454 size_t allocSize = CHUNK_SIZE;
3455 if (allocSize < size + alignment - 1) {
3456 allocSize = size + alignment - 1;
3457 }
3458 Chunk chunk(allocSize);
3459 mData.push_back(chunk);
3460 mCurrentChunk++;
3461 }
3462 }
3463 return mData[mCurrentChunk].allocate(size, alignment);
3464 }
3465
3466 static const size_t CHUNK_SIZE = 128*1024;
3467 // Note: this class does not deallocate its
3468 // memory when it's destroyed. It depends upon
3469 // its parent to deallocate the memory.
3470 struct Chunk {
3471 Chunk() {
3472 mpData = 0;
3473 mSize = 0;
3474 mOffset = 0;
3475 }
3476
3477 Chunk(size_t size) {
3478 mSize = size;
3479 mpData = (char*) malloc(size);
3480 mOffset = 0;
3481 }
3482
3483 ~Chunk() {
3484 // Doesn't deallocate memory.
3485 }
3486
3487 void* allocate(size_t size, size_t alignment) {
3488 size_t alignedOffset = aligned(mOffset, alignment);
3489 void* result = mpData + alignedOffset;
3490 mOffset = alignedOffset + size;
3491 return result;
3492 }
3493
3494 void free() {
3495 if (mpData) {
3496 ::free(mpData);
3497 mpData = 0;
3498 }
3499 }
3500
3501 size_t remainingCapacity(size_t alignment) {
3502 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3503 }
3504
3505 // Assume alignment is a power of two
3506 inline size_t aligned(size_t v, size_t alignment) {
3507 size_t mask = alignment-1;
3508 return (v + mask) & ~mask;
3509 }
3510
3511 char* mpData;
3512 size_t mSize;
3513 size_t mOffset;
3514 };
3515
3516 size_t mCurrentChunk;
3517
3518 Vector<Chunk> mData;
3519 };
3520
Jack Palevich569f1352009-06-29 14:29:08 -07003521 struct VariableInfo;
3522
3523 struct Token {
3524 int hash;
3525 size_t length;
3526 char* pText;
3527 tokenid_t id;
3528
3529 // Current values for the token
3530 char* mpMacroDefinition;
3531 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003532 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003533 };
3534
3535 class TokenTable {
3536 public:
3537 // Don't use 0..0xff, allows characters and operators to be tokens too.
3538
3539 static const int TOKEN_BASE = 0x100;
3540 TokenTable() {
3541 mpMap = hashmapCreate(128, hashFn, equalsFn);
3542 }
3543
3544 ~TokenTable() {
3545 hashmapFree(mpMap);
3546 }
3547
3548 void setArena(Arena* pArena) {
3549 mpArena = pArena;
3550 }
3551
3552 // Returns a token for a given string of characters.
3553 tokenid_t intern(const char* pText, size_t length) {
3554 Token probe;
3555 int hash = hashmapHash((void*) pText, length);
3556 {
3557 Token probe;
3558 probe.hash = hash;
3559 probe.length = length;
3560 probe.pText = (char*) pText;
3561 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3562 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003563 return pValue->id;
3564 }
3565 }
3566
3567 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3568 memset(pToken, 0, sizeof(*pToken));
3569 pToken->hash = hash;
3570 pToken->length = length;
3571 pToken->pText = (char*) mpArena->alloc(length + 1);
3572 memcpy(pToken->pText, pText, length);
3573 pToken->pText[length] = 0;
3574 pToken->id = mTokens.size() + TOKEN_BASE;
3575 mTokens.push_back(pToken);
3576 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003577 return pToken->id;
3578 }
3579
3580 // Return the Token for a given tokenid.
3581 Token& operator[](tokenid_t id) {
3582 return *mTokens[id - TOKEN_BASE];
3583 }
3584
3585 inline size_t size() {
3586 return mTokens.size();
3587 }
3588
3589 private:
3590
3591 static int hashFn(void* pKey) {
3592 Token* pToken = (Token*) pKey;
3593 return pToken->hash;
3594 }
3595
3596 static bool equalsFn(void* keyA, void* keyB) {
3597 Token* pTokenA = (Token*) keyA;
3598 Token* pTokenB = (Token*) keyB;
3599 // Don't need to compare hash values, they should always be equal
3600 return pTokenA->length == pTokenB->length
3601 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3602 }
3603
3604 Hashmap* mpMap;
3605 Vector<Token*> mTokens;
3606 Arena* mpArena;
3607 };
3608
Jack Palevich1cdef202009-05-22 12:06:27 -07003609 class InputStream {
3610 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003611 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003612 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003613 };
3614
3615 class TextInputStream : public InputStream {
3616 public:
3617 TextInputStream(const char* text, size_t textLength)
3618 : pText(text), mTextLength(textLength), mPosition(0) {
3619 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003620
Jack Palevichdc456462009-07-16 16:50:56 -07003621 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003622 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3623 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003624
Jack Palevichdc456462009-07-16 16:50:56 -07003625 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003626 const char* pText;
3627 size_t mTextLength;
3628 size_t mPosition;
3629 };
3630
Jack Palevicheedf9d22009-06-04 16:23:40 -07003631 class String {
3632 public:
3633 String() {
3634 mpBase = 0;
3635 mUsed = 0;
3636 mSize = 0;
3637 }
3638
Jack Palevich303d8ff2009-06-11 19:06:24 -07003639 String(const char* item, int len, bool adopt) {
3640 if (len < 0) {
3641 len = strlen(item);
3642 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003643 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003644 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003645 mUsed = len;
3646 mSize = len + 1;
3647 } else {
3648 mpBase = 0;
3649 mUsed = 0;
3650 mSize = 0;
3651 appendBytes(item, len);
3652 }
3653 }
3654
Jack Palevich303d8ff2009-06-11 19:06:24 -07003655 String(const String& other) {
3656 mpBase = 0;
3657 mUsed = 0;
3658 mSize = 0;
3659 appendBytes(other.getUnwrapped(), other.len());
3660 }
3661
Jack Palevicheedf9d22009-06-04 16:23:40 -07003662 ~String() {
3663 if (mpBase) {
3664 free(mpBase);
3665 }
3666 }
3667
Jack Palevicha6baa232009-06-12 11:25:59 -07003668 String& operator=(const String& other) {
3669 clear();
3670 appendBytes(other.getUnwrapped(), other.len());
3671 return *this;
3672 }
3673
Jack Palevich303d8ff2009-06-11 19:06:24 -07003674 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003675 return mpBase;
3676 }
3677
Jack Palevich303d8ff2009-06-11 19:06:24 -07003678 void clear() {
3679 mUsed = 0;
3680 if (mSize > 0) {
3681 mpBase[0] = 0;
3682 }
3683 }
3684
Jack Palevicheedf9d22009-06-04 16:23:40 -07003685 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003686 appendBytes(s, strlen(s));
3687 }
3688
3689 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003690 memcpy(ensure(n), s, n + 1);
3691 }
3692
3693 void append(char c) {
3694 * ensure(1) = c;
3695 }
3696
Jack Palevich86351982009-06-30 18:09:56 -07003697 void append(String& other) {
3698 appendBytes(other.getUnwrapped(), other.len());
3699 }
3700
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003701 char* orphan() {
3702 char* result = mpBase;
3703 mpBase = 0;
3704 mUsed = 0;
3705 mSize = 0;
3706 return result;
3707 }
3708
Jack Palevicheedf9d22009-06-04 16:23:40 -07003709 void printf(const char* fmt,...) {
3710 va_list ap;
3711 va_start(ap, fmt);
3712 vprintf(fmt, ap);
3713 va_end(ap);
3714 }
3715
3716 void vprintf(const char* fmt, va_list ap) {
3717 char* temp;
3718 int numChars = vasprintf(&temp, fmt, ap);
3719 memcpy(ensure(numChars), temp, numChars+1);
3720 free(temp);
3721 }
3722
Jack Palevich303d8ff2009-06-11 19:06:24 -07003723 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003724 return mUsed;
3725 }
3726
3727 private:
3728 char* ensure(int n) {
3729 size_t newUsed = mUsed + n;
3730 if (newUsed > mSize) {
3731 size_t newSize = mSize * 2 + 10;
3732 if (newSize < newUsed) {
3733 newSize = newUsed;
3734 }
3735 mpBase = (char*) realloc(mpBase, newSize + 1);
3736 mSize = newSize;
3737 }
3738 mpBase[newUsed] = '\0';
3739 char* result = mpBase + mUsed;
3740 mUsed = newUsed;
3741 return result;
3742 }
3743
3744 char* mpBase;
3745 size_t mUsed;
3746 size_t mSize;
3747 };
3748
Jack Palevich569f1352009-06-29 14:29:08 -07003749 void internKeywords() {
3750 // Note: order has to match TOK_ constants
3751 static const char* keywords[] = {
3752 "int",
3753 "char",
3754 "void",
3755 "if",
3756 "else",
3757 "while",
3758 "break",
3759 "return",
3760 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003761 "auto",
3762 "case",
3763 "const",
3764 "continue",
3765 "default",
3766 "do",
3767 "double",
3768 "enum",
3769 "extern",
3770 "float",
3771 "goto",
3772 "long",
3773 "register",
3774 "short",
3775 "signed",
3776 "sizeof",
3777 "static",
3778 "struct",
3779 "switch",
3780 "typedef",
3781 "union",
3782 "unsigned",
3783 "volatile",
3784 "_Bool",
3785 "_Complex",
3786 "_Imaginary",
3787 "inline",
3788 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003789
3790 // predefined tokens that can also be symbols start here:
3791 "pragma",
3792 "define",
3793 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003794 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003795
Jack Palevich569f1352009-06-29 14:29:08 -07003796 for(int i = 0; keywords[i]; i++) {
3797 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003798 }
Jack Palevich569f1352009-06-29 14:29:08 -07003799 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003800
Jack Palevich36d94142009-06-08 15:55:32 -07003801 struct InputState {
3802 InputStream* pStream;
3803 int oldCh;
3804 };
3805
Jack Palevich2db168f2009-06-11 14:29:47 -07003806 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003807 void* pAddress;
3808 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003809 tokenid_t tok;
3810 size_t level;
3811 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003812 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003813 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003814 };
3815
Jack Palevich303d8ff2009-06-11 19:06:24 -07003816 class SymbolStack {
3817 public:
3818 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003819 mpArena = 0;
3820 mpTokenTable = 0;
3821 }
3822
3823 void setArena(Arena* pArena) {
3824 mpArena = pArena;
3825 }
3826
3827 void setTokenTable(TokenTable* pTokenTable) {
3828 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003829 }
3830
3831 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003832 Mark mark;
3833 mark.mArenaMark = mpArena->mark();
3834 mark.mSymbolHead = mStack.size();
3835 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003836 }
3837
3838 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003839 // Undo any shadowing that was done:
3840 Mark mark = mLevelStack.back();
3841 mLevelStack.pop_back();
3842 while (mStack.size() > mark.mSymbolHead) {
3843 VariableInfo* pV = mStack.back();
3844 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003845 if (pV->isStructTag) {
3846 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3847 } else {
3848 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3849 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003850 }
Jack Palevich569f1352009-06-29 14:29:08 -07003851 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003852 }
3853
Jack Palevich569f1352009-06-29 14:29:08 -07003854 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3855 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3856 return pV && pV->level == level();
3857 }
3858
Jack Palevich9221bcc2009-08-26 16:15:07 -07003859 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3860 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3861 return pV && pV->level == level();
3862 }
3863
Jack Palevich569f1352009-06-29 14:29:08 -07003864 VariableInfo* add(tokenid_t tok) {
3865 Token& token = (*mpTokenTable)[tok];
3866 VariableInfo* pOldV = token.mpVariableInfo;
3867 VariableInfo* pNewV =
3868 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3869 memset(pNewV, 0, sizeof(VariableInfo));
3870 pNewV->tok = tok;
3871 pNewV->level = level();
3872 pNewV->pOldDefinition = pOldV;
3873 token.mpVariableInfo = pNewV;
3874 mStack.push_back(pNewV);
3875 return pNewV;
3876 }
3877
Jack Palevich9221bcc2009-08-26 16:15:07 -07003878 VariableInfo* addStructTag(tokenid_t tok) {
3879 Token& token = (*mpTokenTable)[tok];
3880 VariableInfo* pOldS = token.mpStructInfo;
3881 VariableInfo* pNewS =
3882 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3883 memset(pNewS, 0, sizeof(VariableInfo));
3884 pNewS->tok = tok;
3885 pNewS->level = level();
3886 pNewS->isStructTag = true;
3887 pNewS->pOldDefinition = pOldS;
3888 token.mpStructInfo = pNewS;
3889 mStack.push_back(pNewS);
3890 return pNewS;
3891 }
3892
Jack Palevich86351982009-06-30 18:09:56 -07003893 VariableInfo* add(Type* pType) {
3894 VariableInfo* pVI = add(pType->id);
3895 pVI->pType = pType;
3896 return pVI;
3897 }
3898
Jack Palevich569f1352009-06-29 14:29:08 -07003899 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3900 for (size_t i = 0; i < mStack.size(); i++) {
3901 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003902 break;
3903 }
3904 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003905 }
3906
Jack Palevich303d8ff2009-06-11 19:06:24 -07003907 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003908 inline size_t level() {
3909 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003910 }
3911
Jack Palevich569f1352009-06-29 14:29:08 -07003912 struct Mark {
3913 Arena::Mark mArenaMark;
3914 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003915 };
3916
Jack Palevich569f1352009-06-29 14:29:08 -07003917 Arena* mpArena;
3918 TokenTable* mpTokenTable;
3919 Vector<VariableInfo*> mStack;
3920 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003921 };
Jack Palevich36d94142009-06-08 15:55:32 -07003922
Jack Palevich188a5a72009-10-27 17:23:20 -07003923 struct MacroState {
3924 tokenid_t name; // Name of the current macro we are expanding
3925 char* dptr; // point to macro text during macro playback
3926 int dch; // Saves old value of ch during a macro playback
3927 };
3928
3929#define MACRO_NESTING_MAX 32
3930 MacroState macroState[MACRO_NESTING_MAX];
3931 int macroLevel; // -1 means not playing any macro.
3932
Jack Palevich36d94142009-06-08 15:55:32 -07003933 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003934 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003935 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003936 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003937 int tokl; // token operator level
3938 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003939 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003940 intptr_t loc; // local variable index
3941 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003942 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003943 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003944 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003945 ACCSymbolLookupFn mpSymbolLookupFn;
3946 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003947
3948 // Arena for the duration of the compile
3949 Arena mGlobalArena;
3950 // Arena for data that's only needed when compiling a single function
3951 Arena mLocalArena;
3952
Jack Palevich2ff5c222009-07-23 15:11:22 -07003953 Arena* mpCurrentArena;
3954
Jack Palevich569f1352009-06-29 14:29:08 -07003955 TokenTable mTokenTable;
3956 SymbolStack mGlobals;
3957 SymbolStack mLocals;
3958
Jack Palevich9221bcc2009-08-26 16:15:07 -07003959 SymbolStack* mpCurrentSymbolStack;
3960
Jack Palevich40600de2009-07-01 15:32:35 -07003961 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003962 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003963 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003964 Type* mkpChar; // char
3965 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003966 Type* mkpFloat;
3967 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003968 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003969 Type* mkpIntPtr;
3970 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003971 Type* mkpFloatPtr;
3972 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003973 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003974
Jack Palevich36d94142009-06-08 15:55:32 -07003975 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003976 int mLineNumber;
3977 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003978
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003979 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003980 CodeGenerator* pGen;
3981
Jack Palevicheedf9d22009-06-04 16:23:40 -07003982 String mErrorBuf;
3983
Jack Palevicheedf9d22009-06-04 16:23:40 -07003984 String mPragmas;
3985 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003986 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003987
Jack Palevich21a15a22009-05-11 14:49:29 -07003988 static const int ALLOC_SIZE = 99999;
3989
Jack Palevich303d8ff2009-06-11 19:06:24 -07003990 static const int TOK_DUMMY = 1;
3991 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003992 static const int TOK_NUM_FLOAT = 3;
3993 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003994 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003995 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003996
3997 // 3..255 are character and/or operators
3998
Jack Palevich2db168f2009-06-11 14:29:47 -07003999 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07004000 // Order has to match string list in "internKeywords".
4001 enum {
4002 TOK_KEYWORD = TokenTable::TOKEN_BASE,
4003 TOK_INT = TOK_KEYWORD,
4004 TOK_CHAR,
4005 TOK_VOID,
4006 TOK_IF,
4007 TOK_ELSE,
4008 TOK_WHILE,
4009 TOK_BREAK,
4010 TOK_RETURN,
4011 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07004012 TOK_AUTO,
4013 TOK_CASE,
4014 TOK_CONST,
4015 TOK_CONTINUE,
4016 TOK_DEFAULT,
4017 TOK_DO,
4018 TOK_DOUBLE,
4019 TOK_ENUM,
4020 TOK_EXTERN,
4021 TOK_FLOAT,
4022 TOK_GOTO,
4023 TOK_LONG,
4024 TOK_REGISTER,
4025 TOK_SHORT,
4026 TOK_SIGNED,
4027 TOK_SIZEOF,
4028 TOK_STATIC,
4029 TOK_STRUCT,
4030 TOK_SWITCH,
4031 TOK_TYPEDEF,
4032 TOK_UNION,
4033 TOK_UNSIGNED,
4034 TOK_VOLATILE,
4035 TOK__BOOL,
4036 TOK__COMPLEX,
4037 TOK__IMAGINARY,
4038 TOK_INLINE,
4039 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004040
4041 // Symbols start after keywords
4042
4043 TOK_SYMBOL,
4044 TOK_PRAGMA = TOK_SYMBOL,
4045 TOK_DEFINE,
4046 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004047 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004048
4049 static const int LOCAL = 0x200;
4050
Jack Palevich21a15a22009-05-11 14:49:29 -07004051 /* tokens in string heap */
4052 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004053
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004054 static const int OP_INCREMENT = 0;
4055 static const int OP_DECREMENT = 1;
4056 static const int OP_MUL = 2;
4057 static const int OP_DIV = 3;
4058 static const int OP_MOD = 4;
4059 static const int OP_PLUS = 5;
4060 static const int OP_MINUS = 6;
4061 static const int OP_SHIFT_LEFT = 7;
4062 static const int OP_SHIFT_RIGHT = 8;
4063 static const int OP_LESS_EQUAL = 9;
4064 static const int OP_GREATER_EQUAL = 10;
4065 static const int OP_LESS = 11;
4066 static const int OP_GREATER = 12;
4067 static const int OP_EQUALS = 13;
4068 static const int OP_NOT_EQUALS = 14;
4069 static const int OP_LOGICAL_AND = 15;
4070 static const int OP_LOGICAL_OR = 16;
4071 static const int OP_BIT_AND = 17;
4072 static const int OP_BIT_XOR = 18;
4073 static const int OP_BIT_OR = 19;
4074 static const int OP_BIT_NOT = 20;
4075 static const int OP_LOGICAL_NOT = 21;
4076 static const int OP_COUNT = 22;
4077
4078 /* Operators are searched from front, the two-character operators appear
4079 * before the single-character operators with the same first character.
4080 * @ is used to pad out single-character operators.
4081 */
4082 static const char* operatorChars;
4083 static const char operatorLevel[];
4084
Jack Palevich569f1352009-06-29 14:29:08 -07004085 /* Called when we detect an internal problem. Does nothing in production.
4086 *
4087 */
4088 void internalError() {
4089 * (char*) 0 = 0;
4090 }
4091
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004092 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004093 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004094 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004095 internalError();
4096 }
Jack Palevich86351982009-06-30 18:09:56 -07004097 }
4098
Jack Palevich40600de2009-07-01 15:32:35 -07004099 bool isSymbol(tokenid_t t) {
4100 return t >= TOK_SYMBOL &&
4101 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4102 }
4103
4104 bool isSymbolOrKeyword(tokenid_t t) {
4105 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004106 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004107 }
4108
Jack Palevich86351982009-06-30 18:09:56 -07004109 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004110 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004111 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4112 if (pV && pV->tok != t) {
4113 internalError();
4114 }
4115 return pV;
4116 }
4117
4118 inline bool isDefined(tokenid_t t) {
4119 return t >= TOK_SYMBOL && VI(t) != 0;
4120 }
4121
Jack Palevich40600de2009-07-01 15:32:35 -07004122 const char* nameof(tokenid_t t) {
4123 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004124 return mTokenTable[t].pText;
4125 }
4126
Jack Palevich21a15a22009-05-11 14:49:29 -07004127 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004128 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004129 }
4130
4131 void inp() {
Jack Palevich188a5a72009-10-27 17:23:20 -07004132 // Close any totally empty macros. We leave them on the stack until now
4133 // so that we know which macros are being expanded when checking if the
4134 // last token in the macro is a macro that's already being expanded.
4135 while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
4136 macroLevel--;
4137 }
4138 if (macroLevel >= 0) {
4139 ch = *macroState[macroLevel].dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004140 if (ch == 0) {
Jack Palevich188a5a72009-10-27 17:23:20 -07004141 ch = macroState[macroLevel].dch;
4142 macroState[macroLevel].dptr = NULL; // This macro's done
Jack Palevich21a15a22009-05-11 14:49:29 -07004143 }
Jack Palevichdc456462009-07-16 16:50:56 -07004144 } else {
4145 if (mbBumpLine) {
4146 mLineNumber++;
4147 mbBumpLine = false;
4148 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004149 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004150 if (ch == '\n') {
4151 mbBumpLine = true;
4152 }
4153 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004154#if 0
4155 printf("ch='%c' 0x%x\n", ch, ch);
4156#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004157 }
4158
4159 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004160 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004161 }
4162
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004163 int decodeHex(int c) {
4164 if (isdigit(c)) {
4165 c -= '0';
4166 } else if (c <= 'F') {
4167 c = c - 'A' + 10;
4168 } else {
4169 c =c - 'a' + 10;
4170 }
4171 return c;
4172 }
4173
Jack Palevichb4758ff2009-06-12 12:49:14 -07004174 /* read a character constant, advances ch to after end of constant */
4175 int getq() {
4176 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004177 if (ch == '\\') {
4178 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004179 if (isoctal(ch)) {
4180 // 1 to 3 octal characters.
4181 val = 0;
4182 for(int i = 0; i < 3; i++) {
4183 if (isoctal(ch)) {
4184 val = (val << 3) + ch - '0';
4185 inp();
4186 }
4187 }
4188 return val;
4189 } else if (ch == 'x' || ch == 'X') {
4190 // N hex chars
4191 inp();
4192 if (! isxdigit(ch)) {
4193 error("'x' character escape requires at least one digit.");
4194 } else {
4195 val = 0;
4196 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004197 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004198 inp();
4199 }
4200 }
4201 } else {
4202 int val = ch;
4203 switch (ch) {
4204 case 'a':
4205 val = '\a';
4206 break;
4207 case 'b':
4208 val = '\b';
4209 break;
4210 case 'f':
4211 val = '\f';
4212 break;
4213 case 'n':
4214 val = '\n';
4215 break;
4216 case 'r':
4217 val = '\r';
4218 break;
4219 case 't':
4220 val = '\t';
4221 break;
4222 case 'v':
4223 val = '\v';
4224 break;
4225 case '\\':
4226 val = '\\';
4227 break;
4228 case '\'':
4229 val = '\'';
4230 break;
4231 case '"':
4232 val = '"';
4233 break;
4234 case '?':
4235 val = '?';
4236 break;
4237 default:
4238 error("Undefined character escape %c", ch);
4239 break;
4240 }
4241 inp();
4242 return val;
4243 }
4244 } else {
4245 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004246 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004247 return val;
4248 }
4249
4250 static bool isoctal(int ch) {
4251 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004252 }
4253
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004254 bool acceptCh(int c) {
4255 bool result = c == ch;
4256 if (result) {
4257 pdef(ch);
4258 inp();
4259 }
4260 return result;
4261 }
4262
4263 bool acceptDigitsCh() {
4264 bool result = false;
4265 while (isdigit(ch)) {
4266 result = true;
4267 pdef(ch);
4268 inp();
4269 }
4270 return result;
4271 }
4272
4273 void parseFloat() {
4274 tok = TOK_NUM_DOUBLE;
4275 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004276 if(mTokenString.len() == 0) {
4277 mTokenString.append('0');
4278 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004279 acceptCh('.');
4280 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004281 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004282 acceptCh('-') || acceptCh('+');
4283 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004284 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004285 if (ch == 'f' || ch == 'F') {
4286 tok = TOK_NUM_FLOAT;
4287 inp();
4288 } else if (ch == 'l' || ch == 'L') {
4289 inp();
4290 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004291 }
4292 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004293 char* pEnd = pText + strlen(pText);
4294 char* pEndPtr = 0;
4295 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004296 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004297 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004298 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004299 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004300 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004301 if (errno || pEndPtr != pEnd) {
4302 error("Can't parse constant: %s", pText);
4303 }
4304 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004305 }
4306
Jack Palevich188a5a72009-10-27 17:23:20 -07004307 bool currentlyBeingExpanded(tokenid_t id) {
4308 for (int i = 0; i <= macroLevel; i++) {
4309 if (macroState[macroLevel].name == id) {
4310 return true;
4311 }
4312 }
4313 return false;
4314 }
4315
Jack Palevich21a15a22009-05-11 14:49:29 -07004316 void next() {
4317 int l, a;
4318
Jack Palevich546b2242009-05-13 15:10:04 -07004319 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004320 if (ch == '#') {
4321 inp();
4322 next();
4323 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004324 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004325 } else if (tok == TOK_PRAGMA) {
4326 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004327 } else if (tok == TOK_LINE) {
4328 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004329 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004330 error("Unsupported preprocessor directive \"%s\"",
4331 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004332 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004333 }
4334 inp();
4335 }
4336 tokl = 0;
4337 tok = ch;
4338 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004339 if (isdigit(ch) || ch == '.') {
4340 // Start of a numeric constant. Could be integer, float, or
4341 // double, won't know until we look further.
4342 mTokenString.clear();
4343 pdef(ch);
4344 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004345 if (tok == '.' && !isdigit(ch)) {
4346 goto done;
4347 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004348 int base = 10;
4349 if (tok == '0') {
4350 if (ch == 'x' || ch == 'X') {
4351 base = 16;
4352 tok = TOK_NUM;
4353 tokc = 0;
4354 inp();
4355 while ( isxdigit(ch) ) {
4356 tokc = (tokc << 4) + decodeHex(ch);
4357 inp();
4358 }
4359 } else if (isoctal(ch)){
4360 base = 8;
4361 tok = TOK_NUM;
4362 tokc = 0;
4363 while ( isoctal(ch) ) {
4364 tokc = (tokc << 3) + (ch - '0');
4365 inp();
4366 }
4367 }
4368 } else if (isdigit(tok)){
4369 acceptDigitsCh();
4370 }
4371 if (base == 10) {
4372 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4373 parseFloat();
4374 } else {
4375 // It's an integer constant
4376 char* pText = mTokenString.getUnwrapped();
4377 char* pEnd = pText + strlen(pText);
4378 char* pEndPtr = 0;
4379 errno = 0;
4380 tokc = strtol(pText, &pEndPtr, base);
4381 if (errno || pEndPtr != pEnd) {
4382 error("Can't parse constant: %s %d %d", pText, base, errno);
4383 }
4384 tok = TOK_NUM;
4385 }
4386 }
4387 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004388 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004389 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004390 pdef(ch);
4391 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004392 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004393 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004394 if (! mbSuppressMacroExpansion) {
4395 // Is this a macro?
4396 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
Jack Palevich188a5a72009-10-27 17:23:20 -07004397 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
Jack Palevich815d8b82009-08-18 18:25:56 -07004398 // Yes, it is a macro
Jack Palevich188a5a72009-10-27 17:23:20 -07004399#if 0
4400 printf("Expanding macro %s -> %s",
4401 mTokenString.getUnwrapped(), pMacroDefinition);
4402#endif
4403 if (macroLevel >= MACRO_NESTING_MAX-1) {
4404 error("Too many levels of macro recursion.");
4405 } else {
4406 macroLevel++;
4407 macroState[macroLevel].name = tok;
4408 macroState[macroLevel].dptr = pMacroDefinition;
4409 macroState[macroLevel].dch = ch;
4410 inp();
4411 next();
4412 }
Jack Palevich815d8b82009-08-18 18:25:56 -07004413 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004414 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004415 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004416 inp();
4417 if (tok == '\'') {
4418 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004419 tokc = getq();
4420 if (ch != '\'') {
4421 error("Expected a ' character, got %c", ch);
4422 } else {
4423 inp();
4424 }
Jack Palevich546b2242009-05-13 15:10:04 -07004425 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004426 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004427 while (ch && ch != EOF) {
4428 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004429 inp();
4430 inp();
4431 if (ch == '/')
4432 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004433 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004434 if (ch == EOF) {
4435 error("End of file inside comment.");
4436 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004437 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004438 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004439 } else if ((tok == '/') & (ch == '/')) {
4440 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004441 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004442 inp();
4443 }
4444 inp();
4445 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004446 } else if ((tok == '-') & (ch == '>')) {
4447 inp();
4448 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004449 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004450 const char* t = operatorChars;
4451 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004452 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004453 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004454 tokl = operatorLevel[opIndex];
4455 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004456 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004457#if 0
4458 printf("%c%c -> tokl=%d tokc=0x%x\n",
4459 l, a, tokl, tokc);
4460#endif
4461 if (a == ch) {
4462 inp();
4463 tok = TOK_DUMMY; /* dummy token for double tokens */
4464 }
Jack Palevich0c017742009-07-31 12:00:39 -07004465 /* check for op=, valid for * / % + - << >> & ^ | */
4466 if (ch == '=' &&
4467 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004468 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004469 inp();
4470 tok = TOK_OP_ASSIGNMENT;
4471 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004472 break;
4473 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004474 opIndex++;
4475 }
4476 if (l == 0) {
4477 tokl = 0;
4478 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004479 }
4480 }
4481 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004482
4483 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004484#if 0
4485 {
Jack Palevich569f1352009-06-29 14:29:08 -07004486 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004487 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004488 fprintf(stderr, "%s\n", buf.getUnwrapped());
4489 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004490#endif
4491 }
4492
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004493 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004494 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004495 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004496 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004497 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004498 if (ch == '(') {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004499 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004500 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004501 }
4502 while (isspace(ch)) {
4503 inp();
4504 }
Jack Palevich569f1352009-06-29 14:29:08 -07004505 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004506 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004507 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004508 // Check for '//' comments.
4509 if (appendToValue && ch == '/') {
4510 inp();
4511 if (ch == '/') {
4512 appendToValue = false;
4513 } else {
4514 value.append('/');
4515 }
4516 }
4517 if (appendToValue && ch != EOF) {
4518 value.append(ch);
4519 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004520 inp();
4521 }
Jack Palevich569f1352009-06-29 14:29:08 -07004522 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4523 memcpy(pDefn, value.getUnwrapped(), value.len());
4524 pDefn[value.len()] = 0;
4525 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich188a5a72009-10-27 17:23:20 -07004526#if 0
4527 {
4528 String buf;
4529 decodeToken(buf, name, true);
4530 fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
4531 }
4532#endif
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004533 }
4534
Jack Palevicheedf9d22009-06-04 16:23:40 -07004535 void doPragma() {
4536 // # pragma name(val)
4537 int state = 0;
4538 while(ch != EOF && ch != '\n' && state < 10) {
4539 switch(state) {
4540 case 0:
4541 if (isspace(ch)) {
4542 inp();
4543 } else {
4544 state++;
4545 }
4546 break;
4547 case 1:
4548 if (isalnum(ch)) {
4549 mPragmas.append(ch);
4550 inp();
4551 } else if (ch == '(') {
4552 mPragmas.append(0);
4553 inp();
4554 state++;
4555 } else {
4556 state = 11;
4557 }
4558 break;
4559 case 2:
4560 if (isalnum(ch)) {
4561 mPragmas.append(ch);
4562 inp();
4563 } else if (ch == ')') {
4564 mPragmas.append(0);
4565 inp();
4566 state = 10;
4567 } else {
4568 state = 11;
4569 }
4570 break;
4571 }
4572 }
4573 if(state != 10) {
4574 error("Unexpected pragma syntax");
4575 }
4576 mPragmaStringCount += 2;
4577 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004578
Jack Palevichdc456462009-07-16 16:50:56 -07004579 void doLine() {
4580 // # line number { "filename "}
4581 next();
4582 if (tok != TOK_NUM) {
4583 error("Expected a line-number");
4584 } else {
4585 mLineNumber = tokc-1; // The end-of-line will increment it.
4586 }
4587 while(ch != EOF && ch != '\n') {
4588 inp();
4589 }
4590 }
4591
Jack Palevichac0e95e2009-05-29 13:53:44 -07004592 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004593 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004594 mErrorBuf.vprintf(fmt, ap);
4595 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004596 }
4597
Jack Palevich8b0624c2009-05-20 12:12:06 -07004598 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004599 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004600 error("'%c' expected", c);
4601 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004602 }
4603
Jack Palevich86351982009-06-30 18:09:56 -07004604 bool accept(intptr_t c) {
4605 if (tok == c) {
4606 next();
4607 return true;
4608 }
4609 return false;
4610 }
4611
Jack Palevich40600de2009-07-01 15:32:35 -07004612 bool acceptStringLiteral() {
4613 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004614 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004615 // This while loop merges multiple adjacent string constants.
4616 while (tok == '"') {
4617 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004618 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004619 }
4620 if (ch != '"') {
4621 error("Unterminated string constant.");
4622 }
4623 inp();
4624 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004625 }
Jack Palevich40600de2009-07-01 15:32:35 -07004626 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004627 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004628 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004629 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004630
4631 return true;
4632 }
4633 return false;
4634 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004635
Jack Palevichb1544ca2009-07-16 15:09:20 -07004636 void linkGlobal(tokenid_t t, bool isFunction) {
4637 VariableInfo* pVI = VI(t);
4638 void* n = NULL;
4639 if (mpSymbolLookupFn) {
4640 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4641 }
4642 if (pVI->pType == NULL) {
4643 if (isFunction) {
4644 pVI->pType = mkpIntFn;
4645 } else {
4646 pVI->pType = mkpInt;
4647 }
4648 }
4649 pVI->pAddress = n;
4650 }
4651
Jack Palevich29daf572009-07-30 19:38:55 -07004652 void unaryOrAssignment() {
4653 unary();
4654 if (accept('=')) {
4655 checkLVal();
4656 pGen->pushR0();
4657 expr();
4658 pGen->forceR0RVal();
4659 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004660 } else if (tok == TOK_OP_ASSIGNMENT) {
4661 int t = tokc;
4662 next();
4663 checkLVal();
4664 pGen->pushR0();
4665 pGen->forceR0RVal();
4666 pGen->pushR0();
4667 expr();
4668 pGen->forceR0RVal();
4669 pGen->genOp(t);
4670 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004671 }
4672 }
4673
Jack Palevich40600de2009-07-01 15:32:35 -07004674 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004675 */
Jack Palevich29daf572009-07-30 19:38:55 -07004676 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004677 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004678 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004679 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004680 if (acceptStringLiteral()) {
4681 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004682 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004683 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004684 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004685 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004686 t = tok;
4687 next();
4688 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004689 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004690 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004691 // Align to 4-byte boundary
4692 glo = (char*) (((intptr_t) glo + 3) & -4);
4693 * (float*) glo = (float) ad;
4694 pGen->loadFloat((int) glo, mkpFloat);
4695 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004696 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004697 // Align to 8-byte boundary
4698 glo = (char*) (((intptr_t) glo + 7) & -8);
4699 * (double*) glo = ad;
4700 pGen->loadFloat((int) glo, mkpDouble);
4701 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004702 } else if (c == 2) {
4703 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004704 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004705 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004706 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004707 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004708 else if (t == '+') {
4709 // ignore unary plus.
4710 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004711 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004712 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004713 } else if (c == 11) {
4714 // pre increment / pre decrement
4715 unary();
4716 doIncDec(a == OP_INCREMENT, 0);
4717 }
4718 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004719 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004720 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004721 if (pCast) {
4722 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004723 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004724 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004725 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004726 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004727 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004728 skip(')');
4729 }
4730 } else if (t == '*') {
4731 /* This is a pointer dereference.
4732 */
Jack Palevich29daf572009-07-30 19:38:55 -07004733 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004734 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004735 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004736 unary();
4737 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004738 } else if (t == EOF ) {
4739 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004740 } else if (t == ';') {
4741 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004742 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004743 // Don't have to do anything special here, the error
4744 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004745 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004746 if (!isDefined(t)) {
4747 mGlobals.add(t);
4748 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004749 }
Jack Palevich8df46192009-07-07 14:48:51 -07004750 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004751 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004752 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004753 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004754 linkGlobal(t, tok == '(');
4755 n = (intptr_t) pVI->pAddress;
4756 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004757 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004758 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004759 }
Jack Palevich29daf572009-07-30 19:38:55 -07004760 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004761 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004762 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004763 linkGlobal(t, false);
4764 n = (intptr_t) pVI->pAddress;
4765 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004766 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004767 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004768 }
Jack Palevich5b659092009-07-31 14:55:07 -07004769 }
4770 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004771 Type* pVal;
4772 ExpressionType et;
4773 if (pVI->pType->tag == TY_ARRAY) {
4774 pVal = pVI->pType;
4775 et = ET_RVALUE;
4776 } else {
4777 pVal = createPtrType(pVI->pType);
4778 et = ET_LVALUE;
4779 }
Jack Palevich5b659092009-07-31 14:55:07 -07004780 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004781 int tag = pVal->pHead->tag;
4782 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004783 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004784 }
Jack Palevich5b659092009-07-31 14:55:07 -07004785 pGen->leaR0(n, pVal, et);
4786 } else {
4787 pVI->pForward = (void*) pGen->leaForward(
4788 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004789 }
4790 }
4791 }
4792
Jack Palevich5b659092009-07-31 14:55:07 -07004793 /* Now handle postfix operators */
4794 for(;;) {
4795 if (tokl == 11) {
4796 // post inc / post dec
4797 doIncDec(tokc == OP_INCREMENT, true);
4798 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004799 } else if (accept('[')) {
4800 // Array reference
4801 pGen->forceR0RVal();
4802 pGen->pushR0();
4803 commaExpr();
4804 pGen->forceR0RVal();
4805 pGen->genOp(OP_PLUS);
4806 doPointer();
4807 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004808 } else if (accept('.')) {
4809 // struct element
4810 pGen->forceR0RVal();
4811 Type* pStruct = pGen->getR0Type();
4812 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004813 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004814 } else {
4815 error("expected a struct value to the left of '.'");
4816 }
4817 } else if (accept(TOK_OP_ARROW)) {
4818 pGen->forceR0RVal();
4819 Type* pPtr = pGen->getR0Type();
4820 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4821 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004822 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004823 } else {
4824 error("Expected a pointer to a struct to the left of '->'");
4825 }
Jack Palevich5b659092009-07-31 14:55:07 -07004826 } else if (accept('(')) {
4827 /* function call */
4828 Type* pDecl = NULL;
4829 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004830 Type* pFn = pGen->getR0Type();
Jack Palevich188a5a72009-10-27 17:23:20 -07004831 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
4832 pDecl = pFn->pHead;
4833 pGen->pushR0();
4834 Type* pArgList = pDecl->pTail;
4835 bool varArgs = pArgList == NULL;
4836 /* push args and invert order */
4837 a = pGen->beginFunctionCallArguments();
4838 int l = 0;
4839 int argCount = 0;
4840 while (tok != ')' && tok != EOF) {
4841 if (! varArgs && !pArgList) {
4842 error("Unexpected argument.");
Jack Palevich5b659092009-07-31 14:55:07 -07004843 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004844 expr();
4845 pGen->forceR0RVal();
4846 Type* pTargetType;
4847 if (pArgList) {
4848 pTargetType = pArgList->pHead;
4849 pArgList = pArgList->pTail;
4850 } else {
4851 // This is a ... function, just pass arguments in their
4852 // natural type.
4853 pTargetType = pGen->getR0Type();
4854 if (pTargetType->tag == TY_FLOAT) {
4855 pTargetType = mkpDouble;
4856 } else if (pTargetType->tag == TY_ARRAY) {
4857 // Pass arrays by pointer.
4858 pTargetType = pTargetType->pTail;
4859 }
4860 }
4861 if (pTargetType->tag == TY_VOID) {
4862 error("Can't pass void value for argument %d",
4863 argCount + 1);
4864 } else {
4865 l += pGen->storeR0ToArg(l, pTargetType);
4866 }
4867 if (accept(',')) {
4868 // fine
4869 } else if ( tok != ')') {
4870 error("Expected ',' or ')'");
4871 }
4872 argCount += 1;
Jack Palevich5b659092009-07-31 14:55:07 -07004873 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004874 if (! varArgs && pArgList) {
4875 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich5b659092009-07-31 14:55:07 -07004876 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004877 pGen->endFunctionCallArguments(pDecl, a, l);
4878 skip(')');
4879 pGen->callIndirect(l, pDecl);
4880 pGen->adjustStackAfterCall(pDecl, l, true);
4881 } else {
4882 error("Expected a function value to left of '('.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004883 }
Jack Palevich5b659092009-07-31 14:55:07 -07004884 } else {
4885 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004886 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004887 }
4888 }
4889
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004890 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004891 Type* pStructElement = lookupStructMember(pStruct, tok);
4892 if (pStructElement) {
4893 next();
4894 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4895 } else {
4896 String buf;
4897 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004898 error("Expected a struct member to the right of '%s', got %s",
4899 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004900 }
4901 }
4902
Jack Palevichaaac9282009-07-31 14:34:34 -07004903 void doIncDec(int isInc, int isPost) {
4904 // R0 already has the lval
4905 checkLVal();
4906 int lit = isInc ? 1 : -1;
4907 pGen->pushR0();
4908 pGen->loadR0FromR0();
4909 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004910 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4911 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004912 error("++/-- illegal for this type. %d", tag);
4913 }
4914 if (isPost) {
4915 pGen->over();
4916 pGen->pushR0();
4917 pGen->li(lit);
4918 pGen->genOp(OP_PLUS);
4919 pGen->storeR0ToTOS();
4920 pGen->popR0();
4921 } else {
4922 pGen->pushR0();
4923 pGen->li(lit);
4924 pGen->genOp(OP_PLUS);
4925 pGen->over();
4926 pGen->storeR0ToTOS();
4927 pGen->popR0();
4928 }
4929 }
4930
Jack Palevich47cbea92009-07-31 15:25:53 -07004931 void doPointer() {
4932 pGen->forceR0RVal();
4933 Type* pR0Type = pGen->getR0Type();
4934 if (pR0Type->tag != TY_POINTER) {
4935 error("Expected a pointer type.");
4936 } else {
4937 if (pR0Type->pHead->tag != TY_FUNC) {
4938 pGen->setR0ExpressionType(ET_LVALUE);
4939 }
4940 }
4941 }
4942
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004943 void doAddressOf() {
4944 Type* pR0 = pGen->getR0Type();
4945 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4946 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4947 error("Expected an lvalue");
4948 }
4949 Type* pR0Type = pGen->getR0Type();
4950 pGen->setR0ExpressionType(ET_RVALUE);
4951 }
4952
Jack Palevich40600de2009-07-01 15:32:35 -07004953 /* Recursive descent parser for binary operations.
4954 */
4955 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004956 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004957 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004958 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004959 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004960 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004961 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004962 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004963 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004964 t = tokc;
4965 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004966 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004967 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004968 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004969 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004970 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004971 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004972 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004973 // Check for syntax error.
4974 if (pGen->getR0Type() == NULL) {
4975 // We failed to parse a right-hand argument.
4976 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004977 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004978 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004979 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004980 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004981 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004982 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004983 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004984 }
4985 }
4986 }
4987 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004988 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004989 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004990 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004991 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004992 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004993 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004994 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004995 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004996 }
4997 }
4998 }
4999
Jack Palevich43aaee32009-07-31 14:01:37 -07005000 void commaExpr() {
5001 for(;;) {
5002 expr();
5003 if (!accept(',')) {
5004 break;
5005 }
5006 }
5007 }
5008
Jack Palevich21a15a22009-05-11 14:49:29 -07005009 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07005010 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07005011 }
5012
5013 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07005014 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005015 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005016 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07005017 }
5018
Jack Palevich46f2bd22009-10-29 17:56:56 -07005019 void block(intptr_t* breakLabel, intptr_t continueAddress, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07005020 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07005021
Jack Palevich95727a02009-07-06 12:07:15 -07005022 Type* pBaseType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005023 if ((pBaseType = acceptPrimitiveType(true))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07005024 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07005025 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005026 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005027 next();
5028 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07005029 a = test_expr();
5030 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005031 block(breakLabel, continueAddress, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07005032 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005033 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005034 n = pGen->gjmp(0); /* jmp */
5035 pGen->gsym(a);
Jack Palevichc951c592009-10-29 15:04:27 -07005036 block(breakLabel, continueAddress, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005037 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07005038 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005039 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005040 }
Jack Palevich546b2242009-05-13 15:10:04 -07005041 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07005042 t = tok;
5043 next();
5044 skip('(');
5045 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005046 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07005047 a = test_expr();
5048 } else {
5049 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005050 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005051 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005052 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07005053 a = 0;
5054 if (tok != ';')
5055 a = test_expr();
5056 skip(';');
5057 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005058 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005059 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005060 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005061 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005062 n = t + 4;
5063 }
5064 }
5065 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005066 block(&a, n, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005067 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005068 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005069 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005070 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005071 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005072 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005073 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005074 while (tok != '}' && tok != EOF)
Jack Palevichc951c592009-10-29 15:04:27 -07005075 block(breakLabel, continueAddress, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005076 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005077 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005078 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005079 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005080 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005081 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005082 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005083 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005084 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005085 if (pReturnType->tag == TY_VOID) {
5086 error("Must not return a value from a void function");
5087 } else {
5088 pGen->convertR0(pReturnType);
5089 }
5090 } else {
5091 if (pReturnType->tag != TY_VOID) {
5092 error("Must specify a value here");
5093 }
Jack Palevich8df46192009-07-07 14:48:51 -07005094 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005095 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005096 } else if (accept(TOK_BREAK)) {
Jack Palevichc951c592009-10-29 15:04:27 -07005097 if (breakLabel) {
5098 *breakLabel = pGen->gjmp(*breakLabel);
5099 } else {
5100 error("break statement must be within a for, do, while, or switch statement");
5101 }
5102 } else if (accept(TOK_CONTINUE)) {
5103 if (continueAddress) {
5104 pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset());
5105 } else {
5106 error("continue statement must be within a for, do, or while statement");
5107 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005108 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005109 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005110 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005111 }
5112 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005113
Jack Palevicha8f427f2009-07-13 18:40:08 -07005114 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005115 if (a == b) {
5116 return true;
5117 }
5118 if (a == NULL || b == NULL) {
5119 return false;
5120 }
5121 TypeTag at = a->tag;
5122 if (at != b->tag) {
5123 return false;
5124 }
5125 if (at == TY_POINTER) {
5126 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005127 } else if (at == TY_ARRAY) {
5128 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005129 } else if (at == TY_FUNC || at == TY_PARAM) {
5130 return typeEqual(a->pHead, b->pHead)
5131 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005132 } else if (at == TY_STRUCT) {
5133 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005134 }
5135 return true;
5136 }
5137
Jack Palevich2ff5c222009-07-23 15:11:22 -07005138 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005139 assert(tag >= TY_UNKNOWN && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005140 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005141 memset(pType, 0, sizeof(*pType));
Jack Palevichee1f8292009-10-28 16:10:17 -07005142 pType->storageClass = SC_DEFAULT;
Jack Palevich86351982009-06-30 18:09:56 -07005143 pType->tag = tag;
5144 pType->pHead = pHead;
5145 pType->pTail = pTail;
5146 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005147 }
5148
Jack Palevich2ff5c222009-07-23 15:11:22 -07005149 Type* createPtrType(Type* pType) {
5150 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005151 }
5152
5153 /**
5154 * Try to print a type in declaration order
5155 */
Jack Palevich86351982009-06-30 18:09:56 -07005156 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005157 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005158 if (pType == NULL) {
5159 buffer.appendCStr("null");
5160 return;
5161 }
Jack Palevich3f226492009-07-02 14:46:19 -07005162 decodeTypeImp(buffer, pType);
5163 }
5164
5165 void decodeTypeImp(String& buffer, Type* pType) {
5166 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005167 decodeId(buffer, pType->id);
5168 decodeTypeImpPostfix(buffer, pType);
5169 }
Jack Palevich3f226492009-07-02 14:46:19 -07005170
Jack Palevich9221bcc2009-08-26 16:15:07 -07005171 void decodeId(String& buffer, tokenid_t id) {
5172 if (id) {
5173 String temp;
5174 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005175 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005176 }
Jack Palevich3f226492009-07-02 14:46:19 -07005177 }
5178
5179 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5180 TypeTag tag = pType->tag;
5181
Jack Palevich9221bcc2009-08-26 16:15:07 -07005182 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005183 switch (tag) {
5184 case TY_INT:
5185 buffer.appendCStr("int");
5186 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005187 case TY_SHORT:
5188 buffer.appendCStr("short");
5189 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005190 case TY_CHAR:
5191 buffer.appendCStr("char");
5192 break;
5193 case TY_VOID:
5194 buffer.appendCStr("void");
5195 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005196 case TY_FLOAT:
5197 buffer.appendCStr("float");
5198 break;
5199 case TY_DOUBLE:
5200 buffer.appendCStr("double");
5201 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005202 case TY_STRUCT:
5203 {
5204 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5205 buffer.appendCStr(isStruct ? "struct" : "union");
5206 if (pType->pHead && pType->pHead->structTag) {
5207 buffer.append(' ');
5208 decodeId(buffer, pType->pHead->structTag);
5209 }
5210 }
5211 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005212 default:
5213 break;
5214 }
Jack Palevich86351982009-06-30 18:09:56 -07005215 buffer.append(' ');
5216 }
Jack Palevich3f226492009-07-02 14:46:19 -07005217
5218 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005219 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005220 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005221 case TY_SHORT:
5222 break;
Jack Palevich86351982009-06-30 18:09:56 -07005223 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005224 break;
5225 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005226 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005227 case TY_FLOAT:
5228 break;
5229 case TY_DOUBLE:
5230 break;
Jack Palevich86351982009-06-30 18:09:56 -07005231 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005232 decodeTypeImpPrefix(buffer, pType->pHead);
5233 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5234 buffer.append('(');
5235 }
5236 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005237 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005238 case TY_ARRAY:
5239 decodeTypeImpPrefix(buffer, pType->pHead);
5240 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005241 case TY_STRUCT:
5242 break;
Jack Palevich86351982009-06-30 18:09:56 -07005243 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005244 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005245 break;
5246 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005247 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005248 break;
5249 default:
5250 String temp;
5251 temp.printf("Unknown tag %d", pType->tag);
5252 buffer.append(temp);
5253 break;
5254 }
Jack Palevich3f226492009-07-02 14:46:19 -07005255 }
5256
5257 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5258 TypeTag tag = pType->tag;
5259
5260 switch(tag) {
5261 case TY_POINTER:
5262 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5263 buffer.append(')');
5264 }
5265 decodeTypeImpPostfix(buffer, pType->pHead);
5266 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005267 case TY_ARRAY:
5268 {
5269 String temp;
5270 temp.printf("[%d]", pType->length);
5271 buffer.append(temp);
5272 }
5273 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005274 case TY_STRUCT:
5275 if (pType->pHead->length >= 0) {
5276 buffer.appendCStr(" {");
5277 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5278 decodeTypeImp(buffer, pArg->pHead);
5279 buffer.appendCStr(";");
5280 }
5281 buffer.append('}');
5282 }
5283 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005284 case TY_FUNC:
5285 buffer.append('(');
5286 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5287 decodeTypeImp(buffer, pArg);
5288 if (pArg->pTail) {
5289 buffer.appendCStr(", ");
5290 }
5291 }
5292 buffer.append(')');
5293 break;
5294 default:
5295 break;
Jack Palevich86351982009-06-30 18:09:56 -07005296 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005297 }
5298
Jack Palevich86351982009-06-30 18:09:56 -07005299 void printType(Type* pType) {
5300 String buffer;
5301 decodeType(buffer, pType);
5302 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005303 }
5304
Jack Palevichee1f8292009-10-28 16:10:17 -07005305 void insertTypeSpecifier(Type** ppType, TypeTag tag) {
5306 if (! *ppType) {
5307 *ppType = createType(tag, NULL, NULL);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005308 } else {
Jack Palevichee1f8292009-10-28 16:10:17 -07005309 if ((*ppType)->tag != TY_UNKNOWN) {
5310 error("Only one type specifier allowed.");
5311 } else {
5312 (*ppType)->tag = tag;
5313 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005314 }
Jack Palevichee1f8292009-10-28 16:10:17 -07005315 }
5316
5317 void insertStorageClass(Type** ppType, StorageClass storageClass) {
5318 if (! *ppType) {
5319 *ppType = createType(TY_UNKNOWN, NULL, NULL);
5320 }
5321 if ((*ppType)->storageClass != SC_DEFAULT) {
5322 error("Only one storage class allowed.");
5323 } else {
5324 (*ppType)->storageClass = storageClass;
5325 }
5326 }
5327
5328 Type* acceptPrimitiveType(bool allowStorageClass) {
5329 Type* pType = NULL;
5330 for (bool keepGoing = true; keepGoing;) {
5331 switch(tok) {
5332 case TOK_AUTO:
5333 insertStorageClass(&pType, SC_AUTO);
5334 break;
5335 case TOK_REGISTER:
5336 insertStorageClass(&pType, SC_REGISTER);
5337 break;
5338 case TOK_STATIC:
5339 insertStorageClass(&pType, SC_STATIC);
5340 break;
5341 case TOK_EXTERN:
5342 insertStorageClass(&pType, SC_EXTERN);
5343 break;
5344 case TOK_TYPEDEF:
5345 insertStorageClass(&pType, SC_TYPEDEF);
5346 break;
5347 case TOK_INT:
5348 insertTypeSpecifier(&pType, TY_INT);
5349 break;
5350 case TOK_SHORT:
5351 insertTypeSpecifier(&pType, TY_SHORT);
5352 break;
5353 case TOK_CHAR:
5354 insertTypeSpecifier(&pType, TY_CHAR);
5355 break;
5356 case TOK_VOID:
5357 insertTypeSpecifier(&pType, TY_VOID);
5358 break;
5359 case TOK_FLOAT:
5360 insertTypeSpecifier(&pType, TY_FLOAT);
5361 break;
5362 case TOK_DOUBLE:
5363 insertTypeSpecifier(&pType, TY_DOUBLE);
5364 break;
5365 case TOK_STRUCT:
5366 case TOK_UNION:
5367 {
5368 insertTypeSpecifier(&pType, TY_STRUCT);
5369 bool isStruct = (tok == TOK_STRUCT);
5370 next();
5371 pType = acceptStruct(pType, isStruct);
5372 keepGoing = false;
5373 }
5374 break;
5375 default:
5376 // Is it a typedef?
5377 if (isSymbol(tok)) {
5378 VariableInfo* pV = VI(tok);
5379 if (pV && pV->pType->storageClass == SC_TYPEDEF) {
5380 if (! pType) {
5381 pType = createType(TY_UNKNOWN, NULL, NULL);
5382 }
5383 StorageClass storageClass = pType->storageClass;
5384 *pType = *pV->pType;
5385 pType->storageClass = storageClass;
5386 } else {
5387 keepGoing = false;
5388 }
5389 } else {
5390 keepGoing = false;
5391 }
5392 }
5393 if (keepGoing) {
5394 next();
5395 }
5396 }
5397 if (pType) {
5398 if (pType->tag == TY_UNKNOWN) {
5399 pType->tag = TY_INT;
5400 }
5401 if (allowStorageClass) {
5402 switch(pType->storageClass) {
5403 case SC_AUTO: error("auto not supported."); break;
5404 case SC_REGISTER: error("register not supported."); break;
5405 case SC_STATIC: error("static not supported."); break;
5406 case SC_EXTERN: error("extern not supported."); break;
5407 default: break;
5408 }
5409 } else {
5410 if (pType->storageClass != SC_DEFAULT) {
5411 error("An explicit storage class is not allowed in this type declaration");
5412 }
5413 }
5414 }
Jack Palevich86351982009-06-30 18:09:56 -07005415 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005416 }
5417
Jack Palevichee1f8292009-10-28 16:10:17 -07005418 Type* acceptStruct(Type* pStructType, bool isStruct) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005419 tokenid_t structTag = acceptSymbol();
5420 bool isDeclaration = accept('{');
5421 bool fail = false;
5422
Jack Palevich9221bcc2009-08-26 16:15:07 -07005423 if (structTag) {
5424 Token* pToken = &mTokenTable[structTag];
5425 VariableInfo* pStructInfo = pToken->mpStructInfo;
5426 bool needToDeclare = !pStructInfo;
5427 if (pStructInfo) {
5428 if (isDeclaration) {
5429 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5430 if (pStructInfo->pType->pHead->length == -1) {
5431 // we're filling in a forward declaration.
5432 needToDeclare = false;
5433 } else {
5434 error("A struct with the same name is already defined at this level.");
5435 fail = true;
5436 }
5437 } else {
5438 needToDeclare = true;
5439 }
5440 }
5441 if (!fail) {
5442 assert(pStructInfo->isStructTag);
5443 pStructType->pHead = pStructInfo->pType;
5444 pStructType->pTail = pStructType->pHead->pTail;
5445 }
5446 }
5447
5448 if (needToDeclare) {
5449 // This is a new struct name
5450 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
Jack Palevichee1f8292009-10-28 16:10:17 -07005451 StorageClass storageClass = pStructType->storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005452 pStructType = createType(TY_STRUCT, NULL, NULL);
5453 pStructType->structTag = structTag;
5454 pStructType->pHead = pStructType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005455 pStructType->storageClass = storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005456 if (! isDeclaration) {
5457 // A forward declaration
5458 pStructType->length = -1;
5459 }
5460 pToken->mpStructInfo->pType = pStructType;
5461 }
5462 } else {
5463 // An anonymous struct
5464 pStructType->pHead = pStructType;
5465 }
5466
5467 if (isDeclaration) {
5468 size_t offset = 0;
5469 size_t structSize = 0;
5470 size_t structAlignment = 0;
5471 Type** pParamHolder = & pStructType->pHead->pTail;
5472 while (tok != '}' && tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005473 Type* pPrimitiveType = expectPrimitiveType(false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005474 if (pPrimitiveType) {
5475 while (tok != ';' && tok != EOF) {
5476 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5477 if (!pItem) {
5478 break;
5479 }
5480 if (lookupStructMember(pStructType, pItem->id)) {
5481 String buf;
5482 decodeToken(buf, pItem->id, false);
5483 error("Duplicate struct member %s", buf.getUnwrapped());
5484 }
5485 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5486 size_t alignment = pGen->alignmentOf(pItem);
5487 if (alignment > structAlignment) {
5488 structAlignment = alignment;
5489 }
5490 size_t alignmentMask = alignment - 1;
5491 offset = (offset + alignmentMask) & ~alignmentMask;
5492 pStructElement->length = offset;
5493 size_t size = pGen->sizeOf(pItem);
5494 if (isStruct) {
5495 offset += size;
5496 structSize = offset;
5497 } else {
5498 if (size >= structSize) {
5499 structSize = size;
5500 }
5501 }
5502 *pParamHolder = pStructElement;
5503 pParamHolder = &pStructElement->pTail;
5504 accept(',');
5505 }
5506 skip(';');
5507 } else {
5508 // Some sort of syntax error, skip token and keep trying
5509 next();
5510 }
5511 }
5512 if (!fail) {
5513 pStructType->pHead->length = structSize;
5514 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5515 }
5516 skip('}');
5517 }
5518 if (fail) {
5519 pStructType = NULL;
5520 }
5521 return pStructType;
5522 }
5523
5524 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5525 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5526 if (pStructElement->pHead->id == memberId) {
5527 return pStructElement;
5528 }
5529 }
5530 return NULL;
5531 }
5532
Jack Palevich2ff5c222009-07-23 15:11:22 -07005533 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005534 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005535 bool reportFailure = false;
Jack Palevichee1f8292009-10-28 16:10:17 -07005536 StorageClass storageClass = pType->storageClass;
Jack Palevich3f226492009-07-02 14:46:19 -07005537 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005538 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005539 if (declName) {
5540 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005541 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005542 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005543 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005544 pType->id = declName;
Jack Palevichee1f8292009-10-28 16:10:17 -07005545 pType->storageClass = storageClass;
Jack Palevichb6154502009-08-04 14:56:09 -07005546 } else if (nameRequired) {
5547 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005548 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005549#if 0
5550 fprintf(stderr, "Parsed a declaration: ");
5551 printType(pType);
5552#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005553 if (reportFailure) {
5554 return NULL;
5555 }
Jack Palevich86351982009-06-30 18:09:56 -07005556 return pType;
5557 }
5558
Jack Palevich2ff5c222009-07-23 15:11:22 -07005559 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005560 bool nameRequired = pBaseType->tag != TY_STRUCT;
5561 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005562 if (! pType) {
5563 error("Expected a declaration");
5564 }
5565 return pType;
5566 }
5567
Jack Palevich3f226492009-07-02 14:46:19 -07005568 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005569 Type* acceptCastTypeDeclaration() {
Jack Palevichee1f8292009-10-28 16:10:17 -07005570 Type* pType = acceptPrimitiveType(false);
Jack Palevich3f226492009-07-02 14:46:19 -07005571 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005572 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005573 }
Jack Palevich86351982009-06-30 18:09:56 -07005574 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005575 }
5576
Jack Palevich2ff5c222009-07-23 15:11:22 -07005577 Type* expectCastTypeDeclaration() {
5578 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005579 if (! pType) {
5580 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005581 }
Jack Palevich3f226492009-07-02 14:46:19 -07005582 return pType;
5583 }
5584
5585 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005586 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005587 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005588 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005589 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005590 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005591 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005592 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005593 return pType;
5594 }
5595
5596 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005597 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005598 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005599 // direct-dcl :
5600 // name
5601 // (dcl)
5602 // direct-dcl()
5603 // direct-dcl[]
5604 Type* pNewHead = NULL;
5605 if (accept('(')) {
5606 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005607 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005608 skip(')');
5609 } else if ((declName = acceptSymbol()) != 0) {
5610 if (nameAllowed == false && declName) {
5611 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005612 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005613 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005614 } else if (nameRequired && ! declName) {
5615 String temp;
5616 decodeToken(temp, tok, true);
5617 error("Expected name. Got %s", temp.getUnwrapped());
5618 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005619 }
Jack Palevichb6154502009-08-04 14:56:09 -07005620 for(;;) {
5621 if (accept('(')) {
5622 // Function declaration
5623 Type* pTail = acceptArgs(nameAllowed);
5624 pType = createType(TY_FUNC, pType, pTail);
5625 skip(')');
5626 } if (accept('[')) {
5627 if (tok != ']') {
5628 if (tok != TOK_NUM || tokc <= 0) {
5629 error("Expected positive integer constant");
5630 } else {
5631 Type* pDecayType = createPtrType(pType);
5632 pType = createType(TY_ARRAY, pType, pDecayType);
5633 pType->length = tokc;
5634 }
5635 next();
5636 }
5637 skip(']');
5638 } else {
5639 break;
5640 }
Jack Palevich86351982009-06-30 18:09:56 -07005641 }
Jack Palevich3f226492009-07-02 14:46:19 -07005642
5643 if (pNewHead) {
5644 Type* pA = pNewHead;
5645 while (pA->pHead) {
5646 pA = pA->pHead;
5647 }
5648 pA->pHead = pType;
5649 pType = pNewHead;
5650 }
Jack Palevich86351982009-06-30 18:09:56 -07005651 return pType;
5652 }
5653
Jack Palevich2ff5c222009-07-23 15:11:22 -07005654 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005655 Type* pHead = NULL;
5656 Type* pTail = NULL;
5657 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005658 Type* pBaseArg = acceptPrimitiveType(false);
Jack Palevich86351982009-06-30 18:09:56 -07005659 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005660 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005661 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005662 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005663 if (!pHead) {
5664 pHead = pParam;
5665 pTail = pParam;
5666 } else {
5667 pTail->pTail = pParam;
5668 pTail = pParam;
5669 }
5670 }
5671 }
5672 if (! accept(',')) {
5673 break;
5674 }
5675 }
5676 return pHead;
5677 }
5678
Jack Palevichee1f8292009-10-28 16:10:17 -07005679 Type* expectPrimitiveType(bool allowStorageClass) {
5680 Type* pType = acceptPrimitiveType(allowStorageClass);
Jack Palevich86351982009-06-30 18:09:56 -07005681 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005682 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005683 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005684 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005685 }
Jack Palevich86351982009-06-30 18:09:56 -07005686 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005687 }
5688
Jack Palevichb5e33312009-07-30 19:06:34 -07005689 void checkLVal() {
5690 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005691 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005692 }
5693 }
5694
Jack Palevich86351982009-06-30 18:09:56 -07005695 void addGlobalSymbol(Type* pDecl) {
5696 tokenid_t t = pDecl->id;
5697 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005698 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005699 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005700 }
Jack Palevich86351982009-06-30 18:09:56 -07005701 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005702 }
5703
Jack Palevich86351982009-06-30 18:09:56 -07005704 void reportDuplicate(tokenid_t t) {
5705 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005706 }
5707
Jack Palevich86351982009-06-30 18:09:56 -07005708 void addLocalSymbol(Type* pDecl) {
5709 tokenid_t t = pDecl->id;
5710 if (mLocals.isDefinedAtCurrentLevel(t)) {
5711 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005712 }
Jack Palevich86351982009-06-30 18:09:56 -07005713 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005714 }
5715
Jack Palevich61de31f2009-09-08 11:06:40 -07005716 bool checkUndeclaredStruct(Type* pBaseType) {
5717 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5718 String temp;
5719 decodeToken(temp, pBaseType->structTag, false);
5720 error("Undeclared struct %s", temp.getUnwrapped());
5721 return true;
5722 }
5723 return false;
5724 }
5725
Jack Palevich95727a02009-07-06 12:07:15 -07005726 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005727 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005728
Jack Palevich95727a02009-07-06 12:07:15 -07005729 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005730 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005731 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005732 if (!pDecl) {
5733 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005734 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005735 if (!pDecl->id) {
5736 break;
5737 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005738 if (checkUndeclaredStruct(pDecl)) {
5739 break;
5740 }
Jack Palevich86351982009-06-30 18:09:56 -07005741 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005742 if (pDecl->tag == TY_FUNC) {
5743 if (tok == '{') {
5744 error("Nested functions are not allowed. Did you forget a '}' ?");
5745 break;
5746 }
5747 // Else it's a forward declaration of a function.
Jack Palevichee1f8292009-10-28 16:10:17 -07005748 } else if (pDecl->storageClass != SC_TYPEDEF) {
Jack Palevich1c60e462009-09-18 15:03:03 -07005749 int variableAddress = 0;
5750 size_t alignment = pGen->alignmentOf(pDecl);
5751 assert(alignment > 0);
5752 size_t alignmentMask = ~ (alignment - 1);
5753 size_t sizeOf = pGen->sizeOf(pDecl);
5754 assert(sizeOf > 0);
5755 loc = (loc + alignment - 1) & alignmentMask;
5756 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5757 loc = loc + alignedSize;
5758 variableAddress = -loc;
5759 VI(pDecl->id)->pAddress = (void*) variableAddress;
5760 if (accept('=')) {
5761 /* assignment */
5762 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5763 pGen->pushR0();
5764 expr();
5765 pGen->forceR0RVal();
5766 pGen->storeR0ToTOS();
5767 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005768 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005769 if (tok == ',')
5770 next();
5771 }
5772 skip(';');
Jack Palevichee1f8292009-10-28 16:10:17 -07005773 pBaseType = acceptPrimitiveType(true);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005774 }
5775 }
5776
Jack Palevichf1728be2009-06-12 13:53:51 -07005777 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005778 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005779 }
5780
Jack Palevich37c54bd2009-07-14 18:35:36 -07005781 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005782 if (token == EOF ) {
5783 buffer.printf("EOF");
5784 } else if (token == TOK_NUM) {
Jack Palevich188a5a72009-10-27 17:23:20 -07005785 buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
5786 } else if (token == TOK_NUM_FLOAT) {
5787 buffer.printf("numeric constant float %g", tokd);
5788 } else if (token == TOK_NUM_DOUBLE) {
5789 buffer.printf("numeric constant double %g", tokd);
5790 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005791 if (token < 32) {
5792 buffer.printf("'\\x%02x'", token);
5793 } else {
5794 buffer.printf("'%c'", token);
5795 }
Jack Palevich569f1352009-06-29 14:29:08 -07005796 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005797 if (quote) {
5798 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5799 buffer.printf("keyword \"%s\"", nameof(token));
5800 } else {
5801 buffer.printf("symbol \"%s\"", nameof(token));
5802 }
5803 } else {
5804 buffer.printf("%s", nameof(token));
5805 }
Jack Palevich569f1352009-06-29 14:29:08 -07005806 }
5807 }
5808
Jack Palevich9221bcc2009-08-26 16:15:07 -07005809 void printToken(tokenid_t token) {
5810 String buffer;
5811 decodeToken(buffer, token, true);
5812 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5813 }
5814
Jack Palevich40600de2009-07-01 15:32:35 -07005815 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005816 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005817 if (!result) {
5818 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005819 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005820 error("Expected symbol. Got %s", temp.getUnwrapped());
5821 }
5822 return result;
5823 }
5824
Jack Palevich86351982009-06-30 18:09:56 -07005825 tokenid_t acceptSymbol() {
5826 tokenid_t result = 0;
5827 if (tok >= TOK_SYMBOL) {
5828 result = tok;
5829 next();
Jack Palevich86351982009-06-30 18:09:56 -07005830 }
5831 return result;
5832 }
5833
Jack Palevichb7c81e92009-06-04 19:56:13 -07005834 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005835 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005836 while (tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005837 Type* pBaseType = expectPrimitiveType(true);
Jack Palevich86351982009-06-30 18:09:56 -07005838 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005839 break;
5840 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005841 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005842 if (!pDecl) {
5843 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005844 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005845 if (!pDecl->id) {
5846 skip(';');
5847 continue;
5848 }
5849
Jack Palevich61de31f2009-09-08 11:06:40 -07005850 if (checkUndeclaredStruct(pDecl)) {
5851 skip(';');
5852 continue;
5853 }
Jack Palevich86351982009-06-30 18:09:56 -07005854 if (! isDefined(pDecl->id)) {
5855 addGlobalSymbol(pDecl);
5856 }
5857 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005858 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005859 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005860 }
Jack Palevich86351982009-06-30 18:09:56 -07005861 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005862 // it's a variable declaration
5863 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005864 if (pDecl->storageClass == SC_TYPEDEF) {
5865 // Do not allocate storage.
5866 } else {
5867 if (name && !name->pAddress) {
5868 name->pAddress = (int*) allocGlobalSpace(
5869 pGen->alignmentOf(name->pType),
5870 pGen->sizeOf(name->pType));
5871 }
5872 if (accept('=')) {
5873 if (tok == TOK_NUM) {
5874 if (name) {
5875 * (int*) name->pAddress = tokc;
5876 }
5877 next();
5878 } else {
5879 error("Expected an integer constant");
Jack Palevichd7461a72009-06-12 14:26:58 -07005880 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005881 }
5882 }
Jack Palevich86351982009-06-30 18:09:56 -07005883 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005884 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005885 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005886 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005887 if (!pDecl) {
5888 break;
5889 }
5890 if (! isDefined(pDecl->id)) {
5891 addGlobalSymbol(pDecl);
5892 }
5893 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005894 }
5895 skip(';');
5896 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005897 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005898 if (accept(';')) {
5899 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005900 } else if (tok != '{') {
5901 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005902 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005903 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005904 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005905 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005906 /* patch forward references */
5907 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005908 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005909 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005910 }
5911 // Calculate stack offsets for parameters
5912 mLocals.pushLevel();
5913 intptr_t a = 8;
5914 int argCount = 0;
5915 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5916 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005917 if (pArg->id) {
5918 addLocalSymbol(pArg);
5919 }
Jack Palevich95727a02009-07-06 12:07:15 -07005920 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005921 Type* pPassingType = passingType(pArg);
5922 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005923 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005924 if (pArg->id) {
5925 VI(pArg->id)->pAddress = (void*) a;
5926 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005927 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005928 argCount++;
5929 }
5930 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005931 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005932 a = pGen->functionEntry(pDecl);
Jack Palevichc951c592009-10-29 15:04:27 -07005933 block(0, 0, true);
Jack Palevich95727a02009-07-06 12:07:15 -07005934 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005935 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005936 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005937 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005938 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005939 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005940 }
5941 }
5942 }
5943
Jack Palevich9221bcc2009-08-26 16:15:07 -07005944 Type* passingType(Type* pType) {
5945 switch (pType->tag) {
5946 case TY_CHAR:
5947 case TY_SHORT:
5948 return mkpInt;
5949 default:
5950 return pType;
5951 }
5952 }
5953
Jack Palevich9cbd2262009-07-08 16:48:41 -07005954 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5955 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5956 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005957 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005958 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005959 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005960 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005961 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005962 char* result = (char*) base;
5963 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005964 return result;
5965 }
5966
Jack Palevich21a15a22009-05-11 14:49:29 -07005967 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005968 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005969 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005970 pGlobalBase = 0;
5971 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005972 if (pGen) {
5973 delete pGen;
5974 pGen = 0;
5975 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005976 if (pCodeBuf) {
5977 delete pCodeBuf;
5978 pCodeBuf = 0;
5979 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005980 if (file) {
5981 delete file;
5982 file = 0;
5983 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005984 }
5985
Jack Palevich8c246a92009-07-14 21:14:10 -07005986 // One-time initialization, when class is constructed.
5987 void init() {
5988 mpSymbolLookupFn = 0;
5989 mpSymbolLookupContext = 0;
5990 }
5991
Jack Palevich21a15a22009-05-11 14:49:29 -07005992 void clear() {
5993 tok = 0;
5994 tokc = 0;
5995 tokl = 0;
5996 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005997 rsym = 0;
5998 loc = 0;
5999 glo = 0;
Jack Palevich188a5a72009-10-27 17:23:20 -07006000 macroLevel = -1;
Jack Palevich21a15a22009-05-11 14:49:29 -07006001 file = 0;
6002 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006003 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07006004 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07006005 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07006006 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07006007 mLineNumber = 1;
6008 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07006009 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07006010 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006011
Jack Palevich22305132009-05-13 10:58:45 -07006012 void setArchitecture(const char* architecture) {
6013 delete pGen;
6014 pGen = 0;
6015
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006016 delete pCodeBuf;
6017 pCodeBuf = new CodeBuf();
6018
Jack Palevich22305132009-05-13 10:58:45 -07006019 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006020#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006021 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006022 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006023 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07006024 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006025#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07006026#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006027 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006028 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07006029 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006030#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07006031 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006032 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07006033 }
6034 }
6035
6036 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006037#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07006038 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006039 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07006040#elif defined(DEFAULT_X86_CODEGEN)
6041 pGen = new X86CodeGenerator();
6042#endif
6043 }
6044 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006045 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07006046 } else {
6047 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07006048 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07006049 }
6050 }
6051
Jack Palevich77ae76e2009-05-10 19:59:24 -07006052public:
Jack Palevich22305132009-05-13 10:58:45 -07006053 struct args {
6054 args() {
6055 architecture = 0;
6056 }
6057 const char* architecture;
6058 };
6059
Jack Paleviche7b59062009-05-19 17:12:17 -07006060 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07006061 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07006062 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006063 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006064
Jack Paleviche7b59062009-05-19 17:12:17 -07006065 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07006066 cleanup();
6067 }
6068
Jack Palevich8c246a92009-07-14 21:14:10 -07006069 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6070 mpSymbolLookupFn = pFn;
6071 mpSymbolLookupContext = pContext;
6072 }
6073
Jack Palevich1cdef202009-05-22 12:06:27 -07006074 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006075 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07006076
Jack Palevich2ff5c222009-07-23 15:11:22 -07006077 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07006078 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07006079 cleanup();
6080 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07006081 mTokenTable.setArena(&mGlobalArena);
6082 mGlobals.setArena(&mGlobalArena);
6083 mGlobals.setTokenTable(&mTokenTable);
6084 mLocals.setArena(&mLocalArena);
6085 mLocals.setTokenTable(&mTokenTable);
6086
6087 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07006088 setArchitecture(NULL);
6089 if (!pGen) {
6090 return -1;
6091 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07006092#ifdef PROVIDE_TRACE_CODEGEN
6093 pGen = new TraceCodeGenerator(pGen);
6094#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006095 pGen->setErrorSink(this);
6096
6097 if (pCodeBuf) {
6098 pCodeBuf->init(ALLOC_SIZE);
6099 }
6100 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07006101 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07006102 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
6103 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07006104 inp();
6105 next();
6106 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07006107 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07006108 result = pGen->finishCompile();
6109 if (result == 0) {
6110 if (mErrorBuf.len()) {
6111 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006112 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07006113 }
Jack Palevichce105a92009-07-16 14:30:33 -07006114 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006115 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07006116 }
6117
Jack Palevich86351982009-06-30 18:09:56 -07006118 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07006119 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07006120 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07006121 mkpChar = createType(TY_CHAR, NULL, NULL);
6122 mkpVoid = createType(TY_VOID, NULL, NULL);
6123 mkpFloat = createType(TY_FLOAT, NULL, NULL);
6124 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
6125 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
6126 mkpIntPtr = createPtrType(mkpInt);
6127 mkpCharPtr = createPtrType(mkpChar);
6128 mkpFloatPtr = createPtrType(mkpFloat);
6129 mkpDoublePtr = createPtrType(mkpDouble);
6130 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07006131 }
6132
Jack Palevicha6baa232009-06-12 11:25:59 -07006133 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07006134 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07006135 }
6136
Jack Palevich569f1352009-06-29 14:29:08 -07006137 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006138 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07006139 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07006140 }
6141
Jack Palevich569f1352009-06-29 14:29:08 -07006142 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006143 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07006144 error("Undefined forward reference: %s",
6145 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07006146 }
6147 return true;
6148 }
6149
Jack Palevich1cdef202009-05-22 12:06:27 -07006150 /* Look through the symbol table to find a symbol.
6151 * If found, return its value.
6152 */
6153 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07006154 if (mCompileResult == 0) {
6155 tokenid_t tok = mTokenTable.intern(name, strlen(name));
6156 VariableInfo* pVariableInfo = VI(tok);
6157 if (pVariableInfo) {
6158 return pVariableInfo->pAddress;
6159 }
Jack Palevich1cdef202009-05-22 12:06:27 -07006160 }
6161 return NULL;
6162 }
6163
Jack Palevicheedf9d22009-06-04 16:23:40 -07006164 void getPragmas(ACCsizei* actualStringCount,
6165 ACCsizei maxStringCount, ACCchar** strings) {
6166 int stringCount = mPragmaStringCount;
6167 if (actualStringCount) {
6168 *actualStringCount = stringCount;
6169 }
6170 if (stringCount > maxStringCount) {
6171 stringCount = maxStringCount;
6172 }
6173 if (strings) {
6174 char* pPragmas = mPragmas.getUnwrapped();
6175 while (stringCount-- > 0) {
6176 *strings++ = pPragmas;
6177 pPragmas += strlen(pPragmas) + 1;
6178 }
6179 }
6180 }
6181
Jack Palevichd5315572009-09-09 13:19:34 -07006182 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006183 *base = pCodeBuf->getBase();
6184 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006185 }
6186
Jack Palevichac0e95e2009-05-29 13:53:44 -07006187 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006188 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006189 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006190};
6191
Jack Paleviche7b59062009-05-19 17:12:17 -07006192const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006193 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6194
Jack Paleviche7b59062009-05-19 17:12:17 -07006195const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006196 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6197 5, 5, /* ==, != */
6198 9, 10, /* &&, || */
6199 6, 7, 8, /* & ^ | */
6200 2, 2 /* ~ ! */
6201 };
6202
Jack Palevich8b0624c2009-05-20 12:12:06 -07006203#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006204const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006205 0x1, // ++
6206 0xff, // --
6207 0xc1af0f, // *
6208 0xf9f79991, // /
6209 0xf9f79991, // % (With manual assist to swap results)
6210 0xc801, // +
6211 0xd8f7c829, // -
6212 0xe0d391, // <<
6213 0xf8d391, // >>
6214 0xe, // <=
6215 0xd, // >=
6216 0xc, // <
6217 0xf, // >
6218 0x4, // ==
6219 0x5, // !=
6220 0x0, // &&
6221 0x1, // ||
6222 0xc821, // &
6223 0xc831, // ^
6224 0xc809, // |
6225 0xd0f7, // ~
6226 0x4 // !
6227};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006228#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006229
Jack Palevich1cdef202009-05-22 12:06:27 -07006230struct ACCscript {
6231 ACCscript() {
6232 text = 0;
6233 textLength = 0;
6234 accError = ACC_NO_ERROR;
6235 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006236
Jack Palevich1cdef202009-05-22 12:06:27 -07006237 ~ACCscript() {
6238 delete text;
6239 }
Jack Palevich546b2242009-05-13 15:10:04 -07006240
Jack Palevich8c246a92009-07-14 21:14:10 -07006241 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6242 compiler.registerSymbolCallback(pFn, pContext);
6243 }
6244
Jack Palevich1cdef202009-05-22 12:06:27 -07006245 void setError(ACCenum error) {
6246 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6247 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006248 }
6249 }
6250
Jack Palevich1cdef202009-05-22 12:06:27 -07006251 ACCenum getError() {
6252 ACCenum result = accError;
6253 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006254 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006255 }
6256
Jack Palevich1cdef202009-05-22 12:06:27 -07006257 Compiler compiler;
6258 char* text;
6259 int textLength;
6260 ACCenum accError;
6261};
6262
6263
6264extern "C"
6265ACCscript* accCreateScript() {
6266 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006267}
Jack Palevich1cdef202009-05-22 12:06:27 -07006268
6269extern "C"
6270ACCenum accGetError( ACCscript* script ) {
6271 return script->getError();
6272}
6273
6274extern "C"
6275void accDeleteScript(ACCscript* script) {
6276 delete script;
6277}
6278
6279extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006280void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6281 ACCvoid* pContext) {
6282 script->registerSymbolCallback(pFn, pContext);
6283}
6284
6285extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006286void accScriptSource(ACCscript* script,
6287 ACCsizei count,
6288 const ACCchar ** string,
6289 const ACCint * length) {
6290 int totalLength = 0;
6291 for(int i = 0; i < count; i++) {
6292 int len = -1;
6293 const ACCchar* s = string[i];
6294 if (length) {
6295 len = length[i];
6296 }
6297 if (len < 0) {
6298 len = strlen(s);
6299 }
6300 totalLength += len;
6301 }
6302 delete script->text;
6303 char* text = new char[totalLength + 1];
6304 script->text = text;
6305 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006306 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006307 for(int i = 0; i < count; i++) {
6308 int len = -1;
6309 const ACCchar* s = string[i];
6310 if (length) {
6311 len = length[i];
6312 }
6313 if (len < 0) {
6314 len = strlen(s);
6315 }
Jack Palevich09555c72009-05-27 12:25:55 -07006316 memcpy(dest, s, len);
6317 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006318 }
6319 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006320
6321#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006322 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006323 int counter;
6324 char path[PATH_MAX];
6325 for (counter = 0; counter < 4096; counter++) {
6326 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6327 if(access(path, F_OK) != 0) {
6328 break;
6329 }
6330 }
6331 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006332 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006333 FILE* fd = fopen(path, "w");
6334 if (fd) {
6335 fwrite(text, totalLength, 1, fd);
6336 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006337 LOGD("Saved input to file %s", path);
6338 } else {
6339 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006340 }
6341 }
6342#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006343}
6344
6345extern "C"
6346void accCompileScript(ACCscript* script) {
6347 int result = script->compiler.compile(script->text, script->textLength);
6348 if (result) {
6349 script->setError(ACC_INVALID_OPERATION);
6350 }
6351}
6352
6353extern "C"
6354void accGetScriptiv(ACCscript* script,
6355 ACCenum pname,
6356 ACCint * params) {
6357 switch (pname) {
6358 case ACC_INFO_LOG_LENGTH:
6359 *params = 0;
6360 break;
6361 }
6362}
6363
6364extern "C"
6365void accGetScriptInfoLog(ACCscript* script,
6366 ACCsizei maxLength,
6367 ACCsizei * length,
6368 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006369 char* message = script->compiler.getErrorMessage();
6370 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006371 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006372 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006373 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006374 if (infoLog && maxLength > 0) {
6375 int trimmedLength = maxLength < messageLength ?
6376 maxLength : messageLength;
6377 memcpy(infoLog, message, trimmedLength);
6378 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006379 }
6380}
6381
6382extern "C"
6383void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6384 ACCvoid ** address) {
6385 void* value = script->compiler.lookup(name);
6386 if (value) {
6387 *address = value;
6388 } else {
6389 script->setError(ACC_INVALID_VALUE);
6390 }
6391}
6392
Jack Palevicheedf9d22009-06-04 16:23:40 -07006393extern "C"
6394void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6395 ACCsizei maxStringCount, ACCchar** strings){
6396 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6397}
6398
-b master422972c2009-06-17 19:13:52 -07006399extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006400void accGetProgramBinary(ACCscript* script,
6401 ACCvoid** base, ACCsizei* length) {
6402 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006403}
6404
Jack Palevicheedf9d22009-06-04 16:23:40 -07006405
Jack Palevich1cdef202009-05-22 12:06:27 -07006406} // namespace acc
6407