blob: 22cfb55f7ff48fbfc869b9c00a710b8abf31ad46 [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 Palevich02effee2009-11-09 12:52:45 +08001680 setR0Type(pDestType);
Jack Palevich22305132009-05-13 10:58:45 -07001681 }
1682
Jack Palevich58c30ee2009-07-17 16:35:23 -07001683 virtual void loadR0FromR0() {
1684 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001685 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001686 Type* pNewType = pPointerType->pHead;
1687 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001688 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001689 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001690 case TY_INT:
1691 o4(0xE5900000); // ldr r0, [r0]
1692 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001693 case TY_FLOAT:
1694#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001695 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001696#else
1697 o4(0xE5900000); // ldr r0, [r0]
1698#endif
1699 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001700 case TY_SHORT:
1701 o4(0xE1D000F0); // ldrsh r0, [r0]
1702 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001703 case TY_CHAR:
1704 o4(0xE5D00000); // ldrb r0, [r0]
1705 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001706 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001707#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001708 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001709#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001710 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001711#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001712 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001713 case TY_ARRAY:
1714 pNewType = pNewType->pTail;
1715 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001716 case TY_STRUCT:
1717 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001718 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001719 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001720 break;
1721 }
Jack Palevich80e49722009-08-04 15:39:49 -07001722 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001723 }
1724
Jack Palevichb5e33312009-07-30 19:06:34 -07001725 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001726 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001727 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001728
1729 size_t immediate = 0;
1730 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001731 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001732 inRange = encode12BitImmediate(-ea, &immediate);
1733 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001734 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001735 inRange = encode12BitImmediate(ea, &immediate);
1736 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1737 }
1738 if (! inRange) {
1739 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001740 }
Jack Palevichbd894902009-05-14 19:35:31 -07001741 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001742 // Global, absolute.
1743 o4(0xE59F0000); // ldr r0, .L1
1744 o4(0xEA000000); // b .L99
1745 o4(ea); // .L1: .word 0
1746 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001747 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001748 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001749 }
1750
Jack Palevich9f51a262009-07-29 16:22:26 -07001751 virtual int leaForward(int ea, Type* pPointerType) {
1752 setR0Type(pPointerType);
1753 int result = ea;
1754 int pc = getPC();
1755 int offset = 0;
1756 if (ea) {
1757 offset = (pc - ea - 8) >> 2;
1758 if ((offset & 0xffff) != offset) {
1759 error("function forward reference out of bounds");
1760 }
1761 } else {
1762 offset = 0;
1763 }
1764 o4(0xE59F0000 | offset); // ldr r0, .L1
1765
1766 if (ea == 0) {
1767 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001768 result = getPC();
1769 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001770 // .L99:
1771 }
1772 return result;
1773 }
1774
Jack Palevichb6154502009-08-04 14:56:09 -07001775 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001776 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001777 if (isPointerType(pType) && isPointerType(pR0Type)) {
1778 Type* pA = pR0Type;
1779 Type* pB = pType;
1780 // Array decays to pointer
1781 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1782 pA = pA->pTail;
1783 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001784 if (! (typeEqual(pA, pB)
1785 || pB->pHead->tag == TY_VOID
1786 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1787 )) {
1788 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001789 }
Jack Palevichb6154502009-08-04 14:56:09 -07001790 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001791 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001792 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001793 TypeTag r0Tag = collapseType(pR0Type->tag);
1794 TypeTag destTag = collapseType(pType->tag);
1795 if (r0Tag == TY_INT) {
1796 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001797#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001798 o4(0xEE070A90); // fmsr s15, r0
1799 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001800
1801#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001802 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001803#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001804 } else {
1805 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001806#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001807 o4(0xEE070A90); // fmsr s15, r0
1808 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001809
1810#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001811 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001812#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001813 }
1814 } else if (r0Tag == TY_FLOAT) {
1815 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001816#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001817 o4(0xEEFD7AE7); // ftosizs s15, s15
1818 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001819#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001820 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001821#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001822 } else {
1823 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001824#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001825 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001826#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001827 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001828#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001829 }
1830 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001831 if (r0Tag == TY_DOUBLE) {
1832 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001833#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001834 o4(0xEEFD7BC7); // ftosizd s15, d7
1835 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001836#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001837 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001838#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001839 } else {
1840 if(destTag == TY_FLOAT) {
1841#ifdef ARM_USE_VFP
1842 o4(0xEEF77BC7); // fcvtsd s15, d7
1843#else
1844 callRuntime((void*) runtime_double_to_float);
1845#endif
1846 } else {
1847 incompatibleTypes(pR0Type, pType);
1848 }
1849 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001850 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001851 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001852 }
1853 }
Jack Palevich8df46192009-07-07 14:48:51 -07001854 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001855 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001856 }
1857
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001858 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001859 int pc = getPC();
1860 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1861 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001862 }
1863
Jack Palevich8148c5b2009-07-16 18:24:47 -07001864 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001865 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001866 Type* pR0Type = getR0Type();
1867 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001868#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001869 switch(r0ct) {
1870 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001871 if (l < 0 || l > 4096-4) {
1872 error("l out of range for stack offset: 0x%08x", l);
1873 }
1874 o4(0xE58D0000 | l); // str r0, [sp, #l]
1875 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001876 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001877 if (l < 0 || l > 1020 || (l & 3)) {
1878 error("l out of range for stack offset: 0x%08x", l);
1879 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001880 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001881 return 4;
1882 case TY_DOUBLE: {
1883 // Align to 8 byte boundary
1884 int l2 = (l + 7) & ~7;
1885 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1886 error("l out of range for stack offset: 0x%08x", l);
1887 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001888 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001889 return (l2 - l) + 8;
1890 }
1891 default:
1892 assert(false);
1893 return 0;
1894 }
1895#else
1896 switch(r0ct) {
1897 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001898 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001899 if (l < 0 || l > 4096-4) {
1900 error("l out of range for stack offset: 0x%08x", l);
1901 }
1902 o4(0xE58D0000 + l); // str r0, [sp, #l]
1903 return 4;
1904 case TY_DOUBLE: {
1905 // Align to 8 byte boundary
1906 int l2 = (l + 7) & ~7;
1907 if (l2 < 0 || l2 > 4096-8) {
1908 error("l out of range for stack offset: 0x%08x", l);
1909 }
1910 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1911 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1912 return (l2 - l) + 8;
1913 }
1914 default:
1915 assert(false);
1916 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001917 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001918#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001919 }
1920
Jack Palevichb7718b92009-07-09 22:00:24 -07001921 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001922 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001923 // Have to calculate register arg count from actual stack size,
1924 // in order to properly handle ... functions.
1925 int regArgCount = l >> 2;
1926 if (regArgCount > 4) {
1927 regArgCount = 4;
1928 }
1929 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001930 argumentStackUse -= regArgCount * 4;
1931 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1932 }
1933 mStackUse += argumentStackUse;
1934
1935 // Align stack.
1936 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1937 * STACK_ALIGNMENT);
1938 mStackAlignmentAdjustment = 0;
1939 if (missalignment > 0) {
1940 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1941 }
1942 l += mStackAlignmentAdjustment;
1943
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001944 if (l < 0 || l > 0x3FC) {
1945 error("L out of range for stack adjustment: 0x%08x", l);
1946 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001947 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001948 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001949 mStackUse += mStackAlignmentAdjustment;
1950 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1951 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001952 }
1953
Jack Palevich8df46192009-07-07 14:48:51 -07001954 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001955 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001956 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001957 int pc = getPC();
1958 o4(0xEB000000 | encodeAddress(symbol));
1959 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001960 }
1961
Jack Palevich8df46192009-07-07 14:48:51 -07001962 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001963 assert(pFunc->tag == TY_FUNC);
1964 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001965 int argCount = l >> 2;
1966 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001967 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001968 if (adjustedL < 0 || adjustedL > 4096-4) {
1969 error("l out of range for stack offset: 0x%08x", l);
1970 }
1971 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1972 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001973 Type* pReturnType = pFunc->pHead;
1974 setR0Type(pReturnType);
1975#ifdef ARM_USE_VFP
1976 switch(pReturnType->tag) {
1977 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001978 o4(0xEE070A90); // fmsr s15, r0
1979 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001980 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001981 o4(0xEC410B17); // fmdrr d7, r0, r1
1982 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001983 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001984 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001985 }
1986#endif
Jack Palevich22305132009-05-13 10:58:45 -07001987 }
1988
Jack Palevichb7718b92009-07-09 22:00:24 -07001989 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001990 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001991 // Have to calculate register arg count from actual stack size,
1992 // in order to properly handle ... functions.
1993 int regArgCount = l >> 2;
1994 if (regArgCount > 4) {
1995 regArgCount = 4;
1996 }
1997 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001998 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1999 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07002000 if (stackUse) {
2001 if (stackUse < 0 || stackUse > 255) {
2002 error("L out of range for stack adjustment: 0x%08x", l);
2003 }
2004 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07002005 mStackUse -= stackUse * 4;
2006 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002007 }
Jack Palevich22305132009-05-13 10:58:45 -07002008 }
2009
Jack Palevicha6535612009-05-13 16:24:17 -07002010 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07002011 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002012 }
2013
2014 /* output a symbol and patch all calls to it */
2015 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002016 int n;
2017 int base = getBase();
2018 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002019 while (t) {
2020 int data = * (int*) t;
2021 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2022 if (decodedOffset == 0) {
2023 n = 0;
2024 } else {
2025 n = base + decodedOffset; /* next value */
2026 }
2027 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2028 | encodeRelAddress(pc - t - 8);
2029 t = n;
2030 }
2031 }
2032
Jack Palevich9f51a262009-07-29 16:22:26 -07002033 /* output a symbol and patch all calls to it */
2034 virtual void resolveForward(int t) {
2035 if (t) {
2036 int pc = getPC();
2037 *(int *) t = pc;
2038 }
2039 }
2040
Jack Palevich1cdef202009-05-22 12:06:27 -07002041 virtual int finishCompile() {
2042#if defined(__arm__)
2043 const long base = long(getBase());
2044 const long curr = long(getPC());
2045 int err = cacheflush(base, curr, 0);
2046 return err;
2047#else
2048 return 0;
2049#endif
2050 }
2051
Jack Palevich9eed7a22009-07-06 17:24:34 -07002052 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002053 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002054 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002055 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002056 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002057 case TY_CHAR:
2058 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002059 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002060 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002061 case TY_DOUBLE:
2062 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002063 case TY_ARRAY:
2064 return alignmentOf(pType->pHead);
2065 case TY_STRUCT:
2066 return pType->pHead->alignment & 0x7fffffff;
2067 case TY_FUNC:
2068 error("alignment of func not supported");
2069 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002070 default:
2071 return 4;
2072 }
2073 }
2074
2075 /**
2076 * Array element alignment (in bytes) for this type of data.
2077 */
2078 virtual size_t sizeOf(Type* pType){
2079 switch(pType->tag) {
2080 case TY_INT:
2081 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002082 case TY_SHORT:
2083 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002084 case TY_CHAR:
2085 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002086 case TY_FLOAT:
2087 return 4;
2088 case TY_DOUBLE:
2089 return 8;
2090 case TY_POINTER:
2091 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002092 case TY_ARRAY:
2093 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002094 case TY_STRUCT:
2095 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002096 default:
2097 error("Unsupported type %d", pType->tag);
2098 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002099 }
2100 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002101
Jack Palevich22305132009-05-13 10:58:45 -07002102 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002103
2104 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2105
2106 /** Encode a relative address that might also be
2107 * a label.
2108 */
2109 int encodeAddress(int value) {
2110 int base = getBase();
2111 if (value >= base && value <= getPC() ) {
2112 // This is a label, encode it relative to the base.
2113 value = value - base;
2114 }
2115 return encodeRelAddress(value);
2116 }
2117
2118 int encodeRelAddress(int value) {
2119 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2120 }
Jack Palevich22305132009-05-13 10:58:45 -07002121
Jack Palevichb7718b92009-07-09 22:00:24 -07002122 int calcRegArgCount(Type* pDecl) {
2123 int reg = 0;
2124 Type* pArgs = pDecl->pTail;
2125 while (pArgs && reg < 4) {
2126 Type* pArg = pArgs->pHead;
2127 if ( pArg->tag == TY_DOUBLE) {
2128 int evenReg = (reg + 1) & ~1;
2129 if (evenReg >= 4) {
2130 break;
2131 }
2132 reg = evenReg + 2;
2133 } else {
2134 reg++;
2135 }
2136 pArgs = pArgs->pTail;
2137 }
2138 return reg;
2139 }
2140
Jack Palevich58c30ee2009-07-17 16:35:23 -07002141 void setupIntPtrArgs() {
2142 o4(0xE8BD0002); // ldmfd sp!,{r1}
2143 mStackUse -= 4;
2144 popType();
2145 }
2146
Jack Palevich30321cb2009-08-20 15:34:23 -07002147 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002148 * Make sure both R0 and TOS are floats. (Could be ints)
2149 * We know that at least one of R0 and TOS is already a float
2150 */
2151 void setupFloatArgs() {
2152 Type* pR0Type = getR0Type();
2153 Type* pTOSType = getTOSType();
2154 TypeTag tagR0 = collapseType(pR0Type->tag);
2155 TypeTag tagTOS = collapseType(pTOSType->tag);
2156 if (tagR0 != TY_FLOAT) {
2157 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002158#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002159 o4(0xEE070A90); // fmsr s15, r0
2160 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002161#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002162 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002163#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002164 }
2165 if (tagTOS != TY_FLOAT) {
2166 assert(tagTOS == TY_INT);
2167 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002168#ifdef ARM_USE_VFP
2169 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002170 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002171#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002172 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2173 o4(0xE59D0004); // ldr r0, [sp, #4]
2174 callRuntime((void*) runtime_int_to_float);
2175 o4(0xE1A01000); // mov r1, r0
2176 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2177 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002178#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002179 } else {
2180 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002181#ifdef ARM_USE_VFP
2182 o4(0xECBD7A01); // fldmfds sp!, {s14}
2183
2184#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002185 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002186#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002187 }
2188 mStackUse -= 4;
2189 popType();
2190 }
2191
Jack Palevich30321cb2009-08-20 15:34:23 -07002192 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002193 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2194 * We know that at least one of R0 and TOS are already a double.
2195 */
2196
2197 void setupDoubleArgs() {
2198 Type* pR0Type = getR0Type();
2199 Type* pTOSType = getTOSType();
2200 TypeTag tagR0 = collapseType(pR0Type->tag);
2201 TypeTag tagTOS = collapseType(pTOSType->tag);
2202 if (tagR0 != TY_DOUBLE) {
2203 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002204#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002205 o4(0xEE070A90); // fmsr s15, r0
2206 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002207
2208#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002209 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002210#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002211 } else {
2212 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002213#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002214 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002215#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002216 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002217#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002218 }
2219 }
2220 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002221#ifdef ARM_USE_VFP
2222 if (tagTOS == TY_INT) {
2223 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002224 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002225 } else {
2226 assert(tagTOS == TY_FLOAT);
2227 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002228 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002229 }
2230#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002231 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2232 o4(0xE59D0008); // ldr r0, [sp, #8]
2233 if (tagTOS == TY_INT) {
2234 callRuntime((void*) runtime_int_to_double);
2235 } else {
2236 assert(tagTOS == TY_FLOAT);
2237 callRuntime((void*) runtime_float_to_double);
2238 }
2239 o4(0xE1A02000); // mov r2, r0
2240 o4(0xE1A03001); // mov r3, r1
2241 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2242 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002243#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002244 mStackUse -= 4;
2245 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002246#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002247 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002248#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002249 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002250#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002251 mStackUse -= 8;
2252 }
2253 popType();
2254 }
2255
Jack Palevicha8f427f2009-07-13 18:40:08 -07002256 void liReg(int t, int reg) {
2257 assert(reg >= 0 && reg < 16);
2258 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002259 size_t encodedImmediate;
2260 if (encode12BitImmediate(t, &encodedImmediate)) {
2261 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2262 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002263 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002264 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002265 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002266 o4(0xE51F0000 | rN); // ldr rN, .L3
2267 o4(0xEA000000); // b .L99
2268 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002269 // .L99:
2270 }
2271 }
2272
Jack Palevichc408bbf2009-09-08 12:07:32 -07002273 void incompatibleTypes(Type* pR0Type, Type* pType) {
2274 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2275 }
2276
Jack Palevichb7718b92009-07-09 22:00:24 -07002277 void callRuntime(void* fn) {
2278 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002279 o4(0xEA000000); // b .L99
2280 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002281 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002282 }
2283
Jack Palevichb7718b92009-07-09 22:00:24 -07002284 // Integer math:
2285
2286 static int runtime_DIV(int b, int a) {
2287 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002288 }
2289
Jack Palevichb7718b92009-07-09 22:00:24 -07002290 static int runtime_MOD(int b, int a) {
2291 return a % b;
2292 }
2293
Jack Palevich9221bcc2009-08-26 16:15:07 -07002294 static void runtime_structCopy(void* src, size_t size, void* dest) {
2295 memcpy(dest, src, size);
2296 }
2297
Jack Palevich30321cb2009-08-20 15:34:23 -07002298#ifndef ARM_USE_VFP
2299
Jack Palevichb7718b92009-07-09 22:00:24 -07002300 // Comparison to zero
2301
2302 static int runtime_is_non_zero_f(float a) {
2303 return a != 0;
2304 }
2305
2306 static int runtime_is_non_zero_d(double a) {
2307 return a != 0;
2308 }
2309
2310 // Comparison to zero
2311
2312 static int runtime_is_zero_f(float a) {
2313 return a == 0;
2314 }
2315
2316 static int runtime_is_zero_d(double a) {
2317 return a == 0;
2318 }
2319
2320 // Type conversion
2321
2322 static int runtime_float_to_int(float a) {
2323 return (int) a;
2324 }
2325
2326 static double runtime_float_to_double(float a) {
2327 return (double) a;
2328 }
2329
2330 static int runtime_double_to_int(double a) {
2331 return (int) a;
2332 }
2333
2334 static float runtime_double_to_float(double a) {
2335 return (float) a;
2336 }
2337
2338 static float runtime_int_to_float(int a) {
2339 return (float) a;
2340 }
2341
2342 static double runtime_int_to_double(int a) {
2343 return (double) a;
2344 }
2345
2346 // Comparisons float
2347
2348 static int runtime_cmp_eq_ff(float b, float a) {
2349 return a == b;
2350 }
2351
2352 static int runtime_cmp_ne_ff(float b, float a) {
2353 return a != b;
2354 }
2355
2356 static int runtime_cmp_lt_ff(float b, float a) {
2357 return a < b;
2358 }
2359
2360 static int runtime_cmp_le_ff(float b, float a) {
2361 return a <= b;
2362 }
2363
2364 static int runtime_cmp_ge_ff(float b, float a) {
2365 return a >= b;
2366 }
2367
2368 static int runtime_cmp_gt_ff(float b, float a) {
2369 return a > b;
2370 }
2371
2372 // Comparisons double
2373
2374 static int runtime_cmp_eq_dd(double b, double a) {
2375 return a == b;
2376 }
2377
2378 static int runtime_cmp_ne_dd(double b, double a) {
2379 return a != b;
2380 }
2381
2382 static int runtime_cmp_lt_dd(double b, double a) {
2383 return a < b;
2384 }
2385
2386 static int runtime_cmp_le_dd(double b, double a) {
2387 return a <= b;
2388 }
2389
2390 static int runtime_cmp_ge_dd(double b, double a) {
2391 return a >= b;
2392 }
2393
2394 static int runtime_cmp_gt_dd(double b, double a) {
2395 return a > b;
2396 }
2397
2398 // Math float
2399
2400 static float runtime_op_add_ff(float b, float a) {
2401 return a + b;
2402 }
2403
2404 static float runtime_op_sub_ff(float b, float a) {
2405 return a - b;
2406 }
2407
2408 static float runtime_op_mul_ff(float b, float a) {
2409 return a * b;
2410 }
2411
2412 static float runtime_op_div_ff(float b, float a) {
2413 return a / b;
2414 }
2415
2416 static float runtime_op_neg_f(float a) {
2417 return -a;
2418 }
2419
2420 // Math double
2421
2422 static double runtime_op_add_dd(double b, double a) {
2423 return a + b;
2424 }
2425
2426 static double runtime_op_sub_dd(double b, double a) {
2427 return a - b;
2428 }
2429
2430 static double runtime_op_mul_dd(double b, double a) {
2431 return a * b;
2432 }
2433
2434 static double runtime_op_div_dd(double b, double a) {
2435 return a / b;
2436 }
2437
2438 static double runtime_op_neg_d(double a) {
2439 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002440 }
-b master422972c2009-06-17 19:13:52 -07002441
Jack Palevich30321cb2009-08-20 15:34:23 -07002442#endif
2443
-b master422972c2009-06-17 19:13:52 -07002444 static const int STACK_ALIGNMENT = 8;
2445 int mStackUse;
2446 // This variable holds the amount we adjusted the stack in the most
2447 // recent endFunctionCallArguments call. It's examined by the
2448 // following adjustStackAfterCall call.
2449 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002450 };
2451
Jack Palevich09555c72009-05-27 12:25:55 -07002452#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002453
2454#ifdef PROVIDE_X86_CODEGEN
2455
Jack Palevich21a15a22009-05-11 14:49:29 -07002456 class X86CodeGenerator : public CodeGenerator {
2457 public:
2458 X86CodeGenerator() {}
2459 virtual ~X86CodeGenerator() {}
2460
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002461 /* returns address to patch with local variable size
2462 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002463 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002464 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2465 return oad(0xec81, 0); /* sub $xxx, %esp */
2466 }
2467
Jack Palevichb7718b92009-07-09 22:00:24 -07002468 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002469 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002470 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002471 }
2472
Jack Palevich21a15a22009-05-11 14:49:29 -07002473 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002474 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002475 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002476 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002477 }
2478
Jack Palevich1a539db2009-07-08 13:04:41 -07002479 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002480 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002481 switch (pType->tag) {
2482 case TY_FLOAT:
2483 oad(0x05D9, address); // flds
2484 break;
2485 case TY_DOUBLE:
2486 oad(0x05DD, address); // fldl
2487 break;
2488 default:
2489 assert(false);
2490 break;
2491 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002492 }
2493
Jack Palevich9221bcc2009-08-26 16:15:07 -07002494 virtual void addStructOffsetR0(int offset, Type* pType) {
2495 if (offset) {
2496 oad(0x05, offset); // addl offset, %eax
2497 }
2498 setR0Type(pType, ET_LVALUE);
2499 }
2500
Jack Palevich22305132009-05-13 10:58:45 -07002501 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002502 return psym(0xe9, t);
2503 }
2504
2505 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002506 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002507 Type* pR0Type = getR0Type();
2508 TypeTag tagR0 = pR0Type->tag;
2509 bool isFloatR0 = isFloatTag(tagR0);
2510 if (isFloatR0) {
2511 o(0xeed9); // fldz
2512 o(0xe9da); // fucompp
2513 o(0xe0df); // fnstsw %ax
2514 o(0x9e); // sahf
2515 } else {
2516 o(0xc085); // test %eax, %eax
2517 }
2518 // Use two output statements to generate one instruction.
2519 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002520 return psym(0x84 + l, t);
2521 }
2522
Jack Palevich58c30ee2009-07-17 16:35:23 -07002523 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002524 Type* pR0Type = getR0Type();
2525 Type* pTOSType = getTOSType();
2526 TypeTag tagR0 = pR0Type->tag;
2527 TypeTag tagTOS = pTOSType->tag;
2528 bool isFloatR0 = isFloatTag(tagR0);
2529 bool isFloatTOS = isFloatTag(tagTOS);
2530 if (!isFloatR0 && !isFloatTOS) {
2531 int t = decodeOp(op);
2532 o(0x59); /* pop %ecx */
2533 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002534 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002535 o(0x0f); /* setxx %al */
2536 o(t + 0x90);
2537 o(0xc0);
2538 popType();
2539 } else {
2540 setupFloatOperands();
2541 switch (op) {
2542 case OP_EQUALS:
2543 o(0xe9da); // fucompp
2544 o(0xe0df); // fnstsw %ax
2545 o(0x9e); // sahf
2546 o(0xc0940f); // sete %al
2547 o(0xc29b0f); // setnp %dl
2548 o(0xd021); // andl %edx, %eax
2549 break;
2550 case OP_NOT_EQUALS:
2551 o(0xe9da); // fucompp
2552 o(0xe0df); // fnstsw %ax
2553 o(0x9e); // sahf
2554 o(0xc0950f); // setne %al
2555 o(0xc29a0f); // setp %dl
2556 o(0xd009); // orl %edx, %eax
2557 break;
2558 case OP_GREATER_EQUAL:
2559 o(0xe9da); // fucompp
2560 o(0xe0df); // fnstsw %ax
2561 o(0x05c4f6); // testb $5, %ah
2562 o(0xc0940f); // sete %al
2563 break;
2564 case OP_LESS:
2565 o(0xc9d9); // fxch %st(1)
2566 o(0xe9da); // fucompp
2567 o(0xe0df); // fnstsw %ax
2568 o(0x9e); // sahf
2569 o(0xc0970f); // seta %al
2570 break;
2571 case OP_LESS_EQUAL:
2572 o(0xc9d9); // fxch %st(1)
2573 o(0xe9da); // fucompp
2574 o(0xe0df); // fnstsw %ax
2575 o(0x9e); // sahf
2576 o(0xc0930f); // setea %al
2577 break;
2578 case OP_GREATER:
2579 o(0xe9da); // fucompp
2580 o(0xe0df); // fnstsw %ax
2581 o(0x45c4f6); // testb $69, %ah
2582 o(0xc0940f); // sete %al
2583 break;
2584 default:
2585 error("Unknown comparison op");
2586 }
2587 o(0xc0b60f); // movzbl %al, %eax
2588 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002589 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002590 }
2591
Jack Palevich546b2242009-05-13 15:10:04 -07002592 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002593 Type* pR0Type = getR0Type();
2594 Type* pTOSType = getTOSType();
2595 TypeTag tagR0 = pR0Type->tag;
2596 TypeTag tagTOS = pTOSType->tag;
2597 bool isFloatR0 = isFloatTag(tagR0);
2598 bool isFloatTOS = isFloatTag(tagTOS);
2599 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002600 bool isPtrR0 = isPointerTag(tagR0);
2601 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002602 if (isPtrR0 || isPtrTOS) {
2603 if (isPtrR0 && isPtrTOS) {
2604 if (op != OP_MINUS) {
2605 error("Unsupported pointer-pointer operation %d.", op);
2606 }
2607 if (! typeEqual(pR0Type, pTOSType)) {
2608 error("Incompatible pointer types for subtraction.");
2609 }
2610 o(0x59); /* pop %ecx */
2611 o(decodeOp(op));
2612 popType();
2613 setR0Type(mkpInt);
2614 int size = sizeOf(pR0Type->pHead);
2615 if (size != 1) {
2616 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002617 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002618 // TODO: Optimize for power-of-two.
2619 genOp(OP_DIV);
2620 }
2621 } else {
2622 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2623 error("Unsupported pointer-scalar operation %d", op);
2624 }
Jack Palevichb6154502009-08-04 14:56:09 -07002625 Type* pPtrType = getPointerArithmeticResultType(
2626 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002627 o(0x59); /* pop %ecx */
2628 int size = sizeOf(pPtrType->pHead);
2629 if (size != 1) {
2630 // TODO: Optimize for power-of-two.
2631 if (isPtrR0) {
2632 oad(0xC969, size); // imull $size, %ecx
2633 } else {
2634 oad(0xC069, size); // mul $size, %eax
2635 }
2636 }
2637 o(decodeOp(op));
2638 popType();
2639 setR0Type(pPtrType);
2640 }
2641 } else {
2642 o(0x59); /* pop %ecx */
2643 o(decodeOp(op));
2644 if (op == OP_MOD)
2645 o(0x92); /* xchg %edx, %eax */
2646 popType();
2647 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002648 } else {
2649 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2650 setupFloatOperands();
2651 // Both float. x87 R0 == left hand, x87 R1 == right hand
2652 switch (op) {
2653 case OP_MUL:
2654 o(0xc9de); // fmulp
2655 break;
2656 case OP_DIV:
2657 o(0xf1de); // fdivp
2658 break;
2659 case OP_PLUS:
2660 o(0xc1de); // faddp
2661 break;
2662 case OP_MINUS:
2663 o(0xe1de); // fsubp
2664 break;
2665 default:
2666 error("Unsupported binary floating operation.");
2667 break;
2668 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002669 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002670 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002671 }
2672
Jack Palevich58c30ee2009-07-17 16:35:23 -07002673 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002674 if (op != OP_LOGICAL_NOT) {
2675 error("Unknown unary cmp %d", op);
2676 } else {
2677 Type* pR0Type = getR0Type();
2678 TypeTag tag = collapseType(pR0Type->tag);
2679 switch(tag) {
2680 case TY_INT: {
2681 oad(0xb9, 0); /* movl $0, %ecx */
2682 int t = decodeOp(op);
2683 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002684 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002685 o(0x0f); /* setxx %al */
2686 o(t + 0x90);
2687 o(0xc0);
2688 }
2689 break;
2690 case TY_FLOAT:
2691 case TY_DOUBLE:
2692 o(0xeed9); // fldz
2693 o(0xe9da); // fucompp
2694 o(0xe0df); // fnstsw %ax
2695 o(0x9e); // sahf
2696 o(0xc0950f); // setne %al
2697 o(0xc29a0f); // setp %dl
2698 o(0xd009); // orl %edx, %eax
2699 o(0xc0b60f); // movzbl %al, %eax
2700 o(0x01f083); // xorl $1, %eax
2701 break;
2702 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002703 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002704 break;
2705 }
2706 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002707 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002708 }
2709
2710 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002711 Type* pR0Type = getR0Type();
2712 TypeTag tag = collapseType(pR0Type->tag);
2713 switch(tag) {
2714 case TY_INT:
2715 oad(0xb9, 0); /* movl $0, %ecx */
2716 o(decodeOp(op));
2717 break;
2718 case TY_FLOAT:
2719 case TY_DOUBLE:
2720 switch (op) {
2721 case OP_MINUS:
2722 o(0xe0d9); // fchs
2723 break;
2724 case OP_BIT_NOT:
2725 error("Can't apply '~' operator to a float or double.");
2726 break;
2727 default:
2728 error("Unknown unary op %d\n", op);
2729 break;
2730 }
2731 break;
2732 default:
2733 error("genUnaryOp unsupported type");
2734 break;
2735 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002736 }
2737
Jack Palevich1cdef202009-05-22 12:06:27 -07002738 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002739 Type* pR0Type = getR0Type();
2740 TypeTag r0ct = collapseType(pR0Type->tag);
2741 switch(r0ct) {
2742 case TY_INT:
2743 o(0x50); /* push %eax */
2744 break;
2745 case TY_FLOAT:
2746 o(0x50); /* push %eax */
2747 o(0x241cd9); // fstps 0(%esp)
2748 break;
2749 case TY_DOUBLE:
2750 o(0x50); /* push %eax */
2751 o(0x50); /* push %eax */
2752 o(0x241cdd); // fstpl 0(%esp)
2753 break;
2754 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002755 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002756 break;
2757 }
Jack Palevich8df46192009-07-07 14:48:51 -07002758 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002759 }
2760
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002761 virtual void over() {
2762 // We know it's only used for int-ptr ops (++/--)
2763
2764 Type* pR0Type = getR0Type();
2765 TypeTag r0ct = collapseType(pR0Type->tag);
2766
2767 Type* pTOSType = getTOSType();
2768 TypeTag tosct = collapseType(pTOSType->tag);
2769
2770 assert (r0ct == TY_INT && tosct == TY_INT);
2771
2772 o(0x59); /* pop %ecx */
2773 o(0x50); /* push %eax */
2774 o(0x51); /* push %ecx */
2775
2776 overType();
2777 }
2778
Jack Palevich58c30ee2009-07-17 16:35:23 -07002779 virtual void popR0() {
2780 Type* pR0Type = getR0Type();
2781 TypeTag r0ct = collapseType(pR0Type->tag);
2782 switch(r0ct) {
2783 case TY_INT:
2784 o(0x58); /* popl %eax */
2785 break;
2786 case TY_FLOAT:
2787 o(0x2404d9); // flds (%esp)
2788 o(0x58); /* popl %eax */
2789 break;
2790 case TY_DOUBLE:
2791 o(0x2404dd); // fldl (%esp)
2792 o(0x58); /* popl %eax */
2793 o(0x58); /* popl %eax */
2794 break;
2795 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002796 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002797 break;
2798 }
2799 popType();
2800 }
2801
2802 virtual void storeR0ToTOS() {
2803 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002804 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002805 Type* pTargetType = pPointerType->pHead;
2806 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002807 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002808 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002809 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002810 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002811 case TY_INT:
2812 o(0x0189); /* movl %eax/%al, (%ecx) */
2813 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002814 case TY_SHORT:
2815 o(0x018966); /* movw %ax, (%ecx) */
2816 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002817 case TY_CHAR:
2818 o(0x0188); /* movl %eax/%al, (%ecx) */
2819 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002820 case TY_FLOAT:
2821 o(0x19d9); /* fstps (%ecx) */
2822 break;
2823 case TY_DOUBLE:
2824 o(0x19dd); /* fstpl (%ecx) */
2825 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002826 case TY_STRUCT:
2827 {
2828 // TODO: use alignment information to use movsw/movsl instead of movsb
2829 int size = sizeOf(pTargetType);
2830 if (size > 0) {
2831 o(0x9c); // pushf
2832 o(0x57); // pushl %edi
2833 o(0x56); // pushl %esi
2834 o(0xcf89); // movl %ecx, %edi
2835 o(0xc689); // movl %eax, %esi
2836 oad(0xb9, size); // mov #size, %ecx
2837 o(0xfc); // cld
2838 o(0xf3); // rep
2839 o(0xa4); // movsb
2840 o(0x5e); // popl %esi
2841 o(0x5f); // popl %edi
2842 o(0x9d); // popf
2843 }
2844 }
2845 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002846 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002847 error("storeR0ToTOS: unsupported type %d",
2848 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002849 break;
2850 }
Jack Palevich02effee2009-11-09 12:52:45 +08002851 setR0Type(pTargetType);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002852 }
2853
Jack Palevich58c30ee2009-07-17 16:35:23 -07002854 virtual void loadR0FromR0() {
2855 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002856 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002857 Type* pNewType = pPointerType->pHead;
2858 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002859 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002860 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002861 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002862 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002863 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002864 case TY_SHORT:
2865 o(0xbf0f); /* movswl (%eax), %eax */
2866 ob(0);
2867 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002868 case TY_CHAR:
2869 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002870 ob(0); /* add zero in code */
2871 break;
2872 case TY_FLOAT:
2873 o2(0x00d9); // flds (%eax)
2874 break;
2875 case TY_DOUBLE:
2876 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002877 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002878 case TY_ARRAY:
2879 pNewType = pNewType->pTail;
2880 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002881 case TY_STRUCT:
2882 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002883 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002884 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002885 break;
2886 }
Jack Palevich80e49722009-08-04 15:39:49 -07002887 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002888 }
2889
Jack Palevichb5e33312009-07-30 19:06:34 -07002890 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002891 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002892 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002893 }
2894
Jack Palevich9f51a262009-07-29 16:22:26 -07002895 virtual int leaForward(int ea, Type* pPointerType) {
2896 oad(0xb8, ea); /* mov $xx, %eax */
2897 setR0Type(pPointerType);
2898 return getPC() - 4;
2899 }
2900
Jack Palevichb6154502009-08-04 14:56:09 -07002901 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002902 Type* pR0Type = getR0Type();
2903 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002904 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002905 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002906 return;
2907 }
Jack Palevichb6154502009-08-04 14:56:09 -07002908 if (isPointerType(pType) && isPointerType(pR0Type)) {
2909 Type* pA = pR0Type;
2910 Type* pB = pType;
2911 // Array decays to pointer
2912 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2913 pA = pA->pTail;
2914 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002915 if (! (typeEqual(pA, pB)
2916 || pB->pHead->tag == TY_VOID
2917 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2918 )) {
2919 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002920 }
Jack Palevichb6154502009-08-04 14:56:09 -07002921 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002922 // do nothing special
2923 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2924 // do nothing special, both held in same register on x87.
2925 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002926 TypeTag r0Tag = collapseType(pR0Type->tag);
2927 TypeTag destTag = collapseType(pType->tag);
2928 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2929 // Convert R0 from int to float
2930 o(0x50); // push %eax
2931 o(0x2404DB); // fildl 0(%esp)
2932 o(0x58); // pop %eax
2933 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2934 // Convert R0 from float to int. Complicated because
2935 // need to save and restore the rounding mode.
2936 o(0x50); // push %eax
2937 o(0x50); // push %eax
2938 o(0x02247cD9); // fnstcw 2(%esp)
2939 o(0x2444b70f); // movzwl 2(%esp), %eax
2940 o(0x02);
2941 o(0x0cb4); // movb $12, %ah
2942 o(0x24048966); // movw %ax, 0(%esp)
2943 o(0x242cd9); // fldcw 0(%esp)
2944 o(0x04245cdb); // fistpl 4(%esp)
2945 o(0x02246cd9); // fldcw 2(%esp)
2946 o(0x58); // pop %eax
2947 o(0x58); // pop %eax
2948 } else {
2949 error("Incompatible types old: %d new: %d",
2950 pR0Type->tag, pType->tag);
2951 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002952 }
2953 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002954 }
2955
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002956 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002957 return oad(0xec81, 0); /* sub $xxx, %esp */
2958 }
2959
Jack Palevich8148c5b2009-07-16 18:24:47 -07002960 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2961 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002962 Type* pR0Type = getR0Type();
2963 TypeTag r0ct = collapseType(pR0Type->tag);
2964 switch(r0ct) {
2965 case TY_INT:
2966 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2967 return 4;
2968 case TY_FLOAT:
2969 oad(0x249CD9, l); /* fstps xxx(%esp) */
2970 return 4;
2971 case TY_DOUBLE:
2972 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2973 return 8;
2974 default:
2975 assert(false);
2976 return 0;
2977 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002978 }
2979
Jack Palevichb7718b92009-07-09 22:00:24 -07002980 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002981 * (int*) a = l;
2982 }
2983
Jack Palevich8df46192009-07-07 14:48:51 -07002984 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002985 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002986 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002987 return psym(0xe8, symbol); /* call xxx */
2988 }
2989
Jack Palevich8df46192009-07-07 14:48:51 -07002990 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002991 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002992 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002993 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002994 oad(0x2494ff, l); /* call *xxx(%esp) */
2995 }
2996
Jack Palevichb7718b92009-07-09 22:00:24 -07002997 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002998 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002999 if (isIndirect) {
3000 l += 4;
3001 }
-b master422972c2009-06-17 19:13:52 -07003002 if (l > 0) {
3003 oad(0xc481, l); /* add $xxx, %esp */
3004 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003005 }
3006
Jack Palevicha6535612009-05-13 16:24:17 -07003007 virtual int jumpOffset() {
3008 return 5;
3009 }
3010
Jack Paleviche7b59062009-05-19 17:12:17 -07003011 /* output a symbol and patch all calls to it */
3012 virtual void gsym(int t) {
3013 int n;
3014 int pc = getPC();
3015 while (t) {
3016 n = *(int *) t; /* next value */
3017 *(int *) t = pc - t - 4;
3018 t = n;
3019 }
3020 }
3021
Jack Palevich9f51a262009-07-29 16:22:26 -07003022 /* output a symbol and patch all calls to it, using absolute address */
3023 virtual void resolveForward(int t) {
3024 int n;
3025 int pc = getPC();
3026 while (t) {
3027 n = *(int *) t; /* next value */
3028 *(int *) t = pc;
3029 t = n;
3030 }
3031 }
3032
Jack Palevich1cdef202009-05-22 12:06:27 -07003033 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003034 size_t pagesize = 4096;
3035 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3036 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3037 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3038 if (err) {
3039 error("mprotect() failed: %d", errno);
3040 }
3041 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003042 }
3043
Jack Palevich9eed7a22009-07-06 17:24:34 -07003044 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003045 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003046 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003047 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003048 switch (pType->tag) {
3049 case TY_CHAR:
3050 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003051 case TY_SHORT:
3052 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003053 case TY_ARRAY:
3054 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003055 case TY_STRUCT:
3056 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003057 case TY_FUNC:
3058 error("alignment of func not supported");
3059 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003060 default:
3061 return 4;
3062 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003063 }
3064
3065 /**
3066 * Array element alignment (in bytes) for this type of data.
3067 */
3068 virtual size_t sizeOf(Type* pType){
3069 switch(pType->tag) {
3070 case TY_INT:
3071 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003072 case TY_SHORT:
3073 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003074 case TY_CHAR:
3075 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003076 case TY_FLOAT:
3077 return 4;
3078 case TY_DOUBLE:
3079 return 8;
3080 case TY_POINTER:
3081 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003082 case TY_ARRAY:
3083 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003084 case TY_STRUCT:
3085 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003086 default:
3087 error("Unsupported type %d", pType->tag);
3088 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003089 }
3090 }
3091
Jack Palevich21a15a22009-05-11 14:49:29 -07003092 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003093
3094 /** Output 1 to 4 bytes.
3095 *
3096 */
3097 void o(int n) {
3098 /* cannot use unsigned, so we must do a hack */
3099 while (n && n != -1) {
3100 ob(n & 0xff);
3101 n = n >> 8;
3102 }
3103 }
3104
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003105 /* Output exactly 2 bytes
3106 */
3107 void o2(int n) {
3108 ob(n & 0xff);
3109 ob(0xff & (n >> 8));
3110 }
3111
Jack Paleviche7b59062009-05-19 17:12:17 -07003112 /* psym is used to put an instruction with a data field which is a
3113 reference to a symbol. It is in fact the same as oad ! */
3114 int psym(int n, int t) {
3115 return oad(n, t);
3116 }
3117
3118 /* instruction + address */
3119 int oad(int n, int t) {
3120 o(n);
3121 int result = getPC();
3122 o4(t);
3123 return result;
3124 }
3125
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003126 static const int operatorHelper[];
3127
3128 int decodeOp(int op) {
3129 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003130 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003131 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003132 }
3133 return operatorHelper[op];
3134 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003135
Jack Palevich546b2242009-05-13 15:10:04 -07003136 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003137 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003138 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003139 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003140
3141 void setupFloatOperands() {
3142 Type* pR0Type = getR0Type();
3143 Type* pTOSType = getTOSType();
3144 TypeTag tagR0 = pR0Type->tag;
3145 TypeTag tagTOS = pTOSType->tag;
3146 bool isFloatR0 = isFloatTag(tagR0);
3147 bool isFloatTOS = isFloatTag(tagTOS);
3148 if (! isFloatR0) {
3149 // Convert R0 from int to float
3150 o(0x50); // push %eax
3151 o(0x2404DB); // fildl 0(%esp)
3152 o(0x58); // pop %eax
3153 }
3154 if (! isFloatTOS){
3155 o(0x2404DB); // fildl 0(%esp);
3156 o(0x58); // pop %eax
3157 } else {
3158 if (tagTOS == TY_FLOAT) {
3159 o(0x2404d9); // flds (%esp)
3160 o(0x58); // pop %eax
3161 } else {
3162 o(0x2404dd); // fldl (%esp)
3163 o(0x58); // pop %eax
3164 o(0x58); // pop %eax
3165 }
3166 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003167 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003168 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003169 };
3170
Jack Paleviche7b59062009-05-19 17:12:17 -07003171#endif // PROVIDE_X86_CODEGEN
3172
Jack Palevichb67b18f2009-06-11 21:12:23 -07003173#ifdef PROVIDE_TRACE_CODEGEN
3174 class TraceCodeGenerator : public CodeGenerator {
3175 private:
3176 CodeGenerator* mpBase;
3177
3178 public:
3179 TraceCodeGenerator(CodeGenerator* pBase) {
3180 mpBase = pBase;
3181 }
3182
3183 virtual ~TraceCodeGenerator() {
3184 delete mpBase;
3185 }
3186
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003187 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003188 mpBase->init(pCodeBuf);
3189 }
3190
3191 void setErrorSink(ErrorSink* pErrorSink) {
3192 mpBase->setErrorSink(pErrorSink);
3193 }
3194
3195 /* returns address to patch with local variable size
3196 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003197 virtual int functionEntry(Type* pDecl) {
3198 int result = mpBase->functionEntry(pDecl);
3199 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003200 return result;
3201 }
3202
Jack Palevichb7718b92009-07-09 22:00:24 -07003203 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3204 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3205 localVariableAddress, localVariableSize);
3206 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003207 }
3208
3209 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003210 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003211 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003212 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003213 }
3214
Jack Palevich1a539db2009-07-08 13:04:41 -07003215 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003216 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003217 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003218 }
3219
Jack Palevich9221bcc2009-08-26 16:15:07 -07003220 virtual void addStructOffsetR0(int offset, Type* pType) {
3221 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3222 mpBase->addStructOffsetR0(offset, pType);
3223 }
3224
Jack Palevichb67b18f2009-06-11 21:12:23 -07003225 virtual int gjmp(int t) {
3226 int result = mpBase->gjmp(t);
3227 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3228 return result;
3229 }
3230
3231 /* l = 0: je, l == 1: jne */
3232 virtual int gtst(bool l, int t) {
3233 int result = mpBase->gtst(l, t);
3234 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3235 return result;
3236 }
3237
Jack Palevich58c30ee2009-07-17 16:35:23 -07003238 virtual void gcmp(int op) {
3239 fprintf(stderr, "gcmp(%d)\n", op);
3240 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003241 }
3242
3243 virtual void genOp(int op) {
3244 fprintf(stderr, "genOp(%d)\n", op);
3245 mpBase->genOp(op);
3246 }
3247
Jack Palevich9eed7a22009-07-06 17:24:34 -07003248
Jack Palevich58c30ee2009-07-17 16:35:23 -07003249 virtual void gUnaryCmp(int op) {
3250 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3251 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003252 }
3253
3254 virtual void genUnaryOp(int op) {
3255 fprintf(stderr, "genUnaryOp(%d)\n", op);
3256 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003257 }
3258
3259 virtual void pushR0() {
3260 fprintf(stderr, "pushR0()\n");
3261 mpBase->pushR0();
3262 }
3263
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003264 virtual void over() {
3265 fprintf(stderr, "over()\n");
3266 mpBase->over();
3267 }
3268
Jack Palevich58c30ee2009-07-17 16:35:23 -07003269 virtual void popR0() {
3270 fprintf(stderr, "popR0()\n");
3271 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003272 }
3273
Jack Palevich58c30ee2009-07-17 16:35:23 -07003274 virtual void storeR0ToTOS() {
3275 fprintf(stderr, "storeR0ToTOS()\n");
3276 mpBase->storeR0ToTOS();
3277 }
3278
3279 virtual void loadR0FromR0() {
3280 fprintf(stderr, "loadR0FromR0()\n");
3281 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003282 }
3283
Jack Palevichb5e33312009-07-30 19:06:34 -07003284 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3285 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3286 pPointerType->pHead->tag, et);
3287 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003288 }
3289
Jack Palevich9f51a262009-07-29 16:22:26 -07003290 virtual int leaForward(int ea, Type* pPointerType) {
3291 fprintf(stderr, "leaForward(%d)\n", ea);
3292 return mpBase->leaForward(ea, pPointerType);
3293 }
3294
Jack Palevich30321cb2009-08-20 15:34:23 -07003295 virtual void convertR0Imp(Type* pType, bool isCast){
3296 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3297 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003298 }
3299
3300 virtual int beginFunctionCallArguments() {
3301 int result = mpBase->beginFunctionCallArguments();
3302 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3303 return result;
3304 }
3305
Jack Palevich8148c5b2009-07-16 18:24:47 -07003306 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3307 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3308 pArgType->tag);
3309 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003310 }
3311
Jack Palevichb7718b92009-07-09 22:00:24 -07003312 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003313 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003314 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003315 }
3316
Jack Palevich8df46192009-07-07 14:48:51 -07003317 virtual int callForward(int symbol, Type* pFunc) {
3318 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003319 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3320 return result;
3321 }
3322
Jack Palevich8df46192009-07-07 14:48:51 -07003323 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003324 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3325 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003326 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003327 }
3328
Jack Palevichb7718b92009-07-09 22:00:24 -07003329 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3330 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3331 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003332 }
3333
3334 virtual int jumpOffset() {
3335 return mpBase->jumpOffset();
3336 }
3337
Jack Palevichb67b18f2009-06-11 21:12:23 -07003338 /* output a symbol and patch all calls to it */
3339 virtual void gsym(int t) {
3340 fprintf(stderr, "gsym(%d)\n", t);
3341 mpBase->gsym(t);
3342 }
3343
Jack Palevich9f51a262009-07-29 16:22:26 -07003344 virtual void resolveForward(int t) {
3345 mpBase->resolveForward(t);
3346 }
3347
Jack Palevichb67b18f2009-06-11 21:12:23 -07003348 virtual int finishCompile() {
3349 int result = mpBase->finishCompile();
3350 fprintf(stderr, "finishCompile() = %d\n", result);
3351 return result;
3352 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003353
3354 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003355 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003356 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003357 virtual size_t alignmentOf(Type* pType){
3358 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003359 }
3360
3361 /**
3362 * Array element alignment (in bytes) for this type of data.
3363 */
3364 virtual size_t sizeOf(Type* pType){
3365 return mpBase->sizeOf(pType);
3366 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003367
3368 virtual Type* getR0Type() {
3369 return mpBase->getR0Type();
3370 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003371
3372 virtual ExpressionType getR0ExpressionType() {
3373 return mpBase->getR0ExpressionType();
3374 }
3375
3376 virtual void setR0ExpressionType(ExpressionType et) {
3377 mpBase->setR0ExpressionType(et);
3378 }
3379
3380 virtual size_t getExpressionStackDepth() {
3381 return mpBase->getExpressionStackDepth();
3382 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003383
3384 virtual void forceR0RVal() {
3385 return mpBase->forceR0RVal();
3386 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003387 };
3388
3389#endif // PROVIDE_TRACE_CODEGEN
3390
Jack Palevich569f1352009-06-29 14:29:08 -07003391 class Arena {
3392 public:
3393 // Used to record a given allocation amount.
3394 // Used:
3395 // Mark mark = arena.mark();
3396 // ... lots of arena.allocate()
3397 // arena.free(mark);
3398
3399 struct Mark {
3400 size_t chunk;
3401 size_t offset;
3402 };
3403
3404 Arena() {
3405 mCurrentChunk = 0;
3406 Chunk start(CHUNK_SIZE);
3407 mData.push_back(start);
3408 }
3409
3410 ~Arena() {
3411 for(size_t i = 0; i < mData.size(); i++) {
3412 mData[i].free();
3413 }
3414 }
3415
3416 // Alloc using the standard alignment size safe for any variable
3417 void* alloc(size_t size) {
3418 return alloc(size, 8);
3419 }
3420
3421 Mark mark(){
3422 Mark result;
3423 result.chunk = mCurrentChunk;
3424 result.offset = mData[mCurrentChunk].mOffset;
3425 return result;
3426 }
3427
3428 void freeToMark(const Mark& mark) {
3429 mCurrentChunk = mark.chunk;
3430 mData[mCurrentChunk].mOffset = mark.offset;
3431 }
3432
3433 private:
3434 // Allocate memory aligned to a given size
3435 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3436 // Memory is not zero filled.
3437
3438 void* alloc(size_t size, size_t alignment) {
3439 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3440 if (mCurrentChunk + 1 < mData.size()) {
3441 mCurrentChunk++;
3442 } else {
3443 size_t allocSize = CHUNK_SIZE;
3444 if (allocSize < size + alignment - 1) {
3445 allocSize = size + alignment - 1;
3446 }
3447 Chunk chunk(allocSize);
3448 mData.push_back(chunk);
3449 mCurrentChunk++;
3450 }
3451 }
3452 return mData[mCurrentChunk].allocate(size, alignment);
3453 }
3454
3455 static const size_t CHUNK_SIZE = 128*1024;
3456 // Note: this class does not deallocate its
3457 // memory when it's destroyed. It depends upon
3458 // its parent to deallocate the memory.
3459 struct Chunk {
3460 Chunk() {
3461 mpData = 0;
3462 mSize = 0;
3463 mOffset = 0;
3464 }
3465
3466 Chunk(size_t size) {
3467 mSize = size;
3468 mpData = (char*) malloc(size);
3469 mOffset = 0;
3470 }
3471
3472 ~Chunk() {
3473 // Doesn't deallocate memory.
3474 }
3475
3476 void* allocate(size_t size, size_t alignment) {
3477 size_t alignedOffset = aligned(mOffset, alignment);
3478 void* result = mpData + alignedOffset;
3479 mOffset = alignedOffset + size;
3480 return result;
3481 }
3482
3483 void free() {
3484 if (mpData) {
3485 ::free(mpData);
3486 mpData = 0;
3487 }
3488 }
3489
3490 size_t remainingCapacity(size_t alignment) {
3491 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3492 }
3493
3494 // Assume alignment is a power of two
3495 inline size_t aligned(size_t v, size_t alignment) {
3496 size_t mask = alignment-1;
3497 return (v + mask) & ~mask;
3498 }
3499
3500 char* mpData;
3501 size_t mSize;
3502 size_t mOffset;
3503 };
3504
3505 size_t mCurrentChunk;
3506
3507 Vector<Chunk> mData;
3508 };
3509
Jack Palevich569f1352009-06-29 14:29:08 -07003510 struct VariableInfo;
3511
3512 struct Token {
3513 int hash;
3514 size_t length;
3515 char* pText;
3516 tokenid_t id;
3517
3518 // Current values for the token
3519 char* mpMacroDefinition;
3520 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003521 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003522 };
3523
3524 class TokenTable {
3525 public:
3526 // Don't use 0..0xff, allows characters and operators to be tokens too.
3527
3528 static const int TOKEN_BASE = 0x100;
3529 TokenTable() {
3530 mpMap = hashmapCreate(128, hashFn, equalsFn);
3531 }
3532
3533 ~TokenTable() {
3534 hashmapFree(mpMap);
3535 }
3536
3537 void setArena(Arena* pArena) {
3538 mpArena = pArena;
3539 }
3540
3541 // Returns a token for a given string of characters.
3542 tokenid_t intern(const char* pText, size_t length) {
3543 Token probe;
3544 int hash = hashmapHash((void*) pText, length);
3545 {
3546 Token probe;
3547 probe.hash = hash;
3548 probe.length = length;
3549 probe.pText = (char*) pText;
3550 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3551 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003552 return pValue->id;
3553 }
3554 }
3555
3556 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3557 memset(pToken, 0, sizeof(*pToken));
3558 pToken->hash = hash;
3559 pToken->length = length;
3560 pToken->pText = (char*) mpArena->alloc(length + 1);
3561 memcpy(pToken->pText, pText, length);
3562 pToken->pText[length] = 0;
3563 pToken->id = mTokens.size() + TOKEN_BASE;
3564 mTokens.push_back(pToken);
3565 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003566 return pToken->id;
3567 }
3568
3569 // Return the Token for a given tokenid.
3570 Token& operator[](tokenid_t id) {
3571 return *mTokens[id - TOKEN_BASE];
3572 }
3573
3574 inline size_t size() {
3575 return mTokens.size();
3576 }
3577
3578 private:
3579
3580 static int hashFn(void* pKey) {
3581 Token* pToken = (Token*) pKey;
3582 return pToken->hash;
3583 }
3584
3585 static bool equalsFn(void* keyA, void* keyB) {
3586 Token* pTokenA = (Token*) keyA;
3587 Token* pTokenB = (Token*) keyB;
3588 // Don't need to compare hash values, they should always be equal
3589 return pTokenA->length == pTokenB->length
3590 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3591 }
3592
3593 Hashmap* mpMap;
3594 Vector<Token*> mTokens;
3595 Arena* mpArena;
3596 };
3597
Jack Palevich1cdef202009-05-22 12:06:27 -07003598 class InputStream {
3599 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003600 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003601 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003602 };
3603
3604 class TextInputStream : public InputStream {
3605 public:
3606 TextInputStream(const char* text, size_t textLength)
3607 : pText(text), mTextLength(textLength), mPosition(0) {
3608 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003609
Jack Palevichdc456462009-07-16 16:50:56 -07003610 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003611 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3612 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003613
Jack Palevichdc456462009-07-16 16:50:56 -07003614 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003615 const char* pText;
3616 size_t mTextLength;
3617 size_t mPosition;
3618 };
3619
Jack Palevicheedf9d22009-06-04 16:23:40 -07003620 class String {
3621 public:
3622 String() {
3623 mpBase = 0;
3624 mUsed = 0;
3625 mSize = 0;
3626 }
3627
Jack Palevich303d8ff2009-06-11 19:06:24 -07003628 String(const char* item, int len, bool adopt) {
3629 if (len < 0) {
3630 len = strlen(item);
3631 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003632 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003633 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003634 mUsed = len;
3635 mSize = len + 1;
3636 } else {
3637 mpBase = 0;
3638 mUsed = 0;
3639 mSize = 0;
3640 appendBytes(item, len);
3641 }
3642 }
3643
Jack Palevich303d8ff2009-06-11 19:06:24 -07003644 String(const String& other) {
3645 mpBase = 0;
3646 mUsed = 0;
3647 mSize = 0;
3648 appendBytes(other.getUnwrapped(), other.len());
3649 }
3650
Jack Palevicheedf9d22009-06-04 16:23:40 -07003651 ~String() {
3652 if (mpBase) {
3653 free(mpBase);
3654 }
3655 }
3656
Jack Palevicha6baa232009-06-12 11:25:59 -07003657 String& operator=(const String& other) {
3658 clear();
3659 appendBytes(other.getUnwrapped(), other.len());
3660 return *this;
3661 }
3662
Jack Palevich303d8ff2009-06-11 19:06:24 -07003663 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003664 return mpBase;
3665 }
3666
Jack Palevich303d8ff2009-06-11 19:06:24 -07003667 void clear() {
3668 mUsed = 0;
3669 if (mSize > 0) {
3670 mpBase[0] = 0;
3671 }
3672 }
3673
Jack Palevicheedf9d22009-06-04 16:23:40 -07003674 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003675 appendBytes(s, strlen(s));
3676 }
3677
3678 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003679 memcpy(ensure(n), s, n + 1);
3680 }
3681
3682 void append(char c) {
3683 * ensure(1) = c;
3684 }
3685
Jack Palevich86351982009-06-30 18:09:56 -07003686 void append(String& other) {
3687 appendBytes(other.getUnwrapped(), other.len());
3688 }
3689
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003690 char* orphan() {
3691 char* result = mpBase;
3692 mpBase = 0;
3693 mUsed = 0;
3694 mSize = 0;
3695 return result;
3696 }
3697
Jack Palevicheedf9d22009-06-04 16:23:40 -07003698 void printf(const char* fmt,...) {
3699 va_list ap;
3700 va_start(ap, fmt);
3701 vprintf(fmt, ap);
3702 va_end(ap);
3703 }
3704
3705 void vprintf(const char* fmt, va_list ap) {
3706 char* temp;
3707 int numChars = vasprintf(&temp, fmt, ap);
3708 memcpy(ensure(numChars), temp, numChars+1);
3709 free(temp);
3710 }
3711
Jack Palevich303d8ff2009-06-11 19:06:24 -07003712 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003713 return mUsed;
3714 }
3715
3716 private:
3717 char* ensure(int n) {
3718 size_t newUsed = mUsed + n;
3719 if (newUsed > mSize) {
3720 size_t newSize = mSize * 2 + 10;
3721 if (newSize < newUsed) {
3722 newSize = newUsed;
3723 }
3724 mpBase = (char*) realloc(mpBase, newSize + 1);
3725 mSize = newSize;
3726 }
3727 mpBase[newUsed] = '\0';
3728 char* result = mpBase + mUsed;
3729 mUsed = newUsed;
3730 return result;
3731 }
3732
3733 char* mpBase;
3734 size_t mUsed;
3735 size_t mSize;
3736 };
3737
Jack Palevich569f1352009-06-29 14:29:08 -07003738 void internKeywords() {
3739 // Note: order has to match TOK_ constants
3740 static const char* keywords[] = {
3741 "int",
3742 "char",
3743 "void",
3744 "if",
3745 "else",
3746 "while",
3747 "break",
3748 "return",
3749 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003750 "auto",
3751 "case",
3752 "const",
3753 "continue",
3754 "default",
3755 "do",
3756 "double",
3757 "enum",
3758 "extern",
3759 "float",
3760 "goto",
3761 "long",
3762 "register",
3763 "short",
3764 "signed",
3765 "sizeof",
3766 "static",
3767 "struct",
3768 "switch",
3769 "typedef",
3770 "union",
3771 "unsigned",
3772 "volatile",
3773 "_Bool",
3774 "_Complex",
3775 "_Imaginary",
3776 "inline",
3777 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003778
3779 // predefined tokens that can also be symbols start here:
3780 "pragma",
3781 "define",
3782 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003783 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003784
Jack Palevich569f1352009-06-29 14:29:08 -07003785 for(int i = 0; keywords[i]; i++) {
3786 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003787 }
Jack Palevich569f1352009-06-29 14:29:08 -07003788 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003789
Jack Palevich36d94142009-06-08 15:55:32 -07003790 struct InputState {
3791 InputStream* pStream;
3792 int oldCh;
3793 };
3794
Jack Palevich2db168f2009-06-11 14:29:47 -07003795 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003796 void* pAddress;
3797 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003798 tokenid_t tok;
3799 size_t level;
3800 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003801 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003802 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003803 };
3804
Jack Palevich303d8ff2009-06-11 19:06:24 -07003805 class SymbolStack {
3806 public:
3807 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003808 mpArena = 0;
3809 mpTokenTable = 0;
3810 }
3811
3812 void setArena(Arena* pArena) {
3813 mpArena = pArena;
3814 }
3815
3816 void setTokenTable(TokenTable* pTokenTable) {
3817 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003818 }
3819
3820 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003821 Mark mark;
3822 mark.mArenaMark = mpArena->mark();
3823 mark.mSymbolHead = mStack.size();
3824 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003825 }
3826
3827 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003828 // Undo any shadowing that was done:
3829 Mark mark = mLevelStack.back();
3830 mLevelStack.pop_back();
3831 while (mStack.size() > mark.mSymbolHead) {
3832 VariableInfo* pV = mStack.back();
3833 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003834 if (pV->isStructTag) {
3835 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3836 } else {
3837 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3838 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003839 }
Jack Palevich569f1352009-06-29 14:29:08 -07003840 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003841 }
3842
Jack Palevich569f1352009-06-29 14:29:08 -07003843 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3844 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3845 return pV && pV->level == level();
3846 }
3847
Jack Palevich9221bcc2009-08-26 16:15:07 -07003848 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3849 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3850 return pV && pV->level == level();
3851 }
3852
Jack Palevich569f1352009-06-29 14:29:08 -07003853 VariableInfo* add(tokenid_t tok) {
3854 Token& token = (*mpTokenTable)[tok];
3855 VariableInfo* pOldV = token.mpVariableInfo;
3856 VariableInfo* pNewV =
3857 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3858 memset(pNewV, 0, sizeof(VariableInfo));
3859 pNewV->tok = tok;
3860 pNewV->level = level();
3861 pNewV->pOldDefinition = pOldV;
3862 token.mpVariableInfo = pNewV;
3863 mStack.push_back(pNewV);
3864 return pNewV;
3865 }
3866
Jack Palevich9221bcc2009-08-26 16:15:07 -07003867 VariableInfo* addStructTag(tokenid_t tok) {
3868 Token& token = (*mpTokenTable)[tok];
3869 VariableInfo* pOldS = token.mpStructInfo;
3870 VariableInfo* pNewS =
3871 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3872 memset(pNewS, 0, sizeof(VariableInfo));
3873 pNewS->tok = tok;
3874 pNewS->level = level();
3875 pNewS->isStructTag = true;
3876 pNewS->pOldDefinition = pOldS;
3877 token.mpStructInfo = pNewS;
3878 mStack.push_back(pNewS);
3879 return pNewS;
3880 }
3881
Jack Palevich86351982009-06-30 18:09:56 -07003882 VariableInfo* add(Type* pType) {
3883 VariableInfo* pVI = add(pType->id);
3884 pVI->pType = pType;
3885 return pVI;
3886 }
3887
Jack Palevich569f1352009-06-29 14:29:08 -07003888 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3889 for (size_t i = 0; i < mStack.size(); i++) {
3890 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003891 break;
3892 }
3893 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003894 }
3895
Jack Palevich303d8ff2009-06-11 19:06:24 -07003896 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003897 inline size_t level() {
3898 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003899 }
3900
Jack Palevich569f1352009-06-29 14:29:08 -07003901 struct Mark {
3902 Arena::Mark mArenaMark;
3903 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003904 };
3905
Jack Palevich569f1352009-06-29 14:29:08 -07003906 Arena* mpArena;
3907 TokenTable* mpTokenTable;
3908 Vector<VariableInfo*> mStack;
3909 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003910 };
Jack Palevich36d94142009-06-08 15:55:32 -07003911
Jack Palevich188a5a72009-10-27 17:23:20 -07003912 struct MacroState {
3913 tokenid_t name; // Name of the current macro we are expanding
3914 char* dptr; // point to macro text during macro playback
3915 int dch; // Saves old value of ch during a macro playback
3916 };
3917
3918#define MACRO_NESTING_MAX 32
3919 MacroState macroState[MACRO_NESTING_MAX];
3920 int macroLevel; // -1 means not playing any macro.
3921
Jack Palevich36d94142009-06-08 15:55:32 -07003922 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003923 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003924 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003925 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003926 int tokl; // token operator level
3927 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003928 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003929 intptr_t loc; // local variable index
3930 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003931 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003932 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003933 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003934 ACCSymbolLookupFn mpSymbolLookupFn;
3935 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003936
3937 // Arena for the duration of the compile
3938 Arena mGlobalArena;
3939 // Arena for data that's only needed when compiling a single function
3940 Arena mLocalArena;
3941
Jack Palevich2ff5c222009-07-23 15:11:22 -07003942 Arena* mpCurrentArena;
3943
Jack Palevich569f1352009-06-29 14:29:08 -07003944 TokenTable mTokenTable;
3945 SymbolStack mGlobals;
3946 SymbolStack mLocals;
3947
Jack Palevich9221bcc2009-08-26 16:15:07 -07003948 SymbolStack* mpCurrentSymbolStack;
3949
Jack Palevich40600de2009-07-01 15:32:35 -07003950 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003951 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003952 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003953 Type* mkpChar; // char
3954 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003955 Type* mkpFloat;
3956 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003957 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003958 Type* mkpIntPtr;
3959 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003960 Type* mkpFloatPtr;
3961 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003962 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003963
Jack Palevich36d94142009-06-08 15:55:32 -07003964 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003965 int mLineNumber;
3966 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003967
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003968 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003969 CodeGenerator* pGen;
3970
Jack Palevicheedf9d22009-06-04 16:23:40 -07003971 String mErrorBuf;
3972
Jack Palevicheedf9d22009-06-04 16:23:40 -07003973 String mPragmas;
3974 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003975 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003976
Jack Palevich21a15a22009-05-11 14:49:29 -07003977 static const int ALLOC_SIZE = 99999;
3978
Jack Palevich303d8ff2009-06-11 19:06:24 -07003979 static const int TOK_DUMMY = 1;
3980 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003981 static const int TOK_NUM_FLOAT = 3;
3982 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003983 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003984 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003985
3986 // 3..255 are character and/or operators
3987
Jack Palevich2db168f2009-06-11 14:29:47 -07003988 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003989 // Order has to match string list in "internKeywords".
3990 enum {
3991 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3992 TOK_INT = TOK_KEYWORD,
3993 TOK_CHAR,
3994 TOK_VOID,
3995 TOK_IF,
3996 TOK_ELSE,
3997 TOK_WHILE,
3998 TOK_BREAK,
3999 TOK_RETURN,
4000 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07004001 TOK_AUTO,
4002 TOK_CASE,
4003 TOK_CONST,
4004 TOK_CONTINUE,
4005 TOK_DEFAULT,
4006 TOK_DO,
4007 TOK_DOUBLE,
4008 TOK_ENUM,
4009 TOK_EXTERN,
4010 TOK_FLOAT,
4011 TOK_GOTO,
4012 TOK_LONG,
4013 TOK_REGISTER,
4014 TOK_SHORT,
4015 TOK_SIGNED,
4016 TOK_SIZEOF,
4017 TOK_STATIC,
4018 TOK_STRUCT,
4019 TOK_SWITCH,
4020 TOK_TYPEDEF,
4021 TOK_UNION,
4022 TOK_UNSIGNED,
4023 TOK_VOLATILE,
4024 TOK__BOOL,
4025 TOK__COMPLEX,
4026 TOK__IMAGINARY,
4027 TOK_INLINE,
4028 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004029
4030 // Symbols start after keywords
4031
4032 TOK_SYMBOL,
4033 TOK_PRAGMA = TOK_SYMBOL,
4034 TOK_DEFINE,
4035 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004036 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004037
4038 static const int LOCAL = 0x200;
4039
Jack Palevich21a15a22009-05-11 14:49:29 -07004040 /* tokens in string heap */
4041 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004042
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004043 static const int OP_INCREMENT = 0;
4044 static const int OP_DECREMENT = 1;
4045 static const int OP_MUL = 2;
4046 static const int OP_DIV = 3;
4047 static const int OP_MOD = 4;
4048 static const int OP_PLUS = 5;
4049 static const int OP_MINUS = 6;
4050 static const int OP_SHIFT_LEFT = 7;
4051 static const int OP_SHIFT_RIGHT = 8;
4052 static const int OP_LESS_EQUAL = 9;
4053 static const int OP_GREATER_EQUAL = 10;
4054 static const int OP_LESS = 11;
4055 static const int OP_GREATER = 12;
4056 static const int OP_EQUALS = 13;
4057 static const int OP_NOT_EQUALS = 14;
4058 static const int OP_LOGICAL_AND = 15;
4059 static const int OP_LOGICAL_OR = 16;
4060 static const int OP_BIT_AND = 17;
4061 static const int OP_BIT_XOR = 18;
4062 static const int OP_BIT_OR = 19;
4063 static const int OP_BIT_NOT = 20;
4064 static const int OP_LOGICAL_NOT = 21;
4065 static const int OP_COUNT = 22;
4066
4067 /* Operators are searched from front, the two-character operators appear
4068 * before the single-character operators with the same first character.
4069 * @ is used to pad out single-character operators.
4070 */
4071 static const char* operatorChars;
4072 static const char operatorLevel[];
4073
Jack Palevich569f1352009-06-29 14:29:08 -07004074 /* Called when we detect an internal problem. Does nothing in production.
4075 *
4076 */
4077 void internalError() {
4078 * (char*) 0 = 0;
4079 }
4080
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004081 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004082 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004083 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004084 internalError();
4085 }
Jack Palevich86351982009-06-30 18:09:56 -07004086 }
4087
Jack Palevich40600de2009-07-01 15:32:35 -07004088 bool isSymbol(tokenid_t t) {
4089 return t >= TOK_SYMBOL &&
4090 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4091 }
4092
4093 bool isSymbolOrKeyword(tokenid_t t) {
4094 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004095 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004096 }
4097
Jack Palevich86351982009-06-30 18:09:56 -07004098 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004099 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004100 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4101 if (pV && pV->tok != t) {
4102 internalError();
4103 }
4104 return pV;
4105 }
4106
4107 inline bool isDefined(tokenid_t t) {
4108 return t >= TOK_SYMBOL && VI(t) != 0;
4109 }
4110
Jack Palevich40600de2009-07-01 15:32:35 -07004111 const char* nameof(tokenid_t t) {
4112 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004113 return mTokenTable[t].pText;
4114 }
4115
Jack Palevich21a15a22009-05-11 14:49:29 -07004116 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004117 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004118 }
4119
4120 void inp() {
Jack Palevich188a5a72009-10-27 17:23:20 -07004121 // Close any totally empty macros. We leave them on the stack until now
4122 // so that we know which macros are being expanded when checking if the
4123 // last token in the macro is a macro that's already being expanded.
4124 while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
4125 macroLevel--;
4126 }
4127 if (macroLevel >= 0) {
4128 ch = *macroState[macroLevel].dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004129 if (ch == 0) {
Jack Palevich188a5a72009-10-27 17:23:20 -07004130 ch = macroState[macroLevel].dch;
4131 macroState[macroLevel].dptr = NULL; // This macro's done
Jack Palevich21a15a22009-05-11 14:49:29 -07004132 }
Jack Palevichdc456462009-07-16 16:50:56 -07004133 } else {
4134 if (mbBumpLine) {
4135 mLineNumber++;
4136 mbBumpLine = false;
4137 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004138 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004139 if (ch == '\n') {
4140 mbBumpLine = true;
4141 }
4142 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004143#if 0
4144 printf("ch='%c' 0x%x\n", ch, ch);
4145#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004146 }
4147
4148 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004149 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004150 }
4151
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004152 int decodeHex(int c) {
4153 if (isdigit(c)) {
4154 c -= '0';
4155 } else if (c <= 'F') {
4156 c = c - 'A' + 10;
4157 } else {
4158 c =c - 'a' + 10;
4159 }
4160 return c;
4161 }
4162
Jack Palevichb4758ff2009-06-12 12:49:14 -07004163 /* read a character constant, advances ch to after end of constant */
4164 int getq() {
4165 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004166 if (ch == '\\') {
4167 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004168 if (isoctal(ch)) {
4169 // 1 to 3 octal characters.
4170 val = 0;
4171 for(int i = 0; i < 3; i++) {
4172 if (isoctal(ch)) {
4173 val = (val << 3) + ch - '0';
4174 inp();
4175 }
4176 }
4177 return val;
4178 } else if (ch == 'x' || ch == 'X') {
4179 // N hex chars
4180 inp();
4181 if (! isxdigit(ch)) {
4182 error("'x' character escape requires at least one digit.");
4183 } else {
4184 val = 0;
4185 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004186 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004187 inp();
4188 }
4189 }
4190 } else {
4191 int val = ch;
4192 switch (ch) {
4193 case 'a':
4194 val = '\a';
4195 break;
4196 case 'b':
4197 val = '\b';
4198 break;
4199 case 'f':
4200 val = '\f';
4201 break;
4202 case 'n':
4203 val = '\n';
4204 break;
4205 case 'r':
4206 val = '\r';
4207 break;
4208 case 't':
4209 val = '\t';
4210 break;
4211 case 'v':
4212 val = '\v';
4213 break;
4214 case '\\':
4215 val = '\\';
4216 break;
4217 case '\'':
4218 val = '\'';
4219 break;
4220 case '"':
4221 val = '"';
4222 break;
4223 case '?':
4224 val = '?';
4225 break;
4226 default:
4227 error("Undefined character escape %c", ch);
4228 break;
4229 }
4230 inp();
4231 return val;
4232 }
4233 } else {
4234 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004235 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004236 return val;
4237 }
4238
4239 static bool isoctal(int ch) {
4240 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004241 }
4242
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004243 bool acceptCh(int c) {
4244 bool result = c == ch;
4245 if (result) {
4246 pdef(ch);
4247 inp();
4248 }
4249 return result;
4250 }
4251
4252 bool acceptDigitsCh() {
4253 bool result = false;
4254 while (isdigit(ch)) {
4255 result = true;
4256 pdef(ch);
4257 inp();
4258 }
4259 return result;
4260 }
4261
4262 void parseFloat() {
4263 tok = TOK_NUM_DOUBLE;
4264 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004265 if(mTokenString.len() == 0) {
4266 mTokenString.append('0');
4267 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004268 acceptCh('.');
4269 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004270 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004271 acceptCh('-') || acceptCh('+');
4272 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004273 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004274 if (ch == 'f' || ch == 'F') {
4275 tok = TOK_NUM_FLOAT;
4276 inp();
4277 } else if (ch == 'l' || ch == 'L') {
4278 inp();
4279 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004280 }
4281 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004282 char* pEnd = pText + strlen(pText);
4283 char* pEndPtr = 0;
4284 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004285 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004286 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004287 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004288 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004289 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004290 if (errno || pEndPtr != pEnd) {
4291 error("Can't parse constant: %s", pText);
4292 }
4293 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004294 }
4295
Jack Palevich188a5a72009-10-27 17:23:20 -07004296 bool currentlyBeingExpanded(tokenid_t id) {
4297 for (int i = 0; i <= macroLevel; i++) {
4298 if (macroState[macroLevel].name == id) {
4299 return true;
4300 }
4301 }
4302 return false;
4303 }
4304
Jack Palevich21a15a22009-05-11 14:49:29 -07004305 void next() {
4306 int l, a;
4307
Jack Palevich546b2242009-05-13 15:10:04 -07004308 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004309 if (ch == '#') {
4310 inp();
4311 next();
4312 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004313 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004314 } else if (tok == TOK_PRAGMA) {
4315 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004316 } else if (tok == TOK_LINE) {
4317 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004318 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004319 error("Unsupported preprocessor directive \"%s\"",
4320 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004321 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004322 }
4323 inp();
4324 }
4325 tokl = 0;
4326 tok = ch;
4327 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004328 if (isdigit(ch) || ch == '.') {
4329 // Start of a numeric constant. Could be integer, float, or
4330 // double, won't know until we look further.
4331 mTokenString.clear();
4332 pdef(ch);
4333 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004334 if (tok == '.' && !isdigit(ch)) {
4335 goto done;
4336 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004337 int base = 10;
4338 if (tok == '0') {
4339 if (ch == 'x' || ch == 'X') {
4340 base = 16;
4341 tok = TOK_NUM;
4342 tokc = 0;
4343 inp();
4344 while ( isxdigit(ch) ) {
4345 tokc = (tokc << 4) + decodeHex(ch);
4346 inp();
4347 }
4348 } else if (isoctal(ch)){
4349 base = 8;
4350 tok = TOK_NUM;
4351 tokc = 0;
4352 while ( isoctal(ch) ) {
4353 tokc = (tokc << 3) + (ch - '0');
4354 inp();
4355 }
4356 }
4357 } else if (isdigit(tok)){
4358 acceptDigitsCh();
4359 }
4360 if (base == 10) {
4361 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4362 parseFloat();
4363 } else {
4364 // It's an integer constant
4365 char* pText = mTokenString.getUnwrapped();
4366 char* pEnd = pText + strlen(pText);
4367 char* pEndPtr = 0;
4368 errno = 0;
4369 tokc = strtol(pText, &pEndPtr, base);
4370 if (errno || pEndPtr != pEnd) {
4371 error("Can't parse constant: %s %d %d", pText, base, errno);
4372 }
4373 tok = TOK_NUM;
4374 }
4375 }
4376 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004377 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004378 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004379 pdef(ch);
4380 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004381 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004382 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004383 if (! mbSuppressMacroExpansion) {
4384 // Is this a macro?
4385 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
Jack Palevich188a5a72009-10-27 17:23:20 -07004386 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
Jack Palevich815d8b82009-08-18 18:25:56 -07004387 // Yes, it is a macro
Jack Palevich188a5a72009-10-27 17:23:20 -07004388#if 0
4389 printf("Expanding macro %s -> %s",
4390 mTokenString.getUnwrapped(), pMacroDefinition);
4391#endif
4392 if (macroLevel >= MACRO_NESTING_MAX-1) {
4393 error("Too many levels of macro recursion.");
4394 } else {
4395 macroLevel++;
4396 macroState[macroLevel].name = tok;
4397 macroState[macroLevel].dptr = pMacroDefinition;
4398 macroState[macroLevel].dch = ch;
4399 inp();
4400 next();
4401 }
Jack Palevich815d8b82009-08-18 18:25:56 -07004402 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004403 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004404 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004405 inp();
4406 if (tok == '\'') {
4407 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004408 tokc = getq();
4409 if (ch != '\'') {
4410 error("Expected a ' character, got %c", ch);
4411 } else {
4412 inp();
4413 }
Jack Palevich546b2242009-05-13 15:10:04 -07004414 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004415 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004416 while (ch && ch != EOF) {
4417 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004418 inp();
4419 inp();
4420 if (ch == '/')
4421 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004422 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004423 if (ch == EOF) {
4424 error("End of file inside comment.");
4425 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004426 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004427 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004428 } else if ((tok == '/') & (ch == '/')) {
4429 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004430 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004431 inp();
4432 }
4433 inp();
4434 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004435 } else if ((tok == '-') & (ch == '>')) {
4436 inp();
4437 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004438 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004439 const char* t = operatorChars;
4440 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004441 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004442 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004443 tokl = operatorLevel[opIndex];
4444 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004445 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004446#if 0
4447 printf("%c%c -> tokl=%d tokc=0x%x\n",
4448 l, a, tokl, tokc);
4449#endif
4450 if (a == ch) {
4451 inp();
4452 tok = TOK_DUMMY; /* dummy token for double tokens */
4453 }
Jack Palevich0c017742009-07-31 12:00:39 -07004454 /* check for op=, valid for * / % + - << >> & ^ | */
4455 if (ch == '=' &&
4456 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004457 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004458 inp();
4459 tok = TOK_OP_ASSIGNMENT;
4460 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004461 break;
4462 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004463 opIndex++;
4464 }
4465 if (l == 0) {
4466 tokl = 0;
4467 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004468 }
4469 }
4470 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004471
4472 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004473#if 0
4474 {
Jack Palevich569f1352009-06-29 14:29:08 -07004475 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004476 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004477 fprintf(stderr, "%s\n", buf.getUnwrapped());
4478 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004479#endif
4480 }
4481
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004482 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004483 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004484 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004485 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004486 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004487 if (ch == '(') {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004488 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004489 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004490 }
4491 while (isspace(ch)) {
4492 inp();
4493 }
Jack Palevich569f1352009-06-29 14:29:08 -07004494 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004495 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004496 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004497 // Check for '//' comments.
4498 if (appendToValue && ch == '/') {
4499 inp();
4500 if (ch == '/') {
4501 appendToValue = false;
4502 } else {
4503 value.append('/');
4504 }
4505 }
4506 if (appendToValue && ch != EOF) {
4507 value.append(ch);
4508 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004509 inp();
4510 }
Jack Palevich569f1352009-06-29 14:29:08 -07004511 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4512 memcpy(pDefn, value.getUnwrapped(), value.len());
4513 pDefn[value.len()] = 0;
4514 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich188a5a72009-10-27 17:23:20 -07004515#if 0
4516 {
4517 String buf;
4518 decodeToken(buf, name, true);
4519 fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
4520 }
4521#endif
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004522 }
4523
Jack Palevicheedf9d22009-06-04 16:23:40 -07004524 void doPragma() {
4525 // # pragma name(val)
4526 int state = 0;
4527 while(ch != EOF && ch != '\n' && state < 10) {
4528 switch(state) {
4529 case 0:
4530 if (isspace(ch)) {
4531 inp();
4532 } else {
4533 state++;
4534 }
4535 break;
4536 case 1:
4537 if (isalnum(ch)) {
4538 mPragmas.append(ch);
4539 inp();
4540 } else if (ch == '(') {
4541 mPragmas.append(0);
4542 inp();
4543 state++;
4544 } else {
4545 state = 11;
4546 }
4547 break;
4548 case 2:
4549 if (isalnum(ch)) {
4550 mPragmas.append(ch);
4551 inp();
4552 } else if (ch == ')') {
4553 mPragmas.append(0);
4554 inp();
4555 state = 10;
4556 } else {
4557 state = 11;
4558 }
4559 break;
4560 }
4561 }
4562 if(state != 10) {
4563 error("Unexpected pragma syntax");
4564 }
4565 mPragmaStringCount += 2;
4566 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004567
Jack Palevichdc456462009-07-16 16:50:56 -07004568 void doLine() {
4569 // # line number { "filename "}
4570 next();
4571 if (tok != TOK_NUM) {
4572 error("Expected a line-number");
4573 } else {
4574 mLineNumber = tokc-1; // The end-of-line will increment it.
4575 }
4576 while(ch != EOF && ch != '\n') {
4577 inp();
4578 }
4579 }
4580
Jack Palevichac0e95e2009-05-29 13:53:44 -07004581 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004582 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004583 mErrorBuf.vprintf(fmt, ap);
4584 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004585 }
4586
Jack Palevich8b0624c2009-05-20 12:12:06 -07004587 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004588 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004589 error("'%c' expected", c);
4590 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004591 }
4592
Jack Palevich86351982009-06-30 18:09:56 -07004593 bool accept(intptr_t c) {
4594 if (tok == c) {
4595 next();
4596 return true;
4597 }
4598 return false;
4599 }
4600
Jack Palevich40600de2009-07-01 15:32:35 -07004601 bool acceptStringLiteral() {
4602 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004603 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004604 // This while loop merges multiple adjacent string constants.
4605 while (tok == '"') {
4606 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004607 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004608 }
4609 if (ch != '"') {
4610 error("Unterminated string constant.");
4611 }
4612 inp();
4613 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004614 }
Jack Palevich40600de2009-07-01 15:32:35 -07004615 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004616 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004617 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004618 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004619
4620 return true;
4621 }
4622 return false;
4623 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004624
Jack Palevichb1544ca2009-07-16 15:09:20 -07004625 void linkGlobal(tokenid_t t, bool isFunction) {
4626 VariableInfo* pVI = VI(t);
4627 void* n = NULL;
4628 if (mpSymbolLookupFn) {
4629 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4630 }
4631 if (pVI->pType == NULL) {
4632 if (isFunction) {
4633 pVI->pType = mkpIntFn;
4634 } else {
4635 pVI->pType = mkpInt;
4636 }
4637 }
4638 pVI->pAddress = n;
4639 }
4640
Jack Palevich29daf572009-07-30 19:38:55 -07004641 void unaryOrAssignment() {
4642 unary();
4643 if (accept('=')) {
4644 checkLVal();
4645 pGen->pushR0();
4646 expr();
4647 pGen->forceR0RVal();
4648 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004649 } else if (tok == TOK_OP_ASSIGNMENT) {
4650 int t = tokc;
4651 next();
4652 checkLVal();
4653 pGen->pushR0();
4654 pGen->forceR0RVal();
4655 pGen->pushR0();
4656 expr();
4657 pGen->forceR0RVal();
4658 pGen->genOp(t);
4659 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004660 }
4661 }
4662
Jack Palevich40600de2009-07-01 15:32:35 -07004663 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004664 */
Jack Palevich29daf572009-07-30 19:38:55 -07004665 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004666 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004667 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004668 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004669 if (acceptStringLiteral()) {
4670 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004671 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004672 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004673 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004674 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004675 t = tok;
4676 next();
4677 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004678 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004679 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004680 // Align to 4-byte boundary
4681 glo = (char*) (((intptr_t) glo + 3) & -4);
4682 * (float*) glo = (float) ad;
4683 pGen->loadFloat((int) glo, mkpFloat);
4684 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004685 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004686 // Align to 8-byte boundary
4687 glo = (char*) (((intptr_t) glo + 7) & -8);
4688 * (double*) glo = ad;
4689 pGen->loadFloat((int) glo, mkpDouble);
4690 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004691 } else if (c == 2) {
4692 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004693 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004694 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004695 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004696 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004697 else if (t == '+') {
4698 // ignore unary plus.
4699 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004700 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004701 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004702 } else if (c == 11) {
4703 // pre increment / pre decrement
4704 unary();
4705 doIncDec(a == OP_INCREMENT, 0);
4706 }
4707 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004708 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004709 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004710 if (pCast) {
4711 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004712 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004713 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004714 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004715 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004716 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004717 skip(')');
4718 }
4719 } else if (t == '*') {
4720 /* This is a pointer dereference.
4721 */
Jack Palevich29daf572009-07-30 19:38:55 -07004722 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004723 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004724 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004725 unary();
4726 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004727 } else if (t == EOF ) {
4728 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004729 } else if (t == ';') {
4730 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004731 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004732 // Don't have to do anything special here, the error
4733 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004734 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004735 if (!isDefined(t)) {
4736 mGlobals.add(t);
4737 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004738 }
Jack Palevich8df46192009-07-07 14:48:51 -07004739 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004740 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004741 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004742 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004743 linkGlobal(t, tok == '(');
4744 n = (intptr_t) pVI->pAddress;
4745 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004746 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004747 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004748 }
Jack Palevich29daf572009-07-30 19:38:55 -07004749 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004750 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004751 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004752 linkGlobal(t, false);
4753 n = (intptr_t) pVI->pAddress;
4754 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004755 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004756 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004757 }
Jack Palevich5b659092009-07-31 14:55:07 -07004758 }
4759 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004760 Type* pVal;
4761 ExpressionType et;
4762 if (pVI->pType->tag == TY_ARRAY) {
4763 pVal = pVI->pType;
4764 et = ET_RVALUE;
4765 } else {
4766 pVal = createPtrType(pVI->pType);
4767 et = ET_LVALUE;
4768 }
Jack Palevich5b659092009-07-31 14:55:07 -07004769 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004770 int tag = pVal->pHead->tag;
4771 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004772 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004773 }
Jack Palevich5b659092009-07-31 14:55:07 -07004774 pGen->leaR0(n, pVal, et);
4775 } else {
4776 pVI->pForward = (void*) pGen->leaForward(
4777 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004778 }
4779 }
4780 }
4781
Jack Palevich5b659092009-07-31 14:55:07 -07004782 /* Now handle postfix operators */
4783 for(;;) {
4784 if (tokl == 11) {
4785 // post inc / post dec
4786 doIncDec(tokc == OP_INCREMENT, true);
4787 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004788 } else if (accept('[')) {
4789 // Array reference
4790 pGen->forceR0RVal();
4791 pGen->pushR0();
4792 commaExpr();
4793 pGen->forceR0RVal();
4794 pGen->genOp(OP_PLUS);
4795 doPointer();
4796 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004797 } else if (accept('.')) {
4798 // struct element
4799 pGen->forceR0RVal();
4800 Type* pStruct = pGen->getR0Type();
4801 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004802 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004803 } else {
4804 error("expected a struct value to the left of '.'");
4805 }
4806 } else if (accept(TOK_OP_ARROW)) {
4807 pGen->forceR0RVal();
4808 Type* pPtr = pGen->getR0Type();
4809 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4810 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004811 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004812 } else {
4813 error("Expected a pointer to a struct to the left of '->'");
4814 }
Jack Palevich5b659092009-07-31 14:55:07 -07004815 } else if (accept('(')) {
4816 /* function call */
4817 Type* pDecl = NULL;
4818 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004819 Type* pFn = pGen->getR0Type();
Jack Palevich188a5a72009-10-27 17:23:20 -07004820 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
4821 pDecl = pFn->pHead;
4822 pGen->pushR0();
4823 Type* pArgList = pDecl->pTail;
4824 bool varArgs = pArgList == NULL;
4825 /* push args and invert order */
4826 a = pGen->beginFunctionCallArguments();
4827 int l = 0;
4828 int argCount = 0;
4829 while (tok != ')' && tok != EOF) {
4830 if (! varArgs && !pArgList) {
4831 error("Unexpected argument.");
Jack Palevich5b659092009-07-31 14:55:07 -07004832 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004833 expr();
4834 pGen->forceR0RVal();
4835 Type* pTargetType;
4836 if (pArgList) {
4837 pTargetType = pArgList->pHead;
4838 pArgList = pArgList->pTail;
4839 } else {
4840 // This is a ... function, just pass arguments in their
4841 // natural type.
4842 pTargetType = pGen->getR0Type();
4843 if (pTargetType->tag == TY_FLOAT) {
4844 pTargetType = mkpDouble;
4845 } else if (pTargetType->tag == TY_ARRAY) {
4846 // Pass arrays by pointer.
4847 pTargetType = pTargetType->pTail;
4848 }
4849 }
4850 if (pTargetType->tag == TY_VOID) {
4851 error("Can't pass void value for argument %d",
4852 argCount + 1);
4853 } else {
4854 l += pGen->storeR0ToArg(l, pTargetType);
4855 }
4856 if (accept(',')) {
4857 // fine
4858 } else if ( tok != ')') {
4859 error("Expected ',' or ')'");
4860 }
4861 argCount += 1;
Jack Palevich5b659092009-07-31 14:55:07 -07004862 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004863 if (! varArgs && pArgList) {
4864 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich5b659092009-07-31 14:55:07 -07004865 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004866 pGen->endFunctionCallArguments(pDecl, a, l);
4867 skip(')');
4868 pGen->callIndirect(l, pDecl);
4869 pGen->adjustStackAfterCall(pDecl, l, true);
4870 } else {
4871 error("Expected a function value to left of '('.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004872 }
Jack Palevich5b659092009-07-31 14:55:07 -07004873 } else {
4874 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004875 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004876 }
4877 }
4878
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004879 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004880 Type* pStructElement = lookupStructMember(pStruct, tok);
4881 if (pStructElement) {
4882 next();
4883 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4884 } else {
4885 String buf;
4886 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004887 error("Expected a struct member to the right of '%s', got %s",
4888 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004889 }
4890 }
4891
Jack Palevichaaac9282009-07-31 14:34:34 -07004892 void doIncDec(int isInc, int isPost) {
4893 // R0 already has the lval
4894 checkLVal();
4895 int lit = isInc ? 1 : -1;
4896 pGen->pushR0();
4897 pGen->loadR0FromR0();
4898 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004899 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4900 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004901 error("++/-- illegal for this type. %d", tag);
4902 }
4903 if (isPost) {
4904 pGen->over();
4905 pGen->pushR0();
4906 pGen->li(lit);
4907 pGen->genOp(OP_PLUS);
4908 pGen->storeR0ToTOS();
4909 pGen->popR0();
4910 } else {
4911 pGen->pushR0();
4912 pGen->li(lit);
4913 pGen->genOp(OP_PLUS);
4914 pGen->over();
4915 pGen->storeR0ToTOS();
4916 pGen->popR0();
4917 }
4918 }
4919
Jack Palevich47cbea92009-07-31 15:25:53 -07004920 void doPointer() {
4921 pGen->forceR0RVal();
4922 Type* pR0Type = pGen->getR0Type();
4923 if (pR0Type->tag != TY_POINTER) {
4924 error("Expected a pointer type.");
4925 } else {
4926 if (pR0Type->pHead->tag != TY_FUNC) {
4927 pGen->setR0ExpressionType(ET_LVALUE);
4928 }
4929 }
4930 }
4931
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004932 void doAddressOf() {
4933 Type* pR0 = pGen->getR0Type();
4934 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4935 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4936 error("Expected an lvalue");
4937 }
4938 Type* pR0Type = pGen->getR0Type();
4939 pGen->setR0ExpressionType(ET_RVALUE);
4940 }
4941
Jack Palevich40600de2009-07-01 15:32:35 -07004942 /* Recursive descent parser for binary operations.
4943 */
4944 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004945 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004946 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004947 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004948 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004949 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004950 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004951 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004952 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004953 t = tokc;
4954 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004955 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004956 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004957 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004958 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004959 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004960 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004961 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004962 // Check for syntax error.
4963 if (pGen->getR0Type() == NULL) {
4964 // We failed to parse a right-hand argument.
4965 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004966 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004967 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004968 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004969 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004970 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004971 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004972 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004973 }
4974 }
4975 }
4976 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004977 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004978 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004979 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004980 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004981 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004982 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004983 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004984 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004985 }
4986 }
4987 }
4988
Jack Palevich43aaee32009-07-31 14:01:37 -07004989 void commaExpr() {
4990 for(;;) {
4991 expr();
4992 if (!accept(',')) {
4993 break;
4994 }
4995 }
4996 }
4997
Jack Palevich21a15a22009-05-11 14:49:29 -07004998 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004999 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07005000 }
5001
5002 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07005003 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005004 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005005 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07005006 }
5007
Jack Palevich46f2bd22009-10-29 17:56:56 -07005008 void block(intptr_t* breakLabel, intptr_t continueAddress, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07005009 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07005010
Jack Palevich95727a02009-07-06 12:07:15 -07005011 Type* pBaseType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005012 if ((pBaseType = acceptPrimitiveType(true))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07005013 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07005014 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005015 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005016 next();
5017 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07005018 a = test_expr();
5019 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005020 block(breakLabel, continueAddress, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07005021 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005022 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005023 n = pGen->gjmp(0); /* jmp */
5024 pGen->gsym(a);
Jack Palevichc951c592009-10-29 15:04:27 -07005025 block(breakLabel, continueAddress, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005026 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07005027 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005028 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005029 }
Jack Palevich546b2242009-05-13 15:10:04 -07005030 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07005031 t = tok;
5032 next();
5033 skip('(');
5034 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005035 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07005036 a = test_expr();
5037 } else {
5038 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005039 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005040 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005041 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07005042 a = 0;
5043 if (tok != ';')
5044 a = test_expr();
5045 skip(';');
5046 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005047 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005048 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005049 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005050 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005051 n = t + 4;
5052 }
5053 }
5054 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005055 block(&a, n, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005056 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005057 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005058 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005059 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005060 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005061 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005062 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005063 while (tok != '}' && tok != EOF)
Jack Palevichc951c592009-10-29 15:04:27 -07005064 block(breakLabel, continueAddress, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005065 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005066 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005067 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005068 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005069 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005070 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005071 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005072 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005073 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005074 if (pReturnType->tag == TY_VOID) {
5075 error("Must not return a value from a void function");
5076 } else {
5077 pGen->convertR0(pReturnType);
5078 }
5079 } else {
5080 if (pReturnType->tag != TY_VOID) {
5081 error("Must specify a value here");
5082 }
Jack Palevich8df46192009-07-07 14:48:51 -07005083 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005084 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005085 } else if (accept(TOK_BREAK)) {
Jack Palevichc951c592009-10-29 15:04:27 -07005086 if (breakLabel) {
5087 *breakLabel = pGen->gjmp(*breakLabel);
5088 } else {
5089 error("break statement must be within a for, do, while, or switch statement");
5090 }
5091 } else if (accept(TOK_CONTINUE)) {
5092 if (continueAddress) {
5093 pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset());
5094 } else {
5095 error("continue statement must be within a for, do, or while statement");
5096 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005097 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005098 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005099 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005100 }
5101 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005102
Jack Palevicha8f427f2009-07-13 18:40:08 -07005103 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005104 if (a == b) {
5105 return true;
5106 }
5107 if (a == NULL || b == NULL) {
5108 return false;
5109 }
5110 TypeTag at = a->tag;
5111 if (at != b->tag) {
5112 return false;
5113 }
5114 if (at == TY_POINTER) {
5115 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005116 } else if (at == TY_ARRAY) {
5117 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005118 } else if (at == TY_FUNC || at == TY_PARAM) {
5119 return typeEqual(a->pHead, b->pHead)
5120 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005121 } else if (at == TY_STRUCT) {
5122 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005123 }
5124 return true;
5125 }
5126
Jack Palevich2ff5c222009-07-23 15:11:22 -07005127 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005128 assert(tag >= TY_UNKNOWN && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005129 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005130 memset(pType, 0, sizeof(*pType));
Jack Palevichee1f8292009-10-28 16:10:17 -07005131 pType->storageClass = SC_DEFAULT;
Jack Palevich86351982009-06-30 18:09:56 -07005132 pType->tag = tag;
5133 pType->pHead = pHead;
5134 pType->pTail = pTail;
5135 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005136 }
5137
Jack Palevich2ff5c222009-07-23 15:11:22 -07005138 Type* createPtrType(Type* pType) {
5139 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005140 }
5141
5142 /**
5143 * Try to print a type in declaration order
5144 */
Jack Palevich86351982009-06-30 18:09:56 -07005145 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005146 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005147 if (pType == NULL) {
5148 buffer.appendCStr("null");
5149 return;
5150 }
Jack Palevich3f226492009-07-02 14:46:19 -07005151 decodeTypeImp(buffer, pType);
5152 }
5153
5154 void decodeTypeImp(String& buffer, Type* pType) {
5155 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005156 decodeId(buffer, pType->id);
5157 decodeTypeImpPostfix(buffer, pType);
5158 }
Jack Palevich3f226492009-07-02 14:46:19 -07005159
Jack Palevich9221bcc2009-08-26 16:15:07 -07005160 void decodeId(String& buffer, tokenid_t id) {
5161 if (id) {
5162 String temp;
5163 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005164 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005165 }
Jack Palevich3f226492009-07-02 14:46:19 -07005166 }
5167
5168 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5169 TypeTag tag = pType->tag;
5170
Jack Palevich9221bcc2009-08-26 16:15:07 -07005171 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005172 switch (tag) {
5173 case TY_INT:
5174 buffer.appendCStr("int");
5175 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005176 case TY_SHORT:
5177 buffer.appendCStr("short");
5178 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005179 case TY_CHAR:
5180 buffer.appendCStr("char");
5181 break;
5182 case TY_VOID:
5183 buffer.appendCStr("void");
5184 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005185 case TY_FLOAT:
5186 buffer.appendCStr("float");
5187 break;
5188 case TY_DOUBLE:
5189 buffer.appendCStr("double");
5190 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005191 case TY_STRUCT:
5192 {
5193 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5194 buffer.appendCStr(isStruct ? "struct" : "union");
5195 if (pType->pHead && pType->pHead->structTag) {
5196 buffer.append(' ');
5197 decodeId(buffer, pType->pHead->structTag);
5198 }
5199 }
5200 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005201 default:
5202 break;
5203 }
Jack Palevich86351982009-06-30 18:09:56 -07005204 buffer.append(' ');
5205 }
Jack Palevich3f226492009-07-02 14:46:19 -07005206
5207 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005208 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005209 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005210 case TY_SHORT:
5211 break;
Jack Palevich86351982009-06-30 18:09:56 -07005212 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005213 break;
5214 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005215 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005216 case TY_FLOAT:
5217 break;
5218 case TY_DOUBLE:
5219 break;
Jack Palevich86351982009-06-30 18:09:56 -07005220 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005221 decodeTypeImpPrefix(buffer, pType->pHead);
5222 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5223 buffer.append('(');
5224 }
5225 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005226 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005227 case TY_ARRAY:
5228 decodeTypeImpPrefix(buffer, pType->pHead);
5229 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005230 case TY_STRUCT:
5231 break;
Jack Palevich86351982009-06-30 18:09:56 -07005232 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005233 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005234 break;
5235 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005236 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005237 break;
5238 default:
5239 String temp;
5240 temp.printf("Unknown tag %d", pType->tag);
5241 buffer.append(temp);
5242 break;
5243 }
Jack Palevich3f226492009-07-02 14:46:19 -07005244 }
5245
5246 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5247 TypeTag tag = pType->tag;
5248
5249 switch(tag) {
5250 case TY_POINTER:
5251 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5252 buffer.append(')');
5253 }
5254 decodeTypeImpPostfix(buffer, pType->pHead);
5255 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005256 case TY_ARRAY:
5257 {
5258 String temp;
5259 temp.printf("[%d]", pType->length);
5260 buffer.append(temp);
5261 }
5262 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005263 case TY_STRUCT:
5264 if (pType->pHead->length >= 0) {
5265 buffer.appendCStr(" {");
5266 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5267 decodeTypeImp(buffer, pArg->pHead);
5268 buffer.appendCStr(";");
5269 }
5270 buffer.append('}');
5271 }
5272 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005273 case TY_FUNC:
5274 buffer.append('(');
5275 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5276 decodeTypeImp(buffer, pArg);
5277 if (pArg->pTail) {
5278 buffer.appendCStr(", ");
5279 }
5280 }
5281 buffer.append(')');
5282 break;
5283 default:
5284 break;
Jack Palevich86351982009-06-30 18:09:56 -07005285 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005286 }
5287
Jack Palevich86351982009-06-30 18:09:56 -07005288 void printType(Type* pType) {
5289 String buffer;
5290 decodeType(buffer, pType);
5291 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005292 }
5293
Jack Palevichee1f8292009-10-28 16:10:17 -07005294 void insertTypeSpecifier(Type** ppType, TypeTag tag) {
5295 if (! *ppType) {
5296 *ppType = createType(tag, NULL, NULL);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005297 } else {
Jack Palevichee1f8292009-10-28 16:10:17 -07005298 if ((*ppType)->tag != TY_UNKNOWN) {
5299 error("Only one type specifier allowed.");
5300 } else {
5301 (*ppType)->tag = tag;
5302 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005303 }
Jack Palevichee1f8292009-10-28 16:10:17 -07005304 }
5305
5306 void insertStorageClass(Type** ppType, StorageClass storageClass) {
5307 if (! *ppType) {
5308 *ppType = createType(TY_UNKNOWN, NULL, NULL);
5309 }
5310 if ((*ppType)->storageClass != SC_DEFAULT) {
5311 error("Only one storage class allowed.");
5312 } else {
5313 (*ppType)->storageClass = storageClass;
5314 }
5315 }
5316
5317 Type* acceptPrimitiveType(bool allowStorageClass) {
5318 Type* pType = NULL;
5319 for (bool keepGoing = true; keepGoing;) {
5320 switch(tok) {
5321 case TOK_AUTO:
5322 insertStorageClass(&pType, SC_AUTO);
5323 break;
5324 case TOK_REGISTER:
5325 insertStorageClass(&pType, SC_REGISTER);
5326 break;
5327 case TOK_STATIC:
5328 insertStorageClass(&pType, SC_STATIC);
5329 break;
5330 case TOK_EXTERN:
5331 insertStorageClass(&pType, SC_EXTERN);
5332 break;
5333 case TOK_TYPEDEF:
5334 insertStorageClass(&pType, SC_TYPEDEF);
5335 break;
5336 case TOK_INT:
5337 insertTypeSpecifier(&pType, TY_INT);
5338 break;
5339 case TOK_SHORT:
5340 insertTypeSpecifier(&pType, TY_SHORT);
5341 break;
5342 case TOK_CHAR:
5343 insertTypeSpecifier(&pType, TY_CHAR);
5344 break;
5345 case TOK_VOID:
5346 insertTypeSpecifier(&pType, TY_VOID);
5347 break;
5348 case TOK_FLOAT:
5349 insertTypeSpecifier(&pType, TY_FLOAT);
5350 break;
5351 case TOK_DOUBLE:
5352 insertTypeSpecifier(&pType, TY_DOUBLE);
5353 break;
5354 case TOK_STRUCT:
5355 case TOK_UNION:
5356 {
5357 insertTypeSpecifier(&pType, TY_STRUCT);
5358 bool isStruct = (tok == TOK_STRUCT);
5359 next();
5360 pType = acceptStruct(pType, isStruct);
5361 keepGoing = false;
5362 }
5363 break;
5364 default:
5365 // Is it a typedef?
5366 if (isSymbol(tok)) {
5367 VariableInfo* pV = VI(tok);
5368 if (pV && pV->pType->storageClass == SC_TYPEDEF) {
5369 if (! pType) {
5370 pType = createType(TY_UNKNOWN, NULL, NULL);
5371 }
5372 StorageClass storageClass = pType->storageClass;
5373 *pType = *pV->pType;
5374 pType->storageClass = storageClass;
5375 } else {
5376 keepGoing = false;
5377 }
5378 } else {
5379 keepGoing = false;
5380 }
5381 }
5382 if (keepGoing) {
5383 next();
5384 }
5385 }
5386 if (pType) {
5387 if (pType->tag == TY_UNKNOWN) {
5388 pType->tag = TY_INT;
5389 }
5390 if (allowStorageClass) {
5391 switch(pType->storageClass) {
5392 case SC_AUTO: error("auto not supported."); break;
5393 case SC_REGISTER: error("register not supported."); break;
5394 case SC_STATIC: error("static not supported."); break;
5395 case SC_EXTERN: error("extern not supported."); break;
5396 default: break;
5397 }
5398 } else {
5399 if (pType->storageClass != SC_DEFAULT) {
5400 error("An explicit storage class is not allowed in this type declaration");
5401 }
5402 }
5403 }
Jack Palevich86351982009-06-30 18:09:56 -07005404 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005405 }
5406
Jack Palevichee1f8292009-10-28 16:10:17 -07005407 Type* acceptStruct(Type* pStructType, bool isStruct) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005408 tokenid_t structTag = acceptSymbol();
5409 bool isDeclaration = accept('{');
5410 bool fail = false;
5411
Jack Palevich9221bcc2009-08-26 16:15:07 -07005412 if (structTag) {
5413 Token* pToken = &mTokenTable[structTag];
5414 VariableInfo* pStructInfo = pToken->mpStructInfo;
5415 bool needToDeclare = !pStructInfo;
5416 if (pStructInfo) {
5417 if (isDeclaration) {
5418 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5419 if (pStructInfo->pType->pHead->length == -1) {
5420 // we're filling in a forward declaration.
5421 needToDeclare = false;
5422 } else {
5423 error("A struct with the same name is already defined at this level.");
5424 fail = true;
5425 }
5426 } else {
5427 needToDeclare = true;
5428 }
5429 }
5430 if (!fail) {
5431 assert(pStructInfo->isStructTag);
5432 pStructType->pHead = pStructInfo->pType;
5433 pStructType->pTail = pStructType->pHead->pTail;
5434 }
5435 }
5436
5437 if (needToDeclare) {
5438 // This is a new struct name
5439 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
Jack Palevichee1f8292009-10-28 16:10:17 -07005440 StorageClass storageClass = pStructType->storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005441 pStructType = createType(TY_STRUCT, NULL, NULL);
5442 pStructType->structTag = structTag;
5443 pStructType->pHead = pStructType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005444 pStructType->storageClass = storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005445 if (! isDeclaration) {
5446 // A forward declaration
5447 pStructType->length = -1;
5448 }
5449 pToken->mpStructInfo->pType = pStructType;
5450 }
5451 } else {
5452 // An anonymous struct
5453 pStructType->pHead = pStructType;
5454 }
5455
5456 if (isDeclaration) {
5457 size_t offset = 0;
5458 size_t structSize = 0;
5459 size_t structAlignment = 0;
5460 Type** pParamHolder = & pStructType->pHead->pTail;
5461 while (tok != '}' && tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005462 Type* pPrimitiveType = expectPrimitiveType(false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005463 if (pPrimitiveType) {
5464 while (tok != ';' && tok != EOF) {
5465 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5466 if (!pItem) {
5467 break;
5468 }
5469 if (lookupStructMember(pStructType, pItem->id)) {
5470 String buf;
5471 decodeToken(buf, pItem->id, false);
5472 error("Duplicate struct member %s", buf.getUnwrapped());
5473 }
5474 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5475 size_t alignment = pGen->alignmentOf(pItem);
5476 if (alignment > structAlignment) {
5477 structAlignment = alignment;
5478 }
5479 size_t alignmentMask = alignment - 1;
5480 offset = (offset + alignmentMask) & ~alignmentMask;
5481 pStructElement->length = offset;
5482 size_t size = pGen->sizeOf(pItem);
5483 if (isStruct) {
5484 offset += size;
5485 structSize = offset;
5486 } else {
5487 if (size >= structSize) {
5488 structSize = size;
5489 }
5490 }
5491 *pParamHolder = pStructElement;
5492 pParamHolder = &pStructElement->pTail;
5493 accept(',');
5494 }
5495 skip(';');
5496 } else {
5497 // Some sort of syntax error, skip token and keep trying
5498 next();
5499 }
5500 }
5501 if (!fail) {
5502 pStructType->pHead->length = structSize;
5503 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5504 }
5505 skip('}');
5506 }
5507 if (fail) {
5508 pStructType = NULL;
5509 }
5510 return pStructType;
5511 }
5512
5513 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5514 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5515 if (pStructElement->pHead->id == memberId) {
5516 return pStructElement;
5517 }
5518 }
5519 return NULL;
5520 }
5521
Jack Palevich2ff5c222009-07-23 15:11:22 -07005522 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005523 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005524 bool reportFailure = false;
Jack Palevichee1f8292009-10-28 16:10:17 -07005525 StorageClass storageClass = pType->storageClass;
Jack Palevich3f226492009-07-02 14:46:19 -07005526 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005527 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005528 if (declName) {
5529 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005530 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005531 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005532 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005533 pType->id = declName;
Jack Palevichee1f8292009-10-28 16:10:17 -07005534 pType->storageClass = storageClass;
Jack Palevichb6154502009-08-04 14:56:09 -07005535 } else if (nameRequired) {
5536 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005537 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005538#if 0
5539 fprintf(stderr, "Parsed a declaration: ");
5540 printType(pType);
5541#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005542 if (reportFailure) {
5543 return NULL;
5544 }
Jack Palevich86351982009-06-30 18:09:56 -07005545 return pType;
5546 }
5547
Jack Palevich2ff5c222009-07-23 15:11:22 -07005548 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005549 bool nameRequired = pBaseType->tag != TY_STRUCT;
5550 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005551 if (! pType) {
5552 error("Expected a declaration");
5553 }
5554 return pType;
5555 }
5556
Jack Palevich3f226492009-07-02 14:46:19 -07005557 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005558 Type* acceptCastTypeDeclaration() {
Jack Palevichee1f8292009-10-28 16:10:17 -07005559 Type* pType = acceptPrimitiveType(false);
Jack Palevich3f226492009-07-02 14:46:19 -07005560 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005561 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005562 }
Jack Palevich86351982009-06-30 18:09:56 -07005563 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005564 }
5565
Jack Palevich2ff5c222009-07-23 15:11:22 -07005566 Type* expectCastTypeDeclaration() {
5567 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005568 if (! pType) {
5569 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005570 }
Jack Palevich3f226492009-07-02 14:46:19 -07005571 return pType;
5572 }
5573
5574 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005575 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005576 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005577 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005578 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005579 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005580 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005581 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005582 return pType;
5583 }
5584
5585 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005586 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005587 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005588 // direct-dcl :
5589 // name
5590 // (dcl)
5591 // direct-dcl()
5592 // direct-dcl[]
5593 Type* pNewHead = NULL;
5594 if (accept('(')) {
5595 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005596 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005597 skip(')');
5598 } else if ((declName = acceptSymbol()) != 0) {
5599 if (nameAllowed == false && declName) {
5600 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005601 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005602 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005603 } else if (nameRequired && ! declName) {
5604 String temp;
5605 decodeToken(temp, tok, true);
5606 error("Expected name. Got %s", temp.getUnwrapped());
5607 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005608 }
Jack Palevichb6154502009-08-04 14:56:09 -07005609 for(;;) {
5610 if (accept('(')) {
5611 // Function declaration
5612 Type* pTail = acceptArgs(nameAllowed);
5613 pType = createType(TY_FUNC, pType, pTail);
5614 skip(')');
5615 } if (accept('[')) {
5616 if (tok != ']') {
5617 if (tok != TOK_NUM || tokc <= 0) {
5618 error("Expected positive integer constant");
5619 } else {
5620 Type* pDecayType = createPtrType(pType);
5621 pType = createType(TY_ARRAY, pType, pDecayType);
5622 pType->length = tokc;
5623 }
5624 next();
5625 }
5626 skip(']');
5627 } else {
5628 break;
5629 }
Jack Palevich86351982009-06-30 18:09:56 -07005630 }
Jack Palevich3f226492009-07-02 14:46:19 -07005631
5632 if (pNewHead) {
5633 Type* pA = pNewHead;
5634 while (pA->pHead) {
5635 pA = pA->pHead;
5636 }
5637 pA->pHead = pType;
5638 pType = pNewHead;
5639 }
Jack Palevich86351982009-06-30 18:09:56 -07005640 return pType;
5641 }
5642
Jack Palevich2ff5c222009-07-23 15:11:22 -07005643 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005644 Type* pHead = NULL;
5645 Type* pTail = NULL;
5646 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005647 Type* pBaseArg = acceptPrimitiveType(false);
Jack Palevich86351982009-06-30 18:09:56 -07005648 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005649 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005650 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005651 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005652 if (!pHead) {
5653 pHead = pParam;
5654 pTail = pParam;
5655 } else {
5656 pTail->pTail = pParam;
5657 pTail = pParam;
5658 }
5659 }
5660 }
5661 if (! accept(',')) {
5662 break;
5663 }
5664 }
5665 return pHead;
5666 }
5667
Jack Palevichee1f8292009-10-28 16:10:17 -07005668 Type* expectPrimitiveType(bool allowStorageClass) {
5669 Type* pType = acceptPrimitiveType(allowStorageClass);
Jack Palevich86351982009-06-30 18:09:56 -07005670 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005671 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005672 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005673 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005674 }
Jack Palevich86351982009-06-30 18:09:56 -07005675 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005676 }
5677
Jack Palevichb5e33312009-07-30 19:06:34 -07005678 void checkLVal() {
5679 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005680 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005681 }
5682 }
5683
Jack Palevich86351982009-06-30 18:09:56 -07005684 void addGlobalSymbol(Type* pDecl) {
5685 tokenid_t t = pDecl->id;
5686 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005687 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005688 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005689 }
Jack Palevich86351982009-06-30 18:09:56 -07005690 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005691 }
5692
Jack Palevich86351982009-06-30 18:09:56 -07005693 void reportDuplicate(tokenid_t t) {
5694 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005695 }
5696
Jack Palevich86351982009-06-30 18:09:56 -07005697 void addLocalSymbol(Type* pDecl) {
5698 tokenid_t t = pDecl->id;
5699 if (mLocals.isDefinedAtCurrentLevel(t)) {
5700 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005701 }
Jack Palevich86351982009-06-30 18:09:56 -07005702 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005703 }
5704
Jack Palevich61de31f2009-09-08 11:06:40 -07005705 bool checkUndeclaredStruct(Type* pBaseType) {
5706 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5707 String temp;
5708 decodeToken(temp, pBaseType->structTag, false);
5709 error("Undeclared struct %s", temp.getUnwrapped());
5710 return true;
5711 }
5712 return false;
5713 }
5714
Jack Palevich95727a02009-07-06 12:07:15 -07005715 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005716 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005717
Jack Palevich95727a02009-07-06 12:07:15 -07005718 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005719 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005720 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005721 if (!pDecl) {
5722 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005723 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005724 if (!pDecl->id) {
5725 break;
5726 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005727 if (checkUndeclaredStruct(pDecl)) {
5728 break;
5729 }
Jack Palevich86351982009-06-30 18:09:56 -07005730 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005731 if (pDecl->tag == TY_FUNC) {
5732 if (tok == '{') {
5733 error("Nested functions are not allowed. Did you forget a '}' ?");
5734 break;
5735 }
5736 // Else it's a forward declaration of a function.
Jack Palevichee1f8292009-10-28 16:10:17 -07005737 } else if (pDecl->storageClass != SC_TYPEDEF) {
Jack Palevich1c60e462009-09-18 15:03:03 -07005738 int variableAddress = 0;
5739 size_t alignment = pGen->alignmentOf(pDecl);
5740 assert(alignment > 0);
5741 size_t alignmentMask = ~ (alignment - 1);
5742 size_t sizeOf = pGen->sizeOf(pDecl);
5743 assert(sizeOf > 0);
5744 loc = (loc + alignment - 1) & alignmentMask;
5745 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5746 loc = loc + alignedSize;
5747 variableAddress = -loc;
5748 VI(pDecl->id)->pAddress = (void*) variableAddress;
5749 if (accept('=')) {
5750 /* assignment */
5751 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5752 pGen->pushR0();
5753 expr();
5754 pGen->forceR0RVal();
5755 pGen->storeR0ToTOS();
5756 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005757 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005758 if (tok == ',')
5759 next();
5760 }
5761 skip(';');
Jack Palevichee1f8292009-10-28 16:10:17 -07005762 pBaseType = acceptPrimitiveType(true);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005763 }
5764 }
5765
Jack Palevichf1728be2009-06-12 13:53:51 -07005766 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005767 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005768 }
5769
Jack Palevich37c54bd2009-07-14 18:35:36 -07005770 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005771 if (token == EOF ) {
5772 buffer.printf("EOF");
5773 } else if (token == TOK_NUM) {
Jack Palevich188a5a72009-10-27 17:23:20 -07005774 buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
5775 } else if (token == TOK_NUM_FLOAT) {
5776 buffer.printf("numeric constant float %g", tokd);
5777 } else if (token == TOK_NUM_DOUBLE) {
5778 buffer.printf("numeric constant double %g", tokd);
5779 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005780 if (token < 32) {
5781 buffer.printf("'\\x%02x'", token);
5782 } else {
5783 buffer.printf("'%c'", token);
5784 }
Jack Palevich569f1352009-06-29 14:29:08 -07005785 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005786 if (quote) {
5787 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5788 buffer.printf("keyword \"%s\"", nameof(token));
5789 } else {
5790 buffer.printf("symbol \"%s\"", nameof(token));
5791 }
5792 } else {
5793 buffer.printf("%s", nameof(token));
5794 }
Jack Palevich569f1352009-06-29 14:29:08 -07005795 }
5796 }
5797
Jack Palevich9221bcc2009-08-26 16:15:07 -07005798 void printToken(tokenid_t token) {
5799 String buffer;
5800 decodeToken(buffer, token, true);
5801 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5802 }
5803
Jack Palevich40600de2009-07-01 15:32:35 -07005804 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005805 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005806 if (!result) {
5807 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005808 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005809 error("Expected symbol. Got %s", temp.getUnwrapped());
5810 }
5811 return result;
5812 }
5813
Jack Palevich86351982009-06-30 18:09:56 -07005814 tokenid_t acceptSymbol() {
5815 tokenid_t result = 0;
5816 if (tok >= TOK_SYMBOL) {
5817 result = tok;
5818 next();
Jack Palevich86351982009-06-30 18:09:56 -07005819 }
5820 return result;
5821 }
5822
Jack Palevichb7c81e92009-06-04 19:56:13 -07005823 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005824 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005825 while (tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005826 Type* pBaseType = expectPrimitiveType(true);
Jack Palevich86351982009-06-30 18:09:56 -07005827 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005828 break;
5829 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005830 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005831 if (!pDecl) {
5832 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005833 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005834 if (!pDecl->id) {
5835 skip(';');
5836 continue;
5837 }
5838
Jack Palevich61de31f2009-09-08 11:06:40 -07005839 if (checkUndeclaredStruct(pDecl)) {
5840 skip(';');
5841 continue;
5842 }
Jack Palevich86351982009-06-30 18:09:56 -07005843 if (! isDefined(pDecl->id)) {
5844 addGlobalSymbol(pDecl);
5845 }
5846 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005847 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005848 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005849 }
Jack Palevich86351982009-06-30 18:09:56 -07005850 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005851 // it's a variable declaration
5852 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005853 if (pDecl->storageClass == SC_TYPEDEF) {
5854 // Do not allocate storage.
5855 } else {
5856 if (name && !name->pAddress) {
5857 name->pAddress = (int*) allocGlobalSpace(
5858 pGen->alignmentOf(name->pType),
5859 pGen->sizeOf(name->pType));
5860 }
5861 if (accept('=')) {
5862 if (tok == TOK_NUM) {
5863 if (name) {
5864 * (int*) name->pAddress = tokc;
5865 }
5866 next();
5867 } else {
5868 error("Expected an integer constant");
Jack Palevichd7461a72009-06-12 14:26:58 -07005869 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005870 }
5871 }
Jack Palevich86351982009-06-30 18:09:56 -07005872 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005873 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005874 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005875 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005876 if (!pDecl) {
5877 break;
5878 }
5879 if (! isDefined(pDecl->id)) {
5880 addGlobalSymbol(pDecl);
5881 }
5882 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005883 }
5884 skip(';');
5885 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005886 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005887 if (accept(';')) {
5888 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005889 } else if (tok != '{') {
5890 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005891 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005892 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005893 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005894 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005895 /* patch forward references */
5896 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005897 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005898 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005899 }
5900 // Calculate stack offsets for parameters
5901 mLocals.pushLevel();
5902 intptr_t a = 8;
5903 int argCount = 0;
5904 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5905 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005906 if (pArg->id) {
5907 addLocalSymbol(pArg);
5908 }
Jack Palevich95727a02009-07-06 12:07:15 -07005909 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005910 Type* pPassingType = passingType(pArg);
5911 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005912 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005913 if (pArg->id) {
5914 VI(pArg->id)->pAddress = (void*) a;
5915 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005916 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005917 argCount++;
5918 }
5919 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005920 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005921 a = pGen->functionEntry(pDecl);
Jack Palevichc951c592009-10-29 15:04:27 -07005922 block(0, 0, true);
Jack Palevich95727a02009-07-06 12:07:15 -07005923 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005924 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005925 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005926 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005927 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005928 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005929 }
5930 }
5931 }
5932
Jack Palevich9221bcc2009-08-26 16:15:07 -07005933 Type* passingType(Type* pType) {
5934 switch (pType->tag) {
5935 case TY_CHAR:
5936 case TY_SHORT:
5937 return mkpInt;
5938 default:
5939 return pType;
5940 }
5941 }
5942
Jack Palevich9cbd2262009-07-08 16:48:41 -07005943 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5944 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5945 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005946 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005947 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005948 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005949 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005950 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005951 char* result = (char*) base;
5952 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005953 return result;
5954 }
5955
Jack Palevich21a15a22009-05-11 14:49:29 -07005956 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005957 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005958 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005959 pGlobalBase = 0;
5960 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005961 if (pGen) {
5962 delete pGen;
5963 pGen = 0;
5964 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005965 if (pCodeBuf) {
5966 delete pCodeBuf;
5967 pCodeBuf = 0;
5968 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005969 if (file) {
5970 delete file;
5971 file = 0;
5972 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005973 }
5974
Jack Palevich8c246a92009-07-14 21:14:10 -07005975 // One-time initialization, when class is constructed.
5976 void init() {
5977 mpSymbolLookupFn = 0;
5978 mpSymbolLookupContext = 0;
5979 }
5980
Jack Palevich21a15a22009-05-11 14:49:29 -07005981 void clear() {
5982 tok = 0;
5983 tokc = 0;
5984 tokl = 0;
5985 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005986 rsym = 0;
5987 loc = 0;
5988 glo = 0;
Jack Palevich188a5a72009-10-27 17:23:20 -07005989 macroLevel = -1;
Jack Palevich21a15a22009-05-11 14:49:29 -07005990 file = 0;
5991 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005992 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005993 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005994 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005995 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005996 mLineNumber = 1;
5997 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005998 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005999 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006000
Jack Palevich22305132009-05-13 10:58:45 -07006001 void setArchitecture(const char* architecture) {
6002 delete pGen;
6003 pGen = 0;
6004
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006005 delete pCodeBuf;
6006 pCodeBuf = new CodeBuf();
6007
Jack Palevich22305132009-05-13 10:58:45 -07006008 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006009#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006010 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006011 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006012 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07006013 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006014#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07006015#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006016 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006017 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07006018 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006019#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07006020 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006021 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07006022 }
6023 }
6024
6025 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006026#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07006027 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006028 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07006029#elif defined(DEFAULT_X86_CODEGEN)
6030 pGen = new X86CodeGenerator();
6031#endif
6032 }
6033 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006034 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07006035 } else {
6036 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07006037 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07006038 }
6039 }
6040
Jack Palevich77ae76e2009-05-10 19:59:24 -07006041public:
Jack Palevich22305132009-05-13 10:58:45 -07006042 struct args {
6043 args() {
6044 architecture = 0;
6045 }
6046 const char* architecture;
6047 };
6048
Jack Paleviche7b59062009-05-19 17:12:17 -07006049 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07006050 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07006051 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006052 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006053
Jack Paleviche7b59062009-05-19 17:12:17 -07006054 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07006055 cleanup();
6056 }
6057
Jack Palevich8c246a92009-07-14 21:14:10 -07006058 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6059 mpSymbolLookupFn = pFn;
6060 mpSymbolLookupContext = pContext;
6061 }
6062
Jack Palevich1cdef202009-05-22 12:06:27 -07006063 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006064 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07006065
Jack Palevich2ff5c222009-07-23 15:11:22 -07006066 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07006067 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07006068 cleanup();
6069 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07006070 mTokenTable.setArena(&mGlobalArena);
6071 mGlobals.setArena(&mGlobalArena);
6072 mGlobals.setTokenTable(&mTokenTable);
6073 mLocals.setArena(&mLocalArena);
6074 mLocals.setTokenTable(&mTokenTable);
6075
6076 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07006077 setArchitecture(NULL);
6078 if (!pGen) {
6079 return -1;
6080 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07006081#ifdef PROVIDE_TRACE_CODEGEN
6082 pGen = new TraceCodeGenerator(pGen);
6083#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006084 pGen->setErrorSink(this);
6085
6086 if (pCodeBuf) {
6087 pCodeBuf->init(ALLOC_SIZE);
6088 }
6089 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07006090 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07006091 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
6092 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07006093 inp();
6094 next();
6095 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07006096 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07006097 result = pGen->finishCompile();
6098 if (result == 0) {
6099 if (mErrorBuf.len()) {
6100 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006101 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07006102 }
Jack Palevichce105a92009-07-16 14:30:33 -07006103 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006104 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07006105 }
6106
Jack Palevich86351982009-06-30 18:09:56 -07006107 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07006108 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07006109 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07006110 mkpChar = createType(TY_CHAR, NULL, NULL);
6111 mkpVoid = createType(TY_VOID, NULL, NULL);
6112 mkpFloat = createType(TY_FLOAT, NULL, NULL);
6113 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
6114 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
6115 mkpIntPtr = createPtrType(mkpInt);
6116 mkpCharPtr = createPtrType(mkpChar);
6117 mkpFloatPtr = createPtrType(mkpFloat);
6118 mkpDoublePtr = createPtrType(mkpDouble);
6119 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07006120 }
6121
Jack Palevicha6baa232009-06-12 11:25:59 -07006122 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07006123 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07006124 }
6125
Jack Palevich569f1352009-06-29 14:29:08 -07006126 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006127 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07006128 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07006129 }
6130
Jack Palevich569f1352009-06-29 14:29:08 -07006131 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006132 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07006133 error("Undefined forward reference: %s",
6134 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07006135 }
6136 return true;
6137 }
6138
Jack Palevich1cdef202009-05-22 12:06:27 -07006139 /* Look through the symbol table to find a symbol.
6140 * If found, return its value.
6141 */
6142 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07006143 if (mCompileResult == 0) {
6144 tokenid_t tok = mTokenTable.intern(name, strlen(name));
6145 VariableInfo* pVariableInfo = VI(tok);
6146 if (pVariableInfo) {
6147 return pVariableInfo->pAddress;
6148 }
Jack Palevich1cdef202009-05-22 12:06:27 -07006149 }
6150 return NULL;
6151 }
6152
Jack Palevicheedf9d22009-06-04 16:23:40 -07006153 void getPragmas(ACCsizei* actualStringCount,
6154 ACCsizei maxStringCount, ACCchar** strings) {
6155 int stringCount = mPragmaStringCount;
6156 if (actualStringCount) {
6157 *actualStringCount = stringCount;
6158 }
6159 if (stringCount > maxStringCount) {
6160 stringCount = maxStringCount;
6161 }
6162 if (strings) {
6163 char* pPragmas = mPragmas.getUnwrapped();
6164 while (stringCount-- > 0) {
6165 *strings++ = pPragmas;
6166 pPragmas += strlen(pPragmas) + 1;
6167 }
6168 }
6169 }
6170
Jack Palevichd5315572009-09-09 13:19:34 -07006171 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006172 *base = pCodeBuf->getBase();
6173 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006174 }
6175
Jack Palevichac0e95e2009-05-29 13:53:44 -07006176 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006177 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006178 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006179};
6180
Jack Paleviche7b59062009-05-19 17:12:17 -07006181const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006182 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6183
Jack Paleviche7b59062009-05-19 17:12:17 -07006184const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006185 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6186 5, 5, /* ==, != */
6187 9, 10, /* &&, || */
6188 6, 7, 8, /* & ^ | */
6189 2, 2 /* ~ ! */
6190 };
6191
Jack Palevich8b0624c2009-05-20 12:12:06 -07006192#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006193const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006194 0x1, // ++
6195 0xff, // --
6196 0xc1af0f, // *
6197 0xf9f79991, // /
6198 0xf9f79991, // % (With manual assist to swap results)
6199 0xc801, // +
6200 0xd8f7c829, // -
6201 0xe0d391, // <<
6202 0xf8d391, // >>
6203 0xe, // <=
6204 0xd, // >=
6205 0xc, // <
6206 0xf, // >
6207 0x4, // ==
6208 0x5, // !=
6209 0x0, // &&
6210 0x1, // ||
6211 0xc821, // &
6212 0xc831, // ^
6213 0xc809, // |
6214 0xd0f7, // ~
6215 0x4 // !
6216};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006217#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006218
Jack Palevich1cdef202009-05-22 12:06:27 -07006219struct ACCscript {
6220 ACCscript() {
6221 text = 0;
6222 textLength = 0;
6223 accError = ACC_NO_ERROR;
6224 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006225
Jack Palevich1cdef202009-05-22 12:06:27 -07006226 ~ACCscript() {
6227 delete text;
6228 }
Jack Palevich546b2242009-05-13 15:10:04 -07006229
Jack Palevich8c246a92009-07-14 21:14:10 -07006230 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6231 compiler.registerSymbolCallback(pFn, pContext);
6232 }
6233
Jack Palevich1cdef202009-05-22 12:06:27 -07006234 void setError(ACCenum error) {
6235 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6236 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006237 }
6238 }
6239
Jack Palevich1cdef202009-05-22 12:06:27 -07006240 ACCenum getError() {
6241 ACCenum result = accError;
6242 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006243 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006244 }
6245
Jack Palevich1cdef202009-05-22 12:06:27 -07006246 Compiler compiler;
6247 char* text;
6248 int textLength;
6249 ACCenum accError;
6250};
6251
6252
6253extern "C"
6254ACCscript* accCreateScript() {
6255 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006256}
Jack Palevich1cdef202009-05-22 12:06:27 -07006257
6258extern "C"
6259ACCenum accGetError( ACCscript* script ) {
6260 return script->getError();
6261}
6262
6263extern "C"
6264void accDeleteScript(ACCscript* script) {
6265 delete script;
6266}
6267
6268extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006269void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6270 ACCvoid* pContext) {
6271 script->registerSymbolCallback(pFn, pContext);
6272}
6273
6274extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006275void accScriptSource(ACCscript* script,
6276 ACCsizei count,
6277 const ACCchar ** string,
6278 const ACCint * length) {
6279 int totalLength = 0;
6280 for(int i = 0; i < count; i++) {
6281 int len = -1;
6282 const ACCchar* s = string[i];
6283 if (length) {
6284 len = length[i];
6285 }
6286 if (len < 0) {
6287 len = strlen(s);
6288 }
6289 totalLength += len;
6290 }
6291 delete script->text;
6292 char* text = new char[totalLength + 1];
6293 script->text = text;
6294 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006295 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006296 for(int i = 0; i < count; i++) {
6297 int len = -1;
6298 const ACCchar* s = string[i];
6299 if (length) {
6300 len = length[i];
6301 }
6302 if (len < 0) {
6303 len = strlen(s);
6304 }
Jack Palevich09555c72009-05-27 12:25:55 -07006305 memcpy(dest, s, len);
6306 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006307 }
6308 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006309
6310#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006311 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006312 int counter;
6313 char path[PATH_MAX];
6314 for (counter = 0; counter < 4096; counter++) {
6315 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6316 if(access(path, F_OK) != 0) {
6317 break;
6318 }
6319 }
6320 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006321 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006322 FILE* fd = fopen(path, "w");
6323 if (fd) {
6324 fwrite(text, totalLength, 1, fd);
6325 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006326 LOGD("Saved input to file %s", path);
6327 } else {
6328 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006329 }
6330 }
6331#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006332}
6333
6334extern "C"
6335void accCompileScript(ACCscript* script) {
6336 int result = script->compiler.compile(script->text, script->textLength);
6337 if (result) {
6338 script->setError(ACC_INVALID_OPERATION);
6339 }
6340}
6341
6342extern "C"
6343void accGetScriptiv(ACCscript* script,
6344 ACCenum pname,
6345 ACCint * params) {
6346 switch (pname) {
6347 case ACC_INFO_LOG_LENGTH:
6348 *params = 0;
6349 break;
6350 }
6351}
6352
6353extern "C"
6354void accGetScriptInfoLog(ACCscript* script,
6355 ACCsizei maxLength,
6356 ACCsizei * length,
6357 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006358 char* message = script->compiler.getErrorMessage();
6359 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006360 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006361 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006362 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006363 if (infoLog && maxLength > 0) {
6364 int trimmedLength = maxLength < messageLength ?
6365 maxLength : messageLength;
6366 memcpy(infoLog, message, trimmedLength);
6367 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006368 }
6369}
6370
6371extern "C"
6372void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6373 ACCvoid ** address) {
6374 void* value = script->compiler.lookup(name);
6375 if (value) {
6376 *address = value;
6377 } else {
6378 script->setError(ACC_INVALID_VALUE);
6379 }
6380}
6381
Jack Palevicheedf9d22009-06-04 16:23:40 -07006382extern "C"
6383void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6384 ACCsizei maxStringCount, ACCchar** strings){
6385 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6386}
6387
-b master422972c2009-06-17 19:13:52 -07006388extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006389void accGetProgramBinary(ACCscript* script,
6390 ACCvoid** base, ACCsizei* length) {
6391 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006392}
6393
Jack Palevicheedf9d22009-06-04 16:23:40 -07006394
Jack Palevich1cdef202009-05-22 12:06:27 -07006395} // namespace acc
6396