blob: 62dea4cb4c1b1725efd613d1fe1ca9aa76e5e299 [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 Palevichc9b8ffc2009-08-03 14:42:57 -0700154 TY_INT, // 0
155 TY_CHAR, // 1
156 TY_SHORT, // 2
157 TY_VOID, // 3
158 TY_FLOAT, // 4
159 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700160 TY_POINTER, // 6
161 TY_ARRAY, // 7
162 TY_STRUCT, // 8
163 TY_FUNC, // 9
164 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700165 };
166
167 struct Type {
168 TypeTag tag;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700169 tokenid_t id; // For function arguments, global vars, local vars, struct elements
170 tokenid_t structTag; // For structs the name of the struct
171 int length; // length of array, offset of struct element. -1 means struct is forward defined
172 int alignment; // for structs only
173 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700174 Type* pTail;
175 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700176
Jack Palevichba929a42009-07-17 10:20:32 -0700177 enum ExpressionType {
178 ET_RVALUE,
179 ET_LVALUE
180 };
181
182 struct ExpressionValue {
183 ExpressionValue() {
184 et = ET_RVALUE;
185 pType = NULL;
186 }
187 ExpressionType et;
188 Type* pType;
189 };
190
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700191 class ICodeBuf {
192 public:
193 virtual ~ICodeBuf() {}
194 virtual void init(int size) = 0;
195 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
196 virtual void o4(int n) = 0;
197 virtual void ob(int n) = 0;
198 virtual void* getBase() = 0;
199 virtual intptr_t getSize() = 0;
200 virtual intptr_t getPC() = 0;
201 // Call this before trying to modify code in the buffer.
202 virtual void flush() = 0;
203 };
204
205 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700206 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700207 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700208 ErrorSink* mErrorSink;
209 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700210 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700211
Jack Palevich21a15a22009-05-11 14:49:29 -0700212 void release() {
213 if (pProgramBase != 0) {
214 free(pProgramBase);
215 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700216 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 }
218
Jack Palevich0a280a02009-06-11 10:53:51 -0700219 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700220 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700221 bool overflow = newSize > mSize;
222 if (overflow && !mOverflowed) {
223 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700224 if (mErrorSink) {
225 mErrorSink->error("Code too large: %d bytes", newSize);
226 }
227 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700228 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 public:
232 CodeBuf() {
233 pProgramBase = 0;
234 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700235 mErrorSink = 0;
236 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700237 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700238 }
239
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700240 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 release();
242 }
243
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700244 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700245 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700246 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700247 pProgramBase = (char*) calloc(1, size);
248 ind = pProgramBase;
249 }
250
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700251 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700252 mErrorSink = pErrorSink;
253 }
254
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700255 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700256 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700257 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700258 }
Jack Palevich546b2242009-05-13 15:10:04 -0700259 * (int*) ind = n;
260 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700261 }
262
Jack Palevich21a15a22009-05-11 14:49:29 -0700263 /*
264 * Output a byte. Handles all values, 0..ff.
265 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700266 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700267 if(check(1)) {
268 return;
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 *ind++ = n;
271 }
272
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700273 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 return (void*) pProgramBase;
275 }
276
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700277 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700278 return ind - pProgramBase;
279 }
280
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700281 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700282 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700284
285 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700286 };
287
Jack Palevich1cdef202009-05-22 12:06:27 -0700288 /**
289 * A code generator creates an in-memory program, generating the code on
290 * the fly. There is one code generator implementation for each supported
291 * architecture.
292 *
293 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700294 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700295 * FP - a frame pointer for accessing function arguments and local
296 * variables.
297 * SP - a stack pointer for storing intermediate results while evaluating
298 * expressions. The stack pointer grows downwards.
299 *
300 * The function calling convention is that all arguments are placed on the
301 * stack such that the first argument has the lowest address.
302 * After the call, the result is in R0. The caller is responsible for
303 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700304 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700305 * FP and SP registers are saved.
306 */
307
Jack Palevich21a15a22009-05-11 14:49:29 -0700308 class CodeGenerator {
309 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700310 CodeGenerator() {
311 mErrorSink = 0;
312 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700313 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700314 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700315 virtual ~CodeGenerator() {}
316
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700317 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700318 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700319 pCodeBuf->setErrorSink(mErrorSink);
320 }
321
Jack Palevichb67b18f2009-06-11 21:12:23 -0700322 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700323 mErrorSink = pErrorSink;
324 if (pCodeBuf) {
325 pCodeBuf->setErrorSink(mErrorSink);
326 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700327 }
328
Jack Palevich58c30ee2009-07-17 16:35:23 -0700329 /* Give the code generator some utility types so it can
330 * use its own types as needed for the results of some
331 * operations like gcmp.
332 */
333
Jack Palevicha8f427f2009-07-13 18:40:08 -0700334 void setTypes(Type* pInt) {
335 mkpInt = pInt;
336 }
337
Jack Palevich1cdef202009-05-22 12:06:27 -0700338 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700339 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 * Save the old value of the FP.
341 * Set the new value of the FP.
342 * Convert from the native platform calling convention to
343 * our stack-based calling convention. This may require
344 * pushing arguments from registers to the stack.
345 * Allocate "N" bytes of stack space. N isn't known yet, so
346 * just emit the instructions for adjusting the stack, and return
347 * the address to patch up. The patching will be done in
348 * functionExit().
349 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700350 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700351 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700352
Jack Palevich1cdef202009-05-22 12:06:27 -0700353 /* Emit a function epilog.
354 * Restore the old SP and FP register values.
355 * Return to the calling function.
356 * argCount - the number of arguments to the function.
357 * localVariableAddress - returned from functionEntry()
358 * localVariableSize - the size in bytes of the local variables.
359 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700360 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700364 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700365
Jack Palevich1a539db2009-07-08 13:04:41 -0700366 /* Load floating point value from global address. */
367 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich9221bcc2009-08-26 16:15:07 -0700369 /* Add the struct offset in bytes to R0, change the type to pType */
370 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
371
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 /* Jump to a target, and return the address of the word that
373 * holds the target data, in case it needs to be fixed up later.
374 */
Jack Palevich22305132009-05-13 10:58:45 -0700375 virtual int gjmp(int t) = 0;
376
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 /* Test R0 and jump to a target if the test succeeds.
378 * l = 0: je, l == 1: jne
379 * Return the address of the word that holds the targed data, in
380 * case it needs to be fixed up later.
381 */
Jack Palevich22305132009-05-13 10:58:45 -0700382 virtual int gtst(bool l, int t) = 0;
383
Jack Palevich9eed7a22009-07-06 17:24:34 -0700384 /* Compare TOS against R0, and store the boolean result in R0.
385 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 * op specifies the comparison.
387 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700388 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich9eed7a22009-07-06 17:24:34 -0700390 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700392 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 */
Jack Palevich546b2242009-05-13 15:10:04 -0700394 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700395
Jack Palevich9eed7a22009-07-06 17:24:34 -0700396 /* Compare 0 against R0, and store the boolean result in R0.
397 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700398 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700399 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700400
401 /* Perform the arithmetic op specified by op. 0 is the
402 * left argument, R0 is the right argument.
403 */
404 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700406 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 */
408 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700410 /* Turn R0, TOS into R0 TOS R0 */
411
412 virtual void over() = 0;
413
414 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700415 */
416 virtual void popR0() = 0;
417
Jack Palevich9eed7a22009-07-06 17:24:34 -0700418 /* Store R0 to the address stored in TOS.
419 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700421 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700422
Jack Palevich1cdef202009-05-22 12:06:27 -0700423 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700424 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700425 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Load the absolute address of a variable to R0.
428 * If ea <= LOCAL, then this is a local variable, or an
429 * argument, addressed relative to FP.
430 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700431 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700432 * et is ET_RVALUE for things like string constants, ET_LVALUE for
433 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700435 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700436
Jack Palevich9f51a262009-07-29 16:22:26 -0700437 /* Load the pc-relative address of a forward-referenced variable to R0.
438 * Return the address of the 4-byte constant so that it can be filled
439 * in later.
440 */
441 virtual int leaForward(int ea, Type* pPointerType) = 0;
442
Jack Palevich8df46192009-07-07 14:48:51 -0700443 /**
444 * Convert R0 to the given type.
445 */
Jack Palevichb6154502009-08-04 14:56:09 -0700446
447 void convertR0(Type* pType) {
448 convertR0Imp(pType, false);
449 }
450
451 void castR0(Type* pType) {
452 convertR0Imp(pType, true);
453 }
454
455 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700456
Jack Palevich1cdef202009-05-22 12:06:27 -0700457 /* Emit code to adjust the stack for a function call. Return the
458 * label for the address of the instruction that adjusts the
459 * stack size. This will be passed as argument "a" to
460 * endFunctionCallArguments.
461 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700462 virtual int beginFunctionCallArguments() = 0;
463
Jack Palevich1cdef202009-05-22 12:06:27 -0700464 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700465 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700466 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700467 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700468
Jack Palevich1cdef202009-05-22 12:06:27 -0700469 /* Patch the function call preamble.
470 * a is the address returned from beginFunctionCallArguments
471 * l is the number of bytes the arguments took on the stack.
472 * Typically you would also emit code to convert the argument
473 * list into whatever the native function calling convention is.
474 * On ARM for example you would pop the first 5 arguments into
475 * R0..R4
476 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700477 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700478
Jack Palevich1cdef202009-05-22 12:06:27 -0700479 /* Emit a call to an unknown function. The argument "symbol" needs to
480 * be stored in the location where the address should go. It forms
481 * a chain. The address will be patched later.
482 * Return the address of the word that has to be patched.
483 */
Jack Palevich8df46192009-07-07 14:48:51 -0700484 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700485
Jack Palevich1cdef202009-05-22 12:06:27 -0700486 /* Call a function pointer. L is the number of bytes the arguments
487 * take on the stack. The address of the function is stored at
488 * location SP + l.
489 */
Jack Palevich8df46192009-07-07 14:48:51 -0700490 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700491
Jack Palevich1cdef202009-05-22 12:06:27 -0700492 /* Adjust SP after returning from a function call. l is the
493 * number of bytes of arguments stored on the stack. isIndirect
494 * is true if this was an indirect call. (In which case the
495 * address of the function is stored at location SP + l.)
496 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700497 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700498
Jack Palevich1cdef202009-05-22 12:06:27 -0700499 /* Generate a symbol at the current PC. t is the head of a
500 * linked list of addresses to patch.
501 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700502 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700503
Jack Palevich9f51a262009-07-29 16:22:26 -0700504 /* Resolve a forward reference function at the current PC.
505 * t is the head of a
506 * linked list of addresses to patch.
507 * (Like gsym, but using absolute address, not PC relative address.)
508 */
509 virtual void resolveForward(int t) = 0;
510
Jack Palevich1cdef202009-05-22 12:06:27 -0700511 /*
512 * Do any cleanup work required at the end of a compile.
513 * For example, an instruction cache might need to be
514 * invalidated.
515 * Return non-zero if there is an error.
516 */
517 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700518
Jack Palevicha6535612009-05-13 16:24:17 -0700519 /**
520 * Adjust relative branches by this amount.
521 */
522 virtual int jumpOffset() = 0;
523
Jack Palevich9eed7a22009-07-06 17:24:34 -0700524 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700525 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700526 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700527 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700528
529 /**
530 * Array element alignment (in bytes) for this type of data.
531 */
532 virtual size_t sizeOf(Type* type) = 0;
533
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700534 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700535 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700536 }
537
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700538 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700539 return mExpressionStack.back().et;
540 }
541
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700542 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700543 mExpressionStack.back().et = et;
544 }
545
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700546 virtual size_t getExpressionStackDepth() {
547 return mExpressionStack.size();
548 }
549
Jack Palevichb5e33312009-07-30 19:06:34 -0700550 virtual void forceR0RVal() {
551 if (getR0ExpressionType() == ET_LVALUE) {
552 loadR0FromR0();
553 }
554 }
555
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700557 /*
558 * Output a byte. Handles all values, 0..ff.
559 */
560 void ob(int n) {
561 pCodeBuf->ob(n);
562 }
563
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700564 void o4(int data) {
565 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700566 }
567
Jack Palevich8b0624c2009-05-20 12:12:06 -0700568 intptr_t getBase() {
569 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700570 }
571
Jack Palevich8b0624c2009-05-20 12:12:06 -0700572 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700573 return pCodeBuf->getPC();
574 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700575
576 intptr_t getSize() {
577 return pCodeBuf->getSize();
578 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700579
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700580 void flush() {
581 pCodeBuf->flush();
582 }
583
Jack Palevichac0e95e2009-05-29 13:53:44 -0700584 void error(const char* fmt,...) {
585 va_list ap;
586 va_start(ap, fmt);
587 mErrorSink->verror(fmt, ap);
588 va_end(ap);
589 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700590
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700591 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700592 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700593 error("code generator assertion failed at line %s:%d.", __FILE__, line);
594 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700595 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700596 }
597 }
Jack Palevich8df46192009-07-07 14:48:51 -0700598
599 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700600 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700601 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700602 mExpressionStack.back().et = ET_RVALUE;
603 }
604
605 void setR0Type(Type* pType, ExpressionType et) {
606 assert(pType != NULL);
607 mExpressionStack.back().pType = pType;
608 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700609 }
610
Jack Palevich8df46192009-07-07 14:48:51 -0700611 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700612 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700613 }
614
615 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700616 if (mExpressionStack.size()) {
617 mExpressionStack.push_back(mExpressionStack.back());
618 } else {
619 mExpressionStack.push_back(ExpressionValue());
620 }
621
Jack Palevich8df46192009-07-07 14:48:51 -0700622 }
623
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700624 void overType() {
625 size_t size = mExpressionStack.size();
626 if (size >= 2) {
627 mExpressionStack.push_back(mExpressionStack.back());
628 mExpressionStack[size-1] = mExpressionStack[size-2];
629 mExpressionStack[size-2] = mExpressionStack[size];
630 }
631 }
632
Jack Palevich8df46192009-07-07 14:48:51 -0700633 void popType() {
634 mExpressionStack.pop_back();
635 }
636
637 bool bitsSame(Type* pA, Type* pB) {
638 return collapseType(pA->tag) == collapseType(pB->tag);
639 }
640
641 TypeTag collapseType(TypeTag tag) {
642 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700643 TY_INT,
644 TY_INT,
645 TY_INT,
646 TY_VOID,
647 TY_FLOAT,
648 TY_DOUBLE,
649 TY_INT,
650 TY_INT,
651 TY_VOID,
652 TY_VOID,
653 TY_VOID
654 };
Jack Palevich8df46192009-07-07 14:48:51 -0700655 return collapsedTag[tag];
656 }
657
Jack Palevich1a539db2009-07-08 13:04:41 -0700658 TypeTag collapseTypeR0() {
659 return collapseType(getR0Type()->tag);
660 }
661
Jack Palevichb6154502009-08-04 14:56:09 -0700662 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700663 return isFloatTag(pType->tag);
664 }
665
Jack Palevichb6154502009-08-04 14:56:09 -0700666 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700667 return tag == TY_FLOAT || tag == TY_DOUBLE;
668 }
669
Jack Palevichb6154502009-08-04 14:56:09 -0700670 static bool isPointerType(Type* pType) {
671 return isPointerTag(pType->tag);
672 }
673
674 static bool isPointerTag(TypeTag tag) {
675 return tag == TY_POINTER || tag == TY_ARRAY;
676 }
677
678 Type* getPointerArithmeticResultType(Type* a, Type* b) {
679 TypeTag aTag = a->tag;
680 TypeTag bTag = b->tag;
681 if (aTag == TY_POINTER) {
682 return a;
683 }
684 if (bTag == TY_POINTER) {
685 return b;
686 }
687 if (aTag == TY_ARRAY) {
688 return a->pTail;
689 }
690 if (bTag == TY_ARRAY) {
691 return b->pTail;
692 }
693 return NULL;
694 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700695 Type* mkpInt;
696
Jack Palevich21a15a22009-05-11 14:49:29 -0700697 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700698 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700699 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700700 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700701 };
702
Jack Paleviche7b59062009-05-19 17:12:17 -0700703#ifdef PROVIDE_ARM_CODEGEN
704
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700705 static size_t rotateRight(size_t n, size_t rotate) {
706 return (n >> rotate) | (n << (32 - rotate));
707 }
708
709 static size_t rotateLeft(size_t n, size_t rotate) {
710 return (n << rotate) | (n >> (32 - rotate));
711 }
712
713 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
714 for(size_t i = 0; i < 16; i++) {
715 size_t rotate = i * 2;
716 size_t mask = rotateRight(0xff, rotate);
717 if ((immediate | mask) == mask) {
718 size_t bits8 = rotateLeft(immediate, rotate);
719 // assert(bits8 <= 0xff);
720 *pResult = (i << 8) | bits8;
721 return true;
722 }
723 }
724 return false;
725 }
726
727 static size_t decode12BitImmediate(size_t immediate) {
728 size_t data = immediate & 0xff;
729 size_t rotate = 2 * ((immediate >> 8) & 0xf);
730 return rotateRight(data, rotate);
731 }
732
733 class ARMCodeBuf : public ICodeBuf {
734 ICodeBuf* mpBase;
735 ErrorSink* mErrorSink;
736
737 class CircularQueue {
738 static const int SIZE = 16; // Must be power of 2
739 static const int MASK = SIZE-1;
740 unsigned int mBuf[SIZE];
741 int mHead;
742 int mCount;
743
744 public:
745 CircularQueue() {
746 mHead = 0;
747 mCount = 0;
748 }
749
750 void pushBack(unsigned int data) {
751 mBuf[(mHead + mCount) & MASK] = data;
752 mCount += 1;
753 }
754
755 unsigned int popFront() {
756 unsigned int result = mBuf[mHead];
757 mHead = (mHead + 1) & MASK;
758 mCount -= 1;
759 return result;
760 }
761
762 void popBack(int n) {
763 mCount -= n;
764 }
765
766 inline int count() {
767 return mCount;
768 }
769
770 bool empty() {
771 return mCount == 0;
772 }
773
774 bool full() {
775 return mCount == SIZE;
776 }
777
778 // The valid indexes are 1 - count() to 0
779 unsigned int operator[](int i) {
780 return mBuf[(mHead + mCount + i) & MASK];
781 }
782 };
783
784 CircularQueue mQ;
785
786 void error(const char* fmt,...) {
787 va_list ap;
788 va_start(ap, fmt);
789 mErrorSink->verror(fmt, ap);
790 va_end(ap);
791 }
792
793 void flush() {
794 while (!mQ.empty()) {
795 mpBase->o4(mQ.popFront());
796 }
797 mpBase->flush();
798 }
799
800 public:
801 ARMCodeBuf(ICodeBuf* pBase) {
802 mpBase = pBase;
803 }
804
805 virtual ~ARMCodeBuf() {
806 delete mpBase;
807 }
808
809 void init(int size) {
810 mpBase->init(size);
811 }
812
813 void setErrorSink(ErrorSink* pErrorSink) {
814 mErrorSink = pErrorSink;
815 mpBase->setErrorSink(pErrorSink);
816 }
817
818 void o4(int n) {
819 if (mQ.full()) {
820 mpBase->o4(mQ.popFront());
821 }
822 mQ.pushBack(n);
823
824#ifndef DISABLE_ARM_PEEPHOLE
825 // Peephole check
826 bool didPeep;
827 do {
828 const unsigned int opMask = 0x01e00000;
829 const unsigned int immediateMask = 0x00000fff;
830 didPeep = false;
831 if (mQ.count() >= 4) {
832
833 // Operand by a small constant
834 // push;mov #imm;pop;op ==> op #imm
835
836 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
837 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
838 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
839 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
840 unsigned int movConst = mQ[-3];
841 unsigned int op = mQ[-1];
842 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
843 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
844 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
845 mQ.popBack(4);
846 mQ.pushBack(combined);
847 didPeep = true;
848 } else {
849 mQ.popBack(4);
850 didPeep = true;
851 }
852 }
853 }
854
855 // Load local variable
856 // sub r0,r11,#imm;ldr r0,[r0] ==> ldr r0, [r11,#-imm]
857 if (mQ.count() >= 2) {
858 if ((mQ[-2] & ~immediateMask) == 0xe24b0000 && // sub r0,r11,#imm
859 mQ[-1] == 0xe5900000) { // ldr r0, [r0]
860 unsigned int op = mQ[-2];
861 unsigned int ld = mQ[-1];
862 unsigned int combined = (op & immediateMask) | 0xE51B0000; // ldr r0, [r11, #-0]
863 mQ.popBack(2);
864 mQ.pushBack(combined);
865 didPeep = true;
866 }
867 }
868
869 // Constant array lookup
870
871 if (mQ.count() >= 6 &&
872 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
873 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
874 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
875 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
876 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
877 mQ[-1] == 0xe0810000) { // add r0, r1, r0
878 unsigned int mov1 = mQ[-5];
879 unsigned int mov2 = mQ[-3];
880 unsigned int const1 = decode12BitImmediate(mov1);
881 unsigned int const2 = decode12BitImmediate(mov2);
882 unsigned int comboConst = const1 * const2;
883 size_t immediate = 0;
884 if (encode12BitImmediate(comboConst, &immediate)) {
885 mQ.popBack(6);
886 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
887 if (comboConst) {
888 mQ.pushBack(add);
889 }
890 didPeep = true;
891 }
892 }
893
894 } while (didPeep);
895#endif
896 }
897
898 void ob(int n) {
899 error("ob() not supported.");
900 }
901
902 void* getBase() {
903 flush();
904 return mpBase->getBase();
905 }
906
907 intptr_t getSize() {
908 flush();
909 return mpBase->getSize();
910 }
911
912 intptr_t getPC() {
913 flush();
914 return mpBase->getPC();
915 }
916 };
917
Jack Palevich22305132009-05-13 10:58:45 -0700918 class ARMCodeGenerator : public CodeGenerator {
919 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700920 ARMCodeGenerator() {
921#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700922 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700923#else
Jack Palevichd5315572009-09-09 13:19:34 -0700924 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700925#endif
926 }
-b master422972c2009-06-17 19:13:52 -0700927
Jack Palevich22305132009-05-13 10:58:45 -0700928 virtual ~ARMCodeGenerator() {}
929
930 /* returns address to patch with local variable size
931 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700932 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700933 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700934 // sp -> arg4 arg5 ...
935 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700936 int regArgCount = calcRegArgCount(pDecl);
937 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700938 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700939 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700940 }
941 // sp -> arg0 arg1 ...
942 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700943 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700944 // sp, fp -> oldfp, retadr, arg0 arg1 ....
945 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700946 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700947 int pc = getPC();
948 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700949 // We don't know how many local variables we are going to use,
950 // but we will round the allocation up to a multiple of
951 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700952 return pc;
Jack Palevich22305132009-05-13 10:58:45 -0700953 }
954
Jack Palevichb7718b92009-07-09 22:00:24 -0700955 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700956 // Round local variable size up to a multiple of stack alignment
957 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
958 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700959 // Patch local variable allocation code:
960 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700961 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700962 }
Jack Palevich69796b62009-05-14 15:42:26 -0700963 *(char*) (localVariableAddress) = localVariableSize;
964
Jack Palevich30321cb2009-08-20 15:34:23 -0700965#ifdef ARM_USE_VFP
966 {
Jack Palevichc0f25332009-08-25 12:23:43 -0700967 Type* pReturnType = pDecl->pHead;
968 switch(pReturnType->tag) {
969 case TY_FLOAT:
970 o4(0xEE170A90); // fmrs r0, s15
971 break;
972 case TY_DOUBLE:
973 o4(0xEC510B17); // fmrrd r0, r1, d7
974 break;
975 default:
976 break;
977 }
Jack Palevich30321cb2009-08-20 15:34:23 -0700978 }
979#endif
980
Jack Palevich69796b62009-05-14 15:42:26 -0700981 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
982 o4(0xE1A0E00B); // mov lr, fp
983 o4(0xE59BB000); // ldr fp, [fp]
984 o4(0xE28ED004); // add sp, lr, #4
985 // sp -> retadr, arg0, ...
986 o4(0xE8BD4000); // ldmfd sp!, {lr}
987 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700988
989 // We store the PC into the lr so we can adjust the sp before
990 // returning. We need to pull off the registers we pushed
991 // earlier. We don't need to actually store them anywhere,
992 // just adjust the stack.
993 int regArgCount = calcRegArgCount(pDecl);
994 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700995 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
996 }
997 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700998 }
999
1000 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001001 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001002 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001003 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001004 }
1005
Jack Palevich1a539db2009-07-08 13:04:41 -07001006 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001007 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001008 // Global, absolute address
1009 o4(0xE59F0000); // ldr r0, .L1
1010 o4(0xEA000000); // b .L99
1011 o4(address); // .L1: .word ea
1012 // .L99:
1013
1014 switch (pType->tag) {
1015 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001016#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001017 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001018#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001019 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001020#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001021 break;
1022 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001023#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001024 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001025#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001026 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001027#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001028 break;
1029 default:
1030 assert(false);
1031 break;
1032 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001033 }
1034
Jack Palevich9221bcc2009-08-26 16:15:07 -07001035
1036 virtual void addStructOffsetR0(int offset, Type* pType) {
1037 if (offset) {
1038 size_t immediate = 0;
1039 if (encode12BitImmediate(offset, &immediate)) {
1040 o4(0xE2800000 | immediate); // add r0, r0, #offset
1041 } else {
1042 error("structure offset out of range: %d", offset);
1043 }
1044 }
1045 setR0Type(pType, ET_LVALUE);
1046 }
1047
Jack Palevich22305132009-05-13 10:58:45 -07001048 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001049 int pc = getPC();
1050 o4(0xEA000000 | encodeAddress(t)); // b .L33
1051 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001052 }
1053
1054 /* l = 0: je, l == 1: jne */
1055 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001056 Type* pR0Type = getR0Type();
1057 TypeTag tagR0 = pR0Type->tag;
1058 switch(tagR0) {
1059 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001060#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001061 o4(0xEEF57A40); // fcmpzs s15
1062 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001063#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001064 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001065 o4(0xE3500000); // cmp r0,#0
1066#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001067 break;
1068 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001069#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001070 o4(0xEEB57B40); // fcmpzd d7
1071 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001072#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001073 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001074 o4(0xE3500000); // cmp r0,#0
1075#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001076 break;
1077 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001078 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001079 break;
1080 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001081 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001082 int pc = getPC();
1083 o4(branch | encodeAddress(t));
1084 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001085 }
1086
Jack Palevich58c30ee2009-07-17 16:35:23 -07001087 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001088 Type* pR0Type = getR0Type();
1089 Type* pTOSType = getTOSType();
1090 TypeTag tagR0 = collapseType(pR0Type->tag);
1091 TypeTag tagTOS = collapseType(pTOSType->tag);
1092 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001093 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001094 o4(0xE1510000); // cmp r1, r1
1095 switch(op) {
1096 case OP_EQUALS:
1097 o4(0x03A00001); // moveq r0,#1
1098 o4(0x13A00000); // movne r0,#0
1099 break;
1100 case OP_NOT_EQUALS:
1101 o4(0x03A00000); // moveq r0,#0
1102 o4(0x13A00001); // movne r0,#1
1103 break;
1104 case OP_LESS_EQUAL:
1105 o4(0xD3A00001); // movle r0,#1
1106 o4(0xC3A00000); // movgt r0,#0
1107 break;
1108 case OP_GREATER:
1109 o4(0xD3A00000); // movle r0,#0
1110 o4(0xC3A00001); // movgt r0,#1
1111 break;
1112 case OP_GREATER_EQUAL:
1113 o4(0xA3A00001); // movge r0,#1
1114 o4(0xB3A00000); // movlt r0,#0
1115 break;
1116 case OP_LESS:
1117 o4(0xA3A00000); // movge r0,#0
1118 o4(0xB3A00001); // movlt r0,#1
1119 break;
1120 default:
1121 error("Unknown comparison op %d", op);
1122 break;
1123 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001124 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1125 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001126#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001127 o4(0xEEB46BC7); // fcmped d6, d7
1128 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001129 switch(op) {
1130 case OP_EQUALS:
1131 o4(0x03A00001); // moveq r0,#1
1132 o4(0x13A00000); // movne r0,#0
1133 break;
1134 case OP_NOT_EQUALS:
1135 o4(0x03A00000); // moveq r0,#0
1136 o4(0x13A00001); // movne r0,#1
1137 break;
1138 case OP_LESS_EQUAL:
1139 o4(0xD3A00001); // movle r0,#1
1140 o4(0xC3A00000); // movgt r0,#0
1141 break;
1142 case OP_GREATER:
1143 o4(0xD3A00000); // movle r0,#0
1144 o4(0xC3A00001); // movgt r0,#1
1145 break;
1146 case OP_GREATER_EQUAL:
1147 o4(0xA3A00001); // movge r0,#1
1148 o4(0xB3A00000); // movlt r0,#0
1149 break;
1150 case OP_LESS:
1151 o4(0xA3A00000); // movge r0,#0
1152 o4(0xB3A00001); // movlt r0,#1
1153 break;
1154 default:
1155 error("Unknown comparison op %d", op);
1156 break;
1157 }
1158#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001159 switch(op) {
1160 case OP_EQUALS:
1161 callRuntime((void*) runtime_cmp_eq_dd);
1162 break;
1163 case OP_NOT_EQUALS:
1164 callRuntime((void*) runtime_cmp_ne_dd);
1165 break;
1166 case OP_LESS_EQUAL:
1167 callRuntime((void*) runtime_cmp_le_dd);
1168 break;
1169 case OP_GREATER:
1170 callRuntime((void*) runtime_cmp_gt_dd);
1171 break;
1172 case OP_GREATER_EQUAL:
1173 callRuntime((void*) runtime_cmp_ge_dd);
1174 break;
1175 case OP_LESS:
1176 callRuntime((void*) runtime_cmp_lt_dd);
1177 break;
1178 default:
1179 error("Unknown comparison op %d", op);
1180 break;
1181 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001182#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001183 } else {
1184 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001185#ifdef ARM_USE_VFP
1186 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001187 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001188 switch(op) {
1189 case OP_EQUALS:
1190 o4(0x03A00001); // moveq r0,#1
1191 o4(0x13A00000); // movne r0,#0
1192 break;
1193 case OP_NOT_EQUALS:
1194 o4(0x03A00000); // moveq r0,#0
1195 o4(0x13A00001); // movne r0,#1
1196 break;
1197 case OP_LESS_EQUAL:
1198 o4(0xD3A00001); // movle r0,#1
1199 o4(0xC3A00000); // movgt r0,#0
1200 break;
1201 case OP_GREATER:
1202 o4(0xD3A00000); // movle r0,#0
1203 o4(0xC3A00001); // movgt r0,#1
1204 break;
1205 case OP_GREATER_EQUAL:
1206 o4(0xA3A00001); // movge r0,#1
1207 o4(0xB3A00000); // movlt r0,#0
1208 break;
1209 case OP_LESS:
1210 o4(0xA3A00000); // movge r0,#0
1211 o4(0xB3A00001); // movlt r0,#1
1212 break;
1213 default:
1214 error("Unknown comparison op %d", op);
1215 break;
1216 }
1217#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001218 switch(op) {
1219 case OP_EQUALS:
1220 callRuntime((void*) runtime_cmp_eq_ff);
1221 break;
1222 case OP_NOT_EQUALS:
1223 callRuntime((void*) runtime_cmp_ne_ff);
1224 break;
1225 case OP_LESS_EQUAL:
1226 callRuntime((void*) runtime_cmp_le_ff);
1227 break;
1228 case OP_GREATER:
1229 callRuntime((void*) runtime_cmp_gt_ff);
1230 break;
1231 case OP_GREATER_EQUAL:
1232 callRuntime((void*) runtime_cmp_ge_ff);
1233 break;
1234 case OP_LESS:
1235 callRuntime((void*) runtime_cmp_lt_ff);
1236 break;
1237 default:
1238 error("Unknown comparison op %d", op);
1239 break;
1240 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001241#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001242 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001243 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001244 }
1245
Jack Palevich546b2242009-05-13 15:10:04 -07001246 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001247 Type* pR0Type = getR0Type();
1248 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001249 TypeTag tagR0 = pR0Type->tag;
1250 TypeTag tagTOS = pTOSType->tag;
1251 bool isFloatR0 = isFloatTag(tagR0);
1252 bool isFloatTOS = isFloatTag(tagTOS);
1253 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001254 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001255 bool isPtrR0 = isPointerTag(tagR0);
1256 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001257 if (isPtrR0 || isPtrTOS) {
1258 if (isPtrR0 && isPtrTOS) {
1259 if (op != OP_MINUS) {
1260 error("Unsupported pointer-pointer operation %d.", op);
1261 }
1262 if (! typeEqual(pR0Type, pTOSType)) {
1263 error("Incompatible pointer types for subtraction.");
1264 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001265 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001266 setR0Type(mkpInt);
1267 int size = sizeOf(pR0Type->pHead);
1268 if (size != 1) {
1269 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001270 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001271 // TODO: Optimize for power-of-two.
1272 genOp(OP_DIV);
1273 }
1274 } else {
1275 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1276 error("Unsupported pointer-scalar operation %d", op);
1277 }
Jack Palevichb6154502009-08-04 14:56:09 -07001278 Type* pPtrType = getPointerArithmeticResultType(
1279 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001280 int size = sizeOf(pPtrType->pHead);
1281 if (size != 1) {
1282 // TODO: Optimize for power-of-two.
1283 liReg(size, 2);
1284 if (isPtrR0) {
1285 o4(0x0E0010192); // mul r1,r2,r1
1286 } else {
1287 o4(0x0E0000092); // mul r0,r2,r0
1288 }
1289 }
1290 switch(op) {
1291 case OP_PLUS:
1292 o4(0xE0810000); // add r0,r1,r0
1293 break;
1294 case OP_MINUS:
1295 o4(0xE0410000); // sub r0,r1,r0
1296 break;
1297 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001298 setR0Type(pPtrType);
1299 }
1300 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001301 switch(op) {
1302 case OP_MUL:
1303 o4(0x0E0000091); // mul r0,r1,r0
1304 break;
1305 case OP_DIV:
1306 callRuntime((void*) runtime_DIV);
1307 break;
1308 case OP_MOD:
1309 callRuntime((void*) runtime_MOD);
1310 break;
1311 case OP_PLUS:
1312 o4(0xE0810000); // add r0,r1,r0
1313 break;
1314 case OP_MINUS:
1315 o4(0xE0410000); // sub r0,r1,r0
1316 break;
1317 case OP_SHIFT_LEFT:
1318 o4(0xE1A00011); // lsl r0,r1,r0
1319 break;
1320 case OP_SHIFT_RIGHT:
1321 o4(0xE1A00051); // asr r0,r1,r0
1322 break;
1323 case OP_BIT_AND:
1324 o4(0xE0010000); // and r0,r1,r0
1325 break;
1326 case OP_BIT_XOR:
1327 o4(0xE0210000); // eor r0,r1,r0
1328 break;
1329 case OP_BIT_OR:
1330 o4(0xE1810000); // orr r0,r1,r0
1331 break;
1332 case OP_BIT_NOT:
1333 o4(0xE1E00000); // mvn r0, r0
1334 break;
1335 default:
1336 error("Unimplemented op %d\n", op);
1337 break;
1338 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001339 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001340 } else {
1341 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1342 if (pResultType->tag == TY_DOUBLE) {
1343 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001344
Jack Palevichb7718b92009-07-09 22:00:24 -07001345 switch(op) {
1346 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001347#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001348 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001349#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001350 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001351#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001352 break;
1353 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001354#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001355 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001356#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001357 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001358#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001359 break;
1360 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001361#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001362 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001363#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001364 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001365#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001366 break;
1367 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001368#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001369 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001370#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001371 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001372#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001373 break;
1374 default:
1375 error("Unsupported binary floating operation %d\n", op);
1376 break;
1377 }
1378 } else {
1379 setupFloatArgs();
1380 switch(op) {
1381 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001382#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001383 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001384#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001385 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001386#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001387 break;
1388 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001389#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001390 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001391#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001392 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001393#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001394 break;
1395 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001396#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001397 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001398#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001399 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001400#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001401 break;
1402 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001403#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001404 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001405#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001406 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001407#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001408 break;
1409 default:
1410 error("Unsupported binary floating operation %d\n", op);
1411 break;
1412 }
1413 }
1414 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001415 }
Jack Palevich22305132009-05-13 10:58:45 -07001416 }
1417
Jack Palevich58c30ee2009-07-17 16:35:23 -07001418 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001419 if (op != OP_LOGICAL_NOT) {
1420 error("Unknown unary cmp %d", op);
1421 } else {
1422 Type* pR0Type = getR0Type();
1423 TypeTag tag = collapseType(pR0Type->tag);
1424 switch(tag) {
1425 case TY_INT:
1426 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001427 o4(0xE1510000); // cmp r1, r0
1428 o4(0x03A00001); // moveq r0,#1
1429 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001430 break;
1431 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001432#ifdef ARM_USE_VFP
1433 o4(0xEEF57A40); // fcmpzs s15
1434 o4(0xEEF1FA10); // fmstat
1435 o4(0x03A00001); // moveq r0,#1
1436 o4(0x13A00000); // movne r0,#0
1437#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001438 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001439#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001440 break;
1441 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001442#ifdef ARM_USE_VFP
1443 o4(0xEEB57B40); // fcmpzd d7
1444 o4(0xEEF1FA10); // fmstat
1445 o4(0x03A00001); // moveq r0,#1
1446 o4(0x13A00000); // movne r0,#0
1447#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001448 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001449#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001450 break;
1451 default:
1452 error("gUnaryCmp unsupported type");
1453 break;
1454 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001455 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001456 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001457 }
1458
1459 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001460 Type* pR0Type = getR0Type();
1461 TypeTag tag = collapseType(pR0Type->tag);
1462 switch(tag) {
1463 case TY_INT:
1464 switch(op) {
1465 case OP_MINUS:
1466 o4(0xE3A01000); // mov r1, #0
1467 o4(0xE0410000); // sub r0,r1,r0
1468 break;
1469 case OP_BIT_NOT:
1470 o4(0xE1E00000); // mvn r0, r0
1471 break;
1472 default:
1473 error("Unknown unary op %d\n", op);
1474 break;
1475 }
1476 break;
1477 case TY_FLOAT:
1478 case TY_DOUBLE:
1479 switch (op) {
1480 case OP_MINUS:
1481 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001482#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001483 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001484#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001485 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001486#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001487 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001488#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001489 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001490#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001491 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001492#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001493 }
1494 break;
1495 case OP_BIT_NOT:
1496 error("Can't apply '~' operator to a float or double.");
1497 break;
1498 default:
1499 error("Unknown unary op %d\n", op);
1500 break;
1501 }
1502 break;
1503 default:
1504 error("genUnaryOp unsupported type");
1505 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001506 }
Jack Palevich22305132009-05-13 10:58:45 -07001507 }
1508
Jack Palevich1cdef202009-05-22 12:06:27 -07001509 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001510 Type* pR0Type = getR0Type();
1511 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001512
1513#ifdef ARM_USE_VFP
1514 switch (r0ct ) {
1515 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001516 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001517 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001518 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001519 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001520 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001521 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001522 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001523 default:
1524 o4(0xE92D0001); // stmfd sp!,{r0}
1525 mStackUse += 4;
1526 }
1527#else
1528
Jack Palevichb7718b92009-07-09 22:00:24 -07001529 if (r0ct != TY_DOUBLE) {
1530 o4(0xE92D0001); // stmfd sp!,{r0}
1531 mStackUse += 4;
1532 } else {
1533 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1534 mStackUse += 8;
1535 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001536#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001537 pushType();
-b master422972c2009-06-17 19:13:52 -07001538 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001539 }
1540
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001541 virtual void over() {
1542 // We know it's only used for int-ptr ops (++/--)
1543
1544 Type* pR0Type = getR0Type();
1545 TypeTag r0ct = collapseType(pR0Type->tag);
1546
1547 Type* pTOSType = getTOSType();
1548 TypeTag tosct = collapseType(pTOSType->tag);
1549
1550 assert (r0ct == TY_INT && tosct == TY_INT);
1551
1552 o4(0xE8BD0002); // ldmfd sp!,{r1}
1553 o4(0xE92D0001); // stmfd sp!,{r0}
1554 o4(0xE92D0002); // stmfd sp!,{r1}
1555 overType();
1556 mStackUse += 4;
1557 }
1558
Jack Palevich58c30ee2009-07-17 16:35:23 -07001559 virtual void popR0() {
1560 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001561 TypeTag tosct = collapseType(pTOSType->tag);
1562#ifdef ARM_USE_VFP
1563 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001564 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001565 }
1566#endif
1567 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001568 case TY_INT:
1569 case TY_FLOAT:
1570 o4(0xE8BD0001); // ldmfd sp!,{r0}
1571 mStackUse -= 4;
1572 break;
1573 case TY_DOUBLE:
1574 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1575 mStackUse -= 8;
1576 break;
1577 default:
1578 error("Can't pop this type.");
1579 break;
1580 }
1581 popType();
1582 LOG_STACK("popR0: %d\n", mStackUse);
1583 }
1584
1585 virtual void storeR0ToTOS() {
1586 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001587 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001588 Type* pDestType = pPointerType->pHead;
1589 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001590 o4(0xE8BD0004); // ldmfd sp!,{r2}
1591 popType();
-b master422972c2009-06-17 19:13:52 -07001592 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001593 switch (pDestType->tag) {
1594 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001595 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001596 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001597 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001598 case TY_FLOAT:
1599#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001600 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001601#else
1602 o4(0xE5820000); // str r0, [r2]
1603#endif
1604 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001605 case TY_SHORT:
1606 o4(0xE1C200B0); // strh r0, [r2]
1607 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001608 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001609 o4(0xE5C20000); // strb r0, [r2]
1610 break;
1611 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001612#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001613 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001614#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001615 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001616#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001617 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001618 case TY_STRUCT:
1619 {
1620 int size = sizeOf(pDestType);
1621 if (size > 0) {
1622 liReg(size, 1);
1623 callRuntime((void*) runtime_structCopy);
1624 }
1625 }
1626 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001627 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001628 error("storeR0ToTOS: unimplemented type %d",
1629 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001630 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001631 }
Jack Palevich22305132009-05-13 10:58:45 -07001632 }
1633
Jack Palevich58c30ee2009-07-17 16:35:23 -07001634 virtual void loadR0FromR0() {
1635 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001636 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001637 Type* pNewType = pPointerType->pHead;
1638 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001639 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001640 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001641 case TY_INT:
1642 o4(0xE5900000); // ldr r0, [r0]
1643 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001644 case TY_FLOAT:
1645#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001646 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001647#else
1648 o4(0xE5900000); // ldr r0, [r0]
1649#endif
1650 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001651 case TY_SHORT:
1652 o4(0xE1D000F0); // ldrsh r0, [r0]
1653 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001654 case TY_CHAR:
1655 o4(0xE5D00000); // ldrb r0, [r0]
1656 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001657 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001658#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001659 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001660#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001661 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001662#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001663 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001664 case TY_ARRAY:
1665 pNewType = pNewType->pTail;
1666 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001667 case TY_STRUCT:
1668 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001669 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001670 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001671 break;
1672 }
Jack Palevich80e49722009-08-04 15:39:49 -07001673 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001674 }
1675
Jack Palevichb5e33312009-07-30 19:06:34 -07001676 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001677 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001678 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001679
1680 size_t immediate = 0;
1681 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001682 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001683 inRange = encode12BitImmediate(-ea, &immediate);
1684 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001685 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001686 inRange = encode12BitImmediate(ea, &immediate);
1687 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1688 }
1689 if (! inRange) {
1690 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001691 }
Jack Palevichbd894902009-05-14 19:35:31 -07001692 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001693 // Global, absolute.
1694 o4(0xE59F0000); // ldr r0, .L1
1695 o4(0xEA000000); // b .L99
1696 o4(ea); // .L1: .word 0
1697 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001698 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001699 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001700 }
1701
Jack Palevich9f51a262009-07-29 16:22:26 -07001702 virtual int leaForward(int ea, Type* pPointerType) {
1703 setR0Type(pPointerType);
1704 int result = ea;
1705 int pc = getPC();
1706 int offset = 0;
1707 if (ea) {
1708 offset = (pc - ea - 8) >> 2;
1709 if ((offset & 0xffff) != offset) {
1710 error("function forward reference out of bounds");
1711 }
1712 } else {
1713 offset = 0;
1714 }
1715 o4(0xE59F0000 | offset); // ldr r0, .L1
1716
1717 if (ea == 0) {
1718 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001719 result = getPC();
1720 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001721 // .L99:
1722 }
1723 return result;
1724 }
1725
Jack Palevichb6154502009-08-04 14:56:09 -07001726 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001727 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001728 if (isPointerType(pType) && isPointerType(pR0Type)) {
1729 Type* pA = pR0Type;
1730 Type* pB = pType;
1731 // Array decays to pointer
1732 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1733 pA = pA->pTail;
1734 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001735 if (! (typeEqual(pA, pB)
1736 || pB->pHead->tag == TY_VOID
1737 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1738 )) {
1739 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001740 }
Jack Palevichb6154502009-08-04 14:56:09 -07001741 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001742 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001743 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001744 TypeTag r0Tag = collapseType(pR0Type->tag);
1745 TypeTag destTag = collapseType(pType->tag);
1746 if (r0Tag == TY_INT) {
1747 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001748#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001749 o4(0xEE070A90); // fmsr s15, r0
1750 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001751
1752#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001753 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001754#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001755 } else {
1756 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001757#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001758 o4(0xEE070A90); // fmsr s15, r0
1759 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001760
1761#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001762 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001763#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001764 }
1765 } else if (r0Tag == TY_FLOAT) {
1766 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001767#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001768 o4(0xEEFD7AE7); // ftosizs s15, s15
1769 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001770#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001771 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001772#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001773 } else {
1774 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001775#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001776 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001777#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001778 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001779#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001780 }
1781 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001782 if (r0Tag == TY_DOUBLE) {
1783 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001784#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001785 o4(0xEEFD7BC7); // ftosizd s15, d7
1786 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001787#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001788 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001789#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001790 } else {
1791 if(destTag == TY_FLOAT) {
1792#ifdef ARM_USE_VFP
1793 o4(0xEEF77BC7); // fcvtsd s15, d7
1794#else
1795 callRuntime((void*) runtime_double_to_float);
1796#endif
1797 } else {
1798 incompatibleTypes(pR0Type, pType);
1799 }
1800 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001801 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001802 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001803 }
1804 }
Jack Palevich8df46192009-07-07 14:48:51 -07001805 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001806 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001807 }
1808
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001809 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001810 int pc = getPC();
1811 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1812 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001813 }
1814
Jack Palevich8148c5b2009-07-16 18:24:47 -07001815 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001816 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001817 Type* pR0Type = getR0Type();
1818 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001819#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001820 switch(r0ct) {
1821 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001822 if (l < 0 || l > 4096-4) {
1823 error("l out of range for stack offset: 0x%08x", l);
1824 }
1825 o4(0xE58D0000 | l); // str r0, [sp, #l]
1826 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001827 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001828 if (l < 0 || l > 1020 || (l & 3)) {
1829 error("l out of range for stack offset: 0x%08x", l);
1830 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001831 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001832 return 4;
1833 case TY_DOUBLE: {
1834 // Align to 8 byte boundary
1835 int l2 = (l + 7) & ~7;
1836 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1837 error("l out of range for stack offset: 0x%08x", l);
1838 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001839 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001840 return (l2 - l) + 8;
1841 }
1842 default:
1843 assert(false);
1844 return 0;
1845 }
1846#else
1847 switch(r0ct) {
1848 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001849 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001850 if (l < 0 || l > 4096-4) {
1851 error("l out of range for stack offset: 0x%08x", l);
1852 }
1853 o4(0xE58D0000 + l); // str r0, [sp, #l]
1854 return 4;
1855 case TY_DOUBLE: {
1856 // Align to 8 byte boundary
1857 int l2 = (l + 7) & ~7;
1858 if (l2 < 0 || l2 > 4096-8) {
1859 error("l out of range for stack offset: 0x%08x", l);
1860 }
1861 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1862 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1863 return (l2 - l) + 8;
1864 }
1865 default:
1866 assert(false);
1867 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001868 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001869#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001870 }
1871
Jack Palevichb7718b92009-07-09 22:00:24 -07001872 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001873 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001874 // Have to calculate register arg count from actual stack size,
1875 // in order to properly handle ... functions.
1876 int regArgCount = l >> 2;
1877 if (regArgCount > 4) {
1878 regArgCount = 4;
1879 }
1880 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001881 argumentStackUse -= regArgCount * 4;
1882 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1883 }
1884 mStackUse += argumentStackUse;
1885
1886 // Align stack.
1887 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1888 * STACK_ALIGNMENT);
1889 mStackAlignmentAdjustment = 0;
1890 if (missalignment > 0) {
1891 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1892 }
1893 l += mStackAlignmentAdjustment;
1894
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001895 if (l < 0 || l > 0x3FC) {
1896 error("L out of range for stack adjustment: 0x%08x", l);
1897 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001898 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001899 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001900 mStackUse += mStackAlignmentAdjustment;
1901 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1902 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001903 }
1904
Jack Palevich8df46192009-07-07 14:48:51 -07001905 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001906 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001907 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001908 int pc = getPC();
1909 o4(0xEB000000 | encodeAddress(symbol));
1910 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001911 }
1912
Jack Palevich8df46192009-07-07 14:48:51 -07001913 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001914 assert(pFunc->tag == TY_FUNC);
1915 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001916 int argCount = l >> 2;
1917 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001918 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001919 if (adjustedL < 0 || adjustedL > 4096-4) {
1920 error("l out of range for stack offset: 0x%08x", l);
1921 }
1922 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1923 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001924 Type* pReturnType = pFunc->pHead;
1925 setR0Type(pReturnType);
1926#ifdef ARM_USE_VFP
1927 switch(pReturnType->tag) {
1928 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001929 o4(0xEE070A90); // fmsr s15, r0
1930 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001931 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001932 o4(0xEC410B17); // fmdrr d7, r0, r1
1933 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001934 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001935 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001936 }
1937#endif
Jack Palevich22305132009-05-13 10:58:45 -07001938 }
1939
Jack Palevichb7718b92009-07-09 22:00:24 -07001940 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001941 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001942 // Have to calculate register arg count from actual stack size,
1943 // in order to properly handle ... functions.
1944 int regArgCount = l >> 2;
1945 if (regArgCount > 4) {
1946 regArgCount = 4;
1947 }
1948 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001949 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1950 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001951 if (stackUse) {
1952 if (stackUse < 0 || stackUse > 255) {
1953 error("L out of range for stack adjustment: 0x%08x", l);
1954 }
1955 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001956 mStackUse -= stackUse * 4;
1957 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001958 }
Jack Palevich22305132009-05-13 10:58:45 -07001959 }
1960
Jack Palevicha6535612009-05-13 16:24:17 -07001961 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001962 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001963 }
1964
1965 /* output a symbol and patch all calls to it */
1966 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001967 int n;
1968 int base = getBase();
1969 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001970 while (t) {
1971 int data = * (int*) t;
1972 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1973 if (decodedOffset == 0) {
1974 n = 0;
1975 } else {
1976 n = base + decodedOffset; /* next value */
1977 }
1978 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1979 | encodeRelAddress(pc - t - 8);
1980 t = n;
1981 }
1982 }
1983
Jack Palevich9f51a262009-07-29 16:22:26 -07001984 /* output a symbol and patch all calls to it */
1985 virtual void resolveForward(int t) {
1986 if (t) {
1987 int pc = getPC();
1988 *(int *) t = pc;
1989 }
1990 }
1991
Jack Palevich1cdef202009-05-22 12:06:27 -07001992 virtual int finishCompile() {
1993#if defined(__arm__)
1994 const long base = long(getBase());
1995 const long curr = long(getPC());
1996 int err = cacheflush(base, curr, 0);
1997 return err;
1998#else
1999 return 0;
2000#endif
2001 }
2002
Jack Palevich9eed7a22009-07-06 17:24:34 -07002003 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002004 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002005 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002006 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002007 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002008 case TY_CHAR:
2009 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002010 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002011 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002012 case TY_DOUBLE:
2013 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002014 case TY_ARRAY:
2015 return alignmentOf(pType->pHead);
2016 case TY_STRUCT:
2017 return pType->pHead->alignment & 0x7fffffff;
2018 case TY_FUNC:
2019 error("alignment of func not supported");
2020 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002021 default:
2022 return 4;
2023 }
2024 }
2025
2026 /**
2027 * Array element alignment (in bytes) for this type of data.
2028 */
2029 virtual size_t sizeOf(Type* pType){
2030 switch(pType->tag) {
2031 case TY_INT:
2032 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002033 case TY_SHORT:
2034 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002035 case TY_CHAR:
2036 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002037 case TY_FLOAT:
2038 return 4;
2039 case TY_DOUBLE:
2040 return 8;
2041 case TY_POINTER:
2042 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002043 case TY_ARRAY:
2044 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002045 case TY_STRUCT:
2046 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002047 default:
2048 error("Unsupported type %d", pType->tag);
2049 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002050 }
2051 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002052
Jack Palevich22305132009-05-13 10:58:45 -07002053 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002054
2055 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2056
2057 /** Encode a relative address that might also be
2058 * a label.
2059 */
2060 int encodeAddress(int value) {
2061 int base = getBase();
2062 if (value >= base && value <= getPC() ) {
2063 // This is a label, encode it relative to the base.
2064 value = value - base;
2065 }
2066 return encodeRelAddress(value);
2067 }
2068
2069 int encodeRelAddress(int value) {
2070 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2071 }
Jack Palevich22305132009-05-13 10:58:45 -07002072
Jack Palevichb7718b92009-07-09 22:00:24 -07002073 int calcRegArgCount(Type* pDecl) {
2074 int reg = 0;
2075 Type* pArgs = pDecl->pTail;
2076 while (pArgs && reg < 4) {
2077 Type* pArg = pArgs->pHead;
2078 if ( pArg->tag == TY_DOUBLE) {
2079 int evenReg = (reg + 1) & ~1;
2080 if (evenReg >= 4) {
2081 break;
2082 }
2083 reg = evenReg + 2;
2084 } else {
2085 reg++;
2086 }
2087 pArgs = pArgs->pTail;
2088 }
2089 return reg;
2090 }
2091
Jack Palevich58c30ee2009-07-17 16:35:23 -07002092 void setupIntPtrArgs() {
2093 o4(0xE8BD0002); // ldmfd sp!,{r1}
2094 mStackUse -= 4;
2095 popType();
2096 }
2097
Jack Palevich30321cb2009-08-20 15:34:23 -07002098 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002099 * Make sure both R0 and TOS are floats. (Could be ints)
2100 * We know that at least one of R0 and TOS is already a float
2101 */
2102 void setupFloatArgs() {
2103 Type* pR0Type = getR0Type();
2104 Type* pTOSType = getTOSType();
2105 TypeTag tagR0 = collapseType(pR0Type->tag);
2106 TypeTag tagTOS = collapseType(pTOSType->tag);
2107 if (tagR0 != TY_FLOAT) {
2108 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002109#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002110 o4(0xEE070A90); // fmsr s15, r0
2111 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002112#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002113 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002114#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002115 }
2116 if (tagTOS != TY_FLOAT) {
2117 assert(tagTOS == TY_INT);
2118 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002119#ifdef ARM_USE_VFP
2120 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002121 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002122#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002123 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2124 o4(0xE59D0004); // ldr r0, [sp, #4]
2125 callRuntime((void*) runtime_int_to_float);
2126 o4(0xE1A01000); // mov r1, r0
2127 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2128 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002129#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002130 } else {
2131 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002132#ifdef ARM_USE_VFP
2133 o4(0xECBD7A01); // fldmfds sp!, {s14}
2134
2135#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002136 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002137#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002138 }
2139 mStackUse -= 4;
2140 popType();
2141 }
2142
Jack Palevich30321cb2009-08-20 15:34:23 -07002143 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002144 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2145 * We know that at least one of R0 and TOS are already a double.
2146 */
2147
2148 void setupDoubleArgs() {
2149 Type* pR0Type = getR0Type();
2150 Type* pTOSType = getTOSType();
2151 TypeTag tagR0 = collapseType(pR0Type->tag);
2152 TypeTag tagTOS = collapseType(pTOSType->tag);
2153 if (tagR0 != TY_DOUBLE) {
2154 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002155#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002156 o4(0xEE070A90); // fmsr s15, r0
2157 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002158
2159#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002160 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002161#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002162 } else {
2163 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002164#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002165 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002166#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002167 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002168#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002169 }
2170 }
2171 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002172#ifdef ARM_USE_VFP
2173 if (tagTOS == TY_INT) {
2174 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002175 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002176 } else {
2177 assert(tagTOS == TY_FLOAT);
2178 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002179 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002180 }
2181#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002182 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2183 o4(0xE59D0008); // ldr r0, [sp, #8]
2184 if (tagTOS == TY_INT) {
2185 callRuntime((void*) runtime_int_to_double);
2186 } else {
2187 assert(tagTOS == TY_FLOAT);
2188 callRuntime((void*) runtime_float_to_double);
2189 }
2190 o4(0xE1A02000); // mov r2, r0
2191 o4(0xE1A03001); // mov r3, r1
2192 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2193 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002194#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002195 mStackUse -= 4;
2196 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002197#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002198 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002199#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002200 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002201#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002202 mStackUse -= 8;
2203 }
2204 popType();
2205 }
2206
Jack Palevicha8f427f2009-07-13 18:40:08 -07002207 void liReg(int t, int reg) {
2208 assert(reg >= 0 && reg < 16);
2209 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002210 size_t encodedImmediate;
2211 if (encode12BitImmediate(t, &encodedImmediate)) {
2212 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2213 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002214 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002215 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002216 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002217 o4(0xE51F0000 | rN); // ldr rN, .L3
2218 o4(0xEA000000); // b .L99
2219 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002220 // .L99:
2221 }
2222 }
2223
Jack Palevichc408bbf2009-09-08 12:07:32 -07002224 void incompatibleTypes(Type* pR0Type, Type* pType) {
2225 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2226 }
2227
Jack Palevichb7718b92009-07-09 22:00:24 -07002228 void callRuntime(void* fn) {
2229 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002230 o4(0xEA000000); // b .L99
2231 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002232 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002233 }
2234
Jack Palevichb7718b92009-07-09 22:00:24 -07002235 // Integer math:
2236
2237 static int runtime_DIV(int b, int a) {
2238 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002239 }
2240
Jack Palevichb7718b92009-07-09 22:00:24 -07002241 static int runtime_MOD(int b, int a) {
2242 return a % b;
2243 }
2244
Jack Palevich9221bcc2009-08-26 16:15:07 -07002245 static void runtime_structCopy(void* src, size_t size, void* dest) {
2246 memcpy(dest, src, size);
2247 }
2248
Jack Palevich30321cb2009-08-20 15:34:23 -07002249#ifndef ARM_USE_VFP
2250
Jack Palevichb7718b92009-07-09 22:00:24 -07002251 // Comparison to zero
2252
2253 static int runtime_is_non_zero_f(float a) {
2254 return a != 0;
2255 }
2256
2257 static int runtime_is_non_zero_d(double a) {
2258 return a != 0;
2259 }
2260
2261 // Comparison to zero
2262
2263 static int runtime_is_zero_f(float a) {
2264 return a == 0;
2265 }
2266
2267 static int runtime_is_zero_d(double a) {
2268 return a == 0;
2269 }
2270
2271 // Type conversion
2272
2273 static int runtime_float_to_int(float a) {
2274 return (int) a;
2275 }
2276
2277 static double runtime_float_to_double(float a) {
2278 return (double) a;
2279 }
2280
2281 static int runtime_double_to_int(double a) {
2282 return (int) a;
2283 }
2284
2285 static float runtime_double_to_float(double a) {
2286 return (float) a;
2287 }
2288
2289 static float runtime_int_to_float(int a) {
2290 return (float) a;
2291 }
2292
2293 static double runtime_int_to_double(int a) {
2294 return (double) a;
2295 }
2296
2297 // Comparisons float
2298
2299 static int runtime_cmp_eq_ff(float b, float a) {
2300 return a == b;
2301 }
2302
2303 static int runtime_cmp_ne_ff(float b, float a) {
2304 return a != b;
2305 }
2306
2307 static int runtime_cmp_lt_ff(float b, float a) {
2308 return a < b;
2309 }
2310
2311 static int runtime_cmp_le_ff(float b, float a) {
2312 return a <= b;
2313 }
2314
2315 static int runtime_cmp_ge_ff(float b, float a) {
2316 return a >= b;
2317 }
2318
2319 static int runtime_cmp_gt_ff(float b, float a) {
2320 return a > b;
2321 }
2322
2323 // Comparisons double
2324
2325 static int runtime_cmp_eq_dd(double b, double a) {
2326 return a == b;
2327 }
2328
2329 static int runtime_cmp_ne_dd(double b, double a) {
2330 return a != b;
2331 }
2332
2333 static int runtime_cmp_lt_dd(double b, double a) {
2334 return a < b;
2335 }
2336
2337 static int runtime_cmp_le_dd(double b, double a) {
2338 return a <= b;
2339 }
2340
2341 static int runtime_cmp_ge_dd(double b, double a) {
2342 return a >= b;
2343 }
2344
2345 static int runtime_cmp_gt_dd(double b, double a) {
2346 return a > b;
2347 }
2348
2349 // Math float
2350
2351 static float runtime_op_add_ff(float b, float a) {
2352 return a + b;
2353 }
2354
2355 static float runtime_op_sub_ff(float b, float a) {
2356 return a - b;
2357 }
2358
2359 static float runtime_op_mul_ff(float b, float a) {
2360 return a * b;
2361 }
2362
2363 static float runtime_op_div_ff(float b, float a) {
2364 return a / b;
2365 }
2366
2367 static float runtime_op_neg_f(float a) {
2368 return -a;
2369 }
2370
2371 // Math double
2372
2373 static double runtime_op_add_dd(double b, double a) {
2374 return a + b;
2375 }
2376
2377 static double runtime_op_sub_dd(double b, double a) {
2378 return a - b;
2379 }
2380
2381 static double runtime_op_mul_dd(double b, double a) {
2382 return a * b;
2383 }
2384
2385 static double runtime_op_div_dd(double b, double a) {
2386 return a / b;
2387 }
2388
2389 static double runtime_op_neg_d(double a) {
2390 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002391 }
-b master422972c2009-06-17 19:13:52 -07002392
Jack Palevich30321cb2009-08-20 15:34:23 -07002393#endif
2394
-b master422972c2009-06-17 19:13:52 -07002395 static const int STACK_ALIGNMENT = 8;
2396 int mStackUse;
2397 // This variable holds the amount we adjusted the stack in the most
2398 // recent endFunctionCallArguments call. It's examined by the
2399 // following adjustStackAfterCall call.
2400 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002401 };
2402
Jack Palevich09555c72009-05-27 12:25:55 -07002403#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002404
2405#ifdef PROVIDE_X86_CODEGEN
2406
Jack Palevich21a15a22009-05-11 14:49:29 -07002407 class X86CodeGenerator : public CodeGenerator {
2408 public:
2409 X86CodeGenerator() {}
2410 virtual ~X86CodeGenerator() {}
2411
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002412 /* returns address to patch with local variable size
2413 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002414 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002415 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2416 return oad(0xec81, 0); /* sub $xxx, %esp */
2417 }
2418
Jack Palevichb7718b92009-07-09 22:00:24 -07002419 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002420 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002421 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002422 }
2423
Jack Palevich21a15a22009-05-11 14:49:29 -07002424 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002425 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002426 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002427 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002428 }
2429
Jack Palevich1a539db2009-07-08 13:04:41 -07002430 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002431 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002432 switch (pType->tag) {
2433 case TY_FLOAT:
2434 oad(0x05D9, address); // flds
2435 break;
2436 case TY_DOUBLE:
2437 oad(0x05DD, address); // fldl
2438 break;
2439 default:
2440 assert(false);
2441 break;
2442 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002443 }
2444
Jack Palevich9221bcc2009-08-26 16:15:07 -07002445 virtual void addStructOffsetR0(int offset, Type* pType) {
2446 if (offset) {
2447 oad(0x05, offset); // addl offset, %eax
2448 }
2449 setR0Type(pType, ET_LVALUE);
2450 }
2451
Jack Palevich22305132009-05-13 10:58:45 -07002452 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002453 return psym(0xe9, t);
2454 }
2455
2456 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002457 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002458 Type* pR0Type = getR0Type();
2459 TypeTag tagR0 = pR0Type->tag;
2460 bool isFloatR0 = isFloatTag(tagR0);
2461 if (isFloatR0) {
2462 o(0xeed9); // fldz
2463 o(0xe9da); // fucompp
2464 o(0xe0df); // fnstsw %ax
2465 o(0x9e); // sahf
2466 } else {
2467 o(0xc085); // test %eax, %eax
2468 }
2469 // Use two output statements to generate one instruction.
2470 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002471 return psym(0x84 + l, t);
2472 }
2473
Jack Palevich58c30ee2009-07-17 16:35:23 -07002474 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002475 Type* pR0Type = getR0Type();
2476 Type* pTOSType = getTOSType();
2477 TypeTag tagR0 = pR0Type->tag;
2478 TypeTag tagTOS = pTOSType->tag;
2479 bool isFloatR0 = isFloatTag(tagR0);
2480 bool isFloatTOS = isFloatTag(tagTOS);
2481 if (!isFloatR0 && !isFloatTOS) {
2482 int t = decodeOp(op);
2483 o(0x59); /* pop %ecx */
2484 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002485 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002486 o(0x0f); /* setxx %al */
2487 o(t + 0x90);
2488 o(0xc0);
2489 popType();
2490 } else {
2491 setupFloatOperands();
2492 switch (op) {
2493 case OP_EQUALS:
2494 o(0xe9da); // fucompp
2495 o(0xe0df); // fnstsw %ax
2496 o(0x9e); // sahf
2497 o(0xc0940f); // sete %al
2498 o(0xc29b0f); // setnp %dl
2499 o(0xd021); // andl %edx, %eax
2500 break;
2501 case OP_NOT_EQUALS:
2502 o(0xe9da); // fucompp
2503 o(0xe0df); // fnstsw %ax
2504 o(0x9e); // sahf
2505 o(0xc0950f); // setne %al
2506 o(0xc29a0f); // setp %dl
2507 o(0xd009); // orl %edx, %eax
2508 break;
2509 case OP_GREATER_EQUAL:
2510 o(0xe9da); // fucompp
2511 o(0xe0df); // fnstsw %ax
2512 o(0x05c4f6); // testb $5, %ah
2513 o(0xc0940f); // sete %al
2514 break;
2515 case OP_LESS:
2516 o(0xc9d9); // fxch %st(1)
2517 o(0xe9da); // fucompp
2518 o(0xe0df); // fnstsw %ax
2519 o(0x9e); // sahf
2520 o(0xc0970f); // seta %al
2521 break;
2522 case OP_LESS_EQUAL:
2523 o(0xc9d9); // fxch %st(1)
2524 o(0xe9da); // fucompp
2525 o(0xe0df); // fnstsw %ax
2526 o(0x9e); // sahf
2527 o(0xc0930f); // setea %al
2528 break;
2529 case OP_GREATER:
2530 o(0xe9da); // fucompp
2531 o(0xe0df); // fnstsw %ax
2532 o(0x45c4f6); // testb $69, %ah
2533 o(0xc0940f); // sete %al
2534 break;
2535 default:
2536 error("Unknown comparison op");
2537 }
2538 o(0xc0b60f); // movzbl %al, %eax
2539 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002540 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002541 }
2542
Jack Palevich546b2242009-05-13 15:10:04 -07002543 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002544 Type* pR0Type = getR0Type();
2545 Type* pTOSType = getTOSType();
2546 TypeTag tagR0 = pR0Type->tag;
2547 TypeTag tagTOS = pTOSType->tag;
2548 bool isFloatR0 = isFloatTag(tagR0);
2549 bool isFloatTOS = isFloatTag(tagTOS);
2550 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002551 bool isPtrR0 = isPointerTag(tagR0);
2552 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002553 if (isPtrR0 || isPtrTOS) {
2554 if (isPtrR0 && isPtrTOS) {
2555 if (op != OP_MINUS) {
2556 error("Unsupported pointer-pointer operation %d.", op);
2557 }
2558 if (! typeEqual(pR0Type, pTOSType)) {
2559 error("Incompatible pointer types for subtraction.");
2560 }
2561 o(0x59); /* pop %ecx */
2562 o(decodeOp(op));
2563 popType();
2564 setR0Type(mkpInt);
2565 int size = sizeOf(pR0Type->pHead);
2566 if (size != 1) {
2567 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002568 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002569 // TODO: Optimize for power-of-two.
2570 genOp(OP_DIV);
2571 }
2572 } else {
2573 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2574 error("Unsupported pointer-scalar operation %d", op);
2575 }
Jack Palevichb6154502009-08-04 14:56:09 -07002576 Type* pPtrType = getPointerArithmeticResultType(
2577 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002578 o(0x59); /* pop %ecx */
2579 int size = sizeOf(pPtrType->pHead);
2580 if (size != 1) {
2581 // TODO: Optimize for power-of-two.
2582 if (isPtrR0) {
2583 oad(0xC969, size); // imull $size, %ecx
2584 } else {
2585 oad(0xC069, size); // mul $size, %eax
2586 }
2587 }
2588 o(decodeOp(op));
2589 popType();
2590 setR0Type(pPtrType);
2591 }
2592 } else {
2593 o(0x59); /* pop %ecx */
2594 o(decodeOp(op));
2595 if (op == OP_MOD)
2596 o(0x92); /* xchg %edx, %eax */
2597 popType();
2598 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002599 } else {
2600 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2601 setupFloatOperands();
2602 // Both float. x87 R0 == left hand, x87 R1 == right hand
2603 switch (op) {
2604 case OP_MUL:
2605 o(0xc9de); // fmulp
2606 break;
2607 case OP_DIV:
2608 o(0xf1de); // fdivp
2609 break;
2610 case OP_PLUS:
2611 o(0xc1de); // faddp
2612 break;
2613 case OP_MINUS:
2614 o(0xe1de); // fsubp
2615 break;
2616 default:
2617 error("Unsupported binary floating operation.");
2618 break;
2619 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002620 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002621 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002622 }
2623
Jack Palevich58c30ee2009-07-17 16:35:23 -07002624 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002625 if (op != OP_LOGICAL_NOT) {
2626 error("Unknown unary cmp %d", op);
2627 } else {
2628 Type* pR0Type = getR0Type();
2629 TypeTag tag = collapseType(pR0Type->tag);
2630 switch(tag) {
2631 case TY_INT: {
2632 oad(0xb9, 0); /* movl $0, %ecx */
2633 int t = decodeOp(op);
2634 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002635 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002636 o(0x0f); /* setxx %al */
2637 o(t + 0x90);
2638 o(0xc0);
2639 }
2640 break;
2641 case TY_FLOAT:
2642 case TY_DOUBLE:
2643 o(0xeed9); // fldz
2644 o(0xe9da); // fucompp
2645 o(0xe0df); // fnstsw %ax
2646 o(0x9e); // sahf
2647 o(0xc0950f); // setne %al
2648 o(0xc29a0f); // setp %dl
2649 o(0xd009); // orl %edx, %eax
2650 o(0xc0b60f); // movzbl %al, %eax
2651 o(0x01f083); // xorl $1, %eax
2652 break;
2653 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002654 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002655 break;
2656 }
2657 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002658 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002659 }
2660
2661 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002662 Type* pR0Type = getR0Type();
2663 TypeTag tag = collapseType(pR0Type->tag);
2664 switch(tag) {
2665 case TY_INT:
2666 oad(0xb9, 0); /* movl $0, %ecx */
2667 o(decodeOp(op));
2668 break;
2669 case TY_FLOAT:
2670 case TY_DOUBLE:
2671 switch (op) {
2672 case OP_MINUS:
2673 o(0xe0d9); // fchs
2674 break;
2675 case OP_BIT_NOT:
2676 error("Can't apply '~' operator to a float or double.");
2677 break;
2678 default:
2679 error("Unknown unary op %d\n", op);
2680 break;
2681 }
2682 break;
2683 default:
2684 error("genUnaryOp unsupported type");
2685 break;
2686 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002687 }
2688
Jack Palevich1cdef202009-05-22 12:06:27 -07002689 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002690 Type* pR0Type = getR0Type();
2691 TypeTag r0ct = collapseType(pR0Type->tag);
2692 switch(r0ct) {
2693 case TY_INT:
2694 o(0x50); /* push %eax */
2695 break;
2696 case TY_FLOAT:
2697 o(0x50); /* push %eax */
2698 o(0x241cd9); // fstps 0(%esp)
2699 break;
2700 case TY_DOUBLE:
2701 o(0x50); /* push %eax */
2702 o(0x50); /* push %eax */
2703 o(0x241cdd); // fstpl 0(%esp)
2704 break;
2705 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002706 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002707 break;
2708 }
Jack Palevich8df46192009-07-07 14:48:51 -07002709 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002710 }
2711
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002712 virtual void over() {
2713 // We know it's only used for int-ptr ops (++/--)
2714
2715 Type* pR0Type = getR0Type();
2716 TypeTag r0ct = collapseType(pR0Type->tag);
2717
2718 Type* pTOSType = getTOSType();
2719 TypeTag tosct = collapseType(pTOSType->tag);
2720
2721 assert (r0ct == TY_INT && tosct == TY_INT);
2722
2723 o(0x59); /* pop %ecx */
2724 o(0x50); /* push %eax */
2725 o(0x51); /* push %ecx */
2726
2727 overType();
2728 }
2729
Jack Palevich58c30ee2009-07-17 16:35:23 -07002730 virtual void popR0() {
2731 Type* pR0Type = getR0Type();
2732 TypeTag r0ct = collapseType(pR0Type->tag);
2733 switch(r0ct) {
2734 case TY_INT:
2735 o(0x58); /* popl %eax */
2736 break;
2737 case TY_FLOAT:
2738 o(0x2404d9); // flds (%esp)
2739 o(0x58); /* popl %eax */
2740 break;
2741 case TY_DOUBLE:
2742 o(0x2404dd); // fldl (%esp)
2743 o(0x58); /* popl %eax */
2744 o(0x58); /* popl %eax */
2745 break;
2746 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002747 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002748 break;
2749 }
2750 popType();
2751 }
2752
2753 virtual void storeR0ToTOS() {
2754 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002755 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002756 Type* pTargetType = pPointerType->pHead;
2757 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002758 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002759 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002760 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002761 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002762 case TY_INT:
2763 o(0x0189); /* movl %eax/%al, (%ecx) */
2764 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002765 case TY_SHORT:
2766 o(0x018966); /* movw %ax, (%ecx) */
2767 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002768 case TY_CHAR:
2769 o(0x0188); /* movl %eax/%al, (%ecx) */
2770 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002771 case TY_FLOAT:
2772 o(0x19d9); /* fstps (%ecx) */
2773 break;
2774 case TY_DOUBLE:
2775 o(0x19dd); /* fstpl (%ecx) */
2776 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002777 case TY_STRUCT:
2778 {
2779 // TODO: use alignment information to use movsw/movsl instead of movsb
2780 int size = sizeOf(pTargetType);
2781 if (size > 0) {
2782 o(0x9c); // pushf
2783 o(0x57); // pushl %edi
2784 o(0x56); // pushl %esi
2785 o(0xcf89); // movl %ecx, %edi
2786 o(0xc689); // movl %eax, %esi
2787 oad(0xb9, size); // mov #size, %ecx
2788 o(0xfc); // cld
2789 o(0xf3); // rep
2790 o(0xa4); // movsb
2791 o(0x5e); // popl %esi
2792 o(0x5f); // popl %edi
2793 o(0x9d); // popf
2794 }
2795 }
2796 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002797 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002798 error("storeR0ToTOS: unsupported type %d",
2799 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002800 break;
2801 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002802 }
2803
Jack Palevich58c30ee2009-07-17 16:35:23 -07002804 virtual void loadR0FromR0() {
2805 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002806 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002807 Type* pNewType = pPointerType->pHead;
2808 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002809 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002810 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002811 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002812 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002813 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002814 case TY_SHORT:
2815 o(0xbf0f); /* movswl (%eax), %eax */
2816 ob(0);
2817 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002818 case TY_CHAR:
2819 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002820 ob(0); /* add zero in code */
2821 break;
2822 case TY_FLOAT:
2823 o2(0x00d9); // flds (%eax)
2824 break;
2825 case TY_DOUBLE:
2826 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002827 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002828 case TY_ARRAY:
2829 pNewType = pNewType->pTail;
2830 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002831 case TY_STRUCT:
2832 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002833 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002834 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002835 break;
2836 }
Jack Palevich80e49722009-08-04 15:39:49 -07002837 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002838 }
2839
Jack Palevichb5e33312009-07-30 19:06:34 -07002840 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002841 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002842 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002843 }
2844
Jack Palevich9f51a262009-07-29 16:22:26 -07002845 virtual int leaForward(int ea, Type* pPointerType) {
2846 oad(0xb8, ea); /* mov $xx, %eax */
2847 setR0Type(pPointerType);
2848 return getPC() - 4;
2849 }
2850
Jack Palevichb6154502009-08-04 14:56:09 -07002851 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002852 Type* pR0Type = getR0Type();
2853 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002854 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002855 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002856 return;
2857 }
Jack Palevichb6154502009-08-04 14:56:09 -07002858 if (isPointerType(pType) && isPointerType(pR0Type)) {
2859 Type* pA = pR0Type;
2860 Type* pB = pType;
2861 // Array decays to pointer
2862 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2863 pA = pA->pTail;
2864 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002865 if (! (typeEqual(pA, pB)
2866 || pB->pHead->tag == TY_VOID
2867 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2868 )) {
2869 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002870 }
Jack Palevichb6154502009-08-04 14:56:09 -07002871 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002872 // do nothing special
2873 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2874 // do nothing special, both held in same register on x87.
2875 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002876 TypeTag r0Tag = collapseType(pR0Type->tag);
2877 TypeTag destTag = collapseType(pType->tag);
2878 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2879 // Convert R0 from int to float
2880 o(0x50); // push %eax
2881 o(0x2404DB); // fildl 0(%esp)
2882 o(0x58); // pop %eax
2883 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2884 // Convert R0 from float to int. Complicated because
2885 // need to save and restore the rounding mode.
2886 o(0x50); // push %eax
2887 o(0x50); // push %eax
2888 o(0x02247cD9); // fnstcw 2(%esp)
2889 o(0x2444b70f); // movzwl 2(%esp), %eax
2890 o(0x02);
2891 o(0x0cb4); // movb $12, %ah
2892 o(0x24048966); // movw %ax, 0(%esp)
2893 o(0x242cd9); // fldcw 0(%esp)
2894 o(0x04245cdb); // fistpl 4(%esp)
2895 o(0x02246cd9); // fldcw 2(%esp)
2896 o(0x58); // pop %eax
2897 o(0x58); // pop %eax
2898 } else {
2899 error("Incompatible types old: %d new: %d",
2900 pR0Type->tag, pType->tag);
2901 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002902 }
2903 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002904 }
2905
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002906 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002907 return oad(0xec81, 0); /* sub $xxx, %esp */
2908 }
2909
Jack Palevich8148c5b2009-07-16 18:24:47 -07002910 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2911 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002912 Type* pR0Type = getR0Type();
2913 TypeTag r0ct = collapseType(pR0Type->tag);
2914 switch(r0ct) {
2915 case TY_INT:
2916 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2917 return 4;
2918 case TY_FLOAT:
2919 oad(0x249CD9, l); /* fstps xxx(%esp) */
2920 return 4;
2921 case TY_DOUBLE:
2922 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2923 return 8;
2924 default:
2925 assert(false);
2926 return 0;
2927 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002928 }
2929
Jack Palevichb7718b92009-07-09 22:00:24 -07002930 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002931 * (int*) a = l;
2932 }
2933
Jack Palevich8df46192009-07-07 14:48:51 -07002934 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002935 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002936 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002937 return psym(0xe8, symbol); /* call xxx */
2938 }
2939
Jack Palevich8df46192009-07-07 14:48:51 -07002940 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002941 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002942 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002943 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002944 oad(0x2494ff, l); /* call *xxx(%esp) */
2945 }
2946
Jack Palevichb7718b92009-07-09 22:00:24 -07002947 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002948 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002949 if (isIndirect) {
2950 l += 4;
2951 }
-b master422972c2009-06-17 19:13:52 -07002952 if (l > 0) {
2953 oad(0xc481, l); /* add $xxx, %esp */
2954 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002955 }
2956
Jack Palevicha6535612009-05-13 16:24:17 -07002957 virtual int jumpOffset() {
2958 return 5;
2959 }
2960
Jack Paleviche7b59062009-05-19 17:12:17 -07002961 /* output a symbol and patch all calls to it */
2962 virtual void gsym(int t) {
2963 int n;
2964 int pc = getPC();
2965 while (t) {
2966 n = *(int *) t; /* next value */
2967 *(int *) t = pc - t - 4;
2968 t = n;
2969 }
2970 }
2971
Jack Palevich9f51a262009-07-29 16:22:26 -07002972 /* output a symbol and patch all calls to it, using absolute address */
2973 virtual void resolveForward(int t) {
2974 int n;
2975 int pc = getPC();
2976 while (t) {
2977 n = *(int *) t; /* next value */
2978 *(int *) t = pc;
2979 t = n;
2980 }
2981 }
2982
Jack Palevich1cdef202009-05-22 12:06:27 -07002983 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002984 size_t pagesize = 4096;
2985 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2986 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2987 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2988 if (err) {
2989 error("mprotect() failed: %d", errno);
2990 }
2991 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002992 }
2993
Jack Palevich9eed7a22009-07-06 17:24:34 -07002994 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002995 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002996 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002997 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002998 switch (pType->tag) {
2999 case TY_CHAR:
3000 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003001 case TY_SHORT:
3002 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003003 case TY_ARRAY:
3004 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003005 case TY_STRUCT:
3006 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003007 case TY_FUNC:
3008 error("alignment of func not supported");
3009 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003010 default:
3011 return 4;
3012 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003013 }
3014
3015 /**
3016 * Array element alignment (in bytes) for this type of data.
3017 */
3018 virtual size_t sizeOf(Type* pType){
3019 switch(pType->tag) {
3020 case TY_INT:
3021 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003022 case TY_SHORT:
3023 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003024 case TY_CHAR:
3025 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003026 case TY_FLOAT:
3027 return 4;
3028 case TY_DOUBLE:
3029 return 8;
3030 case TY_POINTER:
3031 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003032 case TY_ARRAY:
3033 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003034 case TY_STRUCT:
3035 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003036 default:
3037 error("Unsupported type %d", pType->tag);
3038 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003039 }
3040 }
3041
Jack Palevich21a15a22009-05-11 14:49:29 -07003042 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003043
3044 /** Output 1 to 4 bytes.
3045 *
3046 */
3047 void o(int n) {
3048 /* cannot use unsigned, so we must do a hack */
3049 while (n && n != -1) {
3050 ob(n & 0xff);
3051 n = n >> 8;
3052 }
3053 }
3054
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003055 /* Output exactly 2 bytes
3056 */
3057 void o2(int n) {
3058 ob(n & 0xff);
3059 ob(0xff & (n >> 8));
3060 }
3061
Jack Paleviche7b59062009-05-19 17:12:17 -07003062 /* psym is used to put an instruction with a data field which is a
3063 reference to a symbol. It is in fact the same as oad ! */
3064 int psym(int n, int t) {
3065 return oad(n, t);
3066 }
3067
3068 /* instruction + address */
3069 int oad(int n, int t) {
3070 o(n);
3071 int result = getPC();
3072 o4(t);
3073 return result;
3074 }
3075
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003076 static const int operatorHelper[];
3077
3078 int decodeOp(int op) {
3079 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003080 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003081 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003082 }
3083 return operatorHelper[op];
3084 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003085
Jack Palevich546b2242009-05-13 15:10:04 -07003086 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003087 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003088 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003089 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003090
3091 void setupFloatOperands() {
3092 Type* pR0Type = getR0Type();
3093 Type* pTOSType = getTOSType();
3094 TypeTag tagR0 = pR0Type->tag;
3095 TypeTag tagTOS = pTOSType->tag;
3096 bool isFloatR0 = isFloatTag(tagR0);
3097 bool isFloatTOS = isFloatTag(tagTOS);
3098 if (! isFloatR0) {
3099 // Convert R0 from int to float
3100 o(0x50); // push %eax
3101 o(0x2404DB); // fildl 0(%esp)
3102 o(0x58); // pop %eax
3103 }
3104 if (! isFloatTOS){
3105 o(0x2404DB); // fildl 0(%esp);
3106 o(0x58); // pop %eax
3107 } else {
3108 if (tagTOS == TY_FLOAT) {
3109 o(0x2404d9); // flds (%esp)
3110 o(0x58); // pop %eax
3111 } else {
3112 o(0x2404dd); // fldl (%esp)
3113 o(0x58); // pop %eax
3114 o(0x58); // pop %eax
3115 }
3116 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003117 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003118 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003119 };
3120
Jack Paleviche7b59062009-05-19 17:12:17 -07003121#endif // PROVIDE_X86_CODEGEN
3122
Jack Palevichb67b18f2009-06-11 21:12:23 -07003123#ifdef PROVIDE_TRACE_CODEGEN
3124 class TraceCodeGenerator : public CodeGenerator {
3125 private:
3126 CodeGenerator* mpBase;
3127
3128 public:
3129 TraceCodeGenerator(CodeGenerator* pBase) {
3130 mpBase = pBase;
3131 }
3132
3133 virtual ~TraceCodeGenerator() {
3134 delete mpBase;
3135 }
3136
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003137 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003138 mpBase->init(pCodeBuf);
3139 }
3140
3141 void setErrorSink(ErrorSink* pErrorSink) {
3142 mpBase->setErrorSink(pErrorSink);
3143 }
3144
3145 /* returns address to patch with local variable size
3146 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003147 virtual int functionEntry(Type* pDecl) {
3148 int result = mpBase->functionEntry(pDecl);
3149 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003150 return result;
3151 }
3152
Jack Palevichb7718b92009-07-09 22:00:24 -07003153 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3154 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3155 localVariableAddress, localVariableSize);
3156 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003157 }
3158
3159 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003160 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003161 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003162 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003163 }
3164
Jack Palevich1a539db2009-07-08 13:04:41 -07003165 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003166 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003167 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003168 }
3169
Jack Palevich9221bcc2009-08-26 16:15:07 -07003170 virtual void addStructOffsetR0(int offset, Type* pType) {
3171 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3172 mpBase->addStructOffsetR0(offset, pType);
3173 }
3174
Jack Palevichb67b18f2009-06-11 21:12:23 -07003175 virtual int gjmp(int t) {
3176 int result = mpBase->gjmp(t);
3177 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3178 return result;
3179 }
3180
3181 /* l = 0: je, l == 1: jne */
3182 virtual int gtst(bool l, int t) {
3183 int result = mpBase->gtst(l, t);
3184 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3185 return result;
3186 }
3187
Jack Palevich58c30ee2009-07-17 16:35:23 -07003188 virtual void gcmp(int op) {
3189 fprintf(stderr, "gcmp(%d)\n", op);
3190 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003191 }
3192
3193 virtual void genOp(int op) {
3194 fprintf(stderr, "genOp(%d)\n", op);
3195 mpBase->genOp(op);
3196 }
3197
Jack Palevich9eed7a22009-07-06 17:24:34 -07003198
Jack Palevich58c30ee2009-07-17 16:35:23 -07003199 virtual void gUnaryCmp(int op) {
3200 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3201 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003202 }
3203
3204 virtual void genUnaryOp(int op) {
3205 fprintf(stderr, "genUnaryOp(%d)\n", op);
3206 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003207 }
3208
3209 virtual void pushR0() {
3210 fprintf(stderr, "pushR0()\n");
3211 mpBase->pushR0();
3212 }
3213
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003214 virtual void over() {
3215 fprintf(stderr, "over()\n");
3216 mpBase->over();
3217 }
3218
Jack Palevich58c30ee2009-07-17 16:35:23 -07003219 virtual void popR0() {
3220 fprintf(stderr, "popR0()\n");
3221 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003222 }
3223
Jack Palevich58c30ee2009-07-17 16:35:23 -07003224 virtual void storeR0ToTOS() {
3225 fprintf(stderr, "storeR0ToTOS()\n");
3226 mpBase->storeR0ToTOS();
3227 }
3228
3229 virtual void loadR0FromR0() {
3230 fprintf(stderr, "loadR0FromR0()\n");
3231 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003232 }
3233
Jack Palevichb5e33312009-07-30 19:06:34 -07003234 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3235 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3236 pPointerType->pHead->tag, et);
3237 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003238 }
3239
Jack Palevich9f51a262009-07-29 16:22:26 -07003240 virtual int leaForward(int ea, Type* pPointerType) {
3241 fprintf(stderr, "leaForward(%d)\n", ea);
3242 return mpBase->leaForward(ea, pPointerType);
3243 }
3244
Jack Palevich30321cb2009-08-20 15:34:23 -07003245 virtual void convertR0Imp(Type* pType, bool isCast){
3246 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3247 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003248 }
3249
3250 virtual int beginFunctionCallArguments() {
3251 int result = mpBase->beginFunctionCallArguments();
3252 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3253 return result;
3254 }
3255
Jack Palevich8148c5b2009-07-16 18:24:47 -07003256 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3257 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3258 pArgType->tag);
3259 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003260 }
3261
Jack Palevichb7718b92009-07-09 22:00:24 -07003262 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003263 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003264 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003265 }
3266
Jack Palevich8df46192009-07-07 14:48:51 -07003267 virtual int callForward(int symbol, Type* pFunc) {
3268 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003269 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3270 return result;
3271 }
3272
Jack Palevich8df46192009-07-07 14:48:51 -07003273 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003274 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3275 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003276 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003277 }
3278
Jack Palevichb7718b92009-07-09 22:00:24 -07003279 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3280 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3281 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003282 }
3283
3284 virtual int jumpOffset() {
3285 return mpBase->jumpOffset();
3286 }
3287
Jack Palevichb67b18f2009-06-11 21:12:23 -07003288 /* output a symbol and patch all calls to it */
3289 virtual void gsym(int t) {
3290 fprintf(stderr, "gsym(%d)\n", t);
3291 mpBase->gsym(t);
3292 }
3293
Jack Palevich9f51a262009-07-29 16:22:26 -07003294 virtual void resolveForward(int t) {
3295 mpBase->resolveForward(t);
3296 }
3297
Jack Palevichb67b18f2009-06-11 21:12:23 -07003298 virtual int finishCompile() {
3299 int result = mpBase->finishCompile();
3300 fprintf(stderr, "finishCompile() = %d\n", result);
3301 return result;
3302 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003303
3304 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003305 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003306 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003307 virtual size_t alignmentOf(Type* pType){
3308 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003309 }
3310
3311 /**
3312 * Array element alignment (in bytes) for this type of data.
3313 */
3314 virtual size_t sizeOf(Type* pType){
3315 return mpBase->sizeOf(pType);
3316 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003317
3318 virtual Type* getR0Type() {
3319 return mpBase->getR0Type();
3320 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003321
3322 virtual ExpressionType getR0ExpressionType() {
3323 return mpBase->getR0ExpressionType();
3324 }
3325
3326 virtual void setR0ExpressionType(ExpressionType et) {
3327 mpBase->setR0ExpressionType(et);
3328 }
3329
3330 virtual size_t getExpressionStackDepth() {
3331 return mpBase->getExpressionStackDepth();
3332 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003333
3334 virtual void forceR0RVal() {
3335 return mpBase->forceR0RVal();
3336 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003337 };
3338
3339#endif // PROVIDE_TRACE_CODEGEN
3340
Jack Palevich569f1352009-06-29 14:29:08 -07003341 class Arena {
3342 public:
3343 // Used to record a given allocation amount.
3344 // Used:
3345 // Mark mark = arena.mark();
3346 // ... lots of arena.allocate()
3347 // arena.free(mark);
3348
3349 struct Mark {
3350 size_t chunk;
3351 size_t offset;
3352 };
3353
3354 Arena() {
3355 mCurrentChunk = 0;
3356 Chunk start(CHUNK_SIZE);
3357 mData.push_back(start);
3358 }
3359
3360 ~Arena() {
3361 for(size_t i = 0; i < mData.size(); i++) {
3362 mData[i].free();
3363 }
3364 }
3365
3366 // Alloc using the standard alignment size safe for any variable
3367 void* alloc(size_t size) {
3368 return alloc(size, 8);
3369 }
3370
3371 Mark mark(){
3372 Mark result;
3373 result.chunk = mCurrentChunk;
3374 result.offset = mData[mCurrentChunk].mOffset;
3375 return result;
3376 }
3377
3378 void freeToMark(const Mark& mark) {
3379 mCurrentChunk = mark.chunk;
3380 mData[mCurrentChunk].mOffset = mark.offset;
3381 }
3382
3383 private:
3384 // Allocate memory aligned to a given size
3385 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3386 // Memory is not zero filled.
3387
3388 void* alloc(size_t size, size_t alignment) {
3389 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3390 if (mCurrentChunk + 1 < mData.size()) {
3391 mCurrentChunk++;
3392 } else {
3393 size_t allocSize = CHUNK_SIZE;
3394 if (allocSize < size + alignment - 1) {
3395 allocSize = size + alignment - 1;
3396 }
3397 Chunk chunk(allocSize);
3398 mData.push_back(chunk);
3399 mCurrentChunk++;
3400 }
3401 }
3402 return mData[mCurrentChunk].allocate(size, alignment);
3403 }
3404
3405 static const size_t CHUNK_SIZE = 128*1024;
3406 // Note: this class does not deallocate its
3407 // memory when it's destroyed. It depends upon
3408 // its parent to deallocate the memory.
3409 struct Chunk {
3410 Chunk() {
3411 mpData = 0;
3412 mSize = 0;
3413 mOffset = 0;
3414 }
3415
3416 Chunk(size_t size) {
3417 mSize = size;
3418 mpData = (char*) malloc(size);
3419 mOffset = 0;
3420 }
3421
3422 ~Chunk() {
3423 // Doesn't deallocate memory.
3424 }
3425
3426 void* allocate(size_t size, size_t alignment) {
3427 size_t alignedOffset = aligned(mOffset, alignment);
3428 void* result = mpData + alignedOffset;
3429 mOffset = alignedOffset + size;
3430 return result;
3431 }
3432
3433 void free() {
3434 if (mpData) {
3435 ::free(mpData);
3436 mpData = 0;
3437 }
3438 }
3439
3440 size_t remainingCapacity(size_t alignment) {
3441 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3442 }
3443
3444 // Assume alignment is a power of two
3445 inline size_t aligned(size_t v, size_t alignment) {
3446 size_t mask = alignment-1;
3447 return (v + mask) & ~mask;
3448 }
3449
3450 char* mpData;
3451 size_t mSize;
3452 size_t mOffset;
3453 };
3454
3455 size_t mCurrentChunk;
3456
3457 Vector<Chunk> mData;
3458 };
3459
Jack Palevich569f1352009-06-29 14:29:08 -07003460 struct VariableInfo;
3461
3462 struct Token {
3463 int hash;
3464 size_t length;
3465 char* pText;
3466 tokenid_t id;
3467
3468 // Current values for the token
3469 char* mpMacroDefinition;
3470 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003471 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003472 };
3473
3474 class TokenTable {
3475 public:
3476 // Don't use 0..0xff, allows characters and operators to be tokens too.
3477
3478 static const int TOKEN_BASE = 0x100;
3479 TokenTable() {
3480 mpMap = hashmapCreate(128, hashFn, equalsFn);
3481 }
3482
3483 ~TokenTable() {
3484 hashmapFree(mpMap);
3485 }
3486
3487 void setArena(Arena* pArena) {
3488 mpArena = pArena;
3489 }
3490
3491 // Returns a token for a given string of characters.
3492 tokenid_t intern(const char* pText, size_t length) {
3493 Token probe;
3494 int hash = hashmapHash((void*) pText, length);
3495 {
3496 Token probe;
3497 probe.hash = hash;
3498 probe.length = length;
3499 probe.pText = (char*) pText;
3500 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3501 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003502 return pValue->id;
3503 }
3504 }
3505
3506 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3507 memset(pToken, 0, sizeof(*pToken));
3508 pToken->hash = hash;
3509 pToken->length = length;
3510 pToken->pText = (char*) mpArena->alloc(length + 1);
3511 memcpy(pToken->pText, pText, length);
3512 pToken->pText[length] = 0;
3513 pToken->id = mTokens.size() + TOKEN_BASE;
3514 mTokens.push_back(pToken);
3515 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003516 return pToken->id;
3517 }
3518
3519 // Return the Token for a given tokenid.
3520 Token& operator[](tokenid_t id) {
3521 return *mTokens[id - TOKEN_BASE];
3522 }
3523
3524 inline size_t size() {
3525 return mTokens.size();
3526 }
3527
3528 private:
3529
3530 static int hashFn(void* pKey) {
3531 Token* pToken = (Token*) pKey;
3532 return pToken->hash;
3533 }
3534
3535 static bool equalsFn(void* keyA, void* keyB) {
3536 Token* pTokenA = (Token*) keyA;
3537 Token* pTokenB = (Token*) keyB;
3538 // Don't need to compare hash values, they should always be equal
3539 return pTokenA->length == pTokenB->length
3540 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3541 }
3542
3543 Hashmap* mpMap;
3544 Vector<Token*> mTokens;
3545 Arena* mpArena;
3546 };
3547
Jack Palevich1cdef202009-05-22 12:06:27 -07003548 class InputStream {
3549 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003550 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003551 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003552 };
3553
3554 class TextInputStream : public InputStream {
3555 public:
3556 TextInputStream(const char* text, size_t textLength)
3557 : pText(text), mTextLength(textLength), mPosition(0) {
3558 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003559
Jack Palevichdc456462009-07-16 16:50:56 -07003560 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003561 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3562 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003563
Jack Palevichdc456462009-07-16 16:50:56 -07003564 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003565 const char* pText;
3566 size_t mTextLength;
3567 size_t mPosition;
3568 };
3569
Jack Palevicheedf9d22009-06-04 16:23:40 -07003570 class String {
3571 public:
3572 String() {
3573 mpBase = 0;
3574 mUsed = 0;
3575 mSize = 0;
3576 }
3577
Jack Palevich303d8ff2009-06-11 19:06:24 -07003578 String(const char* item, int len, bool adopt) {
3579 if (len < 0) {
3580 len = strlen(item);
3581 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003582 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003583 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003584 mUsed = len;
3585 mSize = len + 1;
3586 } else {
3587 mpBase = 0;
3588 mUsed = 0;
3589 mSize = 0;
3590 appendBytes(item, len);
3591 }
3592 }
3593
Jack Palevich303d8ff2009-06-11 19:06:24 -07003594 String(const String& other) {
3595 mpBase = 0;
3596 mUsed = 0;
3597 mSize = 0;
3598 appendBytes(other.getUnwrapped(), other.len());
3599 }
3600
Jack Palevicheedf9d22009-06-04 16:23:40 -07003601 ~String() {
3602 if (mpBase) {
3603 free(mpBase);
3604 }
3605 }
3606
Jack Palevicha6baa232009-06-12 11:25:59 -07003607 String& operator=(const String& other) {
3608 clear();
3609 appendBytes(other.getUnwrapped(), other.len());
3610 return *this;
3611 }
3612
Jack Palevich303d8ff2009-06-11 19:06:24 -07003613 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003614 return mpBase;
3615 }
3616
Jack Palevich303d8ff2009-06-11 19:06:24 -07003617 void clear() {
3618 mUsed = 0;
3619 if (mSize > 0) {
3620 mpBase[0] = 0;
3621 }
3622 }
3623
Jack Palevicheedf9d22009-06-04 16:23:40 -07003624 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003625 appendBytes(s, strlen(s));
3626 }
3627
3628 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003629 memcpy(ensure(n), s, n + 1);
3630 }
3631
3632 void append(char c) {
3633 * ensure(1) = c;
3634 }
3635
Jack Palevich86351982009-06-30 18:09:56 -07003636 void append(String& other) {
3637 appendBytes(other.getUnwrapped(), other.len());
3638 }
3639
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003640 char* orphan() {
3641 char* result = mpBase;
3642 mpBase = 0;
3643 mUsed = 0;
3644 mSize = 0;
3645 return result;
3646 }
3647
Jack Palevicheedf9d22009-06-04 16:23:40 -07003648 void printf(const char* fmt,...) {
3649 va_list ap;
3650 va_start(ap, fmt);
3651 vprintf(fmt, ap);
3652 va_end(ap);
3653 }
3654
3655 void vprintf(const char* fmt, va_list ap) {
3656 char* temp;
3657 int numChars = vasprintf(&temp, fmt, ap);
3658 memcpy(ensure(numChars), temp, numChars+1);
3659 free(temp);
3660 }
3661
Jack Palevich303d8ff2009-06-11 19:06:24 -07003662 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003663 return mUsed;
3664 }
3665
3666 private:
3667 char* ensure(int n) {
3668 size_t newUsed = mUsed + n;
3669 if (newUsed > mSize) {
3670 size_t newSize = mSize * 2 + 10;
3671 if (newSize < newUsed) {
3672 newSize = newUsed;
3673 }
3674 mpBase = (char*) realloc(mpBase, newSize + 1);
3675 mSize = newSize;
3676 }
3677 mpBase[newUsed] = '\0';
3678 char* result = mpBase + mUsed;
3679 mUsed = newUsed;
3680 return result;
3681 }
3682
3683 char* mpBase;
3684 size_t mUsed;
3685 size_t mSize;
3686 };
3687
Jack Palevich569f1352009-06-29 14:29:08 -07003688 void internKeywords() {
3689 // Note: order has to match TOK_ constants
3690 static const char* keywords[] = {
3691 "int",
3692 "char",
3693 "void",
3694 "if",
3695 "else",
3696 "while",
3697 "break",
3698 "return",
3699 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003700 "auto",
3701 "case",
3702 "const",
3703 "continue",
3704 "default",
3705 "do",
3706 "double",
3707 "enum",
3708 "extern",
3709 "float",
3710 "goto",
3711 "long",
3712 "register",
3713 "short",
3714 "signed",
3715 "sizeof",
3716 "static",
3717 "struct",
3718 "switch",
3719 "typedef",
3720 "union",
3721 "unsigned",
3722 "volatile",
3723 "_Bool",
3724 "_Complex",
3725 "_Imaginary",
3726 "inline",
3727 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003728
3729 // predefined tokens that can also be symbols start here:
3730 "pragma",
3731 "define",
3732 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003733 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003734
Jack Palevich569f1352009-06-29 14:29:08 -07003735 for(int i = 0; keywords[i]; i++) {
3736 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003737 }
Jack Palevich569f1352009-06-29 14:29:08 -07003738 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003739
Jack Palevich36d94142009-06-08 15:55:32 -07003740 struct InputState {
3741 InputStream* pStream;
3742 int oldCh;
3743 };
3744
Jack Palevich2db168f2009-06-11 14:29:47 -07003745 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003746 void* pAddress;
3747 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003748 tokenid_t tok;
3749 size_t level;
3750 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003751 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003752 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003753 };
3754
Jack Palevich303d8ff2009-06-11 19:06:24 -07003755 class SymbolStack {
3756 public:
3757 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003758 mpArena = 0;
3759 mpTokenTable = 0;
3760 }
3761
3762 void setArena(Arena* pArena) {
3763 mpArena = pArena;
3764 }
3765
3766 void setTokenTable(TokenTable* pTokenTable) {
3767 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003768 }
3769
3770 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003771 Mark mark;
3772 mark.mArenaMark = mpArena->mark();
3773 mark.mSymbolHead = mStack.size();
3774 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003775 }
3776
3777 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003778 // Undo any shadowing that was done:
3779 Mark mark = mLevelStack.back();
3780 mLevelStack.pop_back();
3781 while (mStack.size() > mark.mSymbolHead) {
3782 VariableInfo* pV = mStack.back();
3783 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003784 if (pV->isStructTag) {
3785 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3786 } else {
3787 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3788 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003789 }
Jack Palevich569f1352009-06-29 14:29:08 -07003790 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003791 }
3792
Jack Palevich569f1352009-06-29 14:29:08 -07003793 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3794 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3795 return pV && pV->level == level();
3796 }
3797
Jack Palevich9221bcc2009-08-26 16:15:07 -07003798 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3799 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3800 return pV && pV->level == level();
3801 }
3802
Jack Palevich569f1352009-06-29 14:29:08 -07003803 VariableInfo* add(tokenid_t tok) {
3804 Token& token = (*mpTokenTable)[tok];
3805 VariableInfo* pOldV = token.mpVariableInfo;
3806 VariableInfo* pNewV =
3807 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3808 memset(pNewV, 0, sizeof(VariableInfo));
3809 pNewV->tok = tok;
3810 pNewV->level = level();
3811 pNewV->pOldDefinition = pOldV;
3812 token.mpVariableInfo = pNewV;
3813 mStack.push_back(pNewV);
3814 return pNewV;
3815 }
3816
Jack Palevich9221bcc2009-08-26 16:15:07 -07003817 VariableInfo* addStructTag(tokenid_t tok) {
3818 Token& token = (*mpTokenTable)[tok];
3819 VariableInfo* pOldS = token.mpStructInfo;
3820 VariableInfo* pNewS =
3821 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3822 memset(pNewS, 0, sizeof(VariableInfo));
3823 pNewS->tok = tok;
3824 pNewS->level = level();
3825 pNewS->isStructTag = true;
3826 pNewS->pOldDefinition = pOldS;
3827 token.mpStructInfo = pNewS;
3828 mStack.push_back(pNewS);
3829 return pNewS;
3830 }
3831
Jack Palevich86351982009-06-30 18:09:56 -07003832 VariableInfo* add(Type* pType) {
3833 VariableInfo* pVI = add(pType->id);
3834 pVI->pType = pType;
3835 return pVI;
3836 }
3837
Jack Palevich569f1352009-06-29 14:29:08 -07003838 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3839 for (size_t i = 0; i < mStack.size(); i++) {
3840 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003841 break;
3842 }
3843 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003844 }
3845
Jack Palevich303d8ff2009-06-11 19:06:24 -07003846 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003847 inline size_t level() {
3848 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003849 }
3850
Jack Palevich569f1352009-06-29 14:29:08 -07003851 struct Mark {
3852 Arena::Mark mArenaMark;
3853 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003854 };
3855
Jack Palevich569f1352009-06-29 14:29:08 -07003856 Arena* mpArena;
3857 TokenTable* mpTokenTable;
3858 Vector<VariableInfo*> mStack;
3859 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003860 };
Jack Palevich36d94142009-06-08 15:55:32 -07003861
3862 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003863 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003864 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003865 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003866 int tokl; // token operator level
3867 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003868 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003869 intptr_t loc; // local variable index
3870 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003871 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003872 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003873 char* dptr; // Macro state: Points to macro text during macro playback.
3874 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003875 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003876 ACCSymbolLookupFn mpSymbolLookupFn;
3877 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003878
3879 // Arena for the duration of the compile
3880 Arena mGlobalArena;
3881 // Arena for data that's only needed when compiling a single function
3882 Arena mLocalArena;
3883
Jack Palevich2ff5c222009-07-23 15:11:22 -07003884 Arena* mpCurrentArena;
3885
Jack Palevich569f1352009-06-29 14:29:08 -07003886 TokenTable mTokenTable;
3887 SymbolStack mGlobals;
3888 SymbolStack mLocals;
3889
Jack Palevich9221bcc2009-08-26 16:15:07 -07003890 SymbolStack* mpCurrentSymbolStack;
3891
Jack Palevich40600de2009-07-01 15:32:35 -07003892 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003893 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003894 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003895 Type* mkpChar; // char
3896 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003897 Type* mkpFloat;
3898 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003899 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003900 Type* mkpIntPtr;
3901 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003902 Type* mkpFloatPtr;
3903 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003904 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003905
Jack Palevich36d94142009-06-08 15:55:32 -07003906 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003907 int mLineNumber;
3908 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003909
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003910 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003911 CodeGenerator* pGen;
3912
Jack Palevicheedf9d22009-06-04 16:23:40 -07003913 String mErrorBuf;
3914
Jack Palevicheedf9d22009-06-04 16:23:40 -07003915 String mPragmas;
3916 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003917 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003918
Jack Palevich21a15a22009-05-11 14:49:29 -07003919 static const int ALLOC_SIZE = 99999;
3920
Jack Palevich303d8ff2009-06-11 19:06:24 -07003921 static const int TOK_DUMMY = 1;
3922 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003923 static const int TOK_NUM_FLOAT = 3;
3924 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003925 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003926 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003927
3928 // 3..255 are character and/or operators
3929
Jack Palevich2db168f2009-06-11 14:29:47 -07003930 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003931 // Order has to match string list in "internKeywords".
3932 enum {
3933 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3934 TOK_INT = TOK_KEYWORD,
3935 TOK_CHAR,
3936 TOK_VOID,
3937 TOK_IF,
3938 TOK_ELSE,
3939 TOK_WHILE,
3940 TOK_BREAK,
3941 TOK_RETURN,
3942 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003943 TOK_AUTO,
3944 TOK_CASE,
3945 TOK_CONST,
3946 TOK_CONTINUE,
3947 TOK_DEFAULT,
3948 TOK_DO,
3949 TOK_DOUBLE,
3950 TOK_ENUM,
3951 TOK_EXTERN,
3952 TOK_FLOAT,
3953 TOK_GOTO,
3954 TOK_LONG,
3955 TOK_REGISTER,
3956 TOK_SHORT,
3957 TOK_SIGNED,
3958 TOK_SIZEOF,
3959 TOK_STATIC,
3960 TOK_STRUCT,
3961 TOK_SWITCH,
3962 TOK_TYPEDEF,
3963 TOK_UNION,
3964 TOK_UNSIGNED,
3965 TOK_VOLATILE,
3966 TOK__BOOL,
3967 TOK__COMPLEX,
3968 TOK__IMAGINARY,
3969 TOK_INLINE,
3970 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003971
3972 // Symbols start after keywords
3973
3974 TOK_SYMBOL,
3975 TOK_PRAGMA = TOK_SYMBOL,
3976 TOK_DEFINE,
3977 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003978 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003979
3980 static const int LOCAL = 0x200;
3981
3982 static const int SYM_FORWARD = 0;
3983 static const int SYM_DEFINE = 1;
3984
3985 /* tokens in string heap */
3986 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003987
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003988 static const int OP_INCREMENT = 0;
3989 static const int OP_DECREMENT = 1;
3990 static const int OP_MUL = 2;
3991 static const int OP_DIV = 3;
3992 static const int OP_MOD = 4;
3993 static const int OP_PLUS = 5;
3994 static const int OP_MINUS = 6;
3995 static const int OP_SHIFT_LEFT = 7;
3996 static const int OP_SHIFT_RIGHT = 8;
3997 static const int OP_LESS_EQUAL = 9;
3998 static const int OP_GREATER_EQUAL = 10;
3999 static const int OP_LESS = 11;
4000 static const int OP_GREATER = 12;
4001 static const int OP_EQUALS = 13;
4002 static const int OP_NOT_EQUALS = 14;
4003 static const int OP_LOGICAL_AND = 15;
4004 static const int OP_LOGICAL_OR = 16;
4005 static const int OP_BIT_AND = 17;
4006 static const int OP_BIT_XOR = 18;
4007 static const int OP_BIT_OR = 19;
4008 static const int OP_BIT_NOT = 20;
4009 static const int OP_LOGICAL_NOT = 21;
4010 static const int OP_COUNT = 22;
4011
4012 /* Operators are searched from front, the two-character operators appear
4013 * before the single-character operators with the same first character.
4014 * @ is used to pad out single-character operators.
4015 */
4016 static const char* operatorChars;
4017 static const char operatorLevel[];
4018
Jack Palevich569f1352009-06-29 14:29:08 -07004019 /* Called when we detect an internal problem. Does nothing in production.
4020 *
4021 */
4022 void internalError() {
4023 * (char*) 0 = 0;
4024 }
4025
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004026 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004027 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004028 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004029 internalError();
4030 }
Jack Palevich86351982009-06-30 18:09:56 -07004031 }
4032
Jack Palevich40600de2009-07-01 15:32:35 -07004033 bool isSymbol(tokenid_t t) {
4034 return t >= TOK_SYMBOL &&
4035 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4036 }
4037
4038 bool isSymbolOrKeyword(tokenid_t t) {
4039 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004040 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004041 }
4042
Jack Palevich86351982009-06-30 18:09:56 -07004043 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004044 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004045 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4046 if (pV && pV->tok != t) {
4047 internalError();
4048 }
4049 return pV;
4050 }
4051
4052 inline bool isDefined(tokenid_t t) {
4053 return t >= TOK_SYMBOL && VI(t) != 0;
4054 }
4055
Jack Palevich40600de2009-07-01 15:32:35 -07004056 const char* nameof(tokenid_t t) {
4057 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004058 return mTokenTable[t].pText;
4059 }
4060
Jack Palevich21a15a22009-05-11 14:49:29 -07004061 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004062 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004063 }
4064
4065 void inp() {
4066 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07004067 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004068 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004069 dptr = 0;
4070 ch = dch;
4071 }
Jack Palevichdc456462009-07-16 16:50:56 -07004072 } else {
4073 if (mbBumpLine) {
4074 mLineNumber++;
4075 mbBumpLine = false;
4076 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004077 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004078 if (ch == '\n') {
4079 mbBumpLine = true;
4080 }
4081 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004082#if 0
4083 printf("ch='%c' 0x%x\n", ch, ch);
4084#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004085 }
4086
4087 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004088 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004089 }
4090
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004091 int decodeHex(int c) {
4092 if (isdigit(c)) {
4093 c -= '0';
4094 } else if (c <= 'F') {
4095 c = c - 'A' + 10;
4096 } else {
4097 c =c - 'a' + 10;
4098 }
4099 return c;
4100 }
4101
Jack Palevichb4758ff2009-06-12 12:49:14 -07004102 /* read a character constant, advances ch to after end of constant */
4103 int getq() {
4104 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004105 if (ch == '\\') {
4106 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004107 if (isoctal(ch)) {
4108 // 1 to 3 octal characters.
4109 val = 0;
4110 for(int i = 0; i < 3; i++) {
4111 if (isoctal(ch)) {
4112 val = (val << 3) + ch - '0';
4113 inp();
4114 }
4115 }
4116 return val;
4117 } else if (ch == 'x' || ch == 'X') {
4118 // N hex chars
4119 inp();
4120 if (! isxdigit(ch)) {
4121 error("'x' character escape requires at least one digit.");
4122 } else {
4123 val = 0;
4124 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004125 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004126 inp();
4127 }
4128 }
4129 } else {
4130 int val = ch;
4131 switch (ch) {
4132 case 'a':
4133 val = '\a';
4134 break;
4135 case 'b':
4136 val = '\b';
4137 break;
4138 case 'f':
4139 val = '\f';
4140 break;
4141 case 'n':
4142 val = '\n';
4143 break;
4144 case 'r':
4145 val = '\r';
4146 break;
4147 case 't':
4148 val = '\t';
4149 break;
4150 case 'v':
4151 val = '\v';
4152 break;
4153 case '\\':
4154 val = '\\';
4155 break;
4156 case '\'':
4157 val = '\'';
4158 break;
4159 case '"':
4160 val = '"';
4161 break;
4162 case '?':
4163 val = '?';
4164 break;
4165 default:
4166 error("Undefined character escape %c", ch);
4167 break;
4168 }
4169 inp();
4170 return val;
4171 }
4172 } else {
4173 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004174 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004175 return val;
4176 }
4177
4178 static bool isoctal(int ch) {
4179 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004180 }
4181
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004182 bool acceptCh(int c) {
4183 bool result = c == ch;
4184 if (result) {
4185 pdef(ch);
4186 inp();
4187 }
4188 return result;
4189 }
4190
4191 bool acceptDigitsCh() {
4192 bool result = false;
4193 while (isdigit(ch)) {
4194 result = true;
4195 pdef(ch);
4196 inp();
4197 }
4198 return result;
4199 }
4200
4201 void parseFloat() {
4202 tok = TOK_NUM_DOUBLE;
4203 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004204 if(mTokenString.len() == 0) {
4205 mTokenString.append('0');
4206 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004207 acceptCh('.');
4208 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004209 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004210 acceptCh('-') || acceptCh('+');
4211 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004212 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004213 if (ch == 'f' || ch == 'F') {
4214 tok = TOK_NUM_FLOAT;
4215 inp();
4216 } else if (ch == 'l' || ch == 'L') {
4217 inp();
4218 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004219 }
4220 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004221 char* pEnd = pText + strlen(pText);
4222 char* pEndPtr = 0;
4223 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004224 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004225 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004226 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004227 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004228 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004229 if (errno || pEndPtr != pEnd) {
4230 error("Can't parse constant: %s", pText);
4231 }
4232 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004233 }
4234
Jack Palevich21a15a22009-05-11 14:49:29 -07004235 void next() {
4236 int l, a;
4237
Jack Palevich546b2242009-05-13 15:10:04 -07004238 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004239 if (ch == '#') {
4240 inp();
4241 next();
4242 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004243 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004244 } else if (tok == TOK_PRAGMA) {
4245 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004246 } else if (tok == TOK_LINE) {
4247 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004248 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004249 error("Unsupported preprocessor directive \"%s\"",
4250 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004251 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004252 }
4253 inp();
4254 }
4255 tokl = 0;
4256 tok = ch;
4257 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004258 if (isdigit(ch) || ch == '.') {
4259 // Start of a numeric constant. Could be integer, float, or
4260 // double, won't know until we look further.
4261 mTokenString.clear();
4262 pdef(ch);
4263 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004264 if (tok == '.' && !isdigit(ch)) {
4265 goto done;
4266 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004267 int base = 10;
4268 if (tok == '0') {
4269 if (ch == 'x' || ch == 'X') {
4270 base = 16;
4271 tok = TOK_NUM;
4272 tokc = 0;
4273 inp();
4274 while ( isxdigit(ch) ) {
4275 tokc = (tokc << 4) + decodeHex(ch);
4276 inp();
4277 }
4278 } else if (isoctal(ch)){
4279 base = 8;
4280 tok = TOK_NUM;
4281 tokc = 0;
4282 while ( isoctal(ch) ) {
4283 tokc = (tokc << 3) + (ch - '0');
4284 inp();
4285 }
4286 }
4287 } else if (isdigit(tok)){
4288 acceptDigitsCh();
4289 }
4290 if (base == 10) {
4291 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4292 parseFloat();
4293 } else {
4294 // It's an integer constant
4295 char* pText = mTokenString.getUnwrapped();
4296 char* pEnd = pText + strlen(pText);
4297 char* pEndPtr = 0;
4298 errno = 0;
4299 tokc = strtol(pText, &pEndPtr, base);
4300 if (errno || pEndPtr != pEnd) {
4301 error("Can't parse constant: %s %d %d", pText, base, errno);
4302 }
4303 tok = TOK_NUM;
4304 }
4305 }
4306 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004307 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004308 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004309 pdef(ch);
4310 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004311 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004312 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004313 if (! mbSuppressMacroExpansion) {
4314 // Is this a macro?
4315 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4316 if (pMacroDefinition) {
4317 // Yes, it is a macro
4318 dptr = pMacroDefinition;
4319 dch = ch;
4320 inp();
4321 next();
4322 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004323 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004324 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004325 inp();
4326 if (tok == '\'') {
4327 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004328 tokc = getq();
4329 if (ch != '\'') {
4330 error("Expected a ' character, got %c", ch);
4331 } else {
4332 inp();
4333 }
Jack Palevich546b2242009-05-13 15:10:04 -07004334 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004335 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004336 while (ch && ch != EOF) {
4337 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004338 inp();
4339 inp();
4340 if (ch == '/')
4341 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004342 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004343 if (ch == EOF) {
4344 error("End of file inside comment.");
4345 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004346 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004347 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004348 } else if ((tok == '/') & (ch == '/')) {
4349 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004350 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004351 inp();
4352 }
4353 inp();
4354 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004355 } else if ((tok == '-') & (ch == '>')) {
4356 inp();
4357 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004358 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004359 const char* t = operatorChars;
4360 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004361 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004362 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004363 tokl = operatorLevel[opIndex];
4364 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004365 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004366#if 0
4367 printf("%c%c -> tokl=%d tokc=0x%x\n",
4368 l, a, tokl, tokc);
4369#endif
4370 if (a == ch) {
4371 inp();
4372 tok = TOK_DUMMY; /* dummy token for double tokens */
4373 }
Jack Palevich0c017742009-07-31 12:00:39 -07004374 /* check for op=, valid for * / % + - << >> & ^ | */
4375 if (ch == '=' &&
4376 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004377 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004378 inp();
4379 tok = TOK_OP_ASSIGNMENT;
4380 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004381 break;
4382 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004383 opIndex++;
4384 }
4385 if (l == 0) {
4386 tokl = 0;
4387 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004388 }
4389 }
4390 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004391
4392 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004393#if 0
4394 {
Jack Palevich569f1352009-06-29 14:29:08 -07004395 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004396 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004397 fprintf(stderr, "%s\n", buf.getUnwrapped());
4398 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004399#endif
4400 }
4401
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004402 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004403 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004404 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004405 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004406 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004407 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004408 if (ch == '(') {
4409 delete pName;
4410 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004411 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004412 }
4413 while (isspace(ch)) {
4414 inp();
4415 }
Jack Palevich569f1352009-06-29 14:29:08 -07004416 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004417 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004418 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004419 // Check for '//' comments.
4420 if (appendToValue && ch == '/') {
4421 inp();
4422 if (ch == '/') {
4423 appendToValue = false;
4424 } else {
4425 value.append('/');
4426 }
4427 }
4428 if (appendToValue && ch != EOF) {
4429 value.append(ch);
4430 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004431 inp();
4432 }
Jack Palevich569f1352009-06-29 14:29:08 -07004433 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4434 memcpy(pDefn, value.getUnwrapped(), value.len());
4435 pDefn[value.len()] = 0;
4436 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004437 }
4438
Jack Palevicheedf9d22009-06-04 16:23:40 -07004439 void doPragma() {
4440 // # pragma name(val)
4441 int state = 0;
4442 while(ch != EOF && ch != '\n' && state < 10) {
4443 switch(state) {
4444 case 0:
4445 if (isspace(ch)) {
4446 inp();
4447 } else {
4448 state++;
4449 }
4450 break;
4451 case 1:
4452 if (isalnum(ch)) {
4453 mPragmas.append(ch);
4454 inp();
4455 } else if (ch == '(') {
4456 mPragmas.append(0);
4457 inp();
4458 state++;
4459 } else {
4460 state = 11;
4461 }
4462 break;
4463 case 2:
4464 if (isalnum(ch)) {
4465 mPragmas.append(ch);
4466 inp();
4467 } else if (ch == ')') {
4468 mPragmas.append(0);
4469 inp();
4470 state = 10;
4471 } else {
4472 state = 11;
4473 }
4474 break;
4475 }
4476 }
4477 if(state != 10) {
4478 error("Unexpected pragma syntax");
4479 }
4480 mPragmaStringCount += 2;
4481 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004482
Jack Palevichdc456462009-07-16 16:50:56 -07004483 void doLine() {
4484 // # line number { "filename "}
4485 next();
4486 if (tok != TOK_NUM) {
4487 error("Expected a line-number");
4488 } else {
4489 mLineNumber = tokc-1; // The end-of-line will increment it.
4490 }
4491 while(ch != EOF && ch != '\n') {
4492 inp();
4493 }
4494 }
4495
Jack Palevichac0e95e2009-05-29 13:53:44 -07004496 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004497 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004498 mErrorBuf.vprintf(fmt, ap);
4499 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004500 }
4501
Jack Palevich8b0624c2009-05-20 12:12:06 -07004502 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004503 if (tok != c) {
4504 error("'%c' expected", c);
4505 }
4506 next();
4507 }
4508
Jack Palevich86351982009-06-30 18:09:56 -07004509 bool accept(intptr_t c) {
4510 if (tok == c) {
4511 next();
4512 return true;
4513 }
4514 return false;
4515 }
4516
Jack Palevich40600de2009-07-01 15:32:35 -07004517 bool acceptStringLiteral() {
4518 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004519 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004520 // This while loop merges multiple adjacent string constants.
4521 while (tok == '"') {
4522 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004523 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004524 }
4525 if (ch != '"') {
4526 error("Unterminated string constant.");
4527 }
4528 inp();
4529 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004530 }
Jack Palevich40600de2009-07-01 15:32:35 -07004531 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004532 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004533 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004534 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004535
4536 return true;
4537 }
4538 return false;
4539 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004540
Jack Palevichb1544ca2009-07-16 15:09:20 -07004541 void linkGlobal(tokenid_t t, bool isFunction) {
4542 VariableInfo* pVI = VI(t);
4543 void* n = NULL;
4544 if (mpSymbolLookupFn) {
4545 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4546 }
4547 if (pVI->pType == NULL) {
4548 if (isFunction) {
4549 pVI->pType = mkpIntFn;
4550 } else {
4551 pVI->pType = mkpInt;
4552 }
4553 }
4554 pVI->pAddress = n;
4555 }
4556
Jack Palevich29daf572009-07-30 19:38:55 -07004557 void unaryOrAssignment() {
4558 unary();
4559 if (accept('=')) {
4560 checkLVal();
4561 pGen->pushR0();
4562 expr();
4563 pGen->forceR0RVal();
4564 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004565 } else if (tok == TOK_OP_ASSIGNMENT) {
4566 int t = tokc;
4567 next();
4568 checkLVal();
4569 pGen->pushR0();
4570 pGen->forceR0RVal();
4571 pGen->pushR0();
4572 expr();
4573 pGen->forceR0RVal();
4574 pGen->genOp(t);
4575 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004576 }
4577 }
4578
Jack Palevich40600de2009-07-01 15:32:35 -07004579 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004580 */
Jack Palevich29daf572009-07-30 19:38:55 -07004581 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004582 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004583 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004584 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004585 if (acceptStringLiteral()) {
4586 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004587 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004588 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004589 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004590 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004591 t = tok;
4592 next();
4593 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004594 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004595 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004596 // Align to 4-byte boundary
4597 glo = (char*) (((intptr_t) glo + 3) & -4);
4598 * (float*) glo = (float) ad;
4599 pGen->loadFloat((int) glo, mkpFloat);
4600 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004601 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004602 // Align to 8-byte boundary
4603 glo = (char*) (((intptr_t) glo + 7) & -8);
4604 * (double*) glo = ad;
4605 pGen->loadFloat((int) glo, mkpDouble);
4606 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004607 } else if (c == 2) {
4608 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004609 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004610 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004611 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004612 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004613 else if (t == '+') {
4614 // ignore unary plus.
4615 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004616 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004617 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004618 } else if (c == 11) {
4619 // pre increment / pre decrement
4620 unary();
4621 doIncDec(a == OP_INCREMENT, 0);
4622 }
4623 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004624 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004625 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004626 if (pCast) {
4627 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004628 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004629 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004630 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004631 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004632 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004633 skip(')');
4634 }
4635 } else if (t == '*') {
4636 /* This is a pointer dereference.
4637 */
Jack Palevich29daf572009-07-30 19:38:55 -07004638 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004639 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004640 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004641 unary();
4642 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004643 } else if (t == EOF ) {
4644 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004645 } else if (t == ';') {
4646 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004647 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004648 // Don't have to do anything special here, the error
4649 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004650 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004651 if (!isDefined(t)) {
4652 mGlobals.add(t);
4653 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004654 }
Jack Palevich8df46192009-07-07 14:48:51 -07004655 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004656 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004657 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004658 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004659 linkGlobal(t, tok == '(');
4660 n = (intptr_t) pVI->pAddress;
4661 if (!n && tok != '(') {
4662 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004663 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004664 }
Jack Palevich29daf572009-07-30 19:38:55 -07004665 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004666 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004667 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004668 linkGlobal(t, false);
4669 n = (intptr_t) pVI->pAddress;
4670 if (!n) {
4671 error("Undeclared variable %s\n", nameof(t));
4672 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004673 }
Jack Palevich5b659092009-07-31 14:55:07 -07004674 }
4675 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004676 Type* pVal;
4677 ExpressionType et;
4678 if (pVI->pType->tag == TY_ARRAY) {
4679 pVal = pVI->pType;
4680 et = ET_RVALUE;
4681 } else {
4682 pVal = createPtrType(pVI->pType);
4683 et = ET_LVALUE;
4684 }
Jack Palevich5b659092009-07-31 14:55:07 -07004685 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004686 int tag = pVal->pHead->tag;
4687 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004688 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004689 }
Jack Palevich5b659092009-07-31 14:55:07 -07004690 pGen->leaR0(n, pVal, et);
4691 } else {
4692 pVI->pForward = (void*) pGen->leaForward(
4693 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004694 }
4695 }
4696 }
4697
Jack Palevich5b659092009-07-31 14:55:07 -07004698 /* Now handle postfix operators */
4699 for(;;) {
4700 if (tokl == 11) {
4701 // post inc / post dec
4702 doIncDec(tokc == OP_INCREMENT, true);
4703 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004704 } else if (accept('[')) {
4705 // Array reference
4706 pGen->forceR0RVal();
4707 pGen->pushR0();
4708 commaExpr();
4709 pGen->forceR0RVal();
4710 pGen->genOp(OP_PLUS);
4711 doPointer();
4712 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004713 } else if (accept('.')) {
4714 // struct element
4715 pGen->forceR0RVal();
4716 Type* pStruct = pGen->getR0Type();
4717 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004718 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004719 } else {
4720 error("expected a struct value to the left of '.'");
4721 }
4722 } else if (accept(TOK_OP_ARROW)) {
4723 pGen->forceR0RVal();
4724 Type* pPtr = pGen->getR0Type();
4725 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4726 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004727 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004728 } else {
4729 error("Expected a pointer to a struct to the left of '->'");
4730 }
Jack Palevich5b659092009-07-31 14:55:07 -07004731 } else if (accept('(')) {
4732 /* function call */
4733 Type* pDecl = NULL;
4734 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004735 Type* pFn = pGen->getR0Type();
4736 assert(pFn->tag == TY_POINTER);
4737 assert(pFn->pHead->tag == TY_FUNC);
4738 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004739 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004740 Type* pArgList = pDecl->pTail;
4741 bool varArgs = pArgList == NULL;
4742 /* push args and invert order */
4743 a = pGen->beginFunctionCallArguments();
4744 int l = 0;
4745 int argCount = 0;
4746 while (tok != ')' && tok != EOF) {
4747 if (! varArgs && !pArgList) {
4748 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004749 }
Jack Palevich5b659092009-07-31 14:55:07 -07004750 expr();
4751 pGen->forceR0RVal();
4752 Type* pTargetType;
4753 if (pArgList) {
4754 pTargetType = pArgList->pHead;
4755 pArgList = pArgList->pTail;
4756 } else {
4757 // This is a ... function, just pass arguments in their
4758 // natural type.
4759 pTargetType = pGen->getR0Type();
4760 if (pTargetType->tag == TY_FLOAT) {
4761 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004762 } else if (pTargetType->tag == TY_ARRAY) {
4763 // Pass arrays by pointer.
4764 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004765 }
4766 }
4767 if (pTargetType->tag == TY_VOID) {
4768 error("Can't pass void value for argument %d",
4769 argCount + 1);
4770 } else {
4771 l += pGen->storeR0ToArg(l, pTargetType);
4772 }
4773 if (accept(',')) {
4774 // fine
4775 } else if ( tok != ')') {
4776 error("Expected ',' or ')'");
4777 }
4778 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004779 }
Jack Palevich5b659092009-07-31 14:55:07 -07004780 if (! varArgs && pArgList) {
4781 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004782 }
Jack Palevich5b659092009-07-31 14:55:07 -07004783 pGen->endFunctionCallArguments(pDecl, a, l);
4784 skip(')');
4785 pGen->callIndirect(l, pDecl);
4786 pGen->adjustStackAfterCall(pDecl, l, true);
4787 } else {
4788 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004789 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004790 }
4791 }
4792
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004793 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004794 Type* pStructElement = lookupStructMember(pStruct, tok);
4795 if (pStructElement) {
4796 next();
4797 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4798 } else {
4799 String buf;
4800 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004801 error("Expected a struct member to the right of '%s', got %s",
4802 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004803 }
4804 }
4805
Jack Palevichaaac9282009-07-31 14:34:34 -07004806 void doIncDec(int isInc, int isPost) {
4807 // R0 already has the lval
4808 checkLVal();
4809 int lit = isInc ? 1 : -1;
4810 pGen->pushR0();
4811 pGen->loadR0FromR0();
4812 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004813 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4814 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004815 error("++/-- illegal for this type. %d", tag);
4816 }
4817 if (isPost) {
4818 pGen->over();
4819 pGen->pushR0();
4820 pGen->li(lit);
4821 pGen->genOp(OP_PLUS);
4822 pGen->storeR0ToTOS();
4823 pGen->popR0();
4824 } else {
4825 pGen->pushR0();
4826 pGen->li(lit);
4827 pGen->genOp(OP_PLUS);
4828 pGen->over();
4829 pGen->storeR0ToTOS();
4830 pGen->popR0();
4831 }
4832 }
4833
Jack Palevich47cbea92009-07-31 15:25:53 -07004834 void doPointer() {
4835 pGen->forceR0RVal();
4836 Type* pR0Type = pGen->getR0Type();
4837 if (pR0Type->tag != TY_POINTER) {
4838 error("Expected a pointer type.");
4839 } else {
4840 if (pR0Type->pHead->tag != TY_FUNC) {
4841 pGen->setR0ExpressionType(ET_LVALUE);
4842 }
4843 }
4844 }
4845
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004846 void doAddressOf() {
4847 Type* pR0 = pGen->getR0Type();
4848 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4849 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4850 error("Expected an lvalue");
4851 }
4852 Type* pR0Type = pGen->getR0Type();
4853 pGen->setR0ExpressionType(ET_RVALUE);
4854 }
4855
Jack Palevich40600de2009-07-01 15:32:35 -07004856 /* Recursive descent parser for binary operations.
4857 */
4858 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004859 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004860 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004861 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004862 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004863 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004864 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004865 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004866 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004867 t = tokc;
4868 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004869 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004870 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004871 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004872 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004873 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004874 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004875 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004876 // Check for syntax error.
4877 if (pGen->getR0Type() == NULL) {
4878 // We failed to parse a right-hand argument.
4879 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004880 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004881 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004882 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004883 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004884 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004885 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004886 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004887 }
4888 }
4889 }
4890 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004891 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004892 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004893 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004894 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004895 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004896 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004897 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004898 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004899 }
4900 }
4901 }
4902
Jack Palevich43aaee32009-07-31 14:01:37 -07004903 void commaExpr() {
4904 for(;;) {
4905 expr();
4906 if (!accept(',')) {
4907 break;
4908 }
4909 }
4910 }
4911
Jack Palevich21a15a22009-05-11 14:49:29 -07004912 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004913 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004914 }
4915
4916 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004917 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004918 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004919 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004920 }
4921
Jack Palevicha6baa232009-06-12 11:25:59 -07004922 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004923 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004924
Jack Palevich95727a02009-07-06 12:07:15 -07004925 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004926 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004927 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004928 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004929 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004930 next();
4931 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004932 a = test_expr();
4933 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004934 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004935 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004936 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004937 n = pGen->gjmp(0); /* jmp */
4938 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004939 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004940 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004941 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004942 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004943 }
Jack Palevich546b2242009-05-13 15:10:04 -07004944 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004945 t = tok;
4946 next();
4947 skip('(');
4948 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004949 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004950 a = test_expr();
4951 } else {
4952 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004953 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004954 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004955 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07004956 a = 0;
4957 if (tok != ';')
4958 a = test_expr();
4959 skip(';');
4960 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004961 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004962 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004963 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004964 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004965 n = t + 4;
4966 }
4967 }
4968 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004969 block((intptr_t) &a, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004970 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004971 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004972 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004973 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004974 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004975 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004976 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004977 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004978 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004979 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004980 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004981 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004982 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004983 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004984 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004985 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004986 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004987 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004988 if (pReturnType->tag == TY_VOID) {
4989 error("Must not return a value from a void function");
4990 } else {
4991 pGen->convertR0(pReturnType);
4992 }
4993 } else {
4994 if (pReturnType->tag != TY_VOID) {
4995 error("Must specify a value here");
4996 }
Jack Palevich8df46192009-07-07 14:48:51 -07004997 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004998 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004999 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005000 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07005001 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005002 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005003 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005004 }
5005 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005006
Jack Palevicha8f427f2009-07-13 18:40:08 -07005007 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005008 if (a == b) {
5009 return true;
5010 }
5011 if (a == NULL || b == NULL) {
5012 return false;
5013 }
5014 TypeTag at = a->tag;
5015 if (at != b->tag) {
5016 return false;
5017 }
5018 if (at == TY_POINTER) {
5019 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005020 } else if (at == TY_ARRAY) {
5021 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005022 } else if (at == TY_FUNC || at == TY_PARAM) {
5023 return typeEqual(a->pHead, b->pHead)
5024 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005025 } else if (at == TY_STRUCT) {
5026 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005027 }
5028 return true;
5029 }
5030
Jack Palevich2ff5c222009-07-23 15:11:22 -07005031 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07005032 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005033 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005034 memset(pType, 0, sizeof(*pType));
5035 pType->tag = tag;
5036 pType->pHead = pHead;
5037 pType->pTail = pTail;
5038 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005039 }
5040
Jack Palevich2ff5c222009-07-23 15:11:22 -07005041 Type* createPtrType(Type* pType) {
5042 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005043 }
5044
5045 /**
5046 * Try to print a type in declaration order
5047 */
Jack Palevich86351982009-06-30 18:09:56 -07005048 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005049 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005050 if (pType == NULL) {
5051 buffer.appendCStr("null");
5052 return;
5053 }
Jack Palevich3f226492009-07-02 14:46:19 -07005054 decodeTypeImp(buffer, pType);
5055 }
5056
5057 void decodeTypeImp(String& buffer, Type* pType) {
5058 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005059 decodeId(buffer, pType->id);
5060 decodeTypeImpPostfix(buffer, pType);
5061 }
Jack Palevich3f226492009-07-02 14:46:19 -07005062
Jack Palevich9221bcc2009-08-26 16:15:07 -07005063 void decodeId(String& buffer, tokenid_t id) {
5064 if (id) {
5065 String temp;
5066 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005067 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005068 }
Jack Palevich3f226492009-07-02 14:46:19 -07005069 }
5070
5071 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5072 TypeTag tag = pType->tag;
5073
Jack Palevich9221bcc2009-08-26 16:15:07 -07005074 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005075 switch (tag) {
5076 case TY_INT:
5077 buffer.appendCStr("int");
5078 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005079 case TY_SHORT:
5080 buffer.appendCStr("short");
5081 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005082 case TY_CHAR:
5083 buffer.appendCStr("char");
5084 break;
5085 case TY_VOID:
5086 buffer.appendCStr("void");
5087 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005088 case TY_FLOAT:
5089 buffer.appendCStr("float");
5090 break;
5091 case TY_DOUBLE:
5092 buffer.appendCStr("double");
5093 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005094 case TY_STRUCT:
5095 {
5096 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5097 buffer.appendCStr(isStruct ? "struct" : "union");
5098 if (pType->pHead && pType->pHead->structTag) {
5099 buffer.append(' ');
5100 decodeId(buffer, pType->pHead->structTag);
5101 }
5102 }
5103 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005104 default:
5105 break;
5106 }
Jack Palevich86351982009-06-30 18:09:56 -07005107 buffer.append(' ');
5108 }
Jack Palevich3f226492009-07-02 14:46:19 -07005109
5110 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005111 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005112 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005113 case TY_SHORT:
5114 break;
Jack Palevich86351982009-06-30 18:09:56 -07005115 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005116 break;
5117 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005118 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005119 case TY_FLOAT:
5120 break;
5121 case TY_DOUBLE:
5122 break;
Jack Palevich86351982009-06-30 18:09:56 -07005123 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005124 decodeTypeImpPrefix(buffer, pType->pHead);
5125 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5126 buffer.append('(');
5127 }
5128 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005129 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005130 case TY_ARRAY:
5131 decodeTypeImpPrefix(buffer, pType->pHead);
5132 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005133 case TY_STRUCT:
5134 break;
Jack Palevich86351982009-06-30 18:09:56 -07005135 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005136 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005137 break;
5138 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005139 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005140 break;
5141 default:
5142 String temp;
5143 temp.printf("Unknown tag %d", pType->tag);
5144 buffer.append(temp);
5145 break;
5146 }
Jack Palevich3f226492009-07-02 14:46:19 -07005147 }
5148
5149 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5150 TypeTag tag = pType->tag;
5151
5152 switch(tag) {
5153 case TY_POINTER:
5154 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5155 buffer.append(')');
5156 }
5157 decodeTypeImpPostfix(buffer, pType->pHead);
5158 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005159 case TY_ARRAY:
5160 {
5161 String temp;
5162 temp.printf("[%d]", pType->length);
5163 buffer.append(temp);
5164 }
5165 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005166 case TY_STRUCT:
5167 if (pType->pHead->length >= 0) {
5168 buffer.appendCStr(" {");
5169 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5170 decodeTypeImp(buffer, pArg->pHead);
5171 buffer.appendCStr(";");
5172 }
5173 buffer.append('}');
5174 }
5175 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005176 case TY_FUNC:
5177 buffer.append('(');
5178 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5179 decodeTypeImp(buffer, pArg);
5180 if (pArg->pTail) {
5181 buffer.appendCStr(", ");
5182 }
5183 }
5184 buffer.append(')');
5185 break;
5186 default:
5187 break;
Jack Palevich86351982009-06-30 18:09:56 -07005188 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005189 }
5190
Jack Palevich86351982009-06-30 18:09:56 -07005191 void printType(Type* pType) {
5192 String buffer;
5193 decodeType(buffer, pType);
5194 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005195 }
5196
Jack Palevich2ff5c222009-07-23 15:11:22 -07005197 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005198 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005199 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005200 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005201 } else if (tok == TOK_SHORT) {
5202 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005203 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005204 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005205 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005206 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005207 } else if (tok == TOK_FLOAT) {
5208 pType = mkpFloat;
5209 } else if (tok == TOK_DOUBLE) {
5210 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005211 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5212 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005213 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005214 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005215 }
5216 next();
Jack Palevich86351982009-06-30 18:09:56 -07005217 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005218 }
5219
Jack Palevich9221bcc2009-08-26 16:15:07 -07005220 Type* acceptStruct() {
5221 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5222 bool isStruct = tok == TOK_STRUCT;
5223 next();
5224 tokenid_t structTag = acceptSymbol();
5225 bool isDeclaration = accept('{');
5226 bool fail = false;
5227
5228 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5229 if (structTag) {
5230 Token* pToken = &mTokenTable[structTag];
5231 VariableInfo* pStructInfo = pToken->mpStructInfo;
5232 bool needToDeclare = !pStructInfo;
5233 if (pStructInfo) {
5234 if (isDeclaration) {
5235 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5236 if (pStructInfo->pType->pHead->length == -1) {
5237 // we're filling in a forward declaration.
5238 needToDeclare = false;
5239 } else {
5240 error("A struct with the same name is already defined at this level.");
5241 fail = true;
5242 }
5243 } else {
5244 needToDeclare = true;
5245 }
5246 }
5247 if (!fail) {
5248 assert(pStructInfo->isStructTag);
5249 pStructType->pHead = pStructInfo->pType;
5250 pStructType->pTail = pStructType->pHead->pTail;
5251 }
5252 }
5253
5254 if (needToDeclare) {
5255 // This is a new struct name
5256 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5257 pStructType = createType(TY_STRUCT, NULL, NULL);
5258 pStructType->structTag = structTag;
5259 pStructType->pHead = pStructType;
5260 if (! isDeclaration) {
5261 // A forward declaration
5262 pStructType->length = -1;
5263 }
5264 pToken->mpStructInfo->pType = pStructType;
5265 }
5266 } else {
5267 // An anonymous struct
5268 pStructType->pHead = pStructType;
5269 }
5270
5271 if (isDeclaration) {
5272 size_t offset = 0;
5273 size_t structSize = 0;
5274 size_t structAlignment = 0;
5275 Type** pParamHolder = & pStructType->pHead->pTail;
5276 while (tok != '}' && tok != EOF) {
5277 Type* pPrimitiveType = expectPrimitiveType();
5278 if (pPrimitiveType) {
5279 while (tok != ';' && tok != EOF) {
5280 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5281 if (!pItem) {
5282 break;
5283 }
5284 if (lookupStructMember(pStructType, pItem->id)) {
5285 String buf;
5286 decodeToken(buf, pItem->id, false);
5287 error("Duplicate struct member %s", buf.getUnwrapped());
5288 }
5289 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5290 size_t alignment = pGen->alignmentOf(pItem);
5291 if (alignment > structAlignment) {
5292 structAlignment = alignment;
5293 }
5294 size_t alignmentMask = alignment - 1;
5295 offset = (offset + alignmentMask) & ~alignmentMask;
5296 pStructElement->length = offset;
5297 size_t size = pGen->sizeOf(pItem);
5298 if (isStruct) {
5299 offset += size;
5300 structSize = offset;
5301 } else {
5302 if (size >= structSize) {
5303 structSize = size;
5304 }
5305 }
5306 *pParamHolder = pStructElement;
5307 pParamHolder = &pStructElement->pTail;
5308 accept(',');
5309 }
5310 skip(';');
5311 } else {
5312 // Some sort of syntax error, skip token and keep trying
5313 next();
5314 }
5315 }
5316 if (!fail) {
5317 pStructType->pHead->length = structSize;
5318 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5319 }
5320 skip('}');
5321 }
5322 if (fail) {
5323 pStructType = NULL;
5324 }
5325 return pStructType;
5326 }
5327
5328 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5329 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5330 if (pStructElement->pHead->id == memberId) {
5331 return pStructElement;
5332 }
5333 }
5334 return NULL;
5335 }
5336
Jack Palevich2ff5c222009-07-23 15:11:22 -07005337 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005338 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005339 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005340 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005341 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005342 if (declName) {
5343 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005344 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005345 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005346 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005347 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005348 } else if (nameRequired) {
5349 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005350 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005351#if 0
5352 fprintf(stderr, "Parsed a declaration: ");
5353 printType(pType);
5354#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005355 if (reportFailure) {
5356 return NULL;
5357 }
Jack Palevich86351982009-06-30 18:09:56 -07005358 return pType;
5359 }
5360
Jack Palevich2ff5c222009-07-23 15:11:22 -07005361 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005362 bool nameRequired = pBaseType->tag != TY_STRUCT;
5363 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005364 if (! pType) {
5365 error("Expected a declaration");
5366 }
5367 return pType;
5368 }
5369
Jack Palevich3f226492009-07-02 14:46:19 -07005370 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005371 Type* acceptCastTypeDeclaration() {
5372 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005373 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005374 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005375 }
Jack Palevich86351982009-06-30 18:09:56 -07005376 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005377 }
5378
Jack Palevich2ff5c222009-07-23 15:11:22 -07005379 Type* expectCastTypeDeclaration() {
5380 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005381 if (! pType) {
5382 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005383 }
Jack Palevich3f226492009-07-02 14:46:19 -07005384 return pType;
5385 }
5386
5387 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005388 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005389 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005390 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005391 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005392 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005393 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005394 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005395 return pType;
5396 }
5397
5398 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005399 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005400 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005401 // direct-dcl :
5402 // name
5403 // (dcl)
5404 // direct-dcl()
5405 // direct-dcl[]
5406 Type* pNewHead = NULL;
5407 if (accept('(')) {
5408 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005409 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005410 skip(')');
5411 } else if ((declName = acceptSymbol()) != 0) {
5412 if (nameAllowed == false && declName) {
5413 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005414 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005415 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005416 } else if (nameRequired && ! declName) {
5417 String temp;
5418 decodeToken(temp, tok, true);
5419 error("Expected name. Got %s", temp.getUnwrapped());
5420 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005421 }
Jack Palevichb6154502009-08-04 14:56:09 -07005422 for(;;) {
5423 if (accept('(')) {
5424 // Function declaration
5425 Type* pTail = acceptArgs(nameAllowed);
5426 pType = createType(TY_FUNC, pType, pTail);
5427 skip(')');
5428 } if (accept('[')) {
5429 if (tok != ']') {
5430 if (tok != TOK_NUM || tokc <= 0) {
5431 error("Expected positive integer constant");
5432 } else {
5433 Type* pDecayType = createPtrType(pType);
5434 pType = createType(TY_ARRAY, pType, pDecayType);
5435 pType->length = tokc;
5436 }
5437 next();
5438 }
5439 skip(']');
5440 } else {
5441 break;
5442 }
Jack Palevich86351982009-06-30 18:09:56 -07005443 }
Jack Palevich3f226492009-07-02 14:46:19 -07005444
5445 if (pNewHead) {
5446 Type* pA = pNewHead;
5447 while (pA->pHead) {
5448 pA = pA->pHead;
5449 }
5450 pA->pHead = pType;
5451 pType = pNewHead;
5452 }
Jack Palevich86351982009-06-30 18:09:56 -07005453 return pType;
5454 }
5455
Jack Palevich2ff5c222009-07-23 15:11:22 -07005456 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005457 Type* pHead = NULL;
5458 Type* pTail = NULL;
5459 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005460 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005461 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005462 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005463 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005464 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005465 if (!pHead) {
5466 pHead = pParam;
5467 pTail = pParam;
5468 } else {
5469 pTail->pTail = pParam;
5470 pTail = pParam;
5471 }
5472 }
5473 }
5474 if (! accept(',')) {
5475 break;
5476 }
5477 }
5478 return pHead;
5479 }
5480
Jack Palevich2ff5c222009-07-23 15:11:22 -07005481 Type* expectPrimitiveType() {
5482 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005483 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005484 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005485 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005486 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005487 }
Jack Palevich86351982009-06-30 18:09:56 -07005488 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005489 }
5490
Jack Palevichb5e33312009-07-30 19:06:34 -07005491 void checkLVal() {
5492 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005493 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005494 }
5495 }
5496
Jack Palevich86351982009-06-30 18:09:56 -07005497 void addGlobalSymbol(Type* pDecl) {
5498 tokenid_t t = pDecl->id;
5499 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005500 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005501 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005502 }
Jack Palevich86351982009-06-30 18:09:56 -07005503 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005504 }
5505
Jack Palevich86351982009-06-30 18:09:56 -07005506 void reportDuplicate(tokenid_t t) {
5507 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005508 }
5509
Jack Palevich86351982009-06-30 18:09:56 -07005510 void addLocalSymbol(Type* pDecl) {
5511 tokenid_t t = pDecl->id;
5512 if (mLocals.isDefinedAtCurrentLevel(t)) {
5513 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005514 }
Jack Palevich86351982009-06-30 18:09:56 -07005515 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005516 }
5517
Jack Palevich61de31f2009-09-08 11:06:40 -07005518 bool checkUndeclaredStruct(Type* pBaseType) {
5519 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5520 String temp;
5521 decodeToken(temp, pBaseType->structTag, false);
5522 error("Undeclared struct %s", temp.getUnwrapped());
5523 return true;
5524 }
5525 return false;
5526 }
5527
Jack Palevich95727a02009-07-06 12:07:15 -07005528 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005529 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005530
Jack Palevich95727a02009-07-06 12:07:15 -07005531 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005532 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005533 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005534 if (!pDecl) {
5535 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005536 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005537 if (!pDecl->id) {
5538 break;
5539 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005540 if (checkUndeclaredStruct(pDecl)) {
5541 break;
5542 }
Jack Palevich86351982009-06-30 18:09:56 -07005543 int variableAddress = 0;
5544 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005545 size_t alignment = pGen->alignmentOf(pDecl);
5546 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005547 size_t alignmentMask = ~ (alignment - 1);
5548 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005549 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005550 loc = (loc + alignment - 1) & alignmentMask;
5551 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5552 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005553 variableAddress = -loc;
5554 VI(pDecl->id)->pAddress = (void*) variableAddress;
5555 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005556 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005557 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005558 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005559 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005560 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005561 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005562 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005563 if (tok == ',')
5564 next();
5565 }
5566 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005567 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005568 }
5569 }
5570
Jack Palevichf1728be2009-06-12 13:53:51 -07005571 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005572 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005573 }
5574
Jack Palevich37c54bd2009-07-14 18:35:36 -07005575 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005576 if (token == EOF ) {
5577 buffer.printf("EOF");
5578 } else if (token == TOK_NUM) {
5579 buffer.printf("numeric constant");
5580 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005581 if (token < 32) {
5582 buffer.printf("'\\x%02x'", token);
5583 } else {
5584 buffer.printf("'%c'", token);
5585 }
Jack Palevich569f1352009-06-29 14:29:08 -07005586 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005587 if (quote) {
5588 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5589 buffer.printf("keyword \"%s\"", nameof(token));
5590 } else {
5591 buffer.printf("symbol \"%s\"", nameof(token));
5592 }
5593 } else {
5594 buffer.printf("%s", nameof(token));
5595 }
Jack Palevich569f1352009-06-29 14:29:08 -07005596 }
5597 }
5598
Jack Palevich9221bcc2009-08-26 16:15:07 -07005599 void printToken(tokenid_t token) {
5600 String buffer;
5601 decodeToken(buffer, token, true);
5602 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5603 }
5604
Jack Palevich40600de2009-07-01 15:32:35 -07005605 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005606 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005607 if (!result) {
5608 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005609 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005610 error("Expected symbol. Got %s", temp.getUnwrapped());
5611 }
5612 return result;
5613 }
5614
Jack Palevich86351982009-06-30 18:09:56 -07005615 tokenid_t acceptSymbol() {
5616 tokenid_t result = 0;
5617 if (tok >= TOK_SYMBOL) {
5618 result = tok;
5619 next();
Jack Palevich86351982009-06-30 18:09:56 -07005620 }
5621 return result;
5622 }
5623
Jack Palevichb7c81e92009-06-04 19:56:13 -07005624 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005625 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005626 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005627 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005628 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005629 break;
5630 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005631 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005632 if (!pDecl) {
5633 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005634 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005635 if (!pDecl->id) {
5636 skip(';');
5637 continue;
5638 }
5639
Jack Palevich61de31f2009-09-08 11:06:40 -07005640 if (checkUndeclaredStruct(pDecl)) {
5641 skip(';');
5642 continue;
5643 }
5644
Jack Palevich86351982009-06-30 18:09:56 -07005645 if (! isDefined(pDecl->id)) {
5646 addGlobalSymbol(pDecl);
5647 }
5648 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005649 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005650 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005651 }
Jack Palevich86351982009-06-30 18:09:56 -07005652 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005653 // it's a variable declaration
5654 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005655 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005656 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005657 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005658 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005659 }
Jack Palevich86351982009-06-30 18:09:56 -07005660 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005661 if (tok == TOK_NUM) {
5662 if (name) {
5663 * (int*) name->pAddress = tokc;
5664 }
5665 next();
5666 } else {
5667 error("Expected an integer constant");
5668 }
5669 }
Jack Palevich86351982009-06-30 18:09:56 -07005670 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005671 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005672 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005673 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005674 if (!pDecl) {
5675 break;
5676 }
5677 if (! isDefined(pDecl->id)) {
5678 addGlobalSymbol(pDecl);
5679 }
5680 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005681 }
5682 skip(';');
5683 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005684 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005685 if (accept(';')) {
5686 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005687 } else if (tok != '{') {
5688 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005689 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005690 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005691 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005692 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005693 /* patch forward references */
5694 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005695 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005696 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005697 }
5698 // Calculate stack offsets for parameters
5699 mLocals.pushLevel();
5700 intptr_t a = 8;
5701 int argCount = 0;
5702 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5703 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005704 if (pArg->id) {
5705 addLocalSymbol(pArg);
5706 }
Jack Palevich95727a02009-07-06 12:07:15 -07005707 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005708 Type* pPassingType = passingType(pArg);
5709 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005710 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005711 if (pArg->id) {
5712 VI(pArg->id)->pAddress = (void*) a;
5713 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005714 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005715 argCount++;
5716 }
5717 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005718 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005719 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005720 block(0, true);
5721 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005722 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005723 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005724 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005725 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005726 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005727 }
5728 }
5729 }
5730
Jack Palevich9221bcc2009-08-26 16:15:07 -07005731 Type* passingType(Type* pType) {
5732 switch (pType->tag) {
5733 case TY_CHAR:
5734 case TY_SHORT:
5735 return mkpInt;
5736 default:
5737 return pType;
5738 }
5739 }
5740
Jack Palevich9cbd2262009-07-08 16:48:41 -07005741 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5742 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5743 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005744 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005745 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005746 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005747 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005748 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005749 char* result = (char*) base;
5750 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005751 return result;
5752 }
5753
Jack Palevich21a15a22009-05-11 14:49:29 -07005754 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005755 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005756 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005757 pGlobalBase = 0;
5758 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005759 if (pGen) {
5760 delete pGen;
5761 pGen = 0;
5762 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005763 if (pCodeBuf) {
5764 delete pCodeBuf;
5765 pCodeBuf = 0;
5766 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005767 if (file) {
5768 delete file;
5769 file = 0;
5770 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005771 }
5772
Jack Palevich8c246a92009-07-14 21:14:10 -07005773 // One-time initialization, when class is constructed.
5774 void init() {
5775 mpSymbolLookupFn = 0;
5776 mpSymbolLookupContext = 0;
5777 }
5778
Jack Palevich21a15a22009-05-11 14:49:29 -07005779 void clear() {
5780 tok = 0;
5781 tokc = 0;
5782 tokl = 0;
5783 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005784 rsym = 0;
5785 loc = 0;
5786 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005787 dptr = 0;
5788 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005789 file = 0;
5790 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005791 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005792 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005793 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005794 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005795 mLineNumber = 1;
5796 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005797 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005798 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005799
Jack Palevich22305132009-05-13 10:58:45 -07005800 void setArchitecture(const char* architecture) {
5801 delete pGen;
5802 pGen = 0;
5803
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005804 delete pCodeBuf;
5805 pCodeBuf = new CodeBuf();
5806
Jack Palevich22305132009-05-13 10:58:45 -07005807 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005808#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005809 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005810 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005811 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07005812 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005813#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005814#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005815 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005816 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005817 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005818#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005819 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005820 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005821 }
5822 }
5823
5824 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005825#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005826 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005827 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07005828#elif defined(DEFAULT_X86_CODEGEN)
5829 pGen = new X86CodeGenerator();
5830#endif
5831 }
5832 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005833 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005834 } else {
5835 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005836 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005837 }
5838 }
5839
Jack Palevich77ae76e2009-05-10 19:59:24 -07005840public:
Jack Palevich22305132009-05-13 10:58:45 -07005841 struct args {
5842 args() {
5843 architecture = 0;
5844 }
5845 const char* architecture;
5846 };
5847
Jack Paleviche7b59062009-05-19 17:12:17 -07005848 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005849 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005850 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005851 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005852
Jack Paleviche7b59062009-05-19 17:12:17 -07005853 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005854 cleanup();
5855 }
5856
Jack Palevich8c246a92009-07-14 21:14:10 -07005857 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5858 mpSymbolLookupFn = pFn;
5859 mpSymbolLookupContext = pContext;
5860 }
5861
Jack Palevich1cdef202009-05-22 12:06:27 -07005862 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005863 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005864
Jack Palevich2ff5c222009-07-23 15:11:22 -07005865 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005866 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005867 cleanup();
5868 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005869 mTokenTable.setArena(&mGlobalArena);
5870 mGlobals.setArena(&mGlobalArena);
5871 mGlobals.setTokenTable(&mTokenTable);
5872 mLocals.setArena(&mLocalArena);
5873 mLocals.setTokenTable(&mTokenTable);
5874
5875 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005876 setArchitecture(NULL);
5877 if (!pGen) {
5878 return -1;
5879 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005880#ifdef PROVIDE_TRACE_CODEGEN
5881 pGen = new TraceCodeGenerator(pGen);
5882#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005883 pGen->setErrorSink(this);
5884
5885 if (pCodeBuf) {
5886 pCodeBuf->init(ALLOC_SIZE);
5887 }
5888 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07005889 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005890 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5891 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005892 inp();
5893 next();
5894 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005895 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005896 result = pGen->finishCompile();
5897 if (result == 0) {
5898 if (mErrorBuf.len()) {
5899 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005900 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005901 }
Jack Palevichce105a92009-07-16 14:30:33 -07005902 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005903 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005904 }
5905
Jack Palevich86351982009-06-30 18:09:56 -07005906 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005907 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005908 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005909 mkpChar = createType(TY_CHAR, NULL, NULL);
5910 mkpVoid = createType(TY_VOID, NULL, NULL);
5911 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5912 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5913 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5914 mkpIntPtr = createPtrType(mkpInt);
5915 mkpCharPtr = createPtrType(mkpChar);
5916 mkpFloatPtr = createPtrType(mkpFloat);
5917 mkpDoublePtr = createPtrType(mkpDouble);
5918 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005919 }
5920
Jack Palevicha6baa232009-06-12 11:25:59 -07005921 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005922 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005923 }
5924
Jack Palevich569f1352009-06-29 14:29:08 -07005925 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005926 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005927 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005928 }
5929
Jack Palevich569f1352009-06-29 14:29:08 -07005930 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005931 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005932 error("Undefined forward reference: %s",
5933 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005934 }
5935 return true;
5936 }
5937
Jack Palevich1cdef202009-05-22 12:06:27 -07005938 /* Look through the symbol table to find a symbol.
5939 * If found, return its value.
5940 */
5941 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005942 if (mCompileResult == 0) {
5943 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5944 VariableInfo* pVariableInfo = VI(tok);
5945 if (pVariableInfo) {
5946 return pVariableInfo->pAddress;
5947 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005948 }
5949 return NULL;
5950 }
5951
Jack Palevicheedf9d22009-06-04 16:23:40 -07005952 void getPragmas(ACCsizei* actualStringCount,
5953 ACCsizei maxStringCount, ACCchar** strings) {
5954 int stringCount = mPragmaStringCount;
5955 if (actualStringCount) {
5956 *actualStringCount = stringCount;
5957 }
5958 if (stringCount > maxStringCount) {
5959 stringCount = maxStringCount;
5960 }
5961 if (strings) {
5962 char* pPragmas = mPragmas.getUnwrapped();
5963 while (stringCount-- > 0) {
5964 *strings++ = pPragmas;
5965 pPragmas += strlen(pPragmas) + 1;
5966 }
5967 }
5968 }
5969
Jack Palevichd5315572009-09-09 13:19:34 -07005970 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005971 *base = pCodeBuf->getBase();
5972 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07005973 }
5974
Jack Palevichac0e95e2009-05-29 13:53:44 -07005975 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005976 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005977 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005978};
5979
Jack Paleviche7b59062009-05-19 17:12:17 -07005980const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005981 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5982
Jack Paleviche7b59062009-05-19 17:12:17 -07005983const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005984 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5985 5, 5, /* ==, != */
5986 9, 10, /* &&, || */
5987 6, 7, 8, /* & ^ | */
5988 2, 2 /* ~ ! */
5989 };
5990
Jack Palevich8b0624c2009-05-20 12:12:06 -07005991#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005992const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005993 0x1, // ++
5994 0xff, // --
5995 0xc1af0f, // *
5996 0xf9f79991, // /
5997 0xf9f79991, // % (With manual assist to swap results)
5998 0xc801, // +
5999 0xd8f7c829, // -
6000 0xe0d391, // <<
6001 0xf8d391, // >>
6002 0xe, // <=
6003 0xd, // >=
6004 0xc, // <
6005 0xf, // >
6006 0x4, // ==
6007 0x5, // !=
6008 0x0, // &&
6009 0x1, // ||
6010 0xc821, // &
6011 0xc831, // ^
6012 0xc809, // |
6013 0xd0f7, // ~
6014 0x4 // !
6015};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006016#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006017
Jack Palevich1cdef202009-05-22 12:06:27 -07006018struct ACCscript {
6019 ACCscript() {
6020 text = 0;
6021 textLength = 0;
6022 accError = ACC_NO_ERROR;
6023 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006024
Jack Palevich1cdef202009-05-22 12:06:27 -07006025 ~ACCscript() {
6026 delete text;
6027 }
Jack Palevich546b2242009-05-13 15:10:04 -07006028
Jack Palevich8c246a92009-07-14 21:14:10 -07006029 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6030 compiler.registerSymbolCallback(pFn, pContext);
6031 }
6032
Jack Palevich1cdef202009-05-22 12:06:27 -07006033 void setError(ACCenum error) {
6034 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6035 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006036 }
6037 }
6038
Jack Palevich1cdef202009-05-22 12:06:27 -07006039 ACCenum getError() {
6040 ACCenum result = accError;
6041 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006042 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006043 }
6044
Jack Palevich1cdef202009-05-22 12:06:27 -07006045 Compiler compiler;
6046 char* text;
6047 int textLength;
6048 ACCenum accError;
6049};
6050
6051
6052extern "C"
6053ACCscript* accCreateScript() {
6054 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006055}
Jack Palevich1cdef202009-05-22 12:06:27 -07006056
6057extern "C"
6058ACCenum accGetError( ACCscript* script ) {
6059 return script->getError();
6060}
6061
6062extern "C"
6063void accDeleteScript(ACCscript* script) {
6064 delete script;
6065}
6066
6067extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006068void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6069 ACCvoid* pContext) {
6070 script->registerSymbolCallback(pFn, pContext);
6071}
6072
6073extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006074void accScriptSource(ACCscript* script,
6075 ACCsizei count,
6076 const ACCchar ** string,
6077 const ACCint * length) {
6078 int totalLength = 0;
6079 for(int i = 0; i < count; i++) {
6080 int len = -1;
6081 const ACCchar* s = string[i];
6082 if (length) {
6083 len = length[i];
6084 }
6085 if (len < 0) {
6086 len = strlen(s);
6087 }
6088 totalLength += len;
6089 }
6090 delete script->text;
6091 char* text = new char[totalLength + 1];
6092 script->text = text;
6093 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006094 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006095 for(int i = 0; i < count; i++) {
6096 int len = -1;
6097 const ACCchar* s = string[i];
6098 if (length) {
6099 len = length[i];
6100 }
6101 if (len < 0) {
6102 len = strlen(s);
6103 }
Jack Palevich09555c72009-05-27 12:25:55 -07006104 memcpy(dest, s, len);
6105 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006106 }
6107 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006108
6109#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006110 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006111 int counter;
6112 char path[PATH_MAX];
6113 for (counter = 0; counter < 4096; counter++) {
6114 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6115 if(access(path, F_OK) != 0) {
6116 break;
6117 }
6118 }
6119 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006120 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006121 FILE* fd = fopen(path, "w");
6122 if (fd) {
6123 fwrite(text, totalLength, 1, fd);
6124 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006125 LOGD("Saved input to file %s", path);
6126 } else {
6127 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006128 }
6129 }
6130#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006131}
6132
6133extern "C"
6134void accCompileScript(ACCscript* script) {
6135 int result = script->compiler.compile(script->text, script->textLength);
6136 if (result) {
6137 script->setError(ACC_INVALID_OPERATION);
6138 }
6139}
6140
6141extern "C"
6142void accGetScriptiv(ACCscript* script,
6143 ACCenum pname,
6144 ACCint * params) {
6145 switch (pname) {
6146 case ACC_INFO_LOG_LENGTH:
6147 *params = 0;
6148 break;
6149 }
6150}
6151
6152extern "C"
6153void accGetScriptInfoLog(ACCscript* script,
6154 ACCsizei maxLength,
6155 ACCsizei * length,
6156 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006157 char* message = script->compiler.getErrorMessage();
6158 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006159 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006160 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006161 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006162 if (infoLog && maxLength > 0) {
6163 int trimmedLength = maxLength < messageLength ?
6164 maxLength : messageLength;
6165 memcpy(infoLog, message, trimmedLength);
6166 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006167 }
6168}
6169
6170extern "C"
6171void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6172 ACCvoid ** address) {
6173 void* value = script->compiler.lookup(name);
6174 if (value) {
6175 *address = value;
6176 } else {
6177 script->setError(ACC_INVALID_VALUE);
6178 }
6179}
6180
Jack Palevicheedf9d22009-06-04 16:23:40 -07006181extern "C"
6182void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6183 ACCsizei maxStringCount, ACCchar** strings){
6184 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6185}
6186
-b master422972c2009-06-17 19:13:52 -07006187extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006188void accGetProgramBinary(ACCscript* script,
6189 ACCvoid** base, ACCsizei* length) {
6190 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006191}
6192
Jack Palevicheedf9d22009-06-04 16:23:40 -07006193
Jack Palevich1cdef202009-05-22 12:06:27 -07006194} // namespace acc
6195