blob: d9cecdd6c6efa0d463c38665ba7497cdcf707577 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070016#include <limits.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070017#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070018#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070020#include <stdlib.h>
21#include <string.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070022#include <unistd.h>
23
Jack Palevich2d11dfb2009-06-08 14:34:26 -070024#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070025
Jack Palevich8dc662e2009-06-09 22:53:47 +000026#if defined(__i386__)
27#include <sys/mman.h>
28#endif
29
Jack Palevich546b2242009-05-13 15:10:04 -070030
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Palevich30321cb2009-08-20 15:34:23 -070042#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
43#define ARM_USE_VFP
44#endif
45
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050
-b master422972c2009-06-17 19:13:52 -070051#define LOG_STACK(...) do {} while(0)
52// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
53
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichd30a2ce2009-09-09 19:08:54 -070056// Uncomment to disable ARM peephole optimizations
57// #define DISABLE_ARM_PEEPHOLE
58
Jack Palevich61de31f2009-09-08 11:06:40 -070059// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
60// #define DEBUG_SAVE_INPUT_TO_FILE
61
Jack Palevich9116bc42009-09-08 11:46:42 -070062#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070063#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070064#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070065#else
66#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
67#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070068#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070069
Jack Palevich7f5b1a22009-08-17 16:54:56 -070070#define assert(b) assertImpl(b, __LINE__)
71
Jack Palevichbbf8ab52009-05-11 11:54:30 -070072namespace acc {
73
Jack Palevich8df46192009-07-07 14:48:51 -070074// Subset of STL vector.
75template<class E> class Vector {
76 public:
77 Vector() {
78 mpBase = 0;
79 mUsed = 0;
80 mSize = 0;
81 }
82
83 ~Vector() {
84 if (mpBase) {
85 for(size_t i = 0; i < mUsed; i++) {
86 mpBase[mUsed].~E();
87 }
88 free(mpBase);
89 }
90 }
91
92 inline E& operator[](size_t i) {
93 return mpBase[i];
94 }
95
96 inline E& front() {
97 return mpBase[0];
98 }
99
100 inline E& back() {
101 return mpBase[mUsed - 1];
102 }
103
104 void pop_back() {
105 mUsed -= 1;
106 mpBase[mUsed].~E();
107 }
108
109 void push_back(const E& item) {
110 * ensure(1) = item;
111 }
112
113 size_t size() {
114 return mUsed;
115 }
116
117private:
118 E* ensure(int n) {
119 size_t newUsed = mUsed + n;
120 if (newUsed > mSize) {
121 size_t newSize = mSize * 2 + 10;
122 if (newSize < newUsed) {
123 newSize = newUsed;
124 }
125 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
126 mSize = newSize;
127 }
128 E* result = mpBase + mUsed;
129 mUsed = newUsed;
130 return result;
131 }
132
133 E* mpBase;
134 size_t mUsed;
135 size_t mSize;
136};
137
Jack Palevichac0e95e2009-05-29 13:53:44 -0700138class ErrorSink {
139public:
140 void error(const char *fmt, ...) {
141 va_list ap;
142 va_start(ap, fmt);
143 verror(fmt, ap);
144 va_end(ap);
145 }
146
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700147 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700148 virtual void verror(const char* fmt, va_list ap) = 0;
149};
150
151class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700152 typedef int tokenid_t;
153 enum TypeTag {
Jack Palevichee1f8292009-10-28 16:10:17 -0700154 TY_UNKNOWN = -1,
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700155 TY_INT, // 0
156 TY_CHAR, // 1
157 TY_SHORT, // 2
158 TY_VOID, // 3
159 TY_FLOAT, // 4
160 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700161 TY_POINTER, // 6
162 TY_ARRAY, // 7
163 TY_STRUCT, // 8
164 TY_FUNC, // 9
165 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700166 };
167
Jack Palevichee1f8292009-10-28 16:10:17 -0700168 enum StorageClass {
169 SC_DEFAULT, // 0
170 SC_AUTO, // 1
171 SC_REGISTER, // 2
172 SC_STATIC, // 3
173 SC_EXTERN, // 4
174 SC_TYPEDEF // 5
175 };
176
Jack Palevich8df46192009-07-07 14:48:51 -0700177 struct Type {
178 TypeTag tag;
Jack Palevichee1f8292009-10-28 16:10:17 -0700179 StorageClass storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700180 tokenid_t id; // For function arguments, global vars, local vars, struct elements
181 tokenid_t structTag; // For structs the name of the struct
182 int length; // length of array, offset of struct element. -1 means struct is forward defined
183 int alignment; // for structs only
184 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700185 Type* pTail;
186 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700187
Jack Palevichba929a42009-07-17 10:20:32 -0700188 enum ExpressionType {
189 ET_RVALUE,
190 ET_LVALUE
191 };
192
193 struct ExpressionValue {
194 ExpressionValue() {
195 et = ET_RVALUE;
196 pType = NULL;
197 }
198 ExpressionType et;
199 Type* pType;
200 };
201
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700202 class ICodeBuf {
203 public:
204 virtual ~ICodeBuf() {}
205 virtual void init(int size) = 0;
206 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
207 virtual void o4(int n) = 0;
208 virtual void ob(int n) = 0;
209 virtual void* getBase() = 0;
210 virtual intptr_t getSize() = 0;
211 virtual intptr_t getPC() = 0;
212 // Call this before trying to modify code in the buffer.
213 virtual void flush() = 0;
214 };
215
216 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700217 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700219 ErrorSink* mErrorSink;
220 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700221 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700222
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 void release() {
224 if (pProgramBase != 0) {
225 free(pProgramBase);
226 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700227 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 }
229
Jack Palevich0a280a02009-06-11 10:53:51 -0700230 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700231 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700232 bool overflow = newSize > mSize;
233 if (overflow && !mOverflowed) {
234 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700235 if (mErrorSink) {
236 mErrorSink->error("Code too large: %d bytes", newSize);
237 }
238 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700239 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700240 }
241
Jack Palevich21a15a22009-05-11 14:49:29 -0700242 public:
243 CodeBuf() {
244 pProgramBase = 0;
245 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700246 mErrorSink = 0;
247 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700248 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700249 }
250
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700251 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700252 release();
253 }
254
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700255 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700256 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700257 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700258 pProgramBase = (char*) calloc(1, size);
259 ind = pProgramBase;
260 }
261
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700262 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700263 mErrorSink = pErrorSink;
264 }
265
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700266 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700267 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700268 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700269 }
Jack Palevich546b2242009-05-13 15:10:04 -0700270 * (int*) ind = n;
271 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700272 }
273
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 /*
275 * Output a byte. Handles all values, 0..ff.
276 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700277 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700278 if(check(1)) {
279 return;
280 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700281 *ind++ = n;
282 }
283
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700284 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700285 return (void*) pProgramBase;
286 }
287
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700288 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700289 return ind - pProgramBase;
290 }
291
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700292 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700293 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700294 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700295
296 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700297 };
298
Jack Palevich1cdef202009-05-22 12:06:27 -0700299 /**
300 * A code generator creates an in-memory program, generating the code on
301 * the fly. There is one code generator implementation for each supported
302 * architecture.
303 *
304 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700305 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 * FP - a frame pointer for accessing function arguments and local
307 * variables.
308 * SP - a stack pointer for storing intermediate results while evaluating
309 * expressions. The stack pointer grows downwards.
310 *
311 * The function calling convention is that all arguments are placed on the
312 * stack such that the first argument has the lowest address.
313 * After the call, the result is in R0. The caller is responsible for
314 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700315 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 * FP and SP registers are saved.
317 */
318
Jack Palevich21a15a22009-05-11 14:49:29 -0700319 class CodeGenerator {
320 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700321 CodeGenerator() {
322 mErrorSink = 0;
323 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700324 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700325 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700326 virtual ~CodeGenerator() {}
327
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700328 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700329 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700330 pCodeBuf->setErrorSink(mErrorSink);
331 }
332
Jack Palevichb67b18f2009-06-11 21:12:23 -0700333 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700334 mErrorSink = pErrorSink;
335 if (pCodeBuf) {
336 pCodeBuf->setErrorSink(mErrorSink);
337 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700338 }
339
Jack Palevich58c30ee2009-07-17 16:35:23 -0700340 /* Give the code generator some utility types so it can
341 * use its own types as needed for the results of some
342 * operations like gcmp.
343 */
344
Jack Palevicha8f427f2009-07-13 18:40:08 -0700345 void setTypes(Type* pInt) {
346 mkpInt = pInt;
347 }
348
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700350 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700351 * Save the old value of the FP.
352 * Set the new value of the FP.
353 * Convert from the native platform calling convention to
354 * our stack-based calling convention. This may require
355 * pushing arguments from registers to the stack.
356 * Allocate "N" bytes of stack space. N isn't known yet, so
357 * just emit the instructions for adjusting the stack, and return
358 * the address to patch up. The patching will be done in
359 * functionExit().
360 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700361 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700362 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700363
Jack Palevich1cdef202009-05-22 12:06:27 -0700364 /* Emit a function epilog.
365 * Restore the old SP and FP register values.
366 * Return to the calling function.
367 * argCount - the number of arguments to the function.
368 * localVariableAddress - returned from functionEntry()
369 * localVariableSize - the size in bytes of the local variables.
370 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700371 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700373
Jack Palevich1cdef202009-05-22 12:06:27 -0700374 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700375 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700376
Jack Palevich1a539db2009-07-08 13:04:41 -0700377 /* Load floating point value from global address. */
378 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700379
Jack Palevich9221bcc2009-08-26 16:15:07 -0700380 /* Add the struct offset in bytes to R0, change the type to pType */
381 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
382
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 /* Jump to a target, and return the address of the word that
384 * holds the target data, in case it needs to be fixed up later.
385 */
Jack Palevich22305132009-05-13 10:58:45 -0700386 virtual int gjmp(int t) = 0;
387
Jack Palevich1cdef202009-05-22 12:06:27 -0700388 /* Test R0 and jump to a target if the test succeeds.
389 * l = 0: je, l == 1: jne
390 * Return the address of the word that holds the targed data, in
391 * case it needs to be fixed up later.
392 */
Jack Palevich22305132009-05-13 10:58:45 -0700393 virtual int gtst(bool l, int t) = 0;
394
Jack Palevich9eed7a22009-07-06 17:24:34 -0700395 /* Compare TOS against R0, and store the boolean result in R0.
396 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700397 * op specifies the comparison.
398 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700399 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700400
Jack Palevich9eed7a22009-07-06 17:24:34 -0700401 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700402 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700403 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700404 */
Jack Palevich546b2242009-05-13 15:10:04 -0700405 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700406
Jack Palevich9eed7a22009-07-06 17:24:34 -0700407 /* Compare 0 against R0, and store the boolean result in R0.
408 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700409 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700410 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700411
412 /* Perform the arithmetic op specified by op. 0 is the
413 * left argument, R0 is the right argument.
414 */
415 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700416
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700417 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700418 */
419 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700420
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700421 /* Turn R0, TOS into R0 TOS R0 */
422
423 virtual void over() = 0;
424
425 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700426 */
427 virtual void popR0() = 0;
428
Jack Palevich9eed7a22009-07-06 17:24:34 -0700429 /* Store R0 to the address stored in TOS.
430 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700431 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700432 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700433
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700435 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700436 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700437
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 /* Load the absolute address of a variable to R0.
439 * If ea <= LOCAL, then this is a local variable, or an
440 * argument, addressed relative to FP.
441 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700442 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700443 * et is ET_RVALUE for things like string constants, ET_LVALUE for
444 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700445 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700446 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700447
Jack Palevich9f51a262009-07-29 16:22:26 -0700448 /* Load the pc-relative address of a forward-referenced variable to R0.
449 * Return the address of the 4-byte constant so that it can be filled
450 * in later.
451 */
452 virtual int leaForward(int ea, Type* pPointerType) = 0;
453
Jack Palevich8df46192009-07-07 14:48:51 -0700454 /**
455 * Convert R0 to the given type.
456 */
Jack Palevichb6154502009-08-04 14:56:09 -0700457
458 void convertR0(Type* pType) {
459 convertR0Imp(pType, false);
460 }
461
462 void castR0(Type* pType) {
463 convertR0Imp(pType, true);
464 }
465
466 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700467
Jack Palevich1cdef202009-05-22 12:06:27 -0700468 /* Emit code to adjust the stack for a function call. Return the
469 * label for the address of the instruction that adjusts the
470 * stack size. This will be passed as argument "a" to
471 * endFunctionCallArguments.
472 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700473 virtual int beginFunctionCallArguments() = 0;
474
Jack Palevich1cdef202009-05-22 12:06:27 -0700475 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700476 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700477 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700478 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700479
Jack Palevich1cdef202009-05-22 12:06:27 -0700480 /* Patch the function call preamble.
481 * a is the address returned from beginFunctionCallArguments
482 * l is the number of bytes the arguments took on the stack.
483 * Typically you would also emit code to convert the argument
484 * list into whatever the native function calling convention is.
485 * On ARM for example you would pop the first 5 arguments into
486 * R0..R4
487 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700488 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700489
Jack Palevich1cdef202009-05-22 12:06:27 -0700490 /* Emit a call to an unknown function. The argument "symbol" needs to
491 * be stored in the location where the address should go. It forms
492 * a chain. The address will be patched later.
493 * Return the address of the word that has to be patched.
494 */
Jack Palevich8df46192009-07-07 14:48:51 -0700495 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700496
Jack Palevich1cdef202009-05-22 12:06:27 -0700497 /* Call a function pointer. L is the number of bytes the arguments
498 * take on the stack. The address of the function is stored at
499 * location SP + l.
500 */
Jack Palevich8df46192009-07-07 14:48:51 -0700501 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700502
Jack Palevich1cdef202009-05-22 12:06:27 -0700503 /* Adjust SP after returning from a function call. l is the
504 * number of bytes of arguments stored on the stack. isIndirect
505 * is true if this was an indirect call. (In which case the
506 * address of the function is stored at location SP + l.)
507 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700508 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700509
Jack Palevich1cdef202009-05-22 12:06:27 -0700510 /* Generate a symbol at the current PC. t is the head of a
511 * linked list of addresses to patch.
512 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700513 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700514
Jack Palevich9f51a262009-07-29 16:22:26 -0700515 /* Resolve a forward reference function at the current PC.
516 * t is the head of a
517 * linked list of addresses to patch.
518 * (Like gsym, but using absolute address, not PC relative address.)
519 */
520 virtual void resolveForward(int t) = 0;
521
Jack Palevich1cdef202009-05-22 12:06:27 -0700522 /*
523 * Do any cleanup work required at the end of a compile.
524 * For example, an instruction cache might need to be
525 * invalidated.
526 * Return non-zero if there is an error.
527 */
528 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700529
Jack Palevicha6535612009-05-13 16:24:17 -0700530 /**
531 * Adjust relative branches by this amount.
532 */
533 virtual int jumpOffset() = 0;
534
Jack Palevich9eed7a22009-07-06 17:24:34 -0700535 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700536 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700537 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700538 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700539
540 /**
541 * Array element alignment (in bytes) for this type of data.
542 */
543 virtual size_t sizeOf(Type* type) = 0;
544
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700545 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700546 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700547 }
548
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700549 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700550 return mExpressionStack.back().et;
551 }
552
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700553 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700554 mExpressionStack.back().et = et;
555 }
556
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700557 virtual size_t getExpressionStackDepth() {
558 return mExpressionStack.size();
559 }
560
Jack Palevichb5e33312009-07-30 19:06:34 -0700561 virtual void forceR0RVal() {
562 if (getR0ExpressionType() == ET_LVALUE) {
563 loadR0FromR0();
564 }
565 }
566
Jack Palevich21a15a22009-05-11 14:49:29 -0700567 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700568 /*
569 * Output a byte. Handles all values, 0..ff.
570 */
571 void ob(int n) {
572 pCodeBuf->ob(n);
573 }
574
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700575 void o4(int data) {
576 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700577 }
578
Jack Palevich8b0624c2009-05-20 12:12:06 -0700579 intptr_t getBase() {
580 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700581 }
582
Jack Palevich8b0624c2009-05-20 12:12:06 -0700583 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700584 return pCodeBuf->getPC();
585 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700586
587 intptr_t getSize() {
588 return pCodeBuf->getSize();
589 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700590
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700591 void flush() {
592 pCodeBuf->flush();
593 }
594
Jack Palevichac0e95e2009-05-29 13:53:44 -0700595 void error(const char* fmt,...) {
596 va_list ap;
597 va_start(ap, fmt);
598 mErrorSink->verror(fmt, ap);
599 va_end(ap);
600 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700601
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700602 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700603 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700604 error("code generator assertion failed at line %s:%d.", __FILE__, line);
605 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700606 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700607 }
608 }
Jack Palevich8df46192009-07-07 14:48:51 -0700609
610 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700611 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700612 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700613 mExpressionStack.back().et = ET_RVALUE;
614 }
615
616 void setR0Type(Type* pType, ExpressionType et) {
617 assert(pType != NULL);
618 mExpressionStack.back().pType = pType;
619 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700620 }
621
Jack Palevich8df46192009-07-07 14:48:51 -0700622 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700623 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700624 }
625
626 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700627 if (mExpressionStack.size()) {
628 mExpressionStack.push_back(mExpressionStack.back());
629 } else {
630 mExpressionStack.push_back(ExpressionValue());
631 }
632
Jack Palevich8df46192009-07-07 14:48:51 -0700633 }
634
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700635 void overType() {
636 size_t size = mExpressionStack.size();
637 if (size >= 2) {
638 mExpressionStack.push_back(mExpressionStack.back());
639 mExpressionStack[size-1] = mExpressionStack[size-2];
640 mExpressionStack[size-2] = mExpressionStack[size];
641 }
642 }
643
Jack Palevich8df46192009-07-07 14:48:51 -0700644 void popType() {
645 mExpressionStack.pop_back();
646 }
647
648 bool bitsSame(Type* pA, Type* pB) {
649 return collapseType(pA->tag) == collapseType(pB->tag);
650 }
651
652 TypeTag collapseType(TypeTag tag) {
653 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700654 TY_INT,
655 TY_INT,
656 TY_INT,
657 TY_VOID,
658 TY_FLOAT,
659 TY_DOUBLE,
660 TY_INT,
661 TY_INT,
662 TY_VOID,
663 TY_VOID,
664 TY_VOID
665 };
Jack Palevich8df46192009-07-07 14:48:51 -0700666 return collapsedTag[tag];
667 }
668
Jack Palevich1a539db2009-07-08 13:04:41 -0700669 TypeTag collapseTypeR0() {
670 return collapseType(getR0Type()->tag);
671 }
672
Jack Palevichb6154502009-08-04 14:56:09 -0700673 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700674 return isFloatTag(pType->tag);
675 }
676
Jack Palevichb6154502009-08-04 14:56:09 -0700677 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700678 return tag == TY_FLOAT || tag == TY_DOUBLE;
679 }
680
Jack Palevichb6154502009-08-04 14:56:09 -0700681 static bool isPointerType(Type* pType) {
682 return isPointerTag(pType->tag);
683 }
684
685 static bool isPointerTag(TypeTag tag) {
686 return tag == TY_POINTER || tag == TY_ARRAY;
687 }
688
689 Type* getPointerArithmeticResultType(Type* a, Type* b) {
690 TypeTag aTag = a->tag;
691 TypeTag bTag = b->tag;
692 if (aTag == TY_POINTER) {
693 return a;
694 }
695 if (bTag == TY_POINTER) {
696 return b;
697 }
698 if (aTag == TY_ARRAY) {
699 return a->pTail;
700 }
701 if (bTag == TY_ARRAY) {
702 return b->pTail;
703 }
704 return NULL;
705 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700706 Type* mkpInt;
707
Jack Palevich21a15a22009-05-11 14:49:29 -0700708 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700709 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700710 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700711 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700712 };
713
Jack Paleviche7b59062009-05-19 17:12:17 -0700714#ifdef PROVIDE_ARM_CODEGEN
715
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700716 static size_t rotateRight(size_t n, size_t rotate) {
717 return (n >> rotate) | (n << (32 - rotate));
718 }
719
720 static size_t rotateLeft(size_t n, size_t rotate) {
721 return (n << rotate) | (n >> (32 - rotate));
722 }
723
724 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
725 for(size_t i = 0; i < 16; i++) {
726 size_t rotate = i * 2;
727 size_t mask = rotateRight(0xff, rotate);
728 if ((immediate | mask) == mask) {
729 size_t bits8 = rotateLeft(immediate, rotate);
730 // assert(bits8 <= 0xff);
731 *pResult = (i << 8) | bits8;
732 return true;
733 }
734 }
735 return false;
736 }
737
738 static size_t decode12BitImmediate(size_t immediate) {
739 size_t data = immediate & 0xff;
740 size_t rotate = 2 * ((immediate >> 8) & 0xf);
741 return rotateRight(data, rotate);
742 }
743
Jack Palevich53f06582009-09-10 14:01:58 -0700744 static bool isPowerOfTwo(size_t n) {
745 return (n != 0) & ((n & (n-1)) == 0);
746 }
747
748 static size_t log2(size_t n) {
749 int result = 0;
750 while (n >>= 1) {
751 result++;
752 }
753 return result;
754 }
755
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700756 class ARMCodeBuf : public ICodeBuf {
757 ICodeBuf* mpBase;
758 ErrorSink* mErrorSink;
759
760 class CircularQueue {
761 static const int SIZE = 16; // Must be power of 2
762 static const int MASK = SIZE-1;
763 unsigned int mBuf[SIZE];
764 int mHead;
765 int mCount;
766
767 public:
768 CircularQueue() {
769 mHead = 0;
770 mCount = 0;
771 }
772
773 void pushBack(unsigned int data) {
774 mBuf[(mHead + mCount) & MASK] = data;
775 mCount += 1;
776 }
777
778 unsigned int popFront() {
779 unsigned int result = mBuf[mHead];
780 mHead = (mHead + 1) & MASK;
781 mCount -= 1;
782 return result;
783 }
784
785 void popBack(int n) {
786 mCount -= n;
787 }
788
789 inline int count() {
790 return mCount;
791 }
792
793 bool empty() {
794 return mCount == 0;
795 }
796
797 bool full() {
798 return mCount == SIZE;
799 }
800
801 // The valid indexes are 1 - count() to 0
802 unsigned int operator[](int i) {
803 return mBuf[(mHead + mCount + i) & MASK];
804 }
805 };
806
807 CircularQueue mQ;
808
809 void error(const char* fmt,...) {
810 va_list ap;
811 va_start(ap, fmt);
812 mErrorSink->verror(fmt, ap);
813 va_end(ap);
814 }
815
816 void flush() {
817 while (!mQ.empty()) {
818 mpBase->o4(mQ.popFront());
819 }
820 mpBase->flush();
821 }
822
823 public:
824 ARMCodeBuf(ICodeBuf* pBase) {
825 mpBase = pBase;
826 }
827
828 virtual ~ARMCodeBuf() {
829 delete mpBase;
830 }
831
832 void init(int size) {
833 mpBase->init(size);
834 }
835
836 void setErrorSink(ErrorSink* pErrorSink) {
837 mErrorSink = pErrorSink;
838 mpBase->setErrorSink(pErrorSink);
839 }
840
841 void o4(int n) {
842 if (mQ.full()) {
843 mpBase->o4(mQ.popFront());
844 }
845 mQ.pushBack(n);
846
847#ifndef DISABLE_ARM_PEEPHOLE
848 // Peephole check
849 bool didPeep;
850 do {
Jack Palevich53f06582009-09-10 14:01:58 -0700851 static const unsigned int opMask = 0x01e00000;
852 static const unsigned int immediateMask = 0x00000fff;
853 static const unsigned int BMask = 0x00400000;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700854 didPeep = false;
855 if (mQ.count() >= 4) {
856
857 // Operand by a small constant
858 // push;mov #imm;pop;op ==> op #imm
859
Jack Palevich1c60e462009-09-18 15:03:03 -0700860 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
861 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
862 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
863 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700864 unsigned int movConst = mQ[-3];
865 unsigned int op = mQ[-1];
866 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
867 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
868 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
869 mQ.popBack(4);
870 mQ.pushBack(combined);
871 didPeep = true;
872 } else {
873 mQ.popBack(4);
874 didPeep = true;
875 }
876 }
877 }
878
879 // Load local variable
Jack Palevich53f06582009-09-10 14:01:58 -0700880 // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm]
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700881 if (mQ.count() >= 2) {
Jack Palevich53f06582009-09-10 14:01:58 -0700882 if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
883 const unsigned int encodedImmediate = mQ[-2] & immediateMask;
884 const unsigned int ld = mQ[-1];
885 if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
886 unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
887 mQ.popBack(2);
888 mQ.pushBack(combined);
889 didPeep = true;
Jack Palevich1c60e462009-09-18 15:03:03 -0700890 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
Jack Palevich53f06582009-09-10 14:01:58 -0700891 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
892 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700893 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
Jack Palevich53f06582009-09-10 14:01:58 -0700894 mQ.popBack(2);
895 mQ.pushBack(combined);
896 didPeep = true;
897 }
898 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700899 }
900 }
901
902 // Constant array lookup
903
904 if (mQ.count() >= 6 &&
905 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
906 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
907 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
908 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
909 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
910 mQ[-1] == 0xe0810000) { // add r0, r1, r0
911 unsigned int mov1 = mQ[-5];
912 unsigned int mov2 = mQ[-3];
913 unsigned int const1 = decode12BitImmediate(mov1);
914 unsigned int const2 = decode12BitImmediate(mov2);
915 unsigned int comboConst = const1 * const2;
916 size_t immediate = 0;
917 if (encode12BitImmediate(comboConst, &immediate)) {
918 mQ.popBack(6);
919 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
920 if (comboConst) {
921 mQ.pushBack(add);
922 }
923 didPeep = true;
924 }
925 }
926
Jack Palevich53f06582009-09-10 14:01:58 -0700927 // Pointer arithmetic with a stride that is a power of two
928
929 if (mQ.count() >= 3 &&
Jack Palevich1c60e462009-09-18 15:03:03 -0700930 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
931 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
Jack Palevich53f06582009-09-10 14:01:58 -0700932 mQ[-1] == 0xe0810000) { // add r0, r1, r0
933 int stride = decode12BitImmediate(mQ[-3]);
934 if (isPowerOfTwo(stride)) {
935 mQ.popBack(3);
936 unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
937 mQ.pushBack(add);
938 didPeep = true;
939 }
940 }
941
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700942 } while (didPeep);
943#endif
944 }
945
946 void ob(int n) {
947 error("ob() not supported.");
948 }
949
950 void* getBase() {
951 flush();
952 return mpBase->getBase();
953 }
954
955 intptr_t getSize() {
956 flush();
957 return mpBase->getSize();
958 }
959
960 intptr_t getPC() {
961 flush();
962 return mpBase->getPC();
963 }
964 };
965
Jack Palevich22305132009-05-13 10:58:45 -0700966 class ARMCodeGenerator : public CodeGenerator {
967 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700968 ARMCodeGenerator() {
969#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700970 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700971#else
Jack Palevichd5315572009-09-09 13:19:34 -0700972 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700973#endif
974 }
-b master422972c2009-06-17 19:13:52 -0700975
Jack Palevich22305132009-05-13 10:58:45 -0700976 virtual ~ARMCodeGenerator() {}
977
978 /* returns address to patch with local variable size
979 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700980 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700981 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700982 // sp -> arg4 arg5 ...
983 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700984 int regArgCount = calcRegArgCount(pDecl);
985 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700986 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700987 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700988 }
989 // sp -> arg0 arg1 ...
990 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700991 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700992 // sp, fp -> oldfp, retadr, arg0 arg1 ....
993 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700994 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700995 int pc = getPC();
996 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700997 // We don't know how many local variables we are going to use,
998 // but we will round the allocation up to a multiple of
999 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001000 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001001 }
1002
Jack Palevichb7718b92009-07-09 22:00:24 -07001003 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -07001004 // Round local variable size up to a multiple of stack alignment
1005 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
1006 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -07001007 // Patch local variable allocation code:
1008 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -07001009 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -07001010 }
Jack Palevich69796b62009-05-14 15:42:26 -07001011 *(char*) (localVariableAddress) = localVariableSize;
1012
Jack Palevich30321cb2009-08-20 15:34:23 -07001013#ifdef ARM_USE_VFP
1014 {
Jack Palevichc0f25332009-08-25 12:23:43 -07001015 Type* pReturnType = pDecl->pHead;
1016 switch(pReturnType->tag) {
1017 case TY_FLOAT:
1018 o4(0xEE170A90); // fmrs r0, s15
1019 break;
1020 case TY_DOUBLE:
1021 o4(0xEC510B17); // fmrrd r0, r1, d7
1022 break;
1023 default:
1024 break;
1025 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001026 }
1027#endif
1028
Jack Palevich69796b62009-05-14 15:42:26 -07001029 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
1030 o4(0xE1A0E00B); // mov lr, fp
1031 o4(0xE59BB000); // ldr fp, [fp]
1032 o4(0xE28ED004); // add sp, lr, #4
1033 // sp -> retadr, arg0, ...
1034 o4(0xE8BD4000); // ldmfd sp!, {lr}
1035 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -07001036
1037 // We store the PC into the lr so we can adjust the sp before
1038 // returning. We need to pull off the registers we pushed
1039 // earlier. We don't need to actually store them anywhere,
1040 // just adjust the stack.
1041 int regArgCount = calcRegArgCount(pDecl);
1042 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -07001043 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
1044 }
1045 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -07001046 }
1047
1048 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001049 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001050 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001051 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001052 }
1053
Jack Palevich1a539db2009-07-08 13:04:41 -07001054 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001055 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001056 // Global, absolute address
1057 o4(0xE59F0000); // ldr r0, .L1
1058 o4(0xEA000000); // b .L99
1059 o4(address); // .L1: .word ea
1060 // .L99:
1061
1062 switch (pType->tag) {
1063 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001064#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001065 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001066#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001067 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001068#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001069 break;
1070 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001071#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001072 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001073#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001074 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001075#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001076 break;
1077 default:
1078 assert(false);
1079 break;
1080 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001081 }
1082
Jack Palevich9221bcc2009-08-26 16:15:07 -07001083
1084 virtual void addStructOffsetR0(int offset, Type* pType) {
1085 if (offset) {
1086 size_t immediate = 0;
1087 if (encode12BitImmediate(offset, &immediate)) {
1088 o4(0xE2800000 | immediate); // add r0, r0, #offset
1089 } else {
1090 error("structure offset out of range: %d", offset);
1091 }
1092 }
1093 setR0Type(pType, ET_LVALUE);
1094 }
1095
Jack Palevich22305132009-05-13 10:58:45 -07001096 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001097 int pc = getPC();
1098 o4(0xEA000000 | encodeAddress(t)); // b .L33
1099 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001100 }
1101
1102 /* l = 0: je, l == 1: jne */
1103 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 Type* pR0Type = getR0Type();
1105 TypeTag tagR0 = pR0Type->tag;
1106 switch(tagR0) {
1107 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001108#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001109 o4(0xEEF57A40); // fcmpzs s15
1110 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001111#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001112 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001113 o4(0xE3500000); // cmp r0,#0
1114#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001115 break;
1116 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001117#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001118 o4(0xEEB57B40); // fcmpzd d7
1119 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001120#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001121 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001122 o4(0xE3500000); // cmp r0,#0
1123#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001124 break;
1125 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001126 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001127 break;
1128 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001129 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001130 int pc = getPC();
1131 o4(branch | encodeAddress(t));
1132 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001133 }
1134
Jack Palevich58c30ee2009-07-17 16:35:23 -07001135 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001136 Type* pR0Type = getR0Type();
1137 Type* pTOSType = getTOSType();
1138 TypeTag tagR0 = collapseType(pR0Type->tag);
1139 TypeTag tagTOS = collapseType(pTOSType->tag);
1140 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001141 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001142 o4(0xE1510000); // cmp r1, r1
1143 switch(op) {
1144 case OP_EQUALS:
1145 o4(0x03A00001); // moveq r0,#1
1146 o4(0x13A00000); // movne r0,#0
1147 break;
1148 case OP_NOT_EQUALS:
1149 o4(0x03A00000); // moveq r0,#0
1150 o4(0x13A00001); // movne r0,#1
1151 break;
1152 case OP_LESS_EQUAL:
1153 o4(0xD3A00001); // movle r0,#1
1154 o4(0xC3A00000); // movgt r0,#0
1155 break;
1156 case OP_GREATER:
1157 o4(0xD3A00000); // movle r0,#0
1158 o4(0xC3A00001); // movgt r0,#1
1159 break;
1160 case OP_GREATER_EQUAL:
1161 o4(0xA3A00001); // movge r0,#1
1162 o4(0xB3A00000); // movlt r0,#0
1163 break;
1164 case OP_LESS:
1165 o4(0xA3A00000); // movge r0,#0
1166 o4(0xB3A00001); // movlt r0,#1
1167 break;
1168 default:
1169 error("Unknown comparison op %d", op);
1170 break;
1171 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001172 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1173 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001174#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001175 o4(0xEEB46BC7); // fcmped d6, d7
1176 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001177 switch(op) {
1178 case OP_EQUALS:
1179 o4(0x03A00001); // moveq r0,#1
1180 o4(0x13A00000); // movne r0,#0
1181 break;
1182 case OP_NOT_EQUALS:
1183 o4(0x03A00000); // moveq r0,#0
1184 o4(0x13A00001); // movne r0,#1
1185 break;
1186 case OP_LESS_EQUAL:
1187 o4(0xD3A00001); // movle r0,#1
1188 o4(0xC3A00000); // movgt r0,#0
1189 break;
1190 case OP_GREATER:
1191 o4(0xD3A00000); // movle r0,#0
1192 o4(0xC3A00001); // movgt r0,#1
1193 break;
1194 case OP_GREATER_EQUAL:
1195 o4(0xA3A00001); // movge r0,#1
1196 o4(0xB3A00000); // movlt r0,#0
1197 break;
1198 case OP_LESS:
1199 o4(0xA3A00000); // movge r0,#0
1200 o4(0xB3A00001); // movlt r0,#1
1201 break;
1202 default:
1203 error("Unknown comparison op %d", op);
1204 break;
1205 }
1206#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001207 switch(op) {
1208 case OP_EQUALS:
1209 callRuntime((void*) runtime_cmp_eq_dd);
1210 break;
1211 case OP_NOT_EQUALS:
1212 callRuntime((void*) runtime_cmp_ne_dd);
1213 break;
1214 case OP_LESS_EQUAL:
1215 callRuntime((void*) runtime_cmp_le_dd);
1216 break;
1217 case OP_GREATER:
1218 callRuntime((void*) runtime_cmp_gt_dd);
1219 break;
1220 case OP_GREATER_EQUAL:
1221 callRuntime((void*) runtime_cmp_ge_dd);
1222 break;
1223 case OP_LESS:
1224 callRuntime((void*) runtime_cmp_lt_dd);
1225 break;
1226 default:
1227 error("Unknown comparison op %d", op);
1228 break;
1229 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001230#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001231 } else {
1232 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001233#ifdef ARM_USE_VFP
1234 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001235 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001236 switch(op) {
1237 case OP_EQUALS:
1238 o4(0x03A00001); // moveq r0,#1
1239 o4(0x13A00000); // movne r0,#0
1240 break;
1241 case OP_NOT_EQUALS:
1242 o4(0x03A00000); // moveq r0,#0
1243 o4(0x13A00001); // movne r0,#1
1244 break;
1245 case OP_LESS_EQUAL:
1246 o4(0xD3A00001); // movle r0,#1
1247 o4(0xC3A00000); // movgt r0,#0
1248 break;
1249 case OP_GREATER:
1250 o4(0xD3A00000); // movle r0,#0
1251 o4(0xC3A00001); // movgt r0,#1
1252 break;
1253 case OP_GREATER_EQUAL:
1254 o4(0xA3A00001); // movge r0,#1
1255 o4(0xB3A00000); // movlt r0,#0
1256 break;
1257 case OP_LESS:
1258 o4(0xA3A00000); // movge r0,#0
1259 o4(0xB3A00001); // movlt r0,#1
1260 break;
1261 default:
1262 error("Unknown comparison op %d", op);
1263 break;
1264 }
1265#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001266 switch(op) {
1267 case OP_EQUALS:
1268 callRuntime((void*) runtime_cmp_eq_ff);
1269 break;
1270 case OP_NOT_EQUALS:
1271 callRuntime((void*) runtime_cmp_ne_ff);
1272 break;
1273 case OP_LESS_EQUAL:
1274 callRuntime((void*) runtime_cmp_le_ff);
1275 break;
1276 case OP_GREATER:
1277 callRuntime((void*) runtime_cmp_gt_ff);
1278 break;
1279 case OP_GREATER_EQUAL:
1280 callRuntime((void*) runtime_cmp_ge_ff);
1281 break;
1282 case OP_LESS:
1283 callRuntime((void*) runtime_cmp_lt_ff);
1284 break;
1285 default:
1286 error("Unknown comparison op %d", op);
1287 break;
1288 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001289#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001290 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001291 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001292 }
1293
Jack Palevich546b2242009-05-13 15:10:04 -07001294 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001295 Type* pR0Type = getR0Type();
1296 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001297 TypeTag tagR0 = pR0Type->tag;
1298 TypeTag tagTOS = pTOSType->tag;
1299 bool isFloatR0 = isFloatTag(tagR0);
1300 bool isFloatTOS = isFloatTag(tagTOS);
1301 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001302 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001303 bool isPtrR0 = isPointerTag(tagR0);
1304 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001305 if (isPtrR0 || isPtrTOS) {
1306 if (isPtrR0 && isPtrTOS) {
1307 if (op != OP_MINUS) {
1308 error("Unsupported pointer-pointer operation %d.", op);
1309 }
1310 if (! typeEqual(pR0Type, pTOSType)) {
1311 error("Incompatible pointer types for subtraction.");
1312 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001313 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001314 setR0Type(mkpInt);
1315 int size = sizeOf(pR0Type->pHead);
1316 if (size != 1) {
1317 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001318 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001319 // TODO: Optimize for power-of-two.
1320 genOp(OP_DIV);
1321 }
1322 } else {
1323 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1324 error("Unsupported pointer-scalar operation %d", op);
1325 }
Jack Palevichb6154502009-08-04 14:56:09 -07001326 Type* pPtrType = getPointerArithmeticResultType(
1327 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001328 int size = sizeOf(pPtrType->pHead);
1329 if (size != 1) {
1330 // TODO: Optimize for power-of-two.
1331 liReg(size, 2);
1332 if (isPtrR0) {
1333 o4(0x0E0010192); // mul r1,r2,r1
1334 } else {
1335 o4(0x0E0000092); // mul r0,r2,r0
1336 }
1337 }
1338 switch(op) {
1339 case OP_PLUS:
1340 o4(0xE0810000); // add r0,r1,r0
1341 break;
1342 case OP_MINUS:
1343 o4(0xE0410000); // sub r0,r1,r0
1344 break;
1345 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001346 setR0Type(pPtrType);
1347 }
1348 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001349 switch(op) {
1350 case OP_MUL:
1351 o4(0x0E0000091); // mul r0,r1,r0
1352 break;
1353 case OP_DIV:
1354 callRuntime((void*) runtime_DIV);
1355 break;
1356 case OP_MOD:
1357 callRuntime((void*) runtime_MOD);
1358 break;
1359 case OP_PLUS:
1360 o4(0xE0810000); // add r0,r1,r0
1361 break;
1362 case OP_MINUS:
1363 o4(0xE0410000); // sub r0,r1,r0
1364 break;
1365 case OP_SHIFT_LEFT:
1366 o4(0xE1A00011); // lsl r0,r1,r0
1367 break;
1368 case OP_SHIFT_RIGHT:
1369 o4(0xE1A00051); // asr r0,r1,r0
1370 break;
1371 case OP_BIT_AND:
1372 o4(0xE0010000); // and r0,r1,r0
1373 break;
1374 case OP_BIT_XOR:
1375 o4(0xE0210000); // eor r0,r1,r0
1376 break;
1377 case OP_BIT_OR:
1378 o4(0xE1810000); // orr r0,r1,r0
1379 break;
1380 case OP_BIT_NOT:
1381 o4(0xE1E00000); // mvn r0, r0
1382 break;
1383 default:
1384 error("Unimplemented op %d\n", op);
1385 break;
1386 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001387 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001388 } else {
1389 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1390 if (pResultType->tag == TY_DOUBLE) {
1391 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001392
Jack Palevichb7718b92009-07-09 22:00:24 -07001393 switch(op) {
1394 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001395#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001396 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001397#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001398 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001399#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001400 break;
1401 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001402#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001403 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001404#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001405 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001406#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001407 break;
1408 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001409#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001410 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001411#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001412 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001413#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001414 break;
1415 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001416#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001417 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001418#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001419 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001420#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001421 break;
1422 default:
1423 error("Unsupported binary floating operation %d\n", op);
1424 break;
1425 }
1426 } else {
1427 setupFloatArgs();
1428 switch(op) {
1429 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001430#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001431 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001432#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001433 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001434#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001435 break;
1436 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001437#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001438 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001439#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001440 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001441#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001442 break;
1443 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001444#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001445 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001446#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001447 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001448#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001449 break;
1450 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001451#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001452 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001453#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001454 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001455#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001456 break;
1457 default:
1458 error("Unsupported binary floating operation %d\n", op);
1459 break;
1460 }
1461 }
1462 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001463 }
Jack Palevich22305132009-05-13 10:58:45 -07001464 }
1465
Jack Palevich58c30ee2009-07-17 16:35:23 -07001466 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001467 if (op != OP_LOGICAL_NOT) {
1468 error("Unknown unary cmp %d", op);
1469 } else {
1470 Type* pR0Type = getR0Type();
1471 TypeTag tag = collapseType(pR0Type->tag);
1472 switch(tag) {
1473 case TY_INT:
1474 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001475 o4(0xE1510000); // cmp r1, r0
1476 o4(0x03A00001); // moveq r0,#1
1477 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001478 break;
1479 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001480#ifdef ARM_USE_VFP
1481 o4(0xEEF57A40); // fcmpzs s15
1482 o4(0xEEF1FA10); // fmstat
1483 o4(0x03A00001); // moveq r0,#1
1484 o4(0x13A00000); // movne r0,#0
1485#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001486 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001487#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001488 break;
1489 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001490#ifdef ARM_USE_VFP
1491 o4(0xEEB57B40); // fcmpzd d7
1492 o4(0xEEF1FA10); // fmstat
1493 o4(0x03A00001); // moveq r0,#1
1494 o4(0x13A00000); // movne r0,#0
1495#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001496 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001497#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001498 break;
1499 default:
1500 error("gUnaryCmp unsupported type");
1501 break;
1502 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001503 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001504 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001505 }
1506
1507 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001508 Type* pR0Type = getR0Type();
1509 TypeTag tag = collapseType(pR0Type->tag);
1510 switch(tag) {
1511 case TY_INT:
1512 switch(op) {
1513 case OP_MINUS:
1514 o4(0xE3A01000); // mov r1, #0
1515 o4(0xE0410000); // sub r0,r1,r0
1516 break;
1517 case OP_BIT_NOT:
1518 o4(0xE1E00000); // mvn r0, r0
1519 break;
1520 default:
1521 error("Unknown unary op %d\n", op);
1522 break;
1523 }
1524 break;
1525 case TY_FLOAT:
1526 case TY_DOUBLE:
1527 switch (op) {
1528 case OP_MINUS:
1529 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001530#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001531 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001532#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001533 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001534#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001535 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001536#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001537 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001538#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001539 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001540#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001541 }
1542 break;
1543 case OP_BIT_NOT:
1544 error("Can't apply '~' operator to a float or double.");
1545 break;
1546 default:
1547 error("Unknown unary op %d\n", op);
1548 break;
1549 }
1550 break;
1551 default:
1552 error("genUnaryOp unsupported type");
1553 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001554 }
Jack Palevich22305132009-05-13 10:58:45 -07001555 }
1556
Jack Palevich1cdef202009-05-22 12:06:27 -07001557 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001558 Type* pR0Type = getR0Type();
1559 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001560
1561#ifdef ARM_USE_VFP
1562 switch (r0ct ) {
1563 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001564 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001565 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001566 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001567 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001568 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001569 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001570 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001571 default:
1572 o4(0xE92D0001); // stmfd sp!,{r0}
1573 mStackUse += 4;
1574 }
1575#else
1576
Jack Palevichb7718b92009-07-09 22:00:24 -07001577 if (r0ct != TY_DOUBLE) {
1578 o4(0xE92D0001); // stmfd sp!,{r0}
1579 mStackUse += 4;
1580 } else {
1581 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1582 mStackUse += 8;
1583 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001584#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001585 pushType();
-b master422972c2009-06-17 19:13:52 -07001586 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001587 }
1588
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001589 virtual void over() {
1590 // We know it's only used for int-ptr ops (++/--)
1591
1592 Type* pR0Type = getR0Type();
1593 TypeTag r0ct = collapseType(pR0Type->tag);
1594
1595 Type* pTOSType = getTOSType();
1596 TypeTag tosct = collapseType(pTOSType->tag);
1597
1598 assert (r0ct == TY_INT && tosct == TY_INT);
1599
1600 o4(0xE8BD0002); // ldmfd sp!,{r1}
1601 o4(0xE92D0001); // stmfd sp!,{r0}
1602 o4(0xE92D0002); // stmfd sp!,{r1}
1603 overType();
1604 mStackUse += 4;
1605 }
1606
Jack Palevich58c30ee2009-07-17 16:35:23 -07001607 virtual void popR0() {
1608 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001609 TypeTag tosct = collapseType(pTOSType->tag);
1610#ifdef ARM_USE_VFP
1611 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001612 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001613 }
1614#endif
1615 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001616 case TY_INT:
1617 case TY_FLOAT:
1618 o4(0xE8BD0001); // ldmfd sp!,{r0}
1619 mStackUse -= 4;
1620 break;
1621 case TY_DOUBLE:
1622 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1623 mStackUse -= 8;
1624 break;
1625 default:
1626 error("Can't pop this type.");
1627 break;
1628 }
1629 popType();
1630 LOG_STACK("popR0: %d\n", mStackUse);
1631 }
1632
1633 virtual void storeR0ToTOS() {
1634 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001635 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001636 Type* pDestType = pPointerType->pHead;
1637 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001638 o4(0xE8BD0004); // ldmfd sp!,{r2}
1639 popType();
-b master422972c2009-06-17 19:13:52 -07001640 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001641 switch (pDestType->tag) {
1642 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001643 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001644 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001645 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001646 case TY_FLOAT:
1647#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001648 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001649#else
1650 o4(0xE5820000); // str r0, [r2]
1651#endif
1652 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001653 case TY_SHORT:
1654 o4(0xE1C200B0); // strh r0, [r2]
1655 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001656 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001657 o4(0xE5C20000); // strb r0, [r2]
1658 break;
1659 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001660#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001661 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001662#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001663 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001664#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001665 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001666 case TY_STRUCT:
1667 {
1668 int size = sizeOf(pDestType);
1669 if (size > 0) {
1670 liReg(size, 1);
1671 callRuntime((void*) runtime_structCopy);
1672 }
1673 }
1674 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001675 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001676 error("storeR0ToTOS: unimplemented type %d",
1677 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001678 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001679 }
Jack Palevich22305132009-05-13 10:58:45 -07001680 }
1681
Jack Palevich58c30ee2009-07-17 16:35:23 -07001682 virtual void loadR0FromR0() {
1683 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001684 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001685 Type* pNewType = pPointerType->pHead;
1686 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001687 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001688 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001689 case TY_INT:
1690 o4(0xE5900000); // ldr r0, [r0]
1691 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001692 case TY_FLOAT:
1693#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001694 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001695#else
1696 o4(0xE5900000); // ldr r0, [r0]
1697#endif
1698 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001699 case TY_SHORT:
1700 o4(0xE1D000F0); // ldrsh r0, [r0]
1701 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001702 case TY_CHAR:
1703 o4(0xE5D00000); // ldrb r0, [r0]
1704 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001705 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001706#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001707 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001708#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001709 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001710#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001711 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001712 case TY_ARRAY:
1713 pNewType = pNewType->pTail;
1714 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001715 case TY_STRUCT:
1716 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001717 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001718 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001719 break;
1720 }
Jack Palevich80e49722009-08-04 15:39:49 -07001721 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001722 }
1723
Jack Palevichb5e33312009-07-30 19:06:34 -07001724 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001725 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001726 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001727
1728 size_t immediate = 0;
1729 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001730 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001731 inRange = encode12BitImmediate(-ea, &immediate);
1732 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001733 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001734 inRange = encode12BitImmediate(ea, &immediate);
1735 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1736 }
1737 if (! inRange) {
1738 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001739 }
Jack Palevichbd894902009-05-14 19:35:31 -07001740 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001741 // Global, absolute.
1742 o4(0xE59F0000); // ldr r0, .L1
1743 o4(0xEA000000); // b .L99
1744 o4(ea); // .L1: .word 0
1745 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001746 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001747 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001748 }
1749
Jack Palevich9f51a262009-07-29 16:22:26 -07001750 virtual int leaForward(int ea, Type* pPointerType) {
1751 setR0Type(pPointerType);
1752 int result = ea;
1753 int pc = getPC();
1754 int offset = 0;
1755 if (ea) {
1756 offset = (pc - ea - 8) >> 2;
1757 if ((offset & 0xffff) != offset) {
1758 error("function forward reference out of bounds");
1759 }
1760 } else {
1761 offset = 0;
1762 }
1763 o4(0xE59F0000 | offset); // ldr r0, .L1
1764
1765 if (ea == 0) {
1766 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001767 result = getPC();
1768 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001769 // .L99:
1770 }
1771 return result;
1772 }
1773
Jack Palevichb6154502009-08-04 14:56:09 -07001774 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001775 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001776 if (isPointerType(pType) && isPointerType(pR0Type)) {
1777 Type* pA = pR0Type;
1778 Type* pB = pType;
1779 // Array decays to pointer
1780 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1781 pA = pA->pTail;
1782 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001783 if (! (typeEqual(pA, pB)
1784 || pB->pHead->tag == TY_VOID
1785 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1786 )) {
1787 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001788 }
Jack Palevichb6154502009-08-04 14:56:09 -07001789 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001790 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001791 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001792 TypeTag r0Tag = collapseType(pR0Type->tag);
1793 TypeTag destTag = collapseType(pType->tag);
1794 if (r0Tag == TY_INT) {
1795 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001796#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001797 o4(0xEE070A90); // fmsr s15, r0
1798 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001799
1800#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001801 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001802#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001803 } else {
1804 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001805#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001806 o4(0xEE070A90); // fmsr s15, r0
1807 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001808
1809#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001810 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001811#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001812 }
1813 } else if (r0Tag == TY_FLOAT) {
1814 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001815#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001816 o4(0xEEFD7AE7); // ftosizs s15, s15
1817 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001818#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001819 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001820#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001821 } else {
1822 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001823#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001824 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001825#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001826 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001827#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001828 }
1829 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001830 if (r0Tag == TY_DOUBLE) {
1831 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001832#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001833 o4(0xEEFD7BC7); // ftosizd s15, d7
1834 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001835#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001836 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001837#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001838 } else {
1839 if(destTag == TY_FLOAT) {
1840#ifdef ARM_USE_VFP
1841 o4(0xEEF77BC7); // fcvtsd s15, d7
1842#else
1843 callRuntime((void*) runtime_double_to_float);
1844#endif
1845 } else {
1846 incompatibleTypes(pR0Type, pType);
1847 }
1848 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001849 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001850 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001851 }
1852 }
Jack Palevich8df46192009-07-07 14:48:51 -07001853 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001854 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001855 }
1856
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001857 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001858 int pc = getPC();
1859 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1860 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001861 }
1862
Jack Palevich8148c5b2009-07-16 18:24:47 -07001863 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001864 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001865 Type* pR0Type = getR0Type();
1866 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001867#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001868 switch(r0ct) {
1869 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001870 if (l < 0 || l > 4096-4) {
1871 error("l out of range for stack offset: 0x%08x", l);
1872 }
1873 o4(0xE58D0000 | l); // str r0, [sp, #l]
1874 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001875 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001876 if (l < 0 || l > 1020 || (l & 3)) {
1877 error("l out of range for stack offset: 0x%08x", l);
1878 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001879 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001880 return 4;
1881 case TY_DOUBLE: {
1882 // Align to 8 byte boundary
1883 int l2 = (l + 7) & ~7;
1884 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1885 error("l out of range for stack offset: 0x%08x", l);
1886 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001887 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001888 return (l2 - l) + 8;
1889 }
1890 default:
1891 assert(false);
1892 return 0;
1893 }
1894#else
1895 switch(r0ct) {
1896 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001897 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001898 if (l < 0 || l > 4096-4) {
1899 error("l out of range for stack offset: 0x%08x", l);
1900 }
1901 o4(0xE58D0000 + l); // str r0, [sp, #l]
1902 return 4;
1903 case TY_DOUBLE: {
1904 // Align to 8 byte boundary
1905 int l2 = (l + 7) & ~7;
1906 if (l2 < 0 || l2 > 4096-8) {
1907 error("l out of range for stack offset: 0x%08x", l);
1908 }
1909 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1910 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1911 return (l2 - l) + 8;
1912 }
1913 default:
1914 assert(false);
1915 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001916 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001917#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001918 }
1919
Jack Palevichb7718b92009-07-09 22:00:24 -07001920 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001921 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001922 // Have to calculate register arg count from actual stack size,
1923 // in order to properly handle ... functions.
1924 int regArgCount = l >> 2;
1925 if (regArgCount > 4) {
1926 regArgCount = 4;
1927 }
1928 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001929 argumentStackUse -= regArgCount * 4;
1930 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1931 }
1932 mStackUse += argumentStackUse;
1933
1934 // Align stack.
1935 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1936 * STACK_ALIGNMENT);
1937 mStackAlignmentAdjustment = 0;
1938 if (missalignment > 0) {
1939 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1940 }
1941 l += mStackAlignmentAdjustment;
1942
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001943 if (l < 0 || l > 0x3FC) {
1944 error("L out of range for stack adjustment: 0x%08x", l);
1945 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001946 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001947 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001948 mStackUse += mStackAlignmentAdjustment;
1949 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1950 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001951 }
1952
Jack Palevich8df46192009-07-07 14:48:51 -07001953 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001954 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001955 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001956 int pc = getPC();
1957 o4(0xEB000000 | encodeAddress(symbol));
1958 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001959 }
1960
Jack Palevich8df46192009-07-07 14:48:51 -07001961 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001962 assert(pFunc->tag == TY_FUNC);
1963 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001964 int argCount = l >> 2;
1965 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001966 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001967 if (adjustedL < 0 || adjustedL > 4096-4) {
1968 error("l out of range for stack offset: 0x%08x", l);
1969 }
1970 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1971 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001972 Type* pReturnType = pFunc->pHead;
1973 setR0Type(pReturnType);
1974#ifdef ARM_USE_VFP
1975 switch(pReturnType->tag) {
1976 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001977 o4(0xEE070A90); // fmsr s15, r0
1978 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001979 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001980 o4(0xEC410B17); // fmdrr d7, r0, r1
1981 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001982 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001983 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001984 }
1985#endif
Jack Palevich22305132009-05-13 10:58:45 -07001986 }
1987
Jack Palevichb7718b92009-07-09 22:00:24 -07001988 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001989 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001990 // Have to calculate register arg count from actual stack size,
1991 // in order to properly handle ... functions.
1992 int regArgCount = l >> 2;
1993 if (regArgCount > 4) {
1994 regArgCount = 4;
1995 }
1996 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001997 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1998 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001999 if (stackUse) {
2000 if (stackUse < 0 || stackUse > 255) {
2001 error("L out of range for stack adjustment: 0x%08x", l);
2002 }
2003 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07002004 mStackUse -= stackUse * 4;
2005 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002006 }
Jack Palevich22305132009-05-13 10:58:45 -07002007 }
2008
Jack Palevicha6535612009-05-13 16:24:17 -07002009 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07002010 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002011 }
2012
2013 /* output a symbol and patch all calls to it */
2014 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002015 int n;
2016 int base = getBase();
2017 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002018 while (t) {
2019 int data = * (int*) t;
2020 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2021 if (decodedOffset == 0) {
2022 n = 0;
2023 } else {
2024 n = base + decodedOffset; /* next value */
2025 }
2026 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2027 | encodeRelAddress(pc - t - 8);
2028 t = n;
2029 }
2030 }
2031
Jack Palevich9f51a262009-07-29 16:22:26 -07002032 /* output a symbol and patch all calls to it */
2033 virtual void resolveForward(int t) {
2034 if (t) {
2035 int pc = getPC();
2036 *(int *) t = pc;
2037 }
2038 }
2039
Jack Palevich1cdef202009-05-22 12:06:27 -07002040 virtual int finishCompile() {
2041#if defined(__arm__)
2042 const long base = long(getBase());
2043 const long curr = long(getPC());
2044 int err = cacheflush(base, curr, 0);
2045 return err;
2046#else
2047 return 0;
2048#endif
2049 }
2050
Jack Palevich9eed7a22009-07-06 17:24:34 -07002051 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002052 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002053 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002054 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002055 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002056 case TY_CHAR:
2057 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002058 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002059 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002060 case TY_DOUBLE:
2061 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002062 case TY_ARRAY:
2063 return alignmentOf(pType->pHead);
2064 case TY_STRUCT:
2065 return pType->pHead->alignment & 0x7fffffff;
2066 case TY_FUNC:
2067 error("alignment of func not supported");
2068 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002069 default:
2070 return 4;
2071 }
2072 }
2073
2074 /**
2075 * Array element alignment (in bytes) for this type of data.
2076 */
2077 virtual size_t sizeOf(Type* pType){
2078 switch(pType->tag) {
2079 case TY_INT:
2080 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002081 case TY_SHORT:
2082 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002083 case TY_CHAR:
2084 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002085 case TY_FLOAT:
2086 return 4;
2087 case TY_DOUBLE:
2088 return 8;
2089 case TY_POINTER:
2090 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002091 case TY_ARRAY:
2092 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002093 case TY_STRUCT:
2094 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002095 default:
2096 error("Unsupported type %d", pType->tag);
2097 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002098 }
2099 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002100
Jack Palevich22305132009-05-13 10:58:45 -07002101 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002102
2103 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2104
2105 /** Encode a relative address that might also be
2106 * a label.
2107 */
2108 int encodeAddress(int value) {
2109 int base = getBase();
2110 if (value >= base && value <= getPC() ) {
2111 // This is a label, encode it relative to the base.
2112 value = value - base;
2113 }
2114 return encodeRelAddress(value);
2115 }
2116
2117 int encodeRelAddress(int value) {
2118 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2119 }
Jack Palevich22305132009-05-13 10:58:45 -07002120
Jack Palevichb7718b92009-07-09 22:00:24 -07002121 int calcRegArgCount(Type* pDecl) {
2122 int reg = 0;
2123 Type* pArgs = pDecl->pTail;
2124 while (pArgs && reg < 4) {
2125 Type* pArg = pArgs->pHead;
2126 if ( pArg->tag == TY_DOUBLE) {
2127 int evenReg = (reg + 1) & ~1;
2128 if (evenReg >= 4) {
2129 break;
2130 }
2131 reg = evenReg + 2;
2132 } else {
2133 reg++;
2134 }
2135 pArgs = pArgs->pTail;
2136 }
2137 return reg;
2138 }
2139
Jack Palevich58c30ee2009-07-17 16:35:23 -07002140 void setupIntPtrArgs() {
2141 o4(0xE8BD0002); // ldmfd sp!,{r1}
2142 mStackUse -= 4;
2143 popType();
2144 }
2145
Jack Palevich30321cb2009-08-20 15:34:23 -07002146 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002147 * Make sure both R0 and TOS are floats. (Could be ints)
2148 * We know that at least one of R0 and TOS is already a float
2149 */
2150 void setupFloatArgs() {
2151 Type* pR0Type = getR0Type();
2152 Type* pTOSType = getTOSType();
2153 TypeTag tagR0 = collapseType(pR0Type->tag);
2154 TypeTag tagTOS = collapseType(pTOSType->tag);
2155 if (tagR0 != TY_FLOAT) {
2156 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002157#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002158 o4(0xEE070A90); // fmsr s15, r0
2159 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002160#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002161 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002162#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002163 }
2164 if (tagTOS != TY_FLOAT) {
2165 assert(tagTOS == TY_INT);
2166 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002167#ifdef ARM_USE_VFP
2168 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002169 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002170#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002171 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2172 o4(0xE59D0004); // ldr r0, [sp, #4]
2173 callRuntime((void*) runtime_int_to_float);
2174 o4(0xE1A01000); // mov r1, r0
2175 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2176 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002177#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002178 } else {
2179 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002180#ifdef ARM_USE_VFP
2181 o4(0xECBD7A01); // fldmfds sp!, {s14}
2182
2183#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002184 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002185#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002186 }
2187 mStackUse -= 4;
2188 popType();
2189 }
2190
Jack Palevich30321cb2009-08-20 15:34:23 -07002191 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002192 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2193 * We know that at least one of R0 and TOS are already a double.
2194 */
2195
2196 void setupDoubleArgs() {
2197 Type* pR0Type = getR0Type();
2198 Type* pTOSType = getTOSType();
2199 TypeTag tagR0 = collapseType(pR0Type->tag);
2200 TypeTag tagTOS = collapseType(pTOSType->tag);
2201 if (tagR0 != TY_DOUBLE) {
2202 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002203#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002204 o4(0xEE070A90); // fmsr s15, r0
2205 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002206
2207#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002208 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002209#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002210 } else {
2211 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002212#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002213 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002214#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002215 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002216#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002217 }
2218 }
2219 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002220#ifdef ARM_USE_VFP
2221 if (tagTOS == TY_INT) {
2222 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002223 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002224 } else {
2225 assert(tagTOS == TY_FLOAT);
2226 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002227 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002228 }
2229#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002230 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2231 o4(0xE59D0008); // ldr r0, [sp, #8]
2232 if (tagTOS == TY_INT) {
2233 callRuntime((void*) runtime_int_to_double);
2234 } else {
2235 assert(tagTOS == TY_FLOAT);
2236 callRuntime((void*) runtime_float_to_double);
2237 }
2238 o4(0xE1A02000); // mov r2, r0
2239 o4(0xE1A03001); // mov r3, r1
2240 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2241 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002242#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002243 mStackUse -= 4;
2244 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002245#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002246 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002247#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002248 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002249#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002250 mStackUse -= 8;
2251 }
2252 popType();
2253 }
2254
Jack Palevicha8f427f2009-07-13 18:40:08 -07002255 void liReg(int t, int reg) {
2256 assert(reg >= 0 && reg < 16);
2257 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002258 size_t encodedImmediate;
2259 if (encode12BitImmediate(t, &encodedImmediate)) {
2260 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2261 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002262 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002263 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002264 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002265 o4(0xE51F0000 | rN); // ldr rN, .L3
2266 o4(0xEA000000); // b .L99
2267 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002268 // .L99:
2269 }
2270 }
2271
Jack Palevichc408bbf2009-09-08 12:07:32 -07002272 void incompatibleTypes(Type* pR0Type, Type* pType) {
2273 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2274 }
2275
Jack Palevichb7718b92009-07-09 22:00:24 -07002276 void callRuntime(void* fn) {
2277 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002278 o4(0xEA000000); // b .L99
2279 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002280 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002281 }
2282
Jack Palevichb7718b92009-07-09 22:00:24 -07002283 // Integer math:
2284
2285 static int runtime_DIV(int b, int a) {
2286 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002287 }
2288
Jack Palevichb7718b92009-07-09 22:00:24 -07002289 static int runtime_MOD(int b, int a) {
2290 return a % b;
2291 }
2292
Jack Palevich9221bcc2009-08-26 16:15:07 -07002293 static void runtime_structCopy(void* src, size_t size, void* dest) {
2294 memcpy(dest, src, size);
2295 }
2296
Jack Palevich30321cb2009-08-20 15:34:23 -07002297#ifndef ARM_USE_VFP
2298
Jack Palevichb7718b92009-07-09 22:00:24 -07002299 // Comparison to zero
2300
2301 static int runtime_is_non_zero_f(float a) {
2302 return a != 0;
2303 }
2304
2305 static int runtime_is_non_zero_d(double a) {
2306 return a != 0;
2307 }
2308
2309 // Comparison to zero
2310
2311 static int runtime_is_zero_f(float a) {
2312 return a == 0;
2313 }
2314
2315 static int runtime_is_zero_d(double a) {
2316 return a == 0;
2317 }
2318
2319 // Type conversion
2320
2321 static int runtime_float_to_int(float a) {
2322 return (int) a;
2323 }
2324
2325 static double runtime_float_to_double(float a) {
2326 return (double) a;
2327 }
2328
2329 static int runtime_double_to_int(double a) {
2330 return (int) a;
2331 }
2332
2333 static float runtime_double_to_float(double a) {
2334 return (float) a;
2335 }
2336
2337 static float runtime_int_to_float(int a) {
2338 return (float) a;
2339 }
2340
2341 static double runtime_int_to_double(int a) {
2342 return (double) a;
2343 }
2344
2345 // Comparisons float
2346
2347 static int runtime_cmp_eq_ff(float b, float a) {
2348 return a == b;
2349 }
2350
2351 static int runtime_cmp_ne_ff(float b, float a) {
2352 return a != b;
2353 }
2354
2355 static int runtime_cmp_lt_ff(float b, float a) {
2356 return a < b;
2357 }
2358
2359 static int runtime_cmp_le_ff(float b, float a) {
2360 return a <= b;
2361 }
2362
2363 static int runtime_cmp_ge_ff(float b, float a) {
2364 return a >= b;
2365 }
2366
2367 static int runtime_cmp_gt_ff(float b, float a) {
2368 return a > b;
2369 }
2370
2371 // Comparisons double
2372
2373 static int runtime_cmp_eq_dd(double b, double a) {
2374 return a == b;
2375 }
2376
2377 static int runtime_cmp_ne_dd(double b, double a) {
2378 return a != b;
2379 }
2380
2381 static int runtime_cmp_lt_dd(double b, double a) {
2382 return a < b;
2383 }
2384
2385 static int runtime_cmp_le_dd(double b, double a) {
2386 return a <= b;
2387 }
2388
2389 static int runtime_cmp_ge_dd(double b, double a) {
2390 return a >= b;
2391 }
2392
2393 static int runtime_cmp_gt_dd(double b, double a) {
2394 return a > b;
2395 }
2396
2397 // Math float
2398
2399 static float runtime_op_add_ff(float b, float a) {
2400 return a + b;
2401 }
2402
2403 static float runtime_op_sub_ff(float b, float a) {
2404 return a - b;
2405 }
2406
2407 static float runtime_op_mul_ff(float b, float a) {
2408 return a * b;
2409 }
2410
2411 static float runtime_op_div_ff(float b, float a) {
2412 return a / b;
2413 }
2414
2415 static float runtime_op_neg_f(float a) {
2416 return -a;
2417 }
2418
2419 // Math double
2420
2421 static double runtime_op_add_dd(double b, double a) {
2422 return a + b;
2423 }
2424
2425 static double runtime_op_sub_dd(double b, double a) {
2426 return a - b;
2427 }
2428
2429 static double runtime_op_mul_dd(double b, double a) {
2430 return a * b;
2431 }
2432
2433 static double runtime_op_div_dd(double b, double a) {
2434 return a / b;
2435 }
2436
2437 static double runtime_op_neg_d(double a) {
2438 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002439 }
-b master422972c2009-06-17 19:13:52 -07002440
Jack Palevich30321cb2009-08-20 15:34:23 -07002441#endif
2442
-b master422972c2009-06-17 19:13:52 -07002443 static const int STACK_ALIGNMENT = 8;
2444 int mStackUse;
2445 // This variable holds the amount we adjusted the stack in the most
2446 // recent endFunctionCallArguments call. It's examined by the
2447 // following adjustStackAfterCall call.
2448 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002449 };
2450
Jack Palevich09555c72009-05-27 12:25:55 -07002451#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002452
2453#ifdef PROVIDE_X86_CODEGEN
2454
Jack Palevich21a15a22009-05-11 14:49:29 -07002455 class X86CodeGenerator : public CodeGenerator {
2456 public:
2457 X86CodeGenerator() {}
2458 virtual ~X86CodeGenerator() {}
2459
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002460 /* returns address to patch with local variable size
2461 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002462 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002463 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2464 return oad(0xec81, 0); /* sub $xxx, %esp */
2465 }
2466
Jack Palevichb7718b92009-07-09 22:00:24 -07002467 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002468 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002469 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002470 }
2471
Jack Palevich21a15a22009-05-11 14:49:29 -07002472 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002473 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002474 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002475 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002476 }
2477
Jack Palevich1a539db2009-07-08 13:04:41 -07002478 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002479 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002480 switch (pType->tag) {
2481 case TY_FLOAT:
2482 oad(0x05D9, address); // flds
2483 break;
2484 case TY_DOUBLE:
2485 oad(0x05DD, address); // fldl
2486 break;
2487 default:
2488 assert(false);
2489 break;
2490 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002491 }
2492
Jack Palevich9221bcc2009-08-26 16:15:07 -07002493 virtual void addStructOffsetR0(int offset, Type* pType) {
2494 if (offset) {
2495 oad(0x05, offset); // addl offset, %eax
2496 }
2497 setR0Type(pType, ET_LVALUE);
2498 }
2499
Jack Palevich22305132009-05-13 10:58:45 -07002500 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002501 return psym(0xe9, t);
2502 }
2503
2504 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002505 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002506 Type* pR0Type = getR0Type();
2507 TypeTag tagR0 = pR0Type->tag;
2508 bool isFloatR0 = isFloatTag(tagR0);
2509 if (isFloatR0) {
2510 o(0xeed9); // fldz
2511 o(0xe9da); // fucompp
2512 o(0xe0df); // fnstsw %ax
2513 o(0x9e); // sahf
2514 } else {
2515 o(0xc085); // test %eax, %eax
2516 }
2517 // Use two output statements to generate one instruction.
2518 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002519 return psym(0x84 + l, t);
2520 }
2521
Jack Palevich58c30ee2009-07-17 16:35:23 -07002522 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002523 Type* pR0Type = getR0Type();
2524 Type* pTOSType = getTOSType();
2525 TypeTag tagR0 = pR0Type->tag;
2526 TypeTag tagTOS = pTOSType->tag;
2527 bool isFloatR0 = isFloatTag(tagR0);
2528 bool isFloatTOS = isFloatTag(tagTOS);
2529 if (!isFloatR0 && !isFloatTOS) {
2530 int t = decodeOp(op);
2531 o(0x59); /* pop %ecx */
2532 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002533 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002534 o(0x0f); /* setxx %al */
2535 o(t + 0x90);
2536 o(0xc0);
2537 popType();
2538 } else {
2539 setupFloatOperands();
2540 switch (op) {
2541 case OP_EQUALS:
2542 o(0xe9da); // fucompp
2543 o(0xe0df); // fnstsw %ax
2544 o(0x9e); // sahf
2545 o(0xc0940f); // sete %al
2546 o(0xc29b0f); // setnp %dl
2547 o(0xd021); // andl %edx, %eax
2548 break;
2549 case OP_NOT_EQUALS:
2550 o(0xe9da); // fucompp
2551 o(0xe0df); // fnstsw %ax
2552 o(0x9e); // sahf
2553 o(0xc0950f); // setne %al
2554 o(0xc29a0f); // setp %dl
2555 o(0xd009); // orl %edx, %eax
2556 break;
2557 case OP_GREATER_EQUAL:
2558 o(0xe9da); // fucompp
2559 o(0xe0df); // fnstsw %ax
2560 o(0x05c4f6); // testb $5, %ah
2561 o(0xc0940f); // sete %al
2562 break;
2563 case OP_LESS:
2564 o(0xc9d9); // fxch %st(1)
2565 o(0xe9da); // fucompp
2566 o(0xe0df); // fnstsw %ax
2567 o(0x9e); // sahf
2568 o(0xc0970f); // seta %al
2569 break;
2570 case OP_LESS_EQUAL:
2571 o(0xc9d9); // fxch %st(1)
2572 o(0xe9da); // fucompp
2573 o(0xe0df); // fnstsw %ax
2574 o(0x9e); // sahf
2575 o(0xc0930f); // setea %al
2576 break;
2577 case OP_GREATER:
2578 o(0xe9da); // fucompp
2579 o(0xe0df); // fnstsw %ax
2580 o(0x45c4f6); // testb $69, %ah
2581 o(0xc0940f); // sete %al
2582 break;
2583 default:
2584 error("Unknown comparison op");
2585 }
2586 o(0xc0b60f); // movzbl %al, %eax
2587 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002588 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002589 }
2590
Jack Palevich546b2242009-05-13 15:10:04 -07002591 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002592 Type* pR0Type = getR0Type();
2593 Type* pTOSType = getTOSType();
2594 TypeTag tagR0 = pR0Type->tag;
2595 TypeTag tagTOS = pTOSType->tag;
2596 bool isFloatR0 = isFloatTag(tagR0);
2597 bool isFloatTOS = isFloatTag(tagTOS);
2598 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002599 bool isPtrR0 = isPointerTag(tagR0);
2600 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002601 if (isPtrR0 || isPtrTOS) {
2602 if (isPtrR0 && isPtrTOS) {
2603 if (op != OP_MINUS) {
2604 error("Unsupported pointer-pointer operation %d.", op);
2605 }
2606 if (! typeEqual(pR0Type, pTOSType)) {
2607 error("Incompatible pointer types for subtraction.");
2608 }
2609 o(0x59); /* pop %ecx */
2610 o(decodeOp(op));
2611 popType();
2612 setR0Type(mkpInt);
2613 int size = sizeOf(pR0Type->pHead);
2614 if (size != 1) {
2615 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002616 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002617 // TODO: Optimize for power-of-two.
2618 genOp(OP_DIV);
2619 }
2620 } else {
2621 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2622 error("Unsupported pointer-scalar operation %d", op);
2623 }
Jack Palevichb6154502009-08-04 14:56:09 -07002624 Type* pPtrType = getPointerArithmeticResultType(
2625 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002626 o(0x59); /* pop %ecx */
2627 int size = sizeOf(pPtrType->pHead);
2628 if (size != 1) {
2629 // TODO: Optimize for power-of-two.
2630 if (isPtrR0) {
2631 oad(0xC969, size); // imull $size, %ecx
2632 } else {
2633 oad(0xC069, size); // mul $size, %eax
2634 }
2635 }
2636 o(decodeOp(op));
2637 popType();
2638 setR0Type(pPtrType);
2639 }
2640 } else {
2641 o(0x59); /* pop %ecx */
2642 o(decodeOp(op));
2643 if (op == OP_MOD)
2644 o(0x92); /* xchg %edx, %eax */
2645 popType();
2646 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002647 } else {
2648 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2649 setupFloatOperands();
2650 // Both float. x87 R0 == left hand, x87 R1 == right hand
2651 switch (op) {
2652 case OP_MUL:
2653 o(0xc9de); // fmulp
2654 break;
2655 case OP_DIV:
2656 o(0xf1de); // fdivp
2657 break;
2658 case OP_PLUS:
2659 o(0xc1de); // faddp
2660 break;
2661 case OP_MINUS:
2662 o(0xe1de); // fsubp
2663 break;
2664 default:
2665 error("Unsupported binary floating operation.");
2666 break;
2667 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002668 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002669 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002670 }
2671
Jack Palevich58c30ee2009-07-17 16:35:23 -07002672 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002673 if (op != OP_LOGICAL_NOT) {
2674 error("Unknown unary cmp %d", op);
2675 } else {
2676 Type* pR0Type = getR0Type();
2677 TypeTag tag = collapseType(pR0Type->tag);
2678 switch(tag) {
2679 case TY_INT: {
2680 oad(0xb9, 0); /* movl $0, %ecx */
2681 int t = decodeOp(op);
2682 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002683 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002684 o(0x0f); /* setxx %al */
2685 o(t + 0x90);
2686 o(0xc0);
2687 }
2688 break;
2689 case TY_FLOAT:
2690 case TY_DOUBLE:
2691 o(0xeed9); // fldz
2692 o(0xe9da); // fucompp
2693 o(0xe0df); // fnstsw %ax
2694 o(0x9e); // sahf
2695 o(0xc0950f); // setne %al
2696 o(0xc29a0f); // setp %dl
2697 o(0xd009); // orl %edx, %eax
2698 o(0xc0b60f); // movzbl %al, %eax
2699 o(0x01f083); // xorl $1, %eax
2700 break;
2701 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002702 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002703 break;
2704 }
2705 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002706 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002707 }
2708
2709 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002710 Type* pR0Type = getR0Type();
2711 TypeTag tag = collapseType(pR0Type->tag);
2712 switch(tag) {
2713 case TY_INT:
2714 oad(0xb9, 0); /* movl $0, %ecx */
2715 o(decodeOp(op));
2716 break;
2717 case TY_FLOAT:
2718 case TY_DOUBLE:
2719 switch (op) {
2720 case OP_MINUS:
2721 o(0xe0d9); // fchs
2722 break;
2723 case OP_BIT_NOT:
2724 error("Can't apply '~' operator to a float or double.");
2725 break;
2726 default:
2727 error("Unknown unary op %d\n", op);
2728 break;
2729 }
2730 break;
2731 default:
2732 error("genUnaryOp unsupported type");
2733 break;
2734 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002735 }
2736
Jack Palevich1cdef202009-05-22 12:06:27 -07002737 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002738 Type* pR0Type = getR0Type();
2739 TypeTag r0ct = collapseType(pR0Type->tag);
2740 switch(r0ct) {
2741 case TY_INT:
2742 o(0x50); /* push %eax */
2743 break;
2744 case TY_FLOAT:
2745 o(0x50); /* push %eax */
2746 o(0x241cd9); // fstps 0(%esp)
2747 break;
2748 case TY_DOUBLE:
2749 o(0x50); /* push %eax */
2750 o(0x50); /* push %eax */
2751 o(0x241cdd); // fstpl 0(%esp)
2752 break;
2753 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002754 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002755 break;
2756 }
Jack Palevich8df46192009-07-07 14:48:51 -07002757 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002758 }
2759
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002760 virtual void over() {
2761 // We know it's only used for int-ptr ops (++/--)
2762
2763 Type* pR0Type = getR0Type();
2764 TypeTag r0ct = collapseType(pR0Type->tag);
2765
2766 Type* pTOSType = getTOSType();
2767 TypeTag tosct = collapseType(pTOSType->tag);
2768
2769 assert (r0ct == TY_INT && tosct == TY_INT);
2770
2771 o(0x59); /* pop %ecx */
2772 o(0x50); /* push %eax */
2773 o(0x51); /* push %ecx */
2774
2775 overType();
2776 }
2777
Jack Palevich58c30ee2009-07-17 16:35:23 -07002778 virtual void popR0() {
2779 Type* pR0Type = getR0Type();
2780 TypeTag r0ct = collapseType(pR0Type->tag);
2781 switch(r0ct) {
2782 case TY_INT:
2783 o(0x58); /* popl %eax */
2784 break;
2785 case TY_FLOAT:
2786 o(0x2404d9); // flds (%esp)
2787 o(0x58); /* popl %eax */
2788 break;
2789 case TY_DOUBLE:
2790 o(0x2404dd); // fldl (%esp)
2791 o(0x58); /* popl %eax */
2792 o(0x58); /* popl %eax */
2793 break;
2794 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002795 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002796 break;
2797 }
2798 popType();
2799 }
2800
2801 virtual void storeR0ToTOS() {
2802 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002803 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002804 Type* pTargetType = pPointerType->pHead;
2805 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002806 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002807 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002808 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002809 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002810 case TY_INT:
2811 o(0x0189); /* movl %eax/%al, (%ecx) */
2812 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002813 case TY_SHORT:
2814 o(0x018966); /* movw %ax, (%ecx) */
2815 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002816 case TY_CHAR:
2817 o(0x0188); /* movl %eax/%al, (%ecx) */
2818 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002819 case TY_FLOAT:
2820 o(0x19d9); /* fstps (%ecx) */
2821 break;
2822 case TY_DOUBLE:
2823 o(0x19dd); /* fstpl (%ecx) */
2824 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002825 case TY_STRUCT:
2826 {
2827 // TODO: use alignment information to use movsw/movsl instead of movsb
2828 int size = sizeOf(pTargetType);
2829 if (size > 0) {
2830 o(0x9c); // pushf
2831 o(0x57); // pushl %edi
2832 o(0x56); // pushl %esi
2833 o(0xcf89); // movl %ecx, %edi
2834 o(0xc689); // movl %eax, %esi
2835 oad(0xb9, size); // mov #size, %ecx
2836 o(0xfc); // cld
2837 o(0xf3); // rep
2838 o(0xa4); // movsb
2839 o(0x5e); // popl %esi
2840 o(0x5f); // popl %edi
2841 o(0x9d); // popf
2842 }
2843 }
2844 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002845 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002846 error("storeR0ToTOS: unsupported type %d",
2847 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002848 break;
2849 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002850 }
2851
Jack Palevich58c30ee2009-07-17 16:35:23 -07002852 virtual void loadR0FromR0() {
2853 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002854 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002855 Type* pNewType = pPointerType->pHead;
2856 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002857 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002858 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002859 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002860 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002861 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002862 case TY_SHORT:
2863 o(0xbf0f); /* movswl (%eax), %eax */
2864 ob(0);
2865 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002866 case TY_CHAR:
2867 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002868 ob(0); /* add zero in code */
2869 break;
2870 case TY_FLOAT:
2871 o2(0x00d9); // flds (%eax)
2872 break;
2873 case TY_DOUBLE:
2874 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002875 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002876 case TY_ARRAY:
2877 pNewType = pNewType->pTail;
2878 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002879 case TY_STRUCT:
2880 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002881 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002882 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002883 break;
2884 }
Jack Palevich80e49722009-08-04 15:39:49 -07002885 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002886 }
2887
Jack Palevichb5e33312009-07-30 19:06:34 -07002888 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002889 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002890 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002891 }
2892
Jack Palevich9f51a262009-07-29 16:22:26 -07002893 virtual int leaForward(int ea, Type* pPointerType) {
2894 oad(0xb8, ea); /* mov $xx, %eax */
2895 setR0Type(pPointerType);
2896 return getPC() - 4;
2897 }
2898
Jack Palevichb6154502009-08-04 14:56:09 -07002899 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002900 Type* pR0Type = getR0Type();
2901 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002902 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002903 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002904 return;
2905 }
Jack Palevichb6154502009-08-04 14:56:09 -07002906 if (isPointerType(pType) && isPointerType(pR0Type)) {
2907 Type* pA = pR0Type;
2908 Type* pB = pType;
2909 // Array decays to pointer
2910 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2911 pA = pA->pTail;
2912 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002913 if (! (typeEqual(pA, pB)
2914 || pB->pHead->tag == TY_VOID
2915 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2916 )) {
2917 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002918 }
Jack Palevichb6154502009-08-04 14:56:09 -07002919 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002920 // do nothing special
2921 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2922 // do nothing special, both held in same register on x87.
2923 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002924 TypeTag r0Tag = collapseType(pR0Type->tag);
2925 TypeTag destTag = collapseType(pType->tag);
2926 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2927 // Convert R0 from int to float
2928 o(0x50); // push %eax
2929 o(0x2404DB); // fildl 0(%esp)
2930 o(0x58); // pop %eax
2931 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2932 // Convert R0 from float to int. Complicated because
2933 // need to save and restore the rounding mode.
2934 o(0x50); // push %eax
2935 o(0x50); // push %eax
2936 o(0x02247cD9); // fnstcw 2(%esp)
2937 o(0x2444b70f); // movzwl 2(%esp), %eax
2938 o(0x02);
2939 o(0x0cb4); // movb $12, %ah
2940 o(0x24048966); // movw %ax, 0(%esp)
2941 o(0x242cd9); // fldcw 0(%esp)
2942 o(0x04245cdb); // fistpl 4(%esp)
2943 o(0x02246cd9); // fldcw 2(%esp)
2944 o(0x58); // pop %eax
2945 o(0x58); // pop %eax
2946 } else {
2947 error("Incompatible types old: %d new: %d",
2948 pR0Type->tag, pType->tag);
2949 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002950 }
2951 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002952 }
2953
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002954 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002955 return oad(0xec81, 0); /* sub $xxx, %esp */
2956 }
2957
Jack Palevich8148c5b2009-07-16 18:24:47 -07002958 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2959 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002960 Type* pR0Type = getR0Type();
2961 TypeTag r0ct = collapseType(pR0Type->tag);
2962 switch(r0ct) {
2963 case TY_INT:
2964 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2965 return 4;
2966 case TY_FLOAT:
2967 oad(0x249CD9, l); /* fstps xxx(%esp) */
2968 return 4;
2969 case TY_DOUBLE:
2970 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2971 return 8;
2972 default:
2973 assert(false);
2974 return 0;
2975 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002976 }
2977
Jack Palevichb7718b92009-07-09 22:00:24 -07002978 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002979 * (int*) a = l;
2980 }
2981
Jack Palevich8df46192009-07-07 14:48:51 -07002982 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002983 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002984 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002985 return psym(0xe8, symbol); /* call xxx */
2986 }
2987
Jack Palevich8df46192009-07-07 14:48:51 -07002988 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002989 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002990 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002991 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002992 oad(0x2494ff, l); /* call *xxx(%esp) */
2993 }
2994
Jack Palevichb7718b92009-07-09 22:00:24 -07002995 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002996 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002997 if (isIndirect) {
2998 l += 4;
2999 }
-b master422972c2009-06-17 19:13:52 -07003000 if (l > 0) {
3001 oad(0xc481, l); /* add $xxx, %esp */
3002 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003003 }
3004
Jack Palevicha6535612009-05-13 16:24:17 -07003005 virtual int jumpOffset() {
3006 return 5;
3007 }
3008
Jack Paleviche7b59062009-05-19 17:12:17 -07003009 /* output a symbol and patch all calls to it */
3010 virtual void gsym(int t) {
3011 int n;
3012 int pc = getPC();
3013 while (t) {
3014 n = *(int *) t; /* next value */
3015 *(int *) t = pc - t - 4;
3016 t = n;
3017 }
3018 }
3019
Jack Palevich9f51a262009-07-29 16:22:26 -07003020 /* output a symbol and patch all calls to it, using absolute address */
3021 virtual void resolveForward(int t) {
3022 int n;
3023 int pc = getPC();
3024 while (t) {
3025 n = *(int *) t; /* next value */
3026 *(int *) t = pc;
3027 t = n;
3028 }
3029 }
3030
Jack Palevich1cdef202009-05-22 12:06:27 -07003031 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003032 size_t pagesize = 4096;
3033 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3034 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3035 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3036 if (err) {
3037 error("mprotect() failed: %d", errno);
3038 }
3039 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003040 }
3041
Jack Palevich9eed7a22009-07-06 17:24:34 -07003042 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003043 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003044 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003045 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003046 switch (pType->tag) {
3047 case TY_CHAR:
3048 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003049 case TY_SHORT:
3050 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003051 case TY_ARRAY:
3052 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003053 case TY_STRUCT:
3054 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003055 case TY_FUNC:
3056 error("alignment of func not supported");
3057 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003058 default:
3059 return 4;
3060 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003061 }
3062
3063 /**
3064 * Array element alignment (in bytes) for this type of data.
3065 */
3066 virtual size_t sizeOf(Type* pType){
3067 switch(pType->tag) {
3068 case TY_INT:
3069 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003070 case TY_SHORT:
3071 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003072 case TY_CHAR:
3073 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003074 case TY_FLOAT:
3075 return 4;
3076 case TY_DOUBLE:
3077 return 8;
3078 case TY_POINTER:
3079 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003080 case TY_ARRAY:
3081 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003082 case TY_STRUCT:
3083 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003084 default:
3085 error("Unsupported type %d", pType->tag);
3086 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003087 }
3088 }
3089
Jack Palevich21a15a22009-05-11 14:49:29 -07003090 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003091
3092 /** Output 1 to 4 bytes.
3093 *
3094 */
3095 void o(int n) {
3096 /* cannot use unsigned, so we must do a hack */
3097 while (n && n != -1) {
3098 ob(n & 0xff);
3099 n = n >> 8;
3100 }
3101 }
3102
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003103 /* Output exactly 2 bytes
3104 */
3105 void o2(int n) {
3106 ob(n & 0xff);
3107 ob(0xff & (n >> 8));
3108 }
3109
Jack Paleviche7b59062009-05-19 17:12:17 -07003110 /* psym is used to put an instruction with a data field which is a
3111 reference to a symbol. It is in fact the same as oad ! */
3112 int psym(int n, int t) {
3113 return oad(n, t);
3114 }
3115
3116 /* instruction + address */
3117 int oad(int n, int t) {
3118 o(n);
3119 int result = getPC();
3120 o4(t);
3121 return result;
3122 }
3123
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003124 static const int operatorHelper[];
3125
3126 int decodeOp(int op) {
3127 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003128 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003129 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003130 }
3131 return operatorHelper[op];
3132 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003133
Jack Palevich546b2242009-05-13 15:10:04 -07003134 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003135 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003136 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003137 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003138
3139 void setupFloatOperands() {
3140 Type* pR0Type = getR0Type();
3141 Type* pTOSType = getTOSType();
3142 TypeTag tagR0 = pR0Type->tag;
3143 TypeTag tagTOS = pTOSType->tag;
3144 bool isFloatR0 = isFloatTag(tagR0);
3145 bool isFloatTOS = isFloatTag(tagTOS);
3146 if (! isFloatR0) {
3147 // Convert R0 from int to float
3148 o(0x50); // push %eax
3149 o(0x2404DB); // fildl 0(%esp)
3150 o(0x58); // pop %eax
3151 }
3152 if (! isFloatTOS){
3153 o(0x2404DB); // fildl 0(%esp);
3154 o(0x58); // pop %eax
3155 } else {
3156 if (tagTOS == TY_FLOAT) {
3157 o(0x2404d9); // flds (%esp)
3158 o(0x58); // pop %eax
3159 } else {
3160 o(0x2404dd); // fldl (%esp)
3161 o(0x58); // pop %eax
3162 o(0x58); // pop %eax
3163 }
3164 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003165 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003166 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003167 };
3168
Jack Paleviche7b59062009-05-19 17:12:17 -07003169#endif // PROVIDE_X86_CODEGEN
3170
Jack Palevichb67b18f2009-06-11 21:12:23 -07003171#ifdef PROVIDE_TRACE_CODEGEN
3172 class TraceCodeGenerator : public CodeGenerator {
3173 private:
3174 CodeGenerator* mpBase;
3175
3176 public:
3177 TraceCodeGenerator(CodeGenerator* pBase) {
3178 mpBase = pBase;
3179 }
3180
3181 virtual ~TraceCodeGenerator() {
3182 delete mpBase;
3183 }
3184
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003185 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003186 mpBase->init(pCodeBuf);
3187 }
3188
3189 void setErrorSink(ErrorSink* pErrorSink) {
3190 mpBase->setErrorSink(pErrorSink);
3191 }
3192
3193 /* returns address to patch with local variable size
3194 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003195 virtual int functionEntry(Type* pDecl) {
3196 int result = mpBase->functionEntry(pDecl);
3197 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003198 return result;
3199 }
3200
Jack Palevichb7718b92009-07-09 22:00:24 -07003201 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3202 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3203 localVariableAddress, localVariableSize);
3204 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003205 }
3206
3207 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003208 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003209 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003210 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003211 }
3212
Jack Palevich1a539db2009-07-08 13:04:41 -07003213 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003214 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003215 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003216 }
3217
Jack Palevich9221bcc2009-08-26 16:15:07 -07003218 virtual void addStructOffsetR0(int offset, Type* pType) {
3219 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3220 mpBase->addStructOffsetR0(offset, pType);
3221 }
3222
Jack Palevichb67b18f2009-06-11 21:12:23 -07003223 virtual int gjmp(int t) {
3224 int result = mpBase->gjmp(t);
3225 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3226 return result;
3227 }
3228
3229 /* l = 0: je, l == 1: jne */
3230 virtual int gtst(bool l, int t) {
3231 int result = mpBase->gtst(l, t);
3232 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3233 return result;
3234 }
3235
Jack Palevich58c30ee2009-07-17 16:35:23 -07003236 virtual void gcmp(int op) {
3237 fprintf(stderr, "gcmp(%d)\n", op);
3238 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003239 }
3240
3241 virtual void genOp(int op) {
3242 fprintf(stderr, "genOp(%d)\n", op);
3243 mpBase->genOp(op);
3244 }
3245
Jack Palevich9eed7a22009-07-06 17:24:34 -07003246
Jack Palevich58c30ee2009-07-17 16:35:23 -07003247 virtual void gUnaryCmp(int op) {
3248 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3249 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003250 }
3251
3252 virtual void genUnaryOp(int op) {
3253 fprintf(stderr, "genUnaryOp(%d)\n", op);
3254 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003255 }
3256
3257 virtual void pushR0() {
3258 fprintf(stderr, "pushR0()\n");
3259 mpBase->pushR0();
3260 }
3261
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003262 virtual void over() {
3263 fprintf(stderr, "over()\n");
3264 mpBase->over();
3265 }
3266
Jack Palevich58c30ee2009-07-17 16:35:23 -07003267 virtual void popR0() {
3268 fprintf(stderr, "popR0()\n");
3269 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003270 }
3271
Jack Palevich58c30ee2009-07-17 16:35:23 -07003272 virtual void storeR0ToTOS() {
3273 fprintf(stderr, "storeR0ToTOS()\n");
3274 mpBase->storeR0ToTOS();
3275 }
3276
3277 virtual void loadR0FromR0() {
3278 fprintf(stderr, "loadR0FromR0()\n");
3279 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003280 }
3281
Jack Palevichb5e33312009-07-30 19:06:34 -07003282 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3283 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3284 pPointerType->pHead->tag, et);
3285 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003286 }
3287
Jack Palevich9f51a262009-07-29 16:22:26 -07003288 virtual int leaForward(int ea, Type* pPointerType) {
3289 fprintf(stderr, "leaForward(%d)\n", ea);
3290 return mpBase->leaForward(ea, pPointerType);
3291 }
3292
Jack Palevich30321cb2009-08-20 15:34:23 -07003293 virtual void convertR0Imp(Type* pType, bool isCast){
3294 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3295 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003296 }
3297
3298 virtual int beginFunctionCallArguments() {
3299 int result = mpBase->beginFunctionCallArguments();
3300 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3301 return result;
3302 }
3303
Jack Palevich8148c5b2009-07-16 18:24:47 -07003304 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3305 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3306 pArgType->tag);
3307 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003308 }
3309
Jack Palevichb7718b92009-07-09 22:00:24 -07003310 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003311 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003312 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003313 }
3314
Jack Palevich8df46192009-07-07 14:48:51 -07003315 virtual int callForward(int symbol, Type* pFunc) {
3316 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003317 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3318 return result;
3319 }
3320
Jack Palevich8df46192009-07-07 14:48:51 -07003321 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003322 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3323 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003324 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003325 }
3326
Jack Palevichb7718b92009-07-09 22:00:24 -07003327 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3328 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3329 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003330 }
3331
3332 virtual int jumpOffset() {
3333 return mpBase->jumpOffset();
3334 }
3335
Jack Palevichb67b18f2009-06-11 21:12:23 -07003336 /* output a symbol and patch all calls to it */
3337 virtual void gsym(int t) {
3338 fprintf(stderr, "gsym(%d)\n", t);
3339 mpBase->gsym(t);
3340 }
3341
Jack Palevich9f51a262009-07-29 16:22:26 -07003342 virtual void resolveForward(int t) {
3343 mpBase->resolveForward(t);
3344 }
3345
Jack Palevichb67b18f2009-06-11 21:12:23 -07003346 virtual int finishCompile() {
3347 int result = mpBase->finishCompile();
3348 fprintf(stderr, "finishCompile() = %d\n", result);
3349 return result;
3350 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003351
3352 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003353 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003354 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003355 virtual size_t alignmentOf(Type* pType){
3356 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003357 }
3358
3359 /**
3360 * Array element alignment (in bytes) for this type of data.
3361 */
3362 virtual size_t sizeOf(Type* pType){
3363 return mpBase->sizeOf(pType);
3364 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003365
3366 virtual Type* getR0Type() {
3367 return mpBase->getR0Type();
3368 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003369
3370 virtual ExpressionType getR0ExpressionType() {
3371 return mpBase->getR0ExpressionType();
3372 }
3373
3374 virtual void setR0ExpressionType(ExpressionType et) {
3375 mpBase->setR0ExpressionType(et);
3376 }
3377
3378 virtual size_t getExpressionStackDepth() {
3379 return mpBase->getExpressionStackDepth();
3380 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003381
3382 virtual void forceR0RVal() {
3383 return mpBase->forceR0RVal();
3384 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003385 };
3386
3387#endif // PROVIDE_TRACE_CODEGEN
3388
Jack Palevich569f1352009-06-29 14:29:08 -07003389 class Arena {
3390 public:
3391 // Used to record a given allocation amount.
3392 // Used:
3393 // Mark mark = arena.mark();
3394 // ... lots of arena.allocate()
3395 // arena.free(mark);
3396
3397 struct Mark {
3398 size_t chunk;
3399 size_t offset;
3400 };
3401
3402 Arena() {
3403 mCurrentChunk = 0;
3404 Chunk start(CHUNK_SIZE);
3405 mData.push_back(start);
3406 }
3407
3408 ~Arena() {
3409 for(size_t i = 0; i < mData.size(); i++) {
3410 mData[i].free();
3411 }
3412 }
3413
3414 // Alloc using the standard alignment size safe for any variable
3415 void* alloc(size_t size) {
3416 return alloc(size, 8);
3417 }
3418
3419 Mark mark(){
3420 Mark result;
3421 result.chunk = mCurrentChunk;
3422 result.offset = mData[mCurrentChunk].mOffset;
3423 return result;
3424 }
3425
3426 void freeToMark(const Mark& mark) {
3427 mCurrentChunk = mark.chunk;
3428 mData[mCurrentChunk].mOffset = mark.offset;
3429 }
3430
3431 private:
3432 // Allocate memory aligned to a given size
3433 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3434 // Memory is not zero filled.
3435
3436 void* alloc(size_t size, size_t alignment) {
3437 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3438 if (mCurrentChunk + 1 < mData.size()) {
3439 mCurrentChunk++;
3440 } else {
3441 size_t allocSize = CHUNK_SIZE;
3442 if (allocSize < size + alignment - 1) {
3443 allocSize = size + alignment - 1;
3444 }
3445 Chunk chunk(allocSize);
3446 mData.push_back(chunk);
3447 mCurrentChunk++;
3448 }
3449 }
3450 return mData[mCurrentChunk].allocate(size, alignment);
3451 }
3452
3453 static const size_t CHUNK_SIZE = 128*1024;
3454 // Note: this class does not deallocate its
3455 // memory when it's destroyed. It depends upon
3456 // its parent to deallocate the memory.
3457 struct Chunk {
3458 Chunk() {
3459 mpData = 0;
3460 mSize = 0;
3461 mOffset = 0;
3462 }
3463
3464 Chunk(size_t size) {
3465 mSize = size;
3466 mpData = (char*) malloc(size);
3467 mOffset = 0;
3468 }
3469
3470 ~Chunk() {
3471 // Doesn't deallocate memory.
3472 }
3473
3474 void* allocate(size_t size, size_t alignment) {
3475 size_t alignedOffset = aligned(mOffset, alignment);
3476 void* result = mpData + alignedOffset;
3477 mOffset = alignedOffset + size;
3478 return result;
3479 }
3480
3481 void free() {
3482 if (mpData) {
3483 ::free(mpData);
3484 mpData = 0;
3485 }
3486 }
3487
3488 size_t remainingCapacity(size_t alignment) {
3489 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3490 }
3491
3492 // Assume alignment is a power of two
3493 inline size_t aligned(size_t v, size_t alignment) {
3494 size_t mask = alignment-1;
3495 return (v + mask) & ~mask;
3496 }
3497
3498 char* mpData;
3499 size_t mSize;
3500 size_t mOffset;
3501 };
3502
3503 size_t mCurrentChunk;
3504
3505 Vector<Chunk> mData;
3506 };
3507
Jack Palevich569f1352009-06-29 14:29:08 -07003508 struct VariableInfo;
3509
3510 struct Token {
3511 int hash;
3512 size_t length;
3513 char* pText;
3514 tokenid_t id;
3515
3516 // Current values for the token
3517 char* mpMacroDefinition;
3518 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003519 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003520 };
3521
3522 class TokenTable {
3523 public:
3524 // Don't use 0..0xff, allows characters and operators to be tokens too.
3525
3526 static const int TOKEN_BASE = 0x100;
3527 TokenTable() {
3528 mpMap = hashmapCreate(128, hashFn, equalsFn);
3529 }
3530
3531 ~TokenTable() {
3532 hashmapFree(mpMap);
3533 }
3534
3535 void setArena(Arena* pArena) {
3536 mpArena = pArena;
3537 }
3538
3539 // Returns a token for a given string of characters.
3540 tokenid_t intern(const char* pText, size_t length) {
3541 Token probe;
3542 int hash = hashmapHash((void*) pText, length);
3543 {
3544 Token probe;
3545 probe.hash = hash;
3546 probe.length = length;
3547 probe.pText = (char*) pText;
3548 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3549 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003550 return pValue->id;
3551 }
3552 }
3553
3554 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3555 memset(pToken, 0, sizeof(*pToken));
3556 pToken->hash = hash;
3557 pToken->length = length;
3558 pToken->pText = (char*) mpArena->alloc(length + 1);
3559 memcpy(pToken->pText, pText, length);
3560 pToken->pText[length] = 0;
3561 pToken->id = mTokens.size() + TOKEN_BASE;
3562 mTokens.push_back(pToken);
3563 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003564 return pToken->id;
3565 }
3566
3567 // Return the Token for a given tokenid.
3568 Token& operator[](tokenid_t id) {
3569 return *mTokens[id - TOKEN_BASE];
3570 }
3571
3572 inline size_t size() {
3573 return mTokens.size();
3574 }
3575
3576 private:
3577
3578 static int hashFn(void* pKey) {
3579 Token* pToken = (Token*) pKey;
3580 return pToken->hash;
3581 }
3582
3583 static bool equalsFn(void* keyA, void* keyB) {
3584 Token* pTokenA = (Token*) keyA;
3585 Token* pTokenB = (Token*) keyB;
3586 // Don't need to compare hash values, they should always be equal
3587 return pTokenA->length == pTokenB->length
3588 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3589 }
3590
3591 Hashmap* mpMap;
3592 Vector<Token*> mTokens;
3593 Arena* mpArena;
3594 };
3595
Jack Palevich1cdef202009-05-22 12:06:27 -07003596 class InputStream {
3597 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003598 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003599 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003600 };
3601
3602 class TextInputStream : public InputStream {
3603 public:
3604 TextInputStream(const char* text, size_t textLength)
3605 : pText(text), mTextLength(textLength), mPosition(0) {
3606 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003607
Jack Palevichdc456462009-07-16 16:50:56 -07003608 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003609 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3610 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003611
Jack Palevichdc456462009-07-16 16:50:56 -07003612 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003613 const char* pText;
3614 size_t mTextLength;
3615 size_t mPosition;
3616 };
3617
Jack Palevicheedf9d22009-06-04 16:23:40 -07003618 class String {
3619 public:
3620 String() {
3621 mpBase = 0;
3622 mUsed = 0;
3623 mSize = 0;
3624 }
3625
Jack Palevich303d8ff2009-06-11 19:06:24 -07003626 String(const char* item, int len, bool adopt) {
3627 if (len < 0) {
3628 len = strlen(item);
3629 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003630 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003631 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003632 mUsed = len;
3633 mSize = len + 1;
3634 } else {
3635 mpBase = 0;
3636 mUsed = 0;
3637 mSize = 0;
3638 appendBytes(item, len);
3639 }
3640 }
3641
Jack Palevich303d8ff2009-06-11 19:06:24 -07003642 String(const String& other) {
3643 mpBase = 0;
3644 mUsed = 0;
3645 mSize = 0;
3646 appendBytes(other.getUnwrapped(), other.len());
3647 }
3648
Jack Palevicheedf9d22009-06-04 16:23:40 -07003649 ~String() {
3650 if (mpBase) {
3651 free(mpBase);
3652 }
3653 }
3654
Jack Palevicha6baa232009-06-12 11:25:59 -07003655 String& operator=(const String& other) {
3656 clear();
3657 appendBytes(other.getUnwrapped(), other.len());
3658 return *this;
3659 }
3660
Jack Palevich303d8ff2009-06-11 19:06:24 -07003661 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003662 return mpBase;
3663 }
3664
Jack Palevich303d8ff2009-06-11 19:06:24 -07003665 void clear() {
3666 mUsed = 0;
3667 if (mSize > 0) {
3668 mpBase[0] = 0;
3669 }
3670 }
3671
Jack Palevicheedf9d22009-06-04 16:23:40 -07003672 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003673 appendBytes(s, strlen(s));
3674 }
3675
3676 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003677 memcpy(ensure(n), s, n + 1);
3678 }
3679
3680 void append(char c) {
3681 * ensure(1) = c;
3682 }
3683
Jack Palevich86351982009-06-30 18:09:56 -07003684 void append(String& other) {
3685 appendBytes(other.getUnwrapped(), other.len());
3686 }
3687
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003688 char* orphan() {
3689 char* result = mpBase;
3690 mpBase = 0;
3691 mUsed = 0;
3692 mSize = 0;
3693 return result;
3694 }
3695
Jack Palevicheedf9d22009-06-04 16:23:40 -07003696 void printf(const char* fmt,...) {
3697 va_list ap;
3698 va_start(ap, fmt);
3699 vprintf(fmt, ap);
3700 va_end(ap);
3701 }
3702
3703 void vprintf(const char* fmt, va_list ap) {
3704 char* temp;
3705 int numChars = vasprintf(&temp, fmt, ap);
3706 memcpy(ensure(numChars), temp, numChars+1);
3707 free(temp);
3708 }
3709
Jack Palevich303d8ff2009-06-11 19:06:24 -07003710 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003711 return mUsed;
3712 }
3713
3714 private:
3715 char* ensure(int n) {
3716 size_t newUsed = mUsed + n;
3717 if (newUsed > mSize) {
3718 size_t newSize = mSize * 2 + 10;
3719 if (newSize < newUsed) {
3720 newSize = newUsed;
3721 }
3722 mpBase = (char*) realloc(mpBase, newSize + 1);
3723 mSize = newSize;
3724 }
3725 mpBase[newUsed] = '\0';
3726 char* result = mpBase + mUsed;
3727 mUsed = newUsed;
3728 return result;
3729 }
3730
3731 char* mpBase;
3732 size_t mUsed;
3733 size_t mSize;
3734 };
3735
Jack Palevich569f1352009-06-29 14:29:08 -07003736 void internKeywords() {
3737 // Note: order has to match TOK_ constants
3738 static const char* keywords[] = {
3739 "int",
3740 "char",
3741 "void",
3742 "if",
3743 "else",
3744 "while",
3745 "break",
3746 "return",
3747 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003748 "auto",
3749 "case",
3750 "const",
3751 "continue",
3752 "default",
3753 "do",
3754 "double",
3755 "enum",
3756 "extern",
3757 "float",
3758 "goto",
3759 "long",
3760 "register",
3761 "short",
3762 "signed",
3763 "sizeof",
3764 "static",
3765 "struct",
3766 "switch",
3767 "typedef",
3768 "union",
3769 "unsigned",
3770 "volatile",
3771 "_Bool",
3772 "_Complex",
3773 "_Imaginary",
3774 "inline",
3775 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003776
3777 // predefined tokens that can also be symbols start here:
3778 "pragma",
3779 "define",
3780 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003781 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003782
Jack Palevich569f1352009-06-29 14:29:08 -07003783 for(int i = 0; keywords[i]; i++) {
3784 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003785 }
Jack Palevich569f1352009-06-29 14:29:08 -07003786 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003787
Jack Palevich36d94142009-06-08 15:55:32 -07003788 struct InputState {
3789 InputStream* pStream;
3790 int oldCh;
3791 };
3792
Jack Palevich2db168f2009-06-11 14:29:47 -07003793 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003794 void* pAddress;
3795 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003796 tokenid_t tok;
3797 size_t level;
3798 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003799 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003800 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003801 };
3802
Jack Palevich303d8ff2009-06-11 19:06:24 -07003803 class SymbolStack {
3804 public:
3805 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003806 mpArena = 0;
3807 mpTokenTable = 0;
3808 }
3809
3810 void setArena(Arena* pArena) {
3811 mpArena = pArena;
3812 }
3813
3814 void setTokenTable(TokenTable* pTokenTable) {
3815 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003816 }
3817
3818 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003819 Mark mark;
3820 mark.mArenaMark = mpArena->mark();
3821 mark.mSymbolHead = mStack.size();
3822 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003823 }
3824
3825 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003826 // Undo any shadowing that was done:
3827 Mark mark = mLevelStack.back();
3828 mLevelStack.pop_back();
3829 while (mStack.size() > mark.mSymbolHead) {
3830 VariableInfo* pV = mStack.back();
3831 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003832 if (pV->isStructTag) {
3833 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3834 } else {
3835 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3836 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003837 }
Jack Palevich569f1352009-06-29 14:29:08 -07003838 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003839 }
3840
Jack Palevich569f1352009-06-29 14:29:08 -07003841 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3842 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3843 return pV && pV->level == level();
3844 }
3845
Jack Palevich9221bcc2009-08-26 16:15:07 -07003846 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3847 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3848 return pV && pV->level == level();
3849 }
3850
Jack Palevich569f1352009-06-29 14:29:08 -07003851 VariableInfo* add(tokenid_t tok) {
3852 Token& token = (*mpTokenTable)[tok];
3853 VariableInfo* pOldV = token.mpVariableInfo;
3854 VariableInfo* pNewV =
3855 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3856 memset(pNewV, 0, sizeof(VariableInfo));
3857 pNewV->tok = tok;
3858 pNewV->level = level();
3859 pNewV->pOldDefinition = pOldV;
3860 token.mpVariableInfo = pNewV;
3861 mStack.push_back(pNewV);
3862 return pNewV;
3863 }
3864
Jack Palevich9221bcc2009-08-26 16:15:07 -07003865 VariableInfo* addStructTag(tokenid_t tok) {
3866 Token& token = (*mpTokenTable)[tok];
3867 VariableInfo* pOldS = token.mpStructInfo;
3868 VariableInfo* pNewS =
3869 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3870 memset(pNewS, 0, sizeof(VariableInfo));
3871 pNewS->tok = tok;
3872 pNewS->level = level();
3873 pNewS->isStructTag = true;
3874 pNewS->pOldDefinition = pOldS;
3875 token.mpStructInfo = pNewS;
3876 mStack.push_back(pNewS);
3877 return pNewS;
3878 }
3879
Jack Palevich86351982009-06-30 18:09:56 -07003880 VariableInfo* add(Type* pType) {
3881 VariableInfo* pVI = add(pType->id);
3882 pVI->pType = pType;
3883 return pVI;
3884 }
3885
Jack Palevich569f1352009-06-29 14:29:08 -07003886 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3887 for (size_t i = 0; i < mStack.size(); i++) {
3888 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003889 break;
3890 }
3891 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003892 }
3893
Jack Palevich303d8ff2009-06-11 19:06:24 -07003894 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003895 inline size_t level() {
3896 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003897 }
3898
Jack Palevich569f1352009-06-29 14:29:08 -07003899 struct Mark {
3900 Arena::Mark mArenaMark;
3901 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003902 };
3903
Jack Palevich569f1352009-06-29 14:29:08 -07003904 Arena* mpArena;
3905 TokenTable* mpTokenTable;
3906 Vector<VariableInfo*> mStack;
3907 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003908 };
Jack Palevich36d94142009-06-08 15:55:32 -07003909
Jack Palevich188a5a72009-10-27 17:23:20 -07003910 struct MacroState {
3911 tokenid_t name; // Name of the current macro we are expanding
3912 char* dptr; // point to macro text during macro playback
3913 int dch; // Saves old value of ch during a macro playback
3914 };
3915
3916#define MACRO_NESTING_MAX 32
3917 MacroState macroState[MACRO_NESTING_MAX];
3918 int macroLevel; // -1 means not playing any macro.
3919
Jack Palevich36d94142009-06-08 15:55:32 -07003920 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003921 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003922 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003923 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003924 int tokl; // token operator level
3925 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003926 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003927 intptr_t loc; // local variable index
3928 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003929 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003930 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003931 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003932 ACCSymbolLookupFn mpSymbolLookupFn;
3933 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003934
3935 // Arena for the duration of the compile
3936 Arena mGlobalArena;
3937 // Arena for data that's only needed when compiling a single function
3938 Arena mLocalArena;
3939
Jack Palevich2ff5c222009-07-23 15:11:22 -07003940 Arena* mpCurrentArena;
3941
Jack Palevich569f1352009-06-29 14:29:08 -07003942 TokenTable mTokenTable;
3943 SymbolStack mGlobals;
3944 SymbolStack mLocals;
3945
Jack Palevich9221bcc2009-08-26 16:15:07 -07003946 SymbolStack* mpCurrentSymbolStack;
3947
Jack Palevich40600de2009-07-01 15:32:35 -07003948 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003949 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003950 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003951 Type* mkpChar; // char
3952 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003953 Type* mkpFloat;
3954 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003955 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003956 Type* mkpIntPtr;
3957 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003958 Type* mkpFloatPtr;
3959 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003960 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003961
Jack Palevich36d94142009-06-08 15:55:32 -07003962 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003963 int mLineNumber;
3964 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003965
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003966 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003967 CodeGenerator* pGen;
3968
Jack Palevicheedf9d22009-06-04 16:23:40 -07003969 String mErrorBuf;
3970
Jack Palevicheedf9d22009-06-04 16:23:40 -07003971 String mPragmas;
3972 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003973 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003974
Jack Palevich21a15a22009-05-11 14:49:29 -07003975 static const int ALLOC_SIZE = 99999;
3976
Jack Palevich303d8ff2009-06-11 19:06:24 -07003977 static const int TOK_DUMMY = 1;
3978 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003979 static const int TOK_NUM_FLOAT = 3;
3980 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003981 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003982 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003983
3984 // 3..255 are character and/or operators
3985
Jack Palevich2db168f2009-06-11 14:29:47 -07003986 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003987 // Order has to match string list in "internKeywords".
3988 enum {
3989 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3990 TOK_INT = TOK_KEYWORD,
3991 TOK_CHAR,
3992 TOK_VOID,
3993 TOK_IF,
3994 TOK_ELSE,
3995 TOK_WHILE,
3996 TOK_BREAK,
3997 TOK_RETURN,
3998 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003999 TOK_AUTO,
4000 TOK_CASE,
4001 TOK_CONST,
4002 TOK_CONTINUE,
4003 TOK_DEFAULT,
4004 TOK_DO,
4005 TOK_DOUBLE,
4006 TOK_ENUM,
4007 TOK_EXTERN,
4008 TOK_FLOAT,
4009 TOK_GOTO,
4010 TOK_LONG,
4011 TOK_REGISTER,
4012 TOK_SHORT,
4013 TOK_SIGNED,
4014 TOK_SIZEOF,
4015 TOK_STATIC,
4016 TOK_STRUCT,
4017 TOK_SWITCH,
4018 TOK_TYPEDEF,
4019 TOK_UNION,
4020 TOK_UNSIGNED,
4021 TOK_VOLATILE,
4022 TOK__BOOL,
4023 TOK__COMPLEX,
4024 TOK__IMAGINARY,
4025 TOK_INLINE,
4026 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004027
4028 // Symbols start after keywords
4029
4030 TOK_SYMBOL,
4031 TOK_PRAGMA = TOK_SYMBOL,
4032 TOK_DEFINE,
4033 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004034 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004035
4036 static const int LOCAL = 0x200;
4037
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 /* tokens in string heap */
4039 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004040
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004041 static const int OP_INCREMENT = 0;
4042 static const int OP_DECREMENT = 1;
4043 static const int OP_MUL = 2;
4044 static const int OP_DIV = 3;
4045 static const int OP_MOD = 4;
4046 static const int OP_PLUS = 5;
4047 static const int OP_MINUS = 6;
4048 static const int OP_SHIFT_LEFT = 7;
4049 static const int OP_SHIFT_RIGHT = 8;
4050 static const int OP_LESS_EQUAL = 9;
4051 static const int OP_GREATER_EQUAL = 10;
4052 static const int OP_LESS = 11;
4053 static const int OP_GREATER = 12;
4054 static const int OP_EQUALS = 13;
4055 static const int OP_NOT_EQUALS = 14;
4056 static const int OP_LOGICAL_AND = 15;
4057 static const int OP_LOGICAL_OR = 16;
4058 static const int OP_BIT_AND = 17;
4059 static const int OP_BIT_XOR = 18;
4060 static const int OP_BIT_OR = 19;
4061 static const int OP_BIT_NOT = 20;
4062 static const int OP_LOGICAL_NOT = 21;
4063 static const int OP_COUNT = 22;
4064
4065 /* Operators are searched from front, the two-character operators appear
4066 * before the single-character operators with the same first character.
4067 * @ is used to pad out single-character operators.
4068 */
4069 static const char* operatorChars;
4070 static const char operatorLevel[];
4071
Jack Palevich569f1352009-06-29 14:29:08 -07004072 /* Called when we detect an internal problem. Does nothing in production.
4073 *
4074 */
4075 void internalError() {
4076 * (char*) 0 = 0;
4077 }
4078
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004079 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004080 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004081 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004082 internalError();
4083 }
Jack Palevich86351982009-06-30 18:09:56 -07004084 }
4085
Jack Palevich40600de2009-07-01 15:32:35 -07004086 bool isSymbol(tokenid_t t) {
4087 return t >= TOK_SYMBOL &&
4088 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4089 }
4090
4091 bool isSymbolOrKeyword(tokenid_t t) {
4092 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004093 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004094 }
4095
Jack Palevich86351982009-06-30 18:09:56 -07004096 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004097 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004098 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4099 if (pV && pV->tok != t) {
4100 internalError();
4101 }
4102 return pV;
4103 }
4104
4105 inline bool isDefined(tokenid_t t) {
4106 return t >= TOK_SYMBOL && VI(t) != 0;
4107 }
4108
Jack Palevich40600de2009-07-01 15:32:35 -07004109 const char* nameof(tokenid_t t) {
4110 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004111 return mTokenTable[t].pText;
4112 }
4113
Jack Palevich21a15a22009-05-11 14:49:29 -07004114 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004115 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004116 }
4117
4118 void inp() {
Jack Palevich188a5a72009-10-27 17:23:20 -07004119 // Close any totally empty macros. We leave them on the stack until now
4120 // so that we know which macros are being expanded when checking if the
4121 // last token in the macro is a macro that's already being expanded.
4122 while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
4123 macroLevel--;
4124 }
4125 if (macroLevel >= 0) {
4126 ch = *macroState[macroLevel].dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004127 if (ch == 0) {
Jack Palevich188a5a72009-10-27 17:23:20 -07004128 ch = macroState[macroLevel].dch;
4129 macroState[macroLevel].dptr = NULL; // This macro's done
Jack Palevich21a15a22009-05-11 14:49:29 -07004130 }
Jack Palevichdc456462009-07-16 16:50:56 -07004131 } else {
4132 if (mbBumpLine) {
4133 mLineNumber++;
4134 mbBumpLine = false;
4135 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004136 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004137 if (ch == '\n') {
4138 mbBumpLine = true;
4139 }
4140 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004141#if 0
4142 printf("ch='%c' 0x%x\n", ch, ch);
4143#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004144 }
4145
4146 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004147 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004148 }
4149
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004150 int decodeHex(int c) {
4151 if (isdigit(c)) {
4152 c -= '0';
4153 } else if (c <= 'F') {
4154 c = c - 'A' + 10;
4155 } else {
4156 c =c - 'a' + 10;
4157 }
4158 return c;
4159 }
4160
Jack Palevichb4758ff2009-06-12 12:49:14 -07004161 /* read a character constant, advances ch to after end of constant */
4162 int getq() {
4163 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004164 if (ch == '\\') {
4165 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004166 if (isoctal(ch)) {
4167 // 1 to 3 octal characters.
4168 val = 0;
4169 for(int i = 0; i < 3; i++) {
4170 if (isoctal(ch)) {
4171 val = (val << 3) + ch - '0';
4172 inp();
4173 }
4174 }
4175 return val;
4176 } else if (ch == 'x' || ch == 'X') {
4177 // N hex chars
4178 inp();
4179 if (! isxdigit(ch)) {
4180 error("'x' character escape requires at least one digit.");
4181 } else {
4182 val = 0;
4183 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004184 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004185 inp();
4186 }
4187 }
4188 } else {
4189 int val = ch;
4190 switch (ch) {
4191 case 'a':
4192 val = '\a';
4193 break;
4194 case 'b':
4195 val = '\b';
4196 break;
4197 case 'f':
4198 val = '\f';
4199 break;
4200 case 'n':
4201 val = '\n';
4202 break;
4203 case 'r':
4204 val = '\r';
4205 break;
4206 case 't':
4207 val = '\t';
4208 break;
4209 case 'v':
4210 val = '\v';
4211 break;
4212 case '\\':
4213 val = '\\';
4214 break;
4215 case '\'':
4216 val = '\'';
4217 break;
4218 case '"':
4219 val = '"';
4220 break;
4221 case '?':
4222 val = '?';
4223 break;
4224 default:
4225 error("Undefined character escape %c", ch);
4226 break;
4227 }
4228 inp();
4229 return val;
4230 }
4231 } else {
4232 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004233 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004234 return val;
4235 }
4236
4237 static bool isoctal(int ch) {
4238 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004239 }
4240
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004241 bool acceptCh(int c) {
4242 bool result = c == ch;
4243 if (result) {
4244 pdef(ch);
4245 inp();
4246 }
4247 return result;
4248 }
4249
4250 bool acceptDigitsCh() {
4251 bool result = false;
4252 while (isdigit(ch)) {
4253 result = true;
4254 pdef(ch);
4255 inp();
4256 }
4257 return result;
4258 }
4259
4260 void parseFloat() {
4261 tok = TOK_NUM_DOUBLE;
4262 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004263 if(mTokenString.len() == 0) {
4264 mTokenString.append('0');
4265 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004266 acceptCh('.');
4267 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004268 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004269 acceptCh('-') || acceptCh('+');
4270 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004271 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004272 if (ch == 'f' || ch == 'F') {
4273 tok = TOK_NUM_FLOAT;
4274 inp();
4275 } else if (ch == 'l' || ch == 'L') {
4276 inp();
4277 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004278 }
4279 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004280 char* pEnd = pText + strlen(pText);
4281 char* pEndPtr = 0;
4282 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004283 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004284 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004285 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004286 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004287 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004288 if (errno || pEndPtr != pEnd) {
4289 error("Can't parse constant: %s", pText);
4290 }
4291 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004292 }
4293
Jack Palevich188a5a72009-10-27 17:23:20 -07004294 bool currentlyBeingExpanded(tokenid_t id) {
4295 for (int i = 0; i <= macroLevel; i++) {
4296 if (macroState[macroLevel].name == id) {
4297 return true;
4298 }
4299 }
4300 return false;
4301 }
4302
Jack Palevich21a15a22009-05-11 14:49:29 -07004303 void next() {
4304 int l, a;
4305
Jack Palevich546b2242009-05-13 15:10:04 -07004306 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004307 if (ch == '#') {
4308 inp();
4309 next();
4310 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004311 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004312 } else if (tok == TOK_PRAGMA) {
4313 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004314 } else if (tok == TOK_LINE) {
4315 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004316 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004317 error("Unsupported preprocessor directive \"%s\"",
4318 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004319 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004320 }
4321 inp();
4322 }
4323 tokl = 0;
4324 tok = ch;
4325 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004326 if (isdigit(ch) || ch == '.') {
4327 // Start of a numeric constant. Could be integer, float, or
4328 // double, won't know until we look further.
4329 mTokenString.clear();
4330 pdef(ch);
4331 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004332 if (tok == '.' && !isdigit(ch)) {
4333 goto done;
4334 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004335 int base = 10;
4336 if (tok == '0') {
4337 if (ch == 'x' || ch == 'X') {
4338 base = 16;
4339 tok = TOK_NUM;
4340 tokc = 0;
4341 inp();
4342 while ( isxdigit(ch) ) {
4343 tokc = (tokc << 4) + decodeHex(ch);
4344 inp();
4345 }
4346 } else if (isoctal(ch)){
4347 base = 8;
4348 tok = TOK_NUM;
4349 tokc = 0;
4350 while ( isoctal(ch) ) {
4351 tokc = (tokc << 3) + (ch - '0');
4352 inp();
4353 }
4354 }
4355 } else if (isdigit(tok)){
4356 acceptDigitsCh();
4357 }
4358 if (base == 10) {
4359 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4360 parseFloat();
4361 } else {
4362 // It's an integer constant
4363 char* pText = mTokenString.getUnwrapped();
4364 char* pEnd = pText + strlen(pText);
4365 char* pEndPtr = 0;
4366 errno = 0;
4367 tokc = strtol(pText, &pEndPtr, base);
4368 if (errno || pEndPtr != pEnd) {
4369 error("Can't parse constant: %s %d %d", pText, base, errno);
4370 }
4371 tok = TOK_NUM;
4372 }
4373 }
4374 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004375 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004376 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004377 pdef(ch);
4378 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004379 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004380 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004381 if (! mbSuppressMacroExpansion) {
4382 // Is this a macro?
4383 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
Jack Palevich188a5a72009-10-27 17:23:20 -07004384 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
Jack Palevich815d8b82009-08-18 18:25:56 -07004385 // Yes, it is a macro
Jack Palevich188a5a72009-10-27 17:23:20 -07004386#if 0
4387 printf("Expanding macro %s -> %s",
4388 mTokenString.getUnwrapped(), pMacroDefinition);
4389#endif
4390 if (macroLevel >= MACRO_NESTING_MAX-1) {
4391 error("Too many levels of macro recursion.");
4392 } else {
4393 macroLevel++;
4394 macroState[macroLevel].name = tok;
4395 macroState[macroLevel].dptr = pMacroDefinition;
4396 macroState[macroLevel].dch = ch;
4397 inp();
4398 next();
4399 }
Jack Palevich815d8b82009-08-18 18:25:56 -07004400 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004401 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004402 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004403 inp();
4404 if (tok == '\'') {
4405 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004406 tokc = getq();
4407 if (ch != '\'') {
4408 error("Expected a ' character, got %c", ch);
4409 } else {
4410 inp();
4411 }
Jack Palevich546b2242009-05-13 15:10:04 -07004412 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004413 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004414 while (ch && ch != EOF) {
4415 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004416 inp();
4417 inp();
4418 if (ch == '/')
4419 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004420 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004421 if (ch == EOF) {
4422 error("End of file inside comment.");
4423 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004424 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004425 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004426 } else if ((tok == '/') & (ch == '/')) {
4427 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004428 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004429 inp();
4430 }
4431 inp();
4432 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004433 } else if ((tok == '-') & (ch == '>')) {
4434 inp();
4435 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004436 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004437 const char* t = operatorChars;
4438 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004439 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004440 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004441 tokl = operatorLevel[opIndex];
4442 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004443 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004444#if 0
4445 printf("%c%c -> tokl=%d tokc=0x%x\n",
4446 l, a, tokl, tokc);
4447#endif
4448 if (a == ch) {
4449 inp();
4450 tok = TOK_DUMMY; /* dummy token for double tokens */
4451 }
Jack Palevich0c017742009-07-31 12:00:39 -07004452 /* check for op=, valid for * / % + - << >> & ^ | */
4453 if (ch == '=' &&
4454 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004455 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004456 inp();
4457 tok = TOK_OP_ASSIGNMENT;
4458 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004459 break;
4460 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004461 opIndex++;
4462 }
4463 if (l == 0) {
4464 tokl = 0;
4465 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004466 }
4467 }
4468 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004469
4470 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004471#if 0
4472 {
Jack Palevich569f1352009-06-29 14:29:08 -07004473 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004474 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004475 fprintf(stderr, "%s\n", buf.getUnwrapped());
4476 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004477#endif
4478 }
4479
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004480 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004481 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004482 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004483 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004484 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004485 if (ch == '(') {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004486 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004487 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004488 }
4489 while (isspace(ch)) {
4490 inp();
4491 }
Jack Palevich569f1352009-06-29 14:29:08 -07004492 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004493 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004494 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004495 // Check for '//' comments.
4496 if (appendToValue && ch == '/') {
4497 inp();
4498 if (ch == '/') {
4499 appendToValue = false;
4500 } else {
4501 value.append('/');
4502 }
4503 }
4504 if (appendToValue && ch != EOF) {
4505 value.append(ch);
4506 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004507 inp();
4508 }
Jack Palevich569f1352009-06-29 14:29:08 -07004509 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4510 memcpy(pDefn, value.getUnwrapped(), value.len());
4511 pDefn[value.len()] = 0;
4512 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich188a5a72009-10-27 17:23:20 -07004513#if 0
4514 {
4515 String buf;
4516 decodeToken(buf, name, true);
4517 fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
4518 }
4519#endif
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004520 }
4521
Jack Palevicheedf9d22009-06-04 16:23:40 -07004522 void doPragma() {
4523 // # pragma name(val)
4524 int state = 0;
4525 while(ch != EOF && ch != '\n' && state < 10) {
4526 switch(state) {
4527 case 0:
4528 if (isspace(ch)) {
4529 inp();
4530 } else {
4531 state++;
4532 }
4533 break;
4534 case 1:
4535 if (isalnum(ch)) {
4536 mPragmas.append(ch);
4537 inp();
4538 } else if (ch == '(') {
4539 mPragmas.append(0);
4540 inp();
4541 state++;
4542 } else {
4543 state = 11;
4544 }
4545 break;
4546 case 2:
4547 if (isalnum(ch)) {
4548 mPragmas.append(ch);
4549 inp();
4550 } else if (ch == ')') {
4551 mPragmas.append(0);
4552 inp();
4553 state = 10;
4554 } else {
4555 state = 11;
4556 }
4557 break;
4558 }
4559 }
4560 if(state != 10) {
4561 error("Unexpected pragma syntax");
4562 }
4563 mPragmaStringCount += 2;
4564 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004565
Jack Palevichdc456462009-07-16 16:50:56 -07004566 void doLine() {
4567 // # line number { "filename "}
4568 next();
4569 if (tok != TOK_NUM) {
4570 error("Expected a line-number");
4571 } else {
4572 mLineNumber = tokc-1; // The end-of-line will increment it.
4573 }
4574 while(ch != EOF && ch != '\n') {
4575 inp();
4576 }
4577 }
4578
Jack Palevichac0e95e2009-05-29 13:53:44 -07004579 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004580 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004581 mErrorBuf.vprintf(fmt, ap);
4582 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004583 }
4584
Jack Palevich8b0624c2009-05-20 12:12:06 -07004585 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004586 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004587 error("'%c' expected", c);
4588 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004589 }
4590
Jack Palevich86351982009-06-30 18:09:56 -07004591 bool accept(intptr_t c) {
4592 if (tok == c) {
4593 next();
4594 return true;
4595 }
4596 return false;
4597 }
4598
Jack Palevich40600de2009-07-01 15:32:35 -07004599 bool acceptStringLiteral() {
4600 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004601 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004602 // This while loop merges multiple adjacent string constants.
4603 while (tok == '"') {
4604 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004605 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004606 }
4607 if (ch != '"') {
4608 error("Unterminated string constant.");
4609 }
4610 inp();
4611 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004612 }
Jack Palevich40600de2009-07-01 15:32:35 -07004613 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004614 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004615 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004616 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004617
4618 return true;
4619 }
4620 return false;
4621 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004622
Jack Palevichb1544ca2009-07-16 15:09:20 -07004623 void linkGlobal(tokenid_t t, bool isFunction) {
4624 VariableInfo* pVI = VI(t);
4625 void* n = NULL;
4626 if (mpSymbolLookupFn) {
4627 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4628 }
4629 if (pVI->pType == NULL) {
4630 if (isFunction) {
4631 pVI->pType = mkpIntFn;
4632 } else {
4633 pVI->pType = mkpInt;
4634 }
4635 }
4636 pVI->pAddress = n;
4637 }
4638
Jack Palevich29daf572009-07-30 19:38:55 -07004639 void unaryOrAssignment() {
4640 unary();
4641 if (accept('=')) {
4642 checkLVal();
4643 pGen->pushR0();
4644 expr();
4645 pGen->forceR0RVal();
4646 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004647 } else if (tok == TOK_OP_ASSIGNMENT) {
4648 int t = tokc;
4649 next();
4650 checkLVal();
4651 pGen->pushR0();
4652 pGen->forceR0RVal();
4653 pGen->pushR0();
4654 expr();
4655 pGen->forceR0RVal();
4656 pGen->genOp(t);
4657 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004658 }
4659 }
4660
Jack Palevich40600de2009-07-01 15:32:35 -07004661 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004662 */
Jack Palevich29daf572009-07-30 19:38:55 -07004663 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004664 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004665 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004666 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004667 if (acceptStringLiteral()) {
4668 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004669 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004670 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004671 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004672 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004673 t = tok;
4674 next();
4675 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004676 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004677 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004678 // Align to 4-byte boundary
4679 glo = (char*) (((intptr_t) glo + 3) & -4);
4680 * (float*) glo = (float) ad;
4681 pGen->loadFloat((int) glo, mkpFloat);
4682 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004683 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004684 // Align to 8-byte boundary
4685 glo = (char*) (((intptr_t) glo + 7) & -8);
4686 * (double*) glo = ad;
4687 pGen->loadFloat((int) glo, mkpDouble);
4688 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004689 } else if (c == 2) {
4690 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004691 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004692 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004693 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004694 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004695 else if (t == '+') {
4696 // ignore unary plus.
4697 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004698 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004699 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004700 } else if (c == 11) {
4701 // pre increment / pre decrement
4702 unary();
4703 doIncDec(a == OP_INCREMENT, 0);
4704 }
4705 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004706 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004707 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004708 if (pCast) {
4709 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004710 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004711 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004712 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004713 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004714 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004715 skip(')');
4716 }
4717 } else if (t == '*') {
4718 /* This is a pointer dereference.
4719 */
Jack Palevich29daf572009-07-30 19:38:55 -07004720 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004721 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004722 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004723 unary();
4724 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004725 } else if (t == EOF ) {
4726 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004727 } else if (t == ';') {
4728 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004729 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004730 // Don't have to do anything special here, the error
4731 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004732 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004733 if (!isDefined(t)) {
4734 mGlobals.add(t);
4735 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004736 }
Jack Palevich8df46192009-07-07 14:48:51 -07004737 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004738 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004739 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004740 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004741 linkGlobal(t, tok == '(');
4742 n = (intptr_t) pVI->pAddress;
4743 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004744 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004745 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004746 }
Jack Palevich29daf572009-07-30 19:38:55 -07004747 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004748 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004749 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004750 linkGlobal(t, false);
4751 n = (intptr_t) pVI->pAddress;
4752 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004753 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004754 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004755 }
Jack Palevich5b659092009-07-31 14:55:07 -07004756 }
4757 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004758 Type* pVal;
4759 ExpressionType et;
4760 if (pVI->pType->tag == TY_ARRAY) {
4761 pVal = pVI->pType;
4762 et = ET_RVALUE;
4763 } else {
4764 pVal = createPtrType(pVI->pType);
4765 et = ET_LVALUE;
4766 }
Jack Palevich5b659092009-07-31 14:55:07 -07004767 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004768 int tag = pVal->pHead->tag;
4769 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004770 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004771 }
Jack Palevich5b659092009-07-31 14:55:07 -07004772 pGen->leaR0(n, pVal, et);
4773 } else {
4774 pVI->pForward = (void*) pGen->leaForward(
4775 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004776 }
4777 }
4778 }
4779
Jack Palevich5b659092009-07-31 14:55:07 -07004780 /* Now handle postfix operators */
4781 for(;;) {
4782 if (tokl == 11) {
4783 // post inc / post dec
4784 doIncDec(tokc == OP_INCREMENT, true);
4785 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004786 } else if (accept('[')) {
4787 // Array reference
4788 pGen->forceR0RVal();
4789 pGen->pushR0();
4790 commaExpr();
4791 pGen->forceR0RVal();
4792 pGen->genOp(OP_PLUS);
4793 doPointer();
4794 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004795 } else if (accept('.')) {
4796 // struct element
4797 pGen->forceR0RVal();
4798 Type* pStruct = pGen->getR0Type();
4799 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004800 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004801 } else {
4802 error("expected a struct value to the left of '.'");
4803 }
4804 } else if (accept(TOK_OP_ARROW)) {
4805 pGen->forceR0RVal();
4806 Type* pPtr = pGen->getR0Type();
4807 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4808 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004809 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004810 } else {
4811 error("Expected a pointer to a struct to the left of '->'");
4812 }
Jack Palevich5b659092009-07-31 14:55:07 -07004813 } else if (accept('(')) {
4814 /* function call */
4815 Type* pDecl = NULL;
4816 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004817 Type* pFn = pGen->getR0Type();
Jack Palevich188a5a72009-10-27 17:23:20 -07004818 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
4819 pDecl = pFn->pHead;
4820 pGen->pushR0();
4821 Type* pArgList = pDecl->pTail;
4822 bool varArgs = pArgList == NULL;
4823 /* push args and invert order */
4824 a = pGen->beginFunctionCallArguments();
4825 int l = 0;
4826 int argCount = 0;
4827 while (tok != ')' && tok != EOF) {
4828 if (! varArgs && !pArgList) {
4829 error("Unexpected argument.");
Jack Palevich5b659092009-07-31 14:55:07 -07004830 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004831 expr();
4832 pGen->forceR0RVal();
4833 Type* pTargetType;
4834 if (pArgList) {
4835 pTargetType = pArgList->pHead;
4836 pArgList = pArgList->pTail;
4837 } else {
4838 // This is a ... function, just pass arguments in their
4839 // natural type.
4840 pTargetType = pGen->getR0Type();
4841 if (pTargetType->tag == TY_FLOAT) {
4842 pTargetType = mkpDouble;
4843 } else if (pTargetType->tag == TY_ARRAY) {
4844 // Pass arrays by pointer.
4845 pTargetType = pTargetType->pTail;
4846 }
4847 }
4848 if (pTargetType->tag == TY_VOID) {
4849 error("Can't pass void value for argument %d",
4850 argCount + 1);
4851 } else {
4852 l += pGen->storeR0ToArg(l, pTargetType);
4853 }
4854 if (accept(',')) {
4855 // fine
4856 } else if ( tok != ')') {
4857 error("Expected ',' or ')'");
4858 }
4859 argCount += 1;
Jack Palevich5b659092009-07-31 14:55:07 -07004860 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004861 if (! varArgs && pArgList) {
4862 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich5b659092009-07-31 14:55:07 -07004863 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004864 pGen->endFunctionCallArguments(pDecl, a, l);
4865 skip(')');
4866 pGen->callIndirect(l, pDecl);
4867 pGen->adjustStackAfterCall(pDecl, l, true);
4868 } else {
4869 error("Expected a function value to left of '('.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004870 }
Jack Palevich5b659092009-07-31 14:55:07 -07004871 } else {
4872 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004873 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004874 }
4875 }
4876
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004877 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004878 Type* pStructElement = lookupStructMember(pStruct, tok);
4879 if (pStructElement) {
4880 next();
4881 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4882 } else {
4883 String buf;
4884 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004885 error("Expected a struct member to the right of '%s', got %s",
4886 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004887 }
4888 }
4889
Jack Palevichaaac9282009-07-31 14:34:34 -07004890 void doIncDec(int isInc, int isPost) {
4891 // R0 already has the lval
4892 checkLVal();
4893 int lit = isInc ? 1 : -1;
4894 pGen->pushR0();
4895 pGen->loadR0FromR0();
4896 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004897 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4898 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004899 error("++/-- illegal for this type. %d", tag);
4900 }
4901 if (isPost) {
4902 pGen->over();
4903 pGen->pushR0();
4904 pGen->li(lit);
4905 pGen->genOp(OP_PLUS);
4906 pGen->storeR0ToTOS();
4907 pGen->popR0();
4908 } else {
4909 pGen->pushR0();
4910 pGen->li(lit);
4911 pGen->genOp(OP_PLUS);
4912 pGen->over();
4913 pGen->storeR0ToTOS();
4914 pGen->popR0();
4915 }
4916 }
4917
Jack Palevich47cbea92009-07-31 15:25:53 -07004918 void doPointer() {
4919 pGen->forceR0RVal();
4920 Type* pR0Type = pGen->getR0Type();
4921 if (pR0Type->tag != TY_POINTER) {
4922 error("Expected a pointer type.");
4923 } else {
4924 if (pR0Type->pHead->tag != TY_FUNC) {
4925 pGen->setR0ExpressionType(ET_LVALUE);
4926 }
4927 }
4928 }
4929
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004930 void doAddressOf() {
4931 Type* pR0 = pGen->getR0Type();
4932 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4933 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4934 error("Expected an lvalue");
4935 }
4936 Type* pR0Type = pGen->getR0Type();
4937 pGen->setR0ExpressionType(ET_RVALUE);
4938 }
4939
Jack Palevich40600de2009-07-01 15:32:35 -07004940 /* Recursive descent parser for binary operations.
4941 */
4942 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004943 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004944 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004945 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004946 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004947 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004948 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004949 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004950 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004951 t = tokc;
4952 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004953 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004954 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004955 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004956 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004957 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004958 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004959 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004960 // Check for syntax error.
4961 if (pGen->getR0Type() == NULL) {
4962 // We failed to parse a right-hand argument.
4963 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004964 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004965 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004966 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004967 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004968 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004969 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004970 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004971 }
4972 }
4973 }
4974 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004975 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004976 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004977 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004978 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004979 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004980 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004981 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004982 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004983 }
4984 }
4985 }
4986
Jack Palevich43aaee32009-07-31 14:01:37 -07004987 void commaExpr() {
4988 for(;;) {
4989 expr();
4990 if (!accept(',')) {
4991 break;
4992 }
4993 }
4994 }
4995
Jack Palevich21a15a22009-05-11 14:49:29 -07004996 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004997 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004998 }
4999
5000 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07005001 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005002 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005003 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07005004 }
5005
Jack Palevicha6baa232009-06-12 11:25:59 -07005006 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07005007 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07005008
Jack Palevich95727a02009-07-06 12:07:15 -07005009 Type* pBaseType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005010 if ((pBaseType = acceptPrimitiveType(true))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07005011 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07005012 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005013 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005014 next();
5015 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07005016 a = test_expr();
5017 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07005018 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07005019 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005020 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005021 n = pGen->gjmp(0); /* jmp */
5022 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07005023 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005024 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07005025 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005026 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005027 }
Jack Palevich546b2242009-05-13 15:10:04 -07005028 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07005029 t = tok;
5030 next();
5031 skip('(');
5032 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005033 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07005034 a = test_expr();
5035 } else {
5036 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005037 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005038 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005039 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07005040 a = 0;
5041 if (tok != ';')
5042 a = test_expr();
5043 skip(';');
5044 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005045 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005046 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005047 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005048 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005049 n = t + 4;
5050 }
5051 }
5052 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07005053 block((intptr_t) &a, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005054 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005055 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005056 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005057 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005058 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005059 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005060 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005061 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07005062 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005063 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005064 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005065 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005066 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005067 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005068 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005069 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005070 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005071 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005072 if (pReturnType->tag == TY_VOID) {
5073 error("Must not return a value from a void function");
5074 } else {
5075 pGen->convertR0(pReturnType);
5076 }
5077 } else {
5078 if (pReturnType->tag != TY_VOID) {
5079 error("Must specify a value here");
5080 }
Jack Palevich8df46192009-07-07 14:48:51 -07005081 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005082 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005083 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005084 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07005085 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005086 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005087 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005088 }
5089 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005090
Jack Palevicha8f427f2009-07-13 18:40:08 -07005091 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005092 if (a == b) {
5093 return true;
5094 }
5095 if (a == NULL || b == NULL) {
5096 return false;
5097 }
5098 TypeTag at = a->tag;
5099 if (at != b->tag) {
5100 return false;
5101 }
5102 if (at == TY_POINTER) {
5103 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005104 } else if (at == TY_ARRAY) {
5105 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005106 } else if (at == TY_FUNC || at == TY_PARAM) {
5107 return typeEqual(a->pHead, b->pHead)
5108 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005109 } else if (at == TY_STRUCT) {
5110 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005111 }
5112 return true;
5113 }
5114
Jack Palevich2ff5c222009-07-23 15:11:22 -07005115 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005116 assert(tag >= TY_UNKNOWN && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005117 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005118 memset(pType, 0, sizeof(*pType));
Jack Palevichee1f8292009-10-28 16:10:17 -07005119 pType->storageClass = SC_DEFAULT;
Jack Palevich86351982009-06-30 18:09:56 -07005120 pType->tag = tag;
5121 pType->pHead = pHead;
5122 pType->pTail = pTail;
5123 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005124 }
5125
Jack Palevich2ff5c222009-07-23 15:11:22 -07005126 Type* createPtrType(Type* pType) {
5127 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005128 }
5129
5130 /**
5131 * Try to print a type in declaration order
5132 */
Jack Palevich86351982009-06-30 18:09:56 -07005133 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005134 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005135 if (pType == NULL) {
5136 buffer.appendCStr("null");
5137 return;
5138 }
Jack Palevich3f226492009-07-02 14:46:19 -07005139 decodeTypeImp(buffer, pType);
5140 }
5141
5142 void decodeTypeImp(String& buffer, Type* pType) {
5143 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005144 decodeId(buffer, pType->id);
5145 decodeTypeImpPostfix(buffer, pType);
5146 }
Jack Palevich3f226492009-07-02 14:46:19 -07005147
Jack Palevich9221bcc2009-08-26 16:15:07 -07005148 void decodeId(String& buffer, tokenid_t id) {
5149 if (id) {
5150 String temp;
5151 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005152 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005153 }
Jack Palevich3f226492009-07-02 14:46:19 -07005154 }
5155
5156 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5157 TypeTag tag = pType->tag;
5158
Jack Palevich9221bcc2009-08-26 16:15:07 -07005159 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005160 switch (tag) {
5161 case TY_INT:
5162 buffer.appendCStr("int");
5163 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005164 case TY_SHORT:
5165 buffer.appendCStr("short");
5166 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005167 case TY_CHAR:
5168 buffer.appendCStr("char");
5169 break;
5170 case TY_VOID:
5171 buffer.appendCStr("void");
5172 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005173 case TY_FLOAT:
5174 buffer.appendCStr("float");
5175 break;
5176 case TY_DOUBLE:
5177 buffer.appendCStr("double");
5178 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005179 case TY_STRUCT:
5180 {
5181 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5182 buffer.appendCStr(isStruct ? "struct" : "union");
5183 if (pType->pHead && pType->pHead->structTag) {
5184 buffer.append(' ');
5185 decodeId(buffer, pType->pHead->structTag);
5186 }
5187 }
5188 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005189 default:
5190 break;
5191 }
Jack Palevich86351982009-06-30 18:09:56 -07005192 buffer.append(' ');
5193 }
Jack Palevich3f226492009-07-02 14:46:19 -07005194
5195 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005196 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005197 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005198 case TY_SHORT:
5199 break;
Jack Palevich86351982009-06-30 18:09:56 -07005200 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005201 break;
5202 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005203 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005204 case TY_FLOAT:
5205 break;
5206 case TY_DOUBLE:
5207 break;
Jack Palevich86351982009-06-30 18:09:56 -07005208 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005209 decodeTypeImpPrefix(buffer, pType->pHead);
5210 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5211 buffer.append('(');
5212 }
5213 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005214 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005215 case TY_ARRAY:
5216 decodeTypeImpPrefix(buffer, pType->pHead);
5217 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005218 case TY_STRUCT:
5219 break;
Jack Palevich86351982009-06-30 18:09:56 -07005220 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005221 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005222 break;
5223 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005224 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005225 break;
5226 default:
5227 String temp;
5228 temp.printf("Unknown tag %d", pType->tag);
5229 buffer.append(temp);
5230 break;
5231 }
Jack Palevich3f226492009-07-02 14:46:19 -07005232 }
5233
5234 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5235 TypeTag tag = pType->tag;
5236
5237 switch(tag) {
5238 case TY_POINTER:
5239 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5240 buffer.append(')');
5241 }
5242 decodeTypeImpPostfix(buffer, pType->pHead);
5243 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005244 case TY_ARRAY:
5245 {
5246 String temp;
5247 temp.printf("[%d]", pType->length);
5248 buffer.append(temp);
5249 }
5250 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005251 case TY_STRUCT:
5252 if (pType->pHead->length >= 0) {
5253 buffer.appendCStr(" {");
5254 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5255 decodeTypeImp(buffer, pArg->pHead);
5256 buffer.appendCStr(";");
5257 }
5258 buffer.append('}');
5259 }
5260 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005261 case TY_FUNC:
5262 buffer.append('(');
5263 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5264 decodeTypeImp(buffer, pArg);
5265 if (pArg->pTail) {
5266 buffer.appendCStr(", ");
5267 }
5268 }
5269 buffer.append(')');
5270 break;
5271 default:
5272 break;
Jack Palevich86351982009-06-30 18:09:56 -07005273 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005274 }
5275
Jack Palevich86351982009-06-30 18:09:56 -07005276 void printType(Type* pType) {
5277 String buffer;
5278 decodeType(buffer, pType);
5279 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005280 }
5281
Jack Palevichee1f8292009-10-28 16:10:17 -07005282 void insertTypeSpecifier(Type** ppType, TypeTag tag) {
5283 if (! *ppType) {
5284 *ppType = createType(tag, NULL, NULL);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005285 } else {
Jack Palevichee1f8292009-10-28 16:10:17 -07005286 if ((*ppType)->tag != TY_UNKNOWN) {
5287 error("Only one type specifier allowed.");
5288 } else {
5289 (*ppType)->tag = tag;
5290 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005291 }
Jack Palevichee1f8292009-10-28 16:10:17 -07005292 }
5293
5294 void insertStorageClass(Type** ppType, StorageClass storageClass) {
5295 if (! *ppType) {
5296 *ppType = createType(TY_UNKNOWN, NULL, NULL);
5297 }
5298 if ((*ppType)->storageClass != SC_DEFAULT) {
5299 error("Only one storage class allowed.");
5300 } else {
5301 (*ppType)->storageClass = storageClass;
5302 }
5303 }
5304
5305 Type* acceptPrimitiveType(bool allowStorageClass) {
5306 Type* pType = NULL;
5307 for (bool keepGoing = true; keepGoing;) {
5308 switch(tok) {
5309 case TOK_AUTO:
5310 insertStorageClass(&pType, SC_AUTO);
5311 break;
5312 case TOK_REGISTER:
5313 insertStorageClass(&pType, SC_REGISTER);
5314 break;
5315 case TOK_STATIC:
5316 insertStorageClass(&pType, SC_STATIC);
5317 break;
5318 case TOK_EXTERN:
5319 insertStorageClass(&pType, SC_EXTERN);
5320 break;
5321 case TOK_TYPEDEF:
5322 insertStorageClass(&pType, SC_TYPEDEF);
5323 break;
5324 case TOK_INT:
5325 insertTypeSpecifier(&pType, TY_INT);
5326 break;
5327 case TOK_SHORT:
5328 insertTypeSpecifier(&pType, TY_SHORT);
5329 break;
5330 case TOK_CHAR:
5331 insertTypeSpecifier(&pType, TY_CHAR);
5332 break;
5333 case TOK_VOID:
5334 insertTypeSpecifier(&pType, TY_VOID);
5335 break;
5336 case TOK_FLOAT:
5337 insertTypeSpecifier(&pType, TY_FLOAT);
5338 break;
5339 case TOK_DOUBLE:
5340 insertTypeSpecifier(&pType, TY_DOUBLE);
5341 break;
5342 case TOK_STRUCT:
5343 case TOK_UNION:
5344 {
5345 insertTypeSpecifier(&pType, TY_STRUCT);
5346 bool isStruct = (tok == TOK_STRUCT);
5347 next();
5348 pType = acceptStruct(pType, isStruct);
5349 keepGoing = false;
5350 }
5351 break;
5352 default:
5353 // Is it a typedef?
5354 if (isSymbol(tok)) {
5355 VariableInfo* pV = VI(tok);
5356 if (pV && pV->pType->storageClass == SC_TYPEDEF) {
5357 if (! pType) {
5358 pType = createType(TY_UNKNOWN, NULL, NULL);
5359 }
5360 StorageClass storageClass = pType->storageClass;
5361 *pType = *pV->pType;
5362 pType->storageClass = storageClass;
5363 } else {
5364 keepGoing = false;
5365 }
5366 } else {
5367 keepGoing = false;
5368 }
5369 }
5370 if (keepGoing) {
5371 next();
5372 }
5373 }
5374 if (pType) {
5375 if (pType->tag == TY_UNKNOWN) {
5376 pType->tag = TY_INT;
5377 }
5378 if (allowStorageClass) {
5379 switch(pType->storageClass) {
5380 case SC_AUTO: error("auto not supported."); break;
5381 case SC_REGISTER: error("register not supported."); break;
5382 case SC_STATIC: error("static not supported."); break;
5383 case SC_EXTERN: error("extern not supported."); break;
5384 default: break;
5385 }
5386 } else {
5387 if (pType->storageClass != SC_DEFAULT) {
5388 error("An explicit storage class is not allowed in this type declaration");
5389 }
5390 }
5391 }
Jack Palevich86351982009-06-30 18:09:56 -07005392 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005393 }
5394
Jack Palevichee1f8292009-10-28 16:10:17 -07005395 Type* acceptStruct(Type* pStructType, bool isStruct) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005396 tokenid_t structTag = acceptSymbol();
5397 bool isDeclaration = accept('{');
5398 bool fail = false;
5399
Jack Palevich9221bcc2009-08-26 16:15:07 -07005400 if (structTag) {
5401 Token* pToken = &mTokenTable[structTag];
5402 VariableInfo* pStructInfo = pToken->mpStructInfo;
5403 bool needToDeclare = !pStructInfo;
5404 if (pStructInfo) {
5405 if (isDeclaration) {
5406 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5407 if (pStructInfo->pType->pHead->length == -1) {
5408 // we're filling in a forward declaration.
5409 needToDeclare = false;
5410 } else {
5411 error("A struct with the same name is already defined at this level.");
5412 fail = true;
5413 }
5414 } else {
5415 needToDeclare = true;
5416 }
5417 }
5418 if (!fail) {
5419 assert(pStructInfo->isStructTag);
5420 pStructType->pHead = pStructInfo->pType;
5421 pStructType->pTail = pStructType->pHead->pTail;
5422 }
5423 }
5424
5425 if (needToDeclare) {
5426 // This is a new struct name
5427 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
Jack Palevichee1f8292009-10-28 16:10:17 -07005428 StorageClass storageClass = pStructType->storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005429 pStructType = createType(TY_STRUCT, NULL, NULL);
5430 pStructType->structTag = structTag;
5431 pStructType->pHead = pStructType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005432 pStructType->storageClass = storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005433 if (! isDeclaration) {
5434 // A forward declaration
5435 pStructType->length = -1;
5436 }
5437 pToken->mpStructInfo->pType = pStructType;
5438 }
5439 } else {
5440 // An anonymous struct
5441 pStructType->pHead = pStructType;
5442 }
5443
5444 if (isDeclaration) {
5445 size_t offset = 0;
5446 size_t structSize = 0;
5447 size_t structAlignment = 0;
5448 Type** pParamHolder = & pStructType->pHead->pTail;
5449 while (tok != '}' && tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005450 Type* pPrimitiveType = expectPrimitiveType(false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005451 if (pPrimitiveType) {
5452 while (tok != ';' && tok != EOF) {
5453 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5454 if (!pItem) {
5455 break;
5456 }
5457 if (lookupStructMember(pStructType, pItem->id)) {
5458 String buf;
5459 decodeToken(buf, pItem->id, false);
5460 error("Duplicate struct member %s", buf.getUnwrapped());
5461 }
5462 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5463 size_t alignment = pGen->alignmentOf(pItem);
5464 if (alignment > structAlignment) {
5465 structAlignment = alignment;
5466 }
5467 size_t alignmentMask = alignment - 1;
5468 offset = (offset + alignmentMask) & ~alignmentMask;
5469 pStructElement->length = offset;
5470 size_t size = pGen->sizeOf(pItem);
5471 if (isStruct) {
5472 offset += size;
5473 structSize = offset;
5474 } else {
5475 if (size >= structSize) {
5476 structSize = size;
5477 }
5478 }
5479 *pParamHolder = pStructElement;
5480 pParamHolder = &pStructElement->pTail;
5481 accept(',');
5482 }
5483 skip(';');
5484 } else {
5485 // Some sort of syntax error, skip token and keep trying
5486 next();
5487 }
5488 }
5489 if (!fail) {
5490 pStructType->pHead->length = structSize;
5491 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5492 }
5493 skip('}');
5494 }
5495 if (fail) {
5496 pStructType = NULL;
5497 }
5498 return pStructType;
5499 }
5500
5501 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5502 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5503 if (pStructElement->pHead->id == memberId) {
5504 return pStructElement;
5505 }
5506 }
5507 return NULL;
5508 }
5509
Jack Palevich2ff5c222009-07-23 15:11:22 -07005510 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005511 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005512 bool reportFailure = false;
Jack Palevichee1f8292009-10-28 16:10:17 -07005513 StorageClass storageClass = pType->storageClass;
Jack Palevich3f226492009-07-02 14:46:19 -07005514 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005515 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005516 if (declName) {
5517 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005518 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005519 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005520 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005521 pType->id = declName;
Jack Palevichee1f8292009-10-28 16:10:17 -07005522 pType->storageClass = storageClass;
Jack Palevichb6154502009-08-04 14:56:09 -07005523 } else if (nameRequired) {
5524 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005525 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005526#if 0
5527 fprintf(stderr, "Parsed a declaration: ");
5528 printType(pType);
5529#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005530 if (reportFailure) {
5531 return NULL;
5532 }
Jack Palevich86351982009-06-30 18:09:56 -07005533 return pType;
5534 }
5535
Jack Palevich2ff5c222009-07-23 15:11:22 -07005536 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005537 bool nameRequired = pBaseType->tag != TY_STRUCT;
5538 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005539 if (! pType) {
5540 error("Expected a declaration");
5541 }
5542 return pType;
5543 }
5544
Jack Palevich3f226492009-07-02 14:46:19 -07005545 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005546 Type* acceptCastTypeDeclaration() {
Jack Palevichee1f8292009-10-28 16:10:17 -07005547 Type* pType = acceptPrimitiveType(false);
Jack Palevich3f226492009-07-02 14:46:19 -07005548 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005549 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005550 }
Jack Palevich86351982009-06-30 18:09:56 -07005551 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005552 }
5553
Jack Palevich2ff5c222009-07-23 15:11:22 -07005554 Type* expectCastTypeDeclaration() {
5555 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005556 if (! pType) {
5557 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005558 }
Jack Palevich3f226492009-07-02 14:46:19 -07005559 return pType;
5560 }
5561
5562 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005563 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005564 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005565 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005566 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005567 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005568 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005569 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005570 return pType;
5571 }
5572
5573 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005574 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005575 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005576 // direct-dcl :
5577 // name
5578 // (dcl)
5579 // direct-dcl()
5580 // direct-dcl[]
5581 Type* pNewHead = NULL;
5582 if (accept('(')) {
5583 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005584 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005585 skip(')');
5586 } else if ((declName = acceptSymbol()) != 0) {
5587 if (nameAllowed == false && declName) {
5588 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005589 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005590 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005591 } else if (nameRequired && ! declName) {
5592 String temp;
5593 decodeToken(temp, tok, true);
5594 error("Expected name. Got %s", temp.getUnwrapped());
5595 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005596 }
Jack Palevichb6154502009-08-04 14:56:09 -07005597 for(;;) {
5598 if (accept('(')) {
5599 // Function declaration
5600 Type* pTail = acceptArgs(nameAllowed);
5601 pType = createType(TY_FUNC, pType, pTail);
5602 skip(')');
5603 } if (accept('[')) {
5604 if (tok != ']') {
5605 if (tok != TOK_NUM || tokc <= 0) {
5606 error("Expected positive integer constant");
5607 } else {
5608 Type* pDecayType = createPtrType(pType);
5609 pType = createType(TY_ARRAY, pType, pDecayType);
5610 pType->length = tokc;
5611 }
5612 next();
5613 }
5614 skip(']');
5615 } else {
5616 break;
5617 }
Jack Palevich86351982009-06-30 18:09:56 -07005618 }
Jack Palevich3f226492009-07-02 14:46:19 -07005619
5620 if (pNewHead) {
5621 Type* pA = pNewHead;
5622 while (pA->pHead) {
5623 pA = pA->pHead;
5624 }
5625 pA->pHead = pType;
5626 pType = pNewHead;
5627 }
Jack Palevich86351982009-06-30 18:09:56 -07005628 return pType;
5629 }
5630
Jack Palevich2ff5c222009-07-23 15:11:22 -07005631 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005632 Type* pHead = NULL;
5633 Type* pTail = NULL;
5634 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005635 Type* pBaseArg = acceptPrimitiveType(false);
Jack Palevich86351982009-06-30 18:09:56 -07005636 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005637 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005638 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005639 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005640 if (!pHead) {
5641 pHead = pParam;
5642 pTail = pParam;
5643 } else {
5644 pTail->pTail = pParam;
5645 pTail = pParam;
5646 }
5647 }
5648 }
5649 if (! accept(',')) {
5650 break;
5651 }
5652 }
5653 return pHead;
5654 }
5655
Jack Palevichee1f8292009-10-28 16:10:17 -07005656 Type* expectPrimitiveType(bool allowStorageClass) {
5657 Type* pType = acceptPrimitiveType(allowStorageClass);
Jack Palevich86351982009-06-30 18:09:56 -07005658 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005659 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005660 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005661 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005662 }
Jack Palevich86351982009-06-30 18:09:56 -07005663 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005664 }
5665
Jack Palevichb5e33312009-07-30 19:06:34 -07005666 void checkLVal() {
5667 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005668 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005669 }
5670 }
5671
Jack Palevich86351982009-06-30 18:09:56 -07005672 void addGlobalSymbol(Type* pDecl) {
5673 tokenid_t t = pDecl->id;
5674 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005675 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005676 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005677 }
Jack Palevich86351982009-06-30 18:09:56 -07005678 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005679 }
5680
Jack Palevich86351982009-06-30 18:09:56 -07005681 void reportDuplicate(tokenid_t t) {
5682 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005683 }
5684
Jack Palevich86351982009-06-30 18:09:56 -07005685 void addLocalSymbol(Type* pDecl) {
5686 tokenid_t t = pDecl->id;
5687 if (mLocals.isDefinedAtCurrentLevel(t)) {
5688 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005689 }
Jack Palevich86351982009-06-30 18:09:56 -07005690 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005691 }
5692
Jack Palevich61de31f2009-09-08 11:06:40 -07005693 bool checkUndeclaredStruct(Type* pBaseType) {
5694 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5695 String temp;
5696 decodeToken(temp, pBaseType->structTag, false);
5697 error("Undeclared struct %s", temp.getUnwrapped());
5698 return true;
5699 }
5700 return false;
5701 }
5702
Jack Palevich95727a02009-07-06 12:07:15 -07005703 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005704 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005705
Jack Palevich95727a02009-07-06 12:07:15 -07005706 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005707 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005708 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005709 if (!pDecl) {
5710 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005711 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005712 if (!pDecl->id) {
5713 break;
5714 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005715 if (checkUndeclaredStruct(pDecl)) {
5716 break;
5717 }
Jack Palevich86351982009-06-30 18:09:56 -07005718 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005719 if (pDecl->tag == TY_FUNC) {
5720 if (tok == '{') {
5721 error("Nested functions are not allowed. Did you forget a '}' ?");
5722 break;
5723 }
5724 // Else it's a forward declaration of a function.
Jack Palevichee1f8292009-10-28 16:10:17 -07005725 } else if (pDecl->storageClass != SC_TYPEDEF) {
Jack Palevich1c60e462009-09-18 15:03:03 -07005726 int variableAddress = 0;
5727 size_t alignment = pGen->alignmentOf(pDecl);
5728 assert(alignment > 0);
5729 size_t alignmentMask = ~ (alignment - 1);
5730 size_t sizeOf = pGen->sizeOf(pDecl);
5731 assert(sizeOf > 0);
5732 loc = (loc + alignment - 1) & alignmentMask;
5733 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5734 loc = loc + alignedSize;
5735 variableAddress = -loc;
5736 VI(pDecl->id)->pAddress = (void*) variableAddress;
5737 if (accept('=')) {
5738 /* assignment */
5739 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5740 pGen->pushR0();
5741 expr();
5742 pGen->forceR0RVal();
5743 pGen->storeR0ToTOS();
5744 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005745 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005746 if (tok == ',')
5747 next();
5748 }
5749 skip(';');
Jack Palevichee1f8292009-10-28 16:10:17 -07005750 pBaseType = acceptPrimitiveType(true);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005751 }
5752 }
5753
Jack Palevichf1728be2009-06-12 13:53:51 -07005754 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005755 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005756 }
5757
Jack Palevich37c54bd2009-07-14 18:35:36 -07005758 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005759 if (token == EOF ) {
5760 buffer.printf("EOF");
5761 } else if (token == TOK_NUM) {
Jack Palevich188a5a72009-10-27 17:23:20 -07005762 buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
5763 } else if (token == TOK_NUM_FLOAT) {
5764 buffer.printf("numeric constant float %g", tokd);
5765 } else if (token == TOK_NUM_DOUBLE) {
5766 buffer.printf("numeric constant double %g", tokd);
5767 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005768 if (token < 32) {
5769 buffer.printf("'\\x%02x'", token);
5770 } else {
5771 buffer.printf("'%c'", token);
5772 }
Jack Palevich569f1352009-06-29 14:29:08 -07005773 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005774 if (quote) {
5775 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5776 buffer.printf("keyword \"%s\"", nameof(token));
5777 } else {
5778 buffer.printf("symbol \"%s\"", nameof(token));
5779 }
5780 } else {
5781 buffer.printf("%s", nameof(token));
5782 }
Jack Palevich569f1352009-06-29 14:29:08 -07005783 }
5784 }
5785
Jack Palevich9221bcc2009-08-26 16:15:07 -07005786 void printToken(tokenid_t token) {
5787 String buffer;
5788 decodeToken(buffer, token, true);
5789 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5790 }
5791
Jack Palevich40600de2009-07-01 15:32:35 -07005792 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005793 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005794 if (!result) {
5795 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005796 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005797 error("Expected symbol. Got %s", temp.getUnwrapped());
5798 }
5799 return result;
5800 }
5801
Jack Palevich86351982009-06-30 18:09:56 -07005802 tokenid_t acceptSymbol() {
5803 tokenid_t result = 0;
5804 if (tok >= TOK_SYMBOL) {
5805 result = tok;
5806 next();
Jack Palevich86351982009-06-30 18:09:56 -07005807 }
5808 return result;
5809 }
5810
Jack Palevichb7c81e92009-06-04 19:56:13 -07005811 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005812 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005813 while (tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005814 Type* pBaseType = expectPrimitiveType(true);
Jack Palevich86351982009-06-30 18:09:56 -07005815 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005816 break;
5817 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005818 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005819 if (!pDecl) {
5820 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005821 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005822 if (!pDecl->id) {
5823 skip(';');
5824 continue;
5825 }
5826
Jack Palevich61de31f2009-09-08 11:06:40 -07005827 if (checkUndeclaredStruct(pDecl)) {
5828 skip(';');
5829 continue;
5830 }
Jack Palevich86351982009-06-30 18:09:56 -07005831 if (! isDefined(pDecl->id)) {
5832 addGlobalSymbol(pDecl);
5833 }
5834 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005835 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005836 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005837 }
Jack Palevich86351982009-06-30 18:09:56 -07005838 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005839 // it's a variable declaration
5840 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005841 if (pDecl->storageClass == SC_TYPEDEF) {
5842 // Do not allocate storage.
5843 } else {
5844 if (name && !name->pAddress) {
5845 name->pAddress = (int*) allocGlobalSpace(
5846 pGen->alignmentOf(name->pType),
5847 pGen->sizeOf(name->pType));
5848 }
5849 if (accept('=')) {
5850 if (tok == TOK_NUM) {
5851 if (name) {
5852 * (int*) name->pAddress = tokc;
5853 }
5854 next();
5855 } else {
5856 error("Expected an integer constant");
Jack Palevichd7461a72009-06-12 14:26:58 -07005857 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005858 }
5859 }
Jack Palevich86351982009-06-30 18:09:56 -07005860 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005861 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005862 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005863 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005864 if (!pDecl) {
5865 break;
5866 }
5867 if (! isDefined(pDecl->id)) {
5868 addGlobalSymbol(pDecl);
5869 }
5870 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005871 }
5872 skip(';');
5873 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005874 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005875 if (accept(';')) {
5876 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005877 } else if (tok != '{') {
5878 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005879 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005880 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005881 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005882 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005883 /* patch forward references */
5884 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005885 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005886 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005887 }
5888 // Calculate stack offsets for parameters
5889 mLocals.pushLevel();
5890 intptr_t a = 8;
5891 int argCount = 0;
5892 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5893 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005894 if (pArg->id) {
5895 addLocalSymbol(pArg);
5896 }
Jack Palevich95727a02009-07-06 12:07:15 -07005897 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005898 Type* pPassingType = passingType(pArg);
5899 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005900 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005901 if (pArg->id) {
5902 VI(pArg->id)->pAddress = (void*) a;
5903 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005904 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005905 argCount++;
5906 }
5907 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005908 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005909 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005910 block(0, true);
5911 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005912 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005913 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005914 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005915 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005916 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005917 }
5918 }
5919 }
5920
Jack Palevich9221bcc2009-08-26 16:15:07 -07005921 Type* passingType(Type* pType) {
5922 switch (pType->tag) {
5923 case TY_CHAR:
5924 case TY_SHORT:
5925 return mkpInt;
5926 default:
5927 return pType;
5928 }
5929 }
5930
Jack Palevich9cbd2262009-07-08 16:48:41 -07005931 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5932 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5933 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005934 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005935 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005936 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005937 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005938 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005939 char* result = (char*) base;
5940 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005941 return result;
5942 }
5943
Jack Palevich21a15a22009-05-11 14:49:29 -07005944 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005945 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005946 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005947 pGlobalBase = 0;
5948 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005949 if (pGen) {
5950 delete pGen;
5951 pGen = 0;
5952 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005953 if (pCodeBuf) {
5954 delete pCodeBuf;
5955 pCodeBuf = 0;
5956 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005957 if (file) {
5958 delete file;
5959 file = 0;
5960 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005961 }
5962
Jack Palevich8c246a92009-07-14 21:14:10 -07005963 // One-time initialization, when class is constructed.
5964 void init() {
5965 mpSymbolLookupFn = 0;
5966 mpSymbolLookupContext = 0;
5967 }
5968
Jack Palevich21a15a22009-05-11 14:49:29 -07005969 void clear() {
5970 tok = 0;
5971 tokc = 0;
5972 tokl = 0;
5973 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005974 rsym = 0;
5975 loc = 0;
5976 glo = 0;
Jack Palevich188a5a72009-10-27 17:23:20 -07005977 macroLevel = -1;
Jack Palevich21a15a22009-05-11 14:49:29 -07005978 file = 0;
5979 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005980 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005981 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005982 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005983 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005984 mLineNumber = 1;
5985 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005986 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005987 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005988
Jack Palevich22305132009-05-13 10:58:45 -07005989 void setArchitecture(const char* architecture) {
5990 delete pGen;
5991 pGen = 0;
5992
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005993 delete pCodeBuf;
5994 pCodeBuf = new CodeBuf();
5995
Jack Palevich22305132009-05-13 10:58:45 -07005996 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005997#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005998 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005999 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006000 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07006001 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006002#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07006003#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006004 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006005 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07006006 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006007#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07006008 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006009 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07006010 }
6011 }
6012
6013 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006014#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07006015 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006016 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07006017#elif defined(DEFAULT_X86_CODEGEN)
6018 pGen = new X86CodeGenerator();
6019#endif
6020 }
6021 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006022 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07006023 } else {
6024 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07006025 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07006026 }
6027 }
6028
Jack Palevich77ae76e2009-05-10 19:59:24 -07006029public:
Jack Palevich22305132009-05-13 10:58:45 -07006030 struct args {
6031 args() {
6032 architecture = 0;
6033 }
6034 const char* architecture;
6035 };
6036
Jack Paleviche7b59062009-05-19 17:12:17 -07006037 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07006038 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07006039 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006040 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006041
Jack Paleviche7b59062009-05-19 17:12:17 -07006042 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07006043 cleanup();
6044 }
6045
Jack Palevich8c246a92009-07-14 21:14:10 -07006046 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6047 mpSymbolLookupFn = pFn;
6048 mpSymbolLookupContext = pContext;
6049 }
6050
Jack Palevich1cdef202009-05-22 12:06:27 -07006051 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006052 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07006053
Jack Palevich2ff5c222009-07-23 15:11:22 -07006054 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07006055 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07006056 cleanup();
6057 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07006058 mTokenTable.setArena(&mGlobalArena);
6059 mGlobals.setArena(&mGlobalArena);
6060 mGlobals.setTokenTable(&mTokenTable);
6061 mLocals.setArena(&mLocalArena);
6062 mLocals.setTokenTable(&mTokenTable);
6063
6064 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07006065 setArchitecture(NULL);
6066 if (!pGen) {
6067 return -1;
6068 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07006069#ifdef PROVIDE_TRACE_CODEGEN
6070 pGen = new TraceCodeGenerator(pGen);
6071#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006072 pGen->setErrorSink(this);
6073
6074 if (pCodeBuf) {
6075 pCodeBuf->init(ALLOC_SIZE);
6076 }
6077 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07006078 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07006079 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
6080 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07006081 inp();
6082 next();
6083 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07006084 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07006085 result = pGen->finishCompile();
6086 if (result == 0) {
6087 if (mErrorBuf.len()) {
6088 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006089 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07006090 }
Jack Palevichce105a92009-07-16 14:30:33 -07006091 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006092 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07006093 }
6094
Jack Palevich86351982009-06-30 18:09:56 -07006095 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07006096 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07006097 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07006098 mkpChar = createType(TY_CHAR, NULL, NULL);
6099 mkpVoid = createType(TY_VOID, NULL, NULL);
6100 mkpFloat = createType(TY_FLOAT, NULL, NULL);
6101 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
6102 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
6103 mkpIntPtr = createPtrType(mkpInt);
6104 mkpCharPtr = createPtrType(mkpChar);
6105 mkpFloatPtr = createPtrType(mkpFloat);
6106 mkpDoublePtr = createPtrType(mkpDouble);
6107 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07006108 }
6109
Jack Palevicha6baa232009-06-12 11:25:59 -07006110 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07006111 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07006112 }
6113
Jack Palevich569f1352009-06-29 14:29:08 -07006114 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006115 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07006116 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07006117 }
6118
Jack Palevich569f1352009-06-29 14:29:08 -07006119 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006120 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07006121 error("Undefined forward reference: %s",
6122 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07006123 }
6124 return true;
6125 }
6126
Jack Palevich1cdef202009-05-22 12:06:27 -07006127 /* Look through the symbol table to find a symbol.
6128 * If found, return its value.
6129 */
6130 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07006131 if (mCompileResult == 0) {
6132 tokenid_t tok = mTokenTable.intern(name, strlen(name));
6133 VariableInfo* pVariableInfo = VI(tok);
6134 if (pVariableInfo) {
6135 return pVariableInfo->pAddress;
6136 }
Jack Palevich1cdef202009-05-22 12:06:27 -07006137 }
6138 return NULL;
6139 }
6140
Jack Palevicheedf9d22009-06-04 16:23:40 -07006141 void getPragmas(ACCsizei* actualStringCount,
6142 ACCsizei maxStringCount, ACCchar** strings) {
6143 int stringCount = mPragmaStringCount;
6144 if (actualStringCount) {
6145 *actualStringCount = stringCount;
6146 }
6147 if (stringCount > maxStringCount) {
6148 stringCount = maxStringCount;
6149 }
6150 if (strings) {
6151 char* pPragmas = mPragmas.getUnwrapped();
6152 while (stringCount-- > 0) {
6153 *strings++ = pPragmas;
6154 pPragmas += strlen(pPragmas) + 1;
6155 }
6156 }
6157 }
6158
Jack Palevichd5315572009-09-09 13:19:34 -07006159 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006160 *base = pCodeBuf->getBase();
6161 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006162 }
6163
Jack Palevichac0e95e2009-05-29 13:53:44 -07006164 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006165 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006166 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006167};
6168
Jack Paleviche7b59062009-05-19 17:12:17 -07006169const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006170 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6171
Jack Paleviche7b59062009-05-19 17:12:17 -07006172const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006173 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6174 5, 5, /* ==, != */
6175 9, 10, /* &&, || */
6176 6, 7, 8, /* & ^ | */
6177 2, 2 /* ~ ! */
6178 };
6179
Jack Palevich8b0624c2009-05-20 12:12:06 -07006180#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006181const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006182 0x1, // ++
6183 0xff, // --
6184 0xc1af0f, // *
6185 0xf9f79991, // /
6186 0xf9f79991, // % (With manual assist to swap results)
6187 0xc801, // +
6188 0xd8f7c829, // -
6189 0xe0d391, // <<
6190 0xf8d391, // >>
6191 0xe, // <=
6192 0xd, // >=
6193 0xc, // <
6194 0xf, // >
6195 0x4, // ==
6196 0x5, // !=
6197 0x0, // &&
6198 0x1, // ||
6199 0xc821, // &
6200 0xc831, // ^
6201 0xc809, // |
6202 0xd0f7, // ~
6203 0x4 // !
6204};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006205#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006206
Jack Palevich1cdef202009-05-22 12:06:27 -07006207struct ACCscript {
6208 ACCscript() {
6209 text = 0;
6210 textLength = 0;
6211 accError = ACC_NO_ERROR;
6212 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006213
Jack Palevich1cdef202009-05-22 12:06:27 -07006214 ~ACCscript() {
6215 delete text;
6216 }
Jack Palevich546b2242009-05-13 15:10:04 -07006217
Jack Palevich8c246a92009-07-14 21:14:10 -07006218 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6219 compiler.registerSymbolCallback(pFn, pContext);
6220 }
6221
Jack Palevich1cdef202009-05-22 12:06:27 -07006222 void setError(ACCenum error) {
6223 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6224 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006225 }
6226 }
6227
Jack Palevich1cdef202009-05-22 12:06:27 -07006228 ACCenum getError() {
6229 ACCenum result = accError;
6230 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006231 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006232 }
6233
Jack Palevich1cdef202009-05-22 12:06:27 -07006234 Compiler compiler;
6235 char* text;
6236 int textLength;
6237 ACCenum accError;
6238};
6239
6240
6241extern "C"
6242ACCscript* accCreateScript() {
6243 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006244}
Jack Palevich1cdef202009-05-22 12:06:27 -07006245
6246extern "C"
6247ACCenum accGetError( ACCscript* script ) {
6248 return script->getError();
6249}
6250
6251extern "C"
6252void accDeleteScript(ACCscript* script) {
6253 delete script;
6254}
6255
6256extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006257void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6258 ACCvoid* pContext) {
6259 script->registerSymbolCallback(pFn, pContext);
6260}
6261
6262extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006263void accScriptSource(ACCscript* script,
6264 ACCsizei count,
6265 const ACCchar ** string,
6266 const ACCint * length) {
6267 int totalLength = 0;
6268 for(int i = 0; i < count; i++) {
6269 int len = -1;
6270 const ACCchar* s = string[i];
6271 if (length) {
6272 len = length[i];
6273 }
6274 if (len < 0) {
6275 len = strlen(s);
6276 }
6277 totalLength += len;
6278 }
6279 delete script->text;
6280 char* text = new char[totalLength + 1];
6281 script->text = text;
6282 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006283 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006284 for(int i = 0; i < count; i++) {
6285 int len = -1;
6286 const ACCchar* s = string[i];
6287 if (length) {
6288 len = length[i];
6289 }
6290 if (len < 0) {
6291 len = strlen(s);
6292 }
Jack Palevich09555c72009-05-27 12:25:55 -07006293 memcpy(dest, s, len);
6294 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006295 }
6296 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006297
6298#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006299 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006300 int counter;
6301 char path[PATH_MAX];
6302 for (counter = 0; counter < 4096; counter++) {
6303 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6304 if(access(path, F_OK) != 0) {
6305 break;
6306 }
6307 }
6308 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006309 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006310 FILE* fd = fopen(path, "w");
6311 if (fd) {
6312 fwrite(text, totalLength, 1, fd);
6313 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006314 LOGD("Saved input to file %s", path);
6315 } else {
6316 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006317 }
6318 }
6319#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006320}
6321
6322extern "C"
6323void accCompileScript(ACCscript* script) {
6324 int result = script->compiler.compile(script->text, script->textLength);
6325 if (result) {
6326 script->setError(ACC_INVALID_OPERATION);
6327 }
6328}
6329
6330extern "C"
6331void accGetScriptiv(ACCscript* script,
6332 ACCenum pname,
6333 ACCint * params) {
6334 switch (pname) {
6335 case ACC_INFO_LOG_LENGTH:
6336 *params = 0;
6337 break;
6338 }
6339}
6340
6341extern "C"
6342void accGetScriptInfoLog(ACCscript* script,
6343 ACCsizei maxLength,
6344 ACCsizei * length,
6345 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006346 char* message = script->compiler.getErrorMessage();
6347 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006348 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006349 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006350 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006351 if (infoLog && maxLength > 0) {
6352 int trimmedLength = maxLength < messageLength ?
6353 maxLength : messageLength;
6354 memcpy(infoLog, message, trimmedLength);
6355 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006356 }
6357}
6358
6359extern "C"
6360void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6361 ACCvoid ** address) {
6362 void* value = script->compiler.lookup(name);
6363 if (value) {
6364 *address = value;
6365 } else {
6366 script->setError(ACC_INVALID_VALUE);
6367 }
6368}
6369
Jack Palevicheedf9d22009-06-04 16:23:40 -07006370extern "C"
6371void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6372 ACCsizei maxStringCount, ACCchar** strings){
6373 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6374}
6375
-b master422972c2009-06-17 19:13:52 -07006376extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006377void accGetProgramBinary(ACCscript* script,
6378 ACCvoid** base, ACCsizei* length) {
6379 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006380}
6381
Jack Palevicheedf9d22009-06-04 16:23:40 -07006382
Jack Palevich1cdef202009-05-22 12:06:27 -07006383} // namespace acc
6384