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