blob: 73d2cdd80839f87ae79ad74f8eae591d2304bcc4 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070016#include <limits.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070017#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070018#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070020#include <stdlib.h>
21#include <string.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070022#include <unistd.h>
23
Jack Palevich2d11dfb2009-06-08 14:34:26 -070024#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070025
Jack Palevich8dc662e2009-06-09 22:53:47 +000026#include <sys/mman.h>
Jack Palevich546b2242009-05-13 15:10:04 -070027
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Palevich30321cb2009-08-20 15:34:23 -070039#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
40#define ARM_USE_VFP
41#endif
42
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
Jack Palevichb67b18f2009-06-11 21:12:23 -070051// #define PROVIDE_TRACE_CODEGEN
52
Jack Palevichd30a2ce2009-09-09 19:08:54 -070053// Uncomment to disable ARM peephole optimizations
54// #define DISABLE_ARM_PEEPHOLE
55
Jack Palevich61de31f2009-09-08 11:06:40 -070056// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
57// #define DEBUG_SAVE_INPUT_TO_FILE
58
Jack Palevich9116bc42009-09-08 11:46:42 -070059#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070060#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070061#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070062#else
63#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
64#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070065#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070066
Jack Palevich7f5b1a22009-08-17 16:54:56 -070067#define assert(b) assertImpl(b, __LINE__)
68
Jack Palevichbbf8ab52009-05-11 11:54:30 -070069namespace acc {
70
Jack Palevich8df46192009-07-07 14:48:51 -070071// Subset of STL vector.
72template<class E> class Vector {
73 public:
74 Vector() {
75 mpBase = 0;
76 mUsed = 0;
77 mSize = 0;
78 }
79
80 ~Vector() {
81 if (mpBase) {
Jack Palevichba48fe22009-11-27 11:51:36 +080082 clear();
Jack Palevich8df46192009-07-07 14:48:51 -070083 free(mpBase);
84 }
85 }
86
87 inline E& operator[](size_t i) {
88 return mpBase[i];
89 }
90
91 inline E& front() {
92 return mpBase[0];
93 }
94
95 inline E& back() {
96 return mpBase[mUsed - 1];
97 }
98
99 void pop_back() {
100 mUsed -= 1;
101 mpBase[mUsed].~E();
102 }
103
104 void push_back(const E& item) {
105 * ensure(1) = item;
106 }
107
Jack Palevichba48fe22009-11-27 11:51:36 +0800108 inline size_t size() {
Jack Palevich8df46192009-07-07 14:48:51 -0700109 return mUsed;
110 }
111
Jack Palevichba48fe22009-11-27 11:51:36 +0800112 void clear() {
113 if (mpBase) {
114 size_t used = mUsed;
115 for(size_t i = 0; i < used; i++) {
116 mpBase[i].~E();
117 }
118 }
119 mUsed = 0;
120 }
121
Jack Palevich8df46192009-07-07 14:48:51 -0700122private:
123 E* ensure(int n) {
124 size_t newUsed = mUsed + n;
125 if (newUsed > mSize) {
126 size_t newSize = mSize * 2 + 10;
127 if (newSize < newUsed) {
128 newSize = newUsed;
129 }
130 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
131 mSize = newSize;
132 }
133 E* result = mpBase + mUsed;
134 mUsed = newUsed;
135 return result;
136 }
137
138 E* mpBase;
139 size_t mUsed;
140 size_t mSize;
141};
142
Jack Palevichac0e95e2009-05-29 13:53:44 -0700143class ErrorSink {
144public:
145 void error(const char *fmt, ...) {
146 va_list ap;
147 va_start(ap, fmt);
148 verror(fmt, ap);
149 va_end(ap);
150 }
151
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700152 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700153 virtual void verror(const char* fmt, va_list ap) = 0;
154};
155
156class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700157 typedef int tokenid_t;
158 enum TypeTag {
Jack Palevichee1f8292009-10-28 16:10:17 -0700159 TY_UNKNOWN = -1,
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700160 TY_INT, // 0
161 TY_CHAR, // 1
162 TY_SHORT, // 2
163 TY_VOID, // 3
164 TY_FLOAT, // 4
165 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700166 TY_POINTER, // 6
167 TY_ARRAY, // 7
168 TY_STRUCT, // 8
169 TY_FUNC, // 9
170 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700171 };
172
Jack Palevichee1f8292009-10-28 16:10:17 -0700173 enum StorageClass {
174 SC_DEFAULT, // 0
175 SC_AUTO, // 1
176 SC_REGISTER, // 2
177 SC_STATIC, // 3
178 SC_EXTERN, // 4
179 SC_TYPEDEF // 5
180 };
181
Jack Palevich8df46192009-07-07 14:48:51 -0700182 struct Type {
183 TypeTag tag;
Jack Palevichee1f8292009-10-28 16:10:17 -0700184 StorageClass storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700185 tokenid_t id; // For function arguments, global vars, local vars, struct elements
186 tokenid_t structTag; // For structs the name of the struct
187 int length; // length of array, offset of struct element. -1 means struct is forward defined
188 int alignment; // for structs only
189 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700190 Type* pTail;
191 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700192
Jack Palevichba929a42009-07-17 10:20:32 -0700193 enum ExpressionType {
194 ET_RVALUE,
195 ET_LVALUE
196 };
197
198 struct ExpressionValue {
199 ExpressionValue() {
200 et = ET_RVALUE;
201 pType = NULL;
202 }
203 ExpressionType et;
204 Type* pType;
205 };
206
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700207 class ICodeBuf {
208 public:
209 virtual ~ICodeBuf() {}
210 virtual void init(int size) = 0;
211 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
212 virtual void o4(int n) = 0;
213 virtual void ob(int n) = 0;
214 virtual void* getBase() = 0;
215 virtual intptr_t getSize() = 0;
216 virtual intptr_t getPC() = 0;
217 // Call this before trying to modify code in the buffer.
218 virtual void flush() = 0;
219 };
220
221 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700222 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700223 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700224 ErrorSink* mErrorSink;
225 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700226 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700227
Jack Palevich21a15a22009-05-11 14:49:29 -0700228 void release() {
229 if (pProgramBase != 0) {
Nick Kralevich093ba252010-04-23 09:53:09 -0700230 munmap(pProgramBase, mSize);
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700232 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700233 }
234
Jack Palevich0a280a02009-06-11 10:53:51 -0700235 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700236 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700237 bool overflow = newSize > mSize;
238 if (overflow && !mOverflowed) {
239 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700240 if (mErrorSink) {
241 mErrorSink->error("Code too large: %d bytes", newSize);
242 }
243 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700244 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700245 }
246
Jack Palevich21a15a22009-05-11 14:49:29 -0700247 public:
248 CodeBuf() {
249 pProgramBase = 0;
250 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700251 mErrorSink = 0;
252 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700253 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700254 }
255
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700256 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700257 release();
258 }
259
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700260 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700261 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700262 mSize = size;
Nick Kralevich093ba252010-04-23 09:53:09 -0700263 pProgramBase = (char*) mmap(NULL, size,
264 PROT_EXEC | PROT_READ | PROT_WRITE,
265 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -0700266 ind = pProgramBase;
267 }
268
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700269 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700270 mErrorSink = pErrorSink;
271 }
272
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700273 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700274 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700275 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700276 }
Jack Palevich546b2242009-05-13 15:10:04 -0700277 * (int*) ind = n;
278 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700279 }
280
Jack Palevich21a15a22009-05-11 14:49:29 -0700281 /*
282 * Output a byte. Handles all values, 0..ff.
283 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700284 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700285 if(check(1)) {
286 return;
287 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700288 *ind++ = n;
289 }
290
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700291 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700292 return (void*) pProgramBase;
293 }
294
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700295 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700296 return ind - pProgramBase;
297 }
298
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700299 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700300 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700301 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700302
303 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700304 };
305
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 /**
307 * A code generator creates an in-memory program, generating the code on
308 * the fly. There is one code generator implementation for each supported
309 * architecture.
310 *
311 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700312 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700313 * FP - a frame pointer for accessing function arguments and local
314 * variables.
315 * SP - a stack pointer for storing intermediate results while evaluating
316 * expressions. The stack pointer grows downwards.
317 *
318 * The function calling convention is that all arguments are placed on the
319 * stack such that the first argument has the lowest address.
320 * After the call, the result is in R0. The caller is responsible for
321 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700322 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 * FP and SP registers are saved.
324 */
325
Jack Palevich21a15a22009-05-11 14:49:29 -0700326 class CodeGenerator {
327 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700328 CodeGenerator() {
329 mErrorSink = 0;
330 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700331 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700332 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700333 virtual ~CodeGenerator() {}
334
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700335 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700336 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700337 pCodeBuf->setErrorSink(mErrorSink);
338 }
339
Jack Palevichb67b18f2009-06-11 21:12:23 -0700340 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700341 mErrorSink = pErrorSink;
342 if (pCodeBuf) {
343 pCodeBuf->setErrorSink(mErrorSink);
344 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700345 }
346
Jack Palevich58c30ee2009-07-17 16:35:23 -0700347 /* Give the code generator some utility types so it can
348 * use its own types as needed for the results of some
349 * operations like gcmp.
350 */
351
Jack Palevicha8f427f2009-07-13 18:40:08 -0700352 void setTypes(Type* pInt) {
353 mkpInt = pInt;
354 }
355
Jack Palevich1cdef202009-05-22 12:06:27 -0700356 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700357 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700358 * Save the old value of the FP.
359 * Set the new value of the FP.
360 * Convert from the native platform calling convention to
361 * our stack-based calling convention. This may require
362 * pushing arguments from registers to the stack.
363 * Allocate "N" bytes of stack space. N isn't known yet, so
364 * just emit the instructions for adjusting the stack, and return
365 * the address to patch up. The patching will be done in
366 * functionExit().
367 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700368 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700369 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700370
Jack Palevich1cdef202009-05-22 12:06:27 -0700371 /* Emit a function epilog.
372 * Restore the old SP and FP register values.
373 * Return to the calling function.
374 * argCount - the number of arguments to the function.
375 * localVariableAddress - returned from functionEntry()
376 * localVariableSize - the size in bytes of the local variables.
377 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700378 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700379 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700380
Jack Palevich1cdef202009-05-22 12:06:27 -0700381 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700382 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700383
Jack Palevich1a539db2009-07-08 13:04:41 -0700384 /* Load floating point value from global address. */
385 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700386
Jack Palevich9221bcc2009-08-26 16:15:07 -0700387 /* Add the struct offset in bytes to R0, change the type to pType */
388 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
389
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 /* Jump to a target, and return the address of the word that
391 * holds the target data, in case it needs to be fixed up later.
392 */
Jack Palevich22305132009-05-13 10:58:45 -0700393 virtual int gjmp(int t) = 0;
394
Jack Palevich1cdef202009-05-22 12:06:27 -0700395 /* Test R0 and jump to a target if the test succeeds.
396 * l = 0: je, l == 1: jne
397 * Return the address of the word that holds the targed data, in
398 * case it needs to be fixed up later.
399 */
Jack Palevich22305132009-05-13 10:58:45 -0700400 virtual int gtst(bool l, int t) = 0;
401
Jack Palevich9eed7a22009-07-06 17:24:34 -0700402 /* Compare TOS against R0, and store the boolean result in R0.
403 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700404 * op specifies the comparison.
405 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700406 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700407
Jack Palevich9eed7a22009-07-06 17:24:34 -0700408 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700409 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700410 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700411 */
Jack Palevich546b2242009-05-13 15:10:04 -0700412 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700413
Jack Palevich9eed7a22009-07-06 17:24:34 -0700414 /* Compare 0 against R0, and store the boolean result in R0.
415 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700416 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700417 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700418
419 /* Perform the arithmetic op specified by op. 0 is the
420 * left argument, R0 is the right argument.
421 */
422 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700423
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700424 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700425 */
426 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700427
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700428 /* Turn R0, TOS into R0 TOS R0 */
429
430 virtual void over() = 0;
431
432 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700433 */
434 virtual void popR0() = 0;
435
Jack Palevich9eed7a22009-07-06 17:24:34 -0700436 /* Store R0 to the address stored in TOS.
437 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700438 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700439 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700440
Jack Palevich1cdef202009-05-22 12:06:27 -0700441 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700442 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700443 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700444
Jack Palevich1cdef202009-05-22 12:06:27 -0700445 /* Load the absolute address of a variable to R0.
446 * If ea <= LOCAL, then this is a local variable, or an
447 * argument, addressed relative to FP.
448 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700449 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700450 * et is ET_RVALUE for things like string constants, ET_LVALUE for
451 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700452 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700453 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700454
Jack Palevich9f51a262009-07-29 16:22:26 -0700455 /* Load the pc-relative address of a forward-referenced variable to R0.
456 * Return the address of the 4-byte constant so that it can be filled
457 * in later.
458 */
459 virtual int leaForward(int ea, Type* pPointerType) = 0;
460
Jack Palevich8df46192009-07-07 14:48:51 -0700461 /**
462 * Convert R0 to the given type.
463 */
Jack Palevichb6154502009-08-04 14:56:09 -0700464
465 void convertR0(Type* pType) {
466 convertR0Imp(pType, false);
467 }
468
469 void castR0(Type* pType) {
470 convertR0Imp(pType, true);
471 }
472
473 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700474
Jack Palevich1cdef202009-05-22 12:06:27 -0700475 /* Emit code to adjust the stack for a function call. Return the
476 * label for the address of the instruction that adjusts the
477 * stack size. This will be passed as argument "a" to
478 * endFunctionCallArguments.
479 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700480 virtual int beginFunctionCallArguments() = 0;
481
Jack Palevich1cdef202009-05-22 12:06:27 -0700482 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700483 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700484 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700485 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700486
Jack Palevich1cdef202009-05-22 12:06:27 -0700487 /* Patch the function call preamble.
488 * a is the address returned from beginFunctionCallArguments
489 * l is the number of bytes the arguments took on the stack.
490 * Typically you would also emit code to convert the argument
491 * list into whatever the native function calling convention is.
492 * On ARM for example you would pop the first 5 arguments into
493 * R0..R4
494 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700495 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700496
Jack Palevich1cdef202009-05-22 12:06:27 -0700497 /* Emit a call to an unknown function. The argument "symbol" needs to
498 * be stored in the location where the address should go. It forms
499 * a chain. The address will be patched later.
500 * Return the address of the word that has to be patched.
501 */
Jack Palevich8df46192009-07-07 14:48:51 -0700502 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700503
Jack Palevich1cdef202009-05-22 12:06:27 -0700504 /* Call a function pointer. L is the number of bytes the arguments
505 * take on the stack. The address of the function is stored at
506 * location SP + l.
507 */
Jack Palevich8df46192009-07-07 14:48:51 -0700508 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700509
Jack Palevich1cdef202009-05-22 12:06:27 -0700510 /* Adjust SP after returning from a function call. l is the
511 * number of bytes of arguments stored on the stack. isIndirect
512 * is true if this was an indirect call. (In which case the
513 * address of the function is stored at location SP + l.)
514 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700515 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700516
Jack Palevich1cdef202009-05-22 12:06:27 -0700517 /* Generate a symbol at the current PC. t is the head of a
518 * linked list of addresses to patch.
519 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700520 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700521
Jack Palevich9f51a262009-07-29 16:22:26 -0700522 /* Resolve a forward reference function at the current PC.
523 * t is the head of a
524 * linked list of addresses to patch.
525 * (Like gsym, but using absolute address, not PC relative address.)
526 */
527 virtual void resolveForward(int t) = 0;
528
Jack Palevich1cdef202009-05-22 12:06:27 -0700529 /*
530 * Do any cleanup work required at the end of a compile.
531 * For example, an instruction cache might need to be
532 * invalidated.
533 * Return non-zero if there is an error.
534 */
535 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700536
Jack Palevicha6535612009-05-13 16:24:17 -0700537 /**
538 * Adjust relative branches by this amount.
539 */
540 virtual int jumpOffset() = 0;
541
Jack Palevich9eed7a22009-07-06 17:24:34 -0700542 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700543 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700544 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700545 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700546
547 /**
548 * Array element alignment (in bytes) for this type of data.
549 */
550 virtual size_t sizeOf(Type* type) = 0;
551
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700552 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700553 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700554 }
555
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700556 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700557 return mExpressionStack.back().et;
558 }
559
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700560 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700561 mExpressionStack.back().et = et;
562 }
563
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700564 virtual size_t getExpressionStackDepth() {
565 return mExpressionStack.size();
566 }
567
Jack Palevichb5e33312009-07-30 19:06:34 -0700568 virtual void forceR0RVal() {
569 if (getR0ExpressionType() == ET_LVALUE) {
570 loadR0FromR0();
571 }
572 }
573
Jack Palevich21a15a22009-05-11 14:49:29 -0700574 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700575 /*
576 * Output a byte. Handles all values, 0..ff.
577 */
578 void ob(int n) {
579 pCodeBuf->ob(n);
580 }
581
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700582 void o4(int data) {
583 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700584 }
585
Jack Palevich8b0624c2009-05-20 12:12:06 -0700586 intptr_t getBase() {
587 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700588 }
589
Jack Palevich8b0624c2009-05-20 12:12:06 -0700590 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700591 return pCodeBuf->getPC();
592 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700593
594 intptr_t getSize() {
595 return pCodeBuf->getSize();
596 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700597
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700598 void flush() {
599 pCodeBuf->flush();
600 }
601
Jack Palevichac0e95e2009-05-29 13:53:44 -0700602 void error(const char* fmt,...) {
603 va_list ap;
604 va_start(ap, fmt);
605 mErrorSink->verror(fmt, ap);
606 va_end(ap);
607 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700608
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700609 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700610 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700611 error("code generator assertion failed at line %s:%d.", __FILE__, line);
612 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700613 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700614 }
615 }
Jack Palevich8df46192009-07-07 14:48:51 -0700616
617 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700618 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700619 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700620 mExpressionStack.back().et = ET_RVALUE;
621 }
622
623 void setR0Type(Type* pType, ExpressionType et) {
624 assert(pType != NULL);
625 mExpressionStack.back().pType = pType;
626 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700627 }
628
Jack Palevich8df46192009-07-07 14:48:51 -0700629 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700630 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700631 }
632
633 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700634 if (mExpressionStack.size()) {
635 mExpressionStack.push_back(mExpressionStack.back());
636 } else {
637 mExpressionStack.push_back(ExpressionValue());
638 }
639
Jack Palevich8df46192009-07-07 14:48:51 -0700640 }
641
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700642 void overType() {
643 size_t size = mExpressionStack.size();
644 if (size >= 2) {
645 mExpressionStack.push_back(mExpressionStack.back());
646 mExpressionStack[size-1] = mExpressionStack[size-2];
647 mExpressionStack[size-2] = mExpressionStack[size];
648 }
649 }
650
Jack Palevich8df46192009-07-07 14:48:51 -0700651 void popType() {
652 mExpressionStack.pop_back();
653 }
654
655 bool bitsSame(Type* pA, Type* pB) {
656 return collapseType(pA->tag) == collapseType(pB->tag);
657 }
658
659 TypeTag collapseType(TypeTag tag) {
660 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700661 TY_INT,
662 TY_INT,
663 TY_INT,
664 TY_VOID,
665 TY_FLOAT,
666 TY_DOUBLE,
667 TY_INT,
668 TY_INT,
669 TY_VOID,
670 TY_VOID,
671 TY_VOID
672 };
Jack Palevich8df46192009-07-07 14:48:51 -0700673 return collapsedTag[tag];
674 }
675
Jack Palevich1a539db2009-07-08 13:04:41 -0700676 TypeTag collapseTypeR0() {
677 return collapseType(getR0Type()->tag);
678 }
679
Jack Palevichb6154502009-08-04 14:56:09 -0700680 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700681 return isFloatTag(pType->tag);
682 }
683
Jack Palevichb6154502009-08-04 14:56:09 -0700684 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700685 return tag == TY_FLOAT || tag == TY_DOUBLE;
686 }
687
Jack Palevichb6154502009-08-04 14:56:09 -0700688 static bool isPointerType(Type* pType) {
689 return isPointerTag(pType->tag);
690 }
691
692 static bool isPointerTag(TypeTag tag) {
693 return tag == TY_POINTER || tag == TY_ARRAY;
694 }
695
696 Type* getPointerArithmeticResultType(Type* a, Type* b) {
697 TypeTag aTag = a->tag;
698 TypeTag bTag = b->tag;
699 if (aTag == TY_POINTER) {
700 return a;
701 }
702 if (bTag == TY_POINTER) {
703 return b;
704 }
705 if (aTag == TY_ARRAY) {
706 return a->pTail;
707 }
708 if (bTag == TY_ARRAY) {
709 return b->pTail;
710 }
711 return NULL;
712 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700713 Type* mkpInt;
714
Jack Palevich21a15a22009-05-11 14:49:29 -0700715 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700716 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700717 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700718 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700719 };
720
Jack Paleviche7b59062009-05-19 17:12:17 -0700721#ifdef PROVIDE_ARM_CODEGEN
722
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700723 static size_t rotateRight(size_t n, size_t rotate) {
724 return (n >> rotate) | (n << (32 - rotate));
725 }
726
727 static size_t rotateLeft(size_t n, size_t rotate) {
728 return (n << rotate) | (n >> (32 - rotate));
729 }
730
731 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
732 for(size_t i = 0; i < 16; i++) {
733 size_t rotate = i * 2;
734 size_t mask = rotateRight(0xff, rotate);
735 if ((immediate | mask) == mask) {
736 size_t bits8 = rotateLeft(immediate, rotate);
737 // assert(bits8 <= 0xff);
738 *pResult = (i << 8) | bits8;
739 return true;
740 }
741 }
742 return false;
743 }
744
745 static size_t decode12BitImmediate(size_t immediate) {
746 size_t data = immediate & 0xff;
747 size_t rotate = 2 * ((immediate >> 8) & 0xf);
748 return rotateRight(data, rotate);
749 }
750
Jack Palevich53f06582009-09-10 14:01:58 -0700751 static bool isPowerOfTwo(size_t n) {
752 return (n != 0) & ((n & (n-1)) == 0);
753 }
754
755 static size_t log2(size_t n) {
756 int result = 0;
757 while (n >>= 1) {
758 result++;
759 }
760 return result;
761 }
762
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700763 class ARMCodeBuf : public ICodeBuf {
764 ICodeBuf* mpBase;
765 ErrorSink* mErrorSink;
766
767 class CircularQueue {
768 static const int SIZE = 16; // Must be power of 2
769 static const int MASK = SIZE-1;
770 unsigned int mBuf[SIZE];
771 int mHead;
772 int mCount;
773
774 public:
775 CircularQueue() {
776 mHead = 0;
777 mCount = 0;
778 }
779
780 void pushBack(unsigned int data) {
781 mBuf[(mHead + mCount) & MASK] = data;
782 mCount += 1;
783 }
784
785 unsigned int popFront() {
786 unsigned int result = mBuf[mHead];
787 mHead = (mHead + 1) & MASK;
788 mCount -= 1;
789 return result;
790 }
791
792 void popBack(int n) {
793 mCount -= n;
794 }
795
796 inline int count() {
797 return mCount;
798 }
799
800 bool empty() {
801 return mCount == 0;
802 }
803
804 bool full() {
805 return mCount == SIZE;
806 }
807
808 // The valid indexes are 1 - count() to 0
809 unsigned int operator[](int i) {
810 return mBuf[(mHead + mCount + i) & MASK];
811 }
812 };
813
814 CircularQueue mQ;
815
816 void error(const char* fmt,...) {
817 va_list ap;
818 va_start(ap, fmt);
819 mErrorSink->verror(fmt, ap);
820 va_end(ap);
821 }
822
823 void flush() {
824 while (!mQ.empty()) {
825 mpBase->o4(mQ.popFront());
826 }
827 mpBase->flush();
828 }
829
830 public:
831 ARMCodeBuf(ICodeBuf* pBase) {
832 mpBase = pBase;
833 }
834
835 virtual ~ARMCodeBuf() {
836 delete mpBase;
837 }
838
839 void init(int size) {
840 mpBase->init(size);
841 }
842
843 void setErrorSink(ErrorSink* pErrorSink) {
844 mErrorSink = pErrorSink;
845 mpBase->setErrorSink(pErrorSink);
846 }
847
848 void o4(int n) {
849 if (mQ.full()) {
850 mpBase->o4(mQ.popFront());
851 }
852 mQ.pushBack(n);
853
854#ifndef DISABLE_ARM_PEEPHOLE
855 // Peephole check
856 bool didPeep;
857 do {
Jack Palevich53f06582009-09-10 14:01:58 -0700858 static const unsigned int opMask = 0x01e00000;
859 static const unsigned int immediateMask = 0x00000fff;
860 static const unsigned int BMask = 0x00400000;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700861 didPeep = false;
862 if (mQ.count() >= 4) {
863
864 // Operand by a small constant
865 // push;mov #imm;pop;op ==> op #imm
866
Jack Palevich1c60e462009-09-18 15:03:03 -0700867 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
868 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
869 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
870 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700871 unsigned int movConst = mQ[-3];
872 unsigned int op = mQ[-1];
873 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
874 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
875 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
876 mQ.popBack(4);
877 mQ.pushBack(combined);
878 didPeep = true;
879 } else {
880 mQ.popBack(4);
881 didPeep = true;
882 }
883 }
884 }
885
886 // Load local variable
Jack Palevich53f06582009-09-10 14:01:58 -0700887 // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm]
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700888 if (mQ.count() >= 2) {
Jack Palevich53f06582009-09-10 14:01:58 -0700889 if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
890 const unsigned int encodedImmediate = mQ[-2] & immediateMask;
891 const unsigned int ld = mQ[-1];
892 if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
893 unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
894 mQ.popBack(2);
895 mQ.pushBack(combined);
896 didPeep = true;
Jack Palevich1c60e462009-09-18 15:03:03 -0700897 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
Jack Palevich53f06582009-09-10 14:01:58 -0700898 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
899 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700900 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
Jack Palevich53f06582009-09-10 14:01:58 -0700901 mQ.popBack(2);
902 mQ.pushBack(combined);
903 didPeep = true;
904 }
905 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700906 }
907 }
908
909 // Constant array lookup
910
911 if (mQ.count() >= 6 &&
912 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
913 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
914 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
915 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
916 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
917 mQ[-1] == 0xe0810000) { // add r0, r1, r0
918 unsigned int mov1 = mQ[-5];
919 unsigned int mov2 = mQ[-3];
920 unsigned int const1 = decode12BitImmediate(mov1);
921 unsigned int const2 = decode12BitImmediate(mov2);
922 unsigned int comboConst = const1 * const2;
923 size_t immediate = 0;
924 if (encode12BitImmediate(comboConst, &immediate)) {
925 mQ.popBack(6);
926 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
927 if (comboConst) {
928 mQ.pushBack(add);
929 }
930 didPeep = true;
931 }
932 }
933
Jack Palevich53f06582009-09-10 14:01:58 -0700934 // Pointer arithmetic with a stride that is a power of two
935
936 if (mQ.count() >= 3 &&
Jack Palevich1c60e462009-09-18 15:03:03 -0700937 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
938 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
Jack Palevich53f06582009-09-10 14:01:58 -0700939 mQ[-1] == 0xe0810000) { // add r0, r1, r0
940 int stride = decode12BitImmediate(mQ[-3]);
941 if (isPowerOfTwo(stride)) {
942 mQ.popBack(3);
943 unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
944 mQ.pushBack(add);
945 didPeep = true;
946 }
947 }
948
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700949 } while (didPeep);
950#endif
951 }
952
953 void ob(int n) {
954 error("ob() not supported.");
955 }
956
957 void* getBase() {
958 flush();
959 return mpBase->getBase();
960 }
961
962 intptr_t getSize() {
963 flush();
964 return mpBase->getSize();
965 }
966
967 intptr_t getPC() {
968 flush();
969 return mpBase->getPC();
970 }
971 };
972
Jack Palevich22305132009-05-13 10:58:45 -0700973 class ARMCodeGenerator : public CodeGenerator {
974 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700975 ARMCodeGenerator() {
976#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700977 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700978#else
Jack Palevichd5315572009-09-09 13:19:34 -0700979 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700980#endif
981 }
-b master422972c2009-06-17 19:13:52 -0700982
Jack Palevich22305132009-05-13 10:58:45 -0700983 virtual ~ARMCodeGenerator() {}
984
985 /* returns address to patch with local variable size
986 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700987 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700988 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700989 // sp -> arg4 arg5 ...
990 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700991 int regArgCount = calcRegArgCount(pDecl);
992 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700993 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700994 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700995 }
996 // sp -> arg0 arg1 ...
997 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700998 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700999 // sp, fp -> oldfp, retadr, arg0 arg1 ....
1000 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -07001001 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001002 int pc = getPC();
1003 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -07001004 // We don't know how many local variables we are going to use,
1005 // but we will round the allocation up to a multiple of
1006 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001007 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001008 }
1009
Jack Palevichb7718b92009-07-09 22:00:24 -07001010 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -07001011 // Round local variable size up to a multiple of stack alignment
1012 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
1013 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -07001014 // Patch local variable allocation code:
1015 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -07001016 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -07001017 }
Jack Palevich69796b62009-05-14 15:42:26 -07001018 *(char*) (localVariableAddress) = localVariableSize;
1019
Jack Palevich30321cb2009-08-20 15:34:23 -07001020#ifdef ARM_USE_VFP
1021 {
Jack Palevichc0f25332009-08-25 12:23:43 -07001022 Type* pReturnType = pDecl->pHead;
1023 switch(pReturnType->tag) {
1024 case TY_FLOAT:
1025 o4(0xEE170A90); // fmrs r0, s15
1026 break;
1027 case TY_DOUBLE:
1028 o4(0xEC510B17); // fmrrd r0, r1, d7
1029 break;
1030 default:
1031 break;
1032 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001033 }
1034#endif
1035
Jack Palevich69796b62009-05-14 15:42:26 -07001036 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
1037 o4(0xE1A0E00B); // mov lr, fp
1038 o4(0xE59BB000); // ldr fp, [fp]
1039 o4(0xE28ED004); // add sp, lr, #4
1040 // sp -> retadr, arg0, ...
1041 o4(0xE8BD4000); // ldmfd sp!, {lr}
1042 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -07001043
1044 // We store the PC into the lr so we can adjust the sp before
1045 // returning. We need to pull off the registers we pushed
1046 // earlier. We don't need to actually store them anywhere,
1047 // just adjust the stack.
1048 int regArgCount = calcRegArgCount(pDecl);
1049 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -07001050 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
1051 }
1052 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -07001053 }
1054
1055 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001056 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001057 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001058 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001059 }
1060
Jack Palevich1a539db2009-07-08 13:04:41 -07001061 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001062 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001063 // Global, absolute address
1064 o4(0xE59F0000); // ldr r0, .L1
1065 o4(0xEA000000); // b .L99
1066 o4(address); // .L1: .word ea
1067 // .L99:
1068
1069 switch (pType->tag) {
1070 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001071#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001072 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001073#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001074 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001075#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001076 break;
1077 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001078#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001079 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001080#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001081 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001082#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001083 break;
1084 default:
1085 assert(false);
1086 break;
1087 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001088 }
1089
Jack Palevich9221bcc2009-08-26 16:15:07 -07001090
1091 virtual void addStructOffsetR0(int offset, Type* pType) {
1092 if (offset) {
1093 size_t immediate = 0;
1094 if (encode12BitImmediate(offset, &immediate)) {
1095 o4(0xE2800000 | immediate); // add r0, r0, #offset
1096 } else {
1097 error("structure offset out of range: %d", offset);
1098 }
1099 }
1100 setR0Type(pType, ET_LVALUE);
1101 }
1102
Jack Palevich22305132009-05-13 10:58:45 -07001103 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001104 int pc = getPC();
1105 o4(0xEA000000 | encodeAddress(t)); // b .L33
1106 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001107 }
1108
1109 /* l = 0: je, l == 1: jne */
1110 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001111 Type* pR0Type = getR0Type();
1112 TypeTag tagR0 = pR0Type->tag;
1113 switch(tagR0) {
1114 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001115#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001116 o4(0xEEF57A40); // fcmpzs s15
1117 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001118#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001119 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001120 o4(0xE3500000); // cmp r0,#0
1121#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001122 break;
1123 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001124#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001125 o4(0xEEB57B40); // fcmpzd d7
1126 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001127#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001128 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001129 o4(0xE3500000); // cmp r0,#0
1130#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001131 break;
1132 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001133 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001134 break;
1135 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001136 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001137 int pc = getPC();
1138 o4(branch | encodeAddress(t));
1139 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001140 }
1141
Jack Palevich58c30ee2009-07-17 16:35:23 -07001142 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001143 Type* pR0Type = getR0Type();
1144 Type* pTOSType = getTOSType();
1145 TypeTag tagR0 = collapseType(pR0Type->tag);
1146 TypeTag tagTOS = collapseType(pTOSType->tag);
1147 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001148 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 o4(0xE1510000); // cmp r1, r1
1150 switch(op) {
1151 case OP_EQUALS:
1152 o4(0x03A00001); // moveq r0,#1
1153 o4(0x13A00000); // movne r0,#0
1154 break;
1155 case OP_NOT_EQUALS:
1156 o4(0x03A00000); // moveq r0,#0
1157 o4(0x13A00001); // movne r0,#1
1158 break;
1159 case OP_LESS_EQUAL:
1160 o4(0xD3A00001); // movle r0,#1
1161 o4(0xC3A00000); // movgt r0,#0
1162 break;
1163 case OP_GREATER:
1164 o4(0xD3A00000); // movle r0,#0
1165 o4(0xC3A00001); // movgt r0,#1
1166 break;
1167 case OP_GREATER_EQUAL:
1168 o4(0xA3A00001); // movge r0,#1
1169 o4(0xB3A00000); // movlt r0,#0
1170 break;
1171 case OP_LESS:
1172 o4(0xA3A00000); // movge r0,#0
1173 o4(0xB3A00001); // movlt r0,#1
1174 break;
1175 default:
1176 error("Unknown comparison op %d", op);
1177 break;
1178 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001179 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1180 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001181#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001182 o4(0xEEB46BC7); // fcmped d6, d7
1183 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001184 switch(op) {
1185 case OP_EQUALS:
1186 o4(0x03A00001); // moveq r0,#1
1187 o4(0x13A00000); // movne r0,#0
1188 break;
1189 case OP_NOT_EQUALS:
1190 o4(0x03A00000); // moveq r0,#0
1191 o4(0x13A00001); // movne r0,#1
1192 break;
1193 case OP_LESS_EQUAL:
1194 o4(0xD3A00001); // movle r0,#1
1195 o4(0xC3A00000); // movgt r0,#0
1196 break;
1197 case OP_GREATER:
1198 o4(0xD3A00000); // movle r0,#0
1199 o4(0xC3A00001); // movgt r0,#1
1200 break;
1201 case OP_GREATER_EQUAL:
1202 o4(0xA3A00001); // movge r0,#1
1203 o4(0xB3A00000); // movlt r0,#0
1204 break;
1205 case OP_LESS:
1206 o4(0xA3A00000); // movge r0,#0
1207 o4(0xB3A00001); // movlt r0,#1
1208 break;
1209 default:
1210 error("Unknown comparison op %d", op);
1211 break;
1212 }
1213#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001214 switch(op) {
1215 case OP_EQUALS:
1216 callRuntime((void*) runtime_cmp_eq_dd);
1217 break;
1218 case OP_NOT_EQUALS:
1219 callRuntime((void*) runtime_cmp_ne_dd);
1220 break;
1221 case OP_LESS_EQUAL:
1222 callRuntime((void*) runtime_cmp_le_dd);
1223 break;
1224 case OP_GREATER:
1225 callRuntime((void*) runtime_cmp_gt_dd);
1226 break;
1227 case OP_GREATER_EQUAL:
1228 callRuntime((void*) runtime_cmp_ge_dd);
1229 break;
1230 case OP_LESS:
1231 callRuntime((void*) runtime_cmp_lt_dd);
1232 break;
1233 default:
1234 error("Unknown comparison op %d", op);
1235 break;
1236 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001237#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001238 } else {
1239 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001240#ifdef ARM_USE_VFP
1241 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001242 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001243 switch(op) {
1244 case OP_EQUALS:
1245 o4(0x03A00001); // moveq r0,#1
1246 o4(0x13A00000); // movne r0,#0
1247 break;
1248 case OP_NOT_EQUALS:
1249 o4(0x03A00000); // moveq r0,#0
1250 o4(0x13A00001); // movne r0,#1
1251 break;
1252 case OP_LESS_EQUAL:
1253 o4(0xD3A00001); // movle r0,#1
1254 o4(0xC3A00000); // movgt r0,#0
1255 break;
1256 case OP_GREATER:
1257 o4(0xD3A00000); // movle r0,#0
1258 o4(0xC3A00001); // movgt r0,#1
1259 break;
1260 case OP_GREATER_EQUAL:
1261 o4(0xA3A00001); // movge r0,#1
1262 o4(0xB3A00000); // movlt r0,#0
1263 break;
1264 case OP_LESS:
1265 o4(0xA3A00000); // movge r0,#0
1266 o4(0xB3A00001); // movlt r0,#1
1267 break;
1268 default:
1269 error("Unknown comparison op %d", op);
1270 break;
1271 }
1272#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001273 switch(op) {
1274 case OP_EQUALS:
1275 callRuntime((void*) runtime_cmp_eq_ff);
1276 break;
1277 case OP_NOT_EQUALS:
1278 callRuntime((void*) runtime_cmp_ne_ff);
1279 break;
1280 case OP_LESS_EQUAL:
1281 callRuntime((void*) runtime_cmp_le_ff);
1282 break;
1283 case OP_GREATER:
1284 callRuntime((void*) runtime_cmp_gt_ff);
1285 break;
1286 case OP_GREATER_EQUAL:
1287 callRuntime((void*) runtime_cmp_ge_ff);
1288 break;
1289 case OP_LESS:
1290 callRuntime((void*) runtime_cmp_lt_ff);
1291 break;
1292 default:
1293 error("Unknown comparison op %d", op);
1294 break;
1295 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001296#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001297 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001298 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001299 }
1300
Jack Palevich546b2242009-05-13 15:10:04 -07001301 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001302 Type* pR0Type = getR0Type();
1303 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001304 TypeTag tagR0 = pR0Type->tag;
1305 TypeTag tagTOS = pTOSType->tag;
1306 bool isFloatR0 = isFloatTag(tagR0);
1307 bool isFloatTOS = isFloatTag(tagTOS);
1308 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001309 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001310 bool isPtrR0 = isPointerTag(tagR0);
1311 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001312 if (isPtrR0 || isPtrTOS) {
1313 if (isPtrR0 && isPtrTOS) {
1314 if (op != OP_MINUS) {
1315 error("Unsupported pointer-pointer operation %d.", op);
1316 }
1317 if (! typeEqual(pR0Type, pTOSType)) {
1318 error("Incompatible pointer types for subtraction.");
1319 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001320 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001321 setR0Type(mkpInt);
1322 int size = sizeOf(pR0Type->pHead);
1323 if (size != 1) {
1324 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001325 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001326 // TODO: Optimize for power-of-two.
1327 genOp(OP_DIV);
1328 }
1329 } else {
1330 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1331 error("Unsupported pointer-scalar operation %d", op);
1332 }
Jack Palevichb6154502009-08-04 14:56:09 -07001333 Type* pPtrType = getPointerArithmeticResultType(
1334 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001335 int size = sizeOf(pPtrType->pHead);
1336 if (size != 1) {
1337 // TODO: Optimize for power-of-two.
1338 liReg(size, 2);
1339 if (isPtrR0) {
1340 o4(0x0E0010192); // mul r1,r2,r1
1341 } else {
1342 o4(0x0E0000092); // mul r0,r2,r0
1343 }
1344 }
1345 switch(op) {
1346 case OP_PLUS:
1347 o4(0xE0810000); // add r0,r1,r0
1348 break;
1349 case OP_MINUS:
1350 o4(0xE0410000); // sub r0,r1,r0
1351 break;
1352 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001353 setR0Type(pPtrType);
1354 }
1355 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001356 switch(op) {
1357 case OP_MUL:
1358 o4(0x0E0000091); // mul r0,r1,r0
1359 break;
1360 case OP_DIV:
1361 callRuntime((void*) runtime_DIV);
1362 break;
1363 case OP_MOD:
1364 callRuntime((void*) runtime_MOD);
1365 break;
1366 case OP_PLUS:
1367 o4(0xE0810000); // add r0,r1,r0
1368 break;
1369 case OP_MINUS:
1370 o4(0xE0410000); // sub r0,r1,r0
1371 break;
1372 case OP_SHIFT_LEFT:
1373 o4(0xE1A00011); // lsl r0,r1,r0
1374 break;
1375 case OP_SHIFT_RIGHT:
1376 o4(0xE1A00051); // asr r0,r1,r0
1377 break;
1378 case OP_BIT_AND:
1379 o4(0xE0010000); // and r0,r1,r0
1380 break;
1381 case OP_BIT_XOR:
1382 o4(0xE0210000); // eor r0,r1,r0
1383 break;
1384 case OP_BIT_OR:
1385 o4(0xE1810000); // orr r0,r1,r0
1386 break;
1387 case OP_BIT_NOT:
1388 o4(0xE1E00000); // mvn r0, r0
1389 break;
1390 default:
1391 error("Unimplemented op %d\n", op);
1392 break;
1393 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001394 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001395 } else {
1396 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1397 if (pResultType->tag == TY_DOUBLE) {
1398 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001399
Jack Palevichb7718b92009-07-09 22:00:24 -07001400 switch(op) {
1401 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001402#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001403 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001404#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001405 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001406#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001407 break;
1408 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001409#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001410 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001411#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001412 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001413#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001414 break;
1415 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001416#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001417 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001418#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001419 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001420#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001421 break;
1422 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001423#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001424 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001425#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001426 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001427#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001428 break;
1429 default:
1430 error("Unsupported binary floating operation %d\n", op);
1431 break;
1432 }
1433 } else {
1434 setupFloatArgs();
1435 switch(op) {
1436 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001437#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001438 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001439#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001440 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001441#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001442 break;
1443 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001444#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001445 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001446#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001447 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001448#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001449 break;
1450 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001451#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001452 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001453#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001454 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001455#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001456 break;
1457 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001458#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001459 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001460#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001461 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001462#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001463 break;
1464 default:
1465 error("Unsupported binary floating operation %d\n", op);
1466 break;
1467 }
1468 }
1469 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001470 }
Jack Palevich22305132009-05-13 10:58:45 -07001471 }
1472
Jack Palevich58c30ee2009-07-17 16:35:23 -07001473 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001474 if (op != OP_LOGICAL_NOT) {
1475 error("Unknown unary cmp %d", op);
1476 } else {
1477 Type* pR0Type = getR0Type();
1478 TypeTag tag = collapseType(pR0Type->tag);
1479 switch(tag) {
1480 case TY_INT:
1481 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001482 o4(0xE1510000); // cmp r1, r0
1483 o4(0x03A00001); // moveq r0,#1
1484 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001485 break;
1486 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001487#ifdef ARM_USE_VFP
1488 o4(0xEEF57A40); // fcmpzs s15
1489 o4(0xEEF1FA10); // fmstat
1490 o4(0x03A00001); // moveq r0,#1
1491 o4(0x13A00000); // movne r0,#0
1492#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001493 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001494#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001495 break;
1496 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001497#ifdef ARM_USE_VFP
1498 o4(0xEEB57B40); // fcmpzd d7
1499 o4(0xEEF1FA10); // fmstat
1500 o4(0x03A00001); // moveq r0,#1
1501 o4(0x13A00000); // movne r0,#0
1502#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001503 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001504#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001505 break;
1506 default:
1507 error("gUnaryCmp unsupported type");
1508 break;
1509 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001510 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001511 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001512 }
1513
1514 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001515 Type* pR0Type = getR0Type();
1516 TypeTag tag = collapseType(pR0Type->tag);
1517 switch(tag) {
1518 case TY_INT:
1519 switch(op) {
1520 case OP_MINUS:
1521 o4(0xE3A01000); // mov r1, #0
1522 o4(0xE0410000); // sub r0,r1,r0
1523 break;
1524 case OP_BIT_NOT:
1525 o4(0xE1E00000); // mvn r0, r0
1526 break;
1527 default:
1528 error("Unknown unary op %d\n", op);
1529 break;
1530 }
1531 break;
1532 case TY_FLOAT:
1533 case TY_DOUBLE:
1534 switch (op) {
1535 case OP_MINUS:
1536 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001537#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001538 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001539#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001540 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001541#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001542 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001543#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001544 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001545#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001546 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001547#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001548 }
1549 break;
1550 case OP_BIT_NOT:
1551 error("Can't apply '~' operator to a float or double.");
1552 break;
1553 default:
1554 error("Unknown unary op %d\n", op);
1555 break;
1556 }
1557 break;
1558 default:
1559 error("genUnaryOp unsupported type");
1560 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001561 }
Jack Palevich22305132009-05-13 10:58:45 -07001562 }
1563
Jack Palevich1cdef202009-05-22 12:06:27 -07001564 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001565 Type* pR0Type = getR0Type();
1566 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001567
1568#ifdef ARM_USE_VFP
1569 switch (r0ct ) {
1570 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001571 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001572 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001573 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001574 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001575 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001576 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001577 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001578 default:
1579 o4(0xE92D0001); // stmfd sp!,{r0}
1580 mStackUse += 4;
1581 }
1582#else
1583
Jack Palevichb7718b92009-07-09 22:00:24 -07001584 if (r0ct != TY_DOUBLE) {
1585 o4(0xE92D0001); // stmfd sp!,{r0}
1586 mStackUse += 4;
1587 } else {
1588 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1589 mStackUse += 8;
1590 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001591#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001592 pushType();
-b master422972c2009-06-17 19:13:52 -07001593 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001594 }
1595
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001596 virtual void over() {
1597 // We know it's only used for int-ptr ops (++/--)
1598
1599 Type* pR0Type = getR0Type();
1600 TypeTag r0ct = collapseType(pR0Type->tag);
1601
1602 Type* pTOSType = getTOSType();
1603 TypeTag tosct = collapseType(pTOSType->tag);
1604
1605 assert (r0ct == TY_INT && tosct == TY_INT);
1606
1607 o4(0xE8BD0002); // ldmfd sp!,{r1}
1608 o4(0xE92D0001); // stmfd sp!,{r0}
1609 o4(0xE92D0002); // stmfd sp!,{r1}
1610 overType();
1611 mStackUse += 4;
1612 }
1613
Jack Palevich58c30ee2009-07-17 16:35:23 -07001614 virtual void popR0() {
1615 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001616 TypeTag tosct = collapseType(pTOSType->tag);
1617#ifdef ARM_USE_VFP
1618 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001619 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001620 }
1621#endif
1622 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001623 case TY_INT:
1624 case TY_FLOAT:
1625 o4(0xE8BD0001); // ldmfd sp!,{r0}
1626 mStackUse -= 4;
1627 break;
1628 case TY_DOUBLE:
1629 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1630 mStackUse -= 8;
1631 break;
1632 default:
1633 error("Can't pop this type.");
1634 break;
1635 }
1636 popType();
1637 LOG_STACK("popR0: %d\n", mStackUse);
1638 }
1639
1640 virtual void storeR0ToTOS() {
1641 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001642 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001643 Type* pDestType = pPointerType->pHead;
1644 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001645 o4(0xE8BD0004); // ldmfd sp!,{r2}
1646 popType();
-b master422972c2009-06-17 19:13:52 -07001647 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001648 switch (pDestType->tag) {
1649 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001650 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001651 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001652 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001653 case TY_FLOAT:
1654#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001655 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001656#else
1657 o4(0xE5820000); // str r0, [r2]
1658#endif
1659 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001660 case TY_SHORT:
1661 o4(0xE1C200B0); // strh r0, [r2]
1662 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001663 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001664 o4(0xE5C20000); // strb r0, [r2]
1665 break;
1666 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001667#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001668 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001669#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001670 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001671#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001672 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001673 case TY_STRUCT:
1674 {
1675 int size = sizeOf(pDestType);
1676 if (size > 0) {
1677 liReg(size, 1);
1678 callRuntime((void*) runtime_structCopy);
1679 }
1680 }
1681 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001682 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001683 error("storeR0ToTOS: unimplemented type %d",
1684 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001685 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001686 }
Jack Palevich02effee2009-11-09 12:52:45 +08001687 setR0Type(pDestType);
Jack Palevich22305132009-05-13 10:58:45 -07001688 }
1689
Jack Palevich58c30ee2009-07-17 16:35:23 -07001690 virtual void loadR0FromR0() {
1691 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001692 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001693 Type* pNewType = pPointerType->pHead;
1694 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001695 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001696 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001697 case TY_INT:
1698 o4(0xE5900000); // ldr r0, [r0]
1699 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001700 case TY_FLOAT:
1701#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001702 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001703#else
1704 o4(0xE5900000); // ldr r0, [r0]
1705#endif
1706 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001707 case TY_SHORT:
1708 o4(0xE1D000F0); // ldrsh r0, [r0]
1709 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001710 case TY_CHAR:
1711 o4(0xE5D00000); // ldrb r0, [r0]
1712 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001713 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001714#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001715 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001716#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001717 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001718#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001719 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001720 case TY_ARRAY:
1721 pNewType = pNewType->pTail;
1722 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001723 case TY_STRUCT:
1724 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001725 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001726 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001727 break;
1728 }
Jack Palevich80e49722009-08-04 15:39:49 -07001729 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001730 }
1731
Jack Palevichb5e33312009-07-30 19:06:34 -07001732 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001733 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001734 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001735
1736 size_t immediate = 0;
1737 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001738 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001739 inRange = encode12BitImmediate(-ea, &immediate);
1740 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001741 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001742 inRange = encode12BitImmediate(ea, &immediate);
1743 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1744 }
1745 if (! inRange) {
1746 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001747 }
Jack Palevichbd894902009-05-14 19:35:31 -07001748 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001749 // Global, absolute.
1750 o4(0xE59F0000); // ldr r0, .L1
1751 o4(0xEA000000); // b .L99
1752 o4(ea); // .L1: .word 0
1753 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001754 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001755 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001756 }
1757
Jack Palevich9f51a262009-07-29 16:22:26 -07001758 virtual int leaForward(int ea, Type* pPointerType) {
1759 setR0Type(pPointerType);
1760 int result = ea;
1761 int pc = getPC();
1762 int offset = 0;
1763 if (ea) {
1764 offset = (pc - ea - 8) >> 2;
1765 if ((offset & 0xffff) != offset) {
1766 error("function forward reference out of bounds");
1767 }
1768 } else {
1769 offset = 0;
1770 }
1771 o4(0xE59F0000 | offset); // ldr r0, .L1
1772
1773 if (ea == 0) {
1774 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001775 result = getPC();
1776 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001777 // .L99:
1778 }
1779 return result;
1780 }
1781
Jack Palevichb6154502009-08-04 14:56:09 -07001782 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001783 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001784 if (isPointerType(pType) && isPointerType(pR0Type)) {
1785 Type* pA = pR0Type;
1786 Type* pB = pType;
1787 // Array decays to pointer
1788 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1789 pA = pA->pTail;
1790 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001791 if (! (typeEqual(pA, pB)
1792 || pB->pHead->tag == TY_VOID
1793 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1794 )) {
1795 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001796 }
Jack Palevichb6154502009-08-04 14:56:09 -07001797 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001798 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001799 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001800 TypeTag r0Tag = collapseType(pR0Type->tag);
1801 TypeTag destTag = collapseType(pType->tag);
1802 if (r0Tag == TY_INT) {
1803 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001804#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001805 o4(0xEE070A90); // fmsr s15, r0
1806 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001807
1808#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001809 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001810#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001811 } else {
1812 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001813#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001814 o4(0xEE070A90); // fmsr s15, r0
1815 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001816
1817#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001818 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001819#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001820 }
1821 } else if (r0Tag == TY_FLOAT) {
1822 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001823#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001824 o4(0xEEFD7AE7); // ftosizs s15, s15
1825 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001826#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001827 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001828#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001829 } else {
1830 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001831#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001832 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001833#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001834 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001835#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001836 }
1837 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001838 if (r0Tag == TY_DOUBLE) {
1839 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001840#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001841 o4(0xEEFD7BC7); // ftosizd s15, d7
1842 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001843#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001844 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001845#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001846 } else {
1847 if(destTag == TY_FLOAT) {
1848#ifdef ARM_USE_VFP
1849 o4(0xEEF77BC7); // fcvtsd s15, d7
1850#else
1851 callRuntime((void*) runtime_double_to_float);
1852#endif
1853 } else {
1854 incompatibleTypes(pR0Type, pType);
1855 }
1856 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001857 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001858 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001859 }
1860 }
Jack Palevich8df46192009-07-07 14:48:51 -07001861 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001862 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001863 }
1864
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001865 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001866 int pc = getPC();
1867 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1868 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001869 }
1870
Jack Palevich8148c5b2009-07-16 18:24:47 -07001871 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001872 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001873 Type* pR0Type = getR0Type();
1874 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001875#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001876 switch(r0ct) {
1877 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001878 if (l < 0 || l > 4096-4) {
1879 error("l out of range for stack offset: 0x%08x", l);
1880 }
1881 o4(0xE58D0000 | l); // str r0, [sp, #l]
1882 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001883 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001884 if (l < 0 || l > 1020 || (l & 3)) {
1885 error("l out of range for stack offset: 0x%08x", l);
1886 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001887 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001888 return 4;
1889 case TY_DOUBLE: {
1890 // Align to 8 byte boundary
1891 int l2 = (l + 7) & ~7;
1892 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1893 error("l out of range for stack offset: 0x%08x", l);
1894 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001895 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001896 return (l2 - l) + 8;
1897 }
1898 default:
1899 assert(false);
1900 return 0;
1901 }
1902#else
1903 switch(r0ct) {
1904 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001905 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001906 if (l < 0 || l > 4096-4) {
1907 error("l out of range for stack offset: 0x%08x", l);
1908 }
1909 o4(0xE58D0000 + l); // str r0, [sp, #l]
1910 return 4;
1911 case TY_DOUBLE: {
1912 // Align to 8 byte boundary
1913 int l2 = (l + 7) & ~7;
1914 if (l2 < 0 || l2 > 4096-8) {
1915 error("l out of range for stack offset: 0x%08x", l);
1916 }
1917 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1918 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1919 return (l2 - l) + 8;
1920 }
1921 default:
1922 assert(false);
1923 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001924 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001925#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001926 }
1927
Jack Palevichb7718b92009-07-09 22:00:24 -07001928 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001929 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001930 // Have to calculate register arg count from actual stack size,
1931 // in order to properly handle ... functions.
1932 int regArgCount = l >> 2;
1933 if (regArgCount > 4) {
1934 regArgCount = 4;
1935 }
1936 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001937 argumentStackUse -= regArgCount * 4;
1938 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1939 }
1940 mStackUse += argumentStackUse;
1941
1942 // Align stack.
1943 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1944 * STACK_ALIGNMENT);
1945 mStackAlignmentAdjustment = 0;
1946 if (missalignment > 0) {
1947 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1948 }
1949 l += mStackAlignmentAdjustment;
1950
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001951 if (l < 0 || l > 0x3FC) {
1952 error("L out of range for stack adjustment: 0x%08x", l);
1953 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001954 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001955 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001956 mStackUse += mStackAlignmentAdjustment;
1957 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1958 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001959 }
1960
Jack Palevich8df46192009-07-07 14:48:51 -07001961 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001962 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001963 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001964 int pc = getPC();
1965 o4(0xEB000000 | encodeAddress(symbol));
1966 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001967 }
1968
Jack Palevich8df46192009-07-07 14:48:51 -07001969 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001970 assert(pFunc->tag == TY_FUNC);
1971 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001972 int argCount = l >> 2;
1973 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001974 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001975 if (adjustedL < 0 || adjustedL > 4096-4) {
1976 error("l out of range for stack offset: 0x%08x", l);
1977 }
1978 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1979 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001980 Type* pReturnType = pFunc->pHead;
1981 setR0Type(pReturnType);
1982#ifdef ARM_USE_VFP
1983 switch(pReturnType->tag) {
1984 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001985 o4(0xEE070A90); // fmsr s15, r0
1986 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001987 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001988 o4(0xEC410B17); // fmdrr d7, r0, r1
1989 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001990 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001991 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001992 }
1993#endif
Jack Palevich22305132009-05-13 10:58:45 -07001994 }
1995
Jack Palevichb7718b92009-07-09 22:00:24 -07001996 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001997 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001998 // Have to calculate register arg count from actual stack size,
1999 // in order to properly handle ... functions.
2000 int regArgCount = l >> 2;
2001 if (regArgCount > 4) {
2002 regArgCount = 4;
2003 }
2004 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07002005 int stackUse = stackArgs + (isIndirect ? 1 : 0)
2006 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07002007 if (stackUse) {
2008 if (stackUse < 0 || stackUse > 255) {
2009 error("L out of range for stack adjustment: 0x%08x", l);
2010 }
2011 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07002012 mStackUse -= stackUse * 4;
2013 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002014 }
Jack Palevich22305132009-05-13 10:58:45 -07002015 }
2016
Jack Palevicha6535612009-05-13 16:24:17 -07002017 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07002018 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002019 }
2020
2021 /* output a symbol and patch all calls to it */
2022 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002023 int n;
2024 int base = getBase();
2025 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002026 while (t) {
2027 int data = * (int*) t;
2028 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2029 if (decodedOffset == 0) {
2030 n = 0;
2031 } else {
2032 n = base + decodedOffset; /* next value */
2033 }
2034 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2035 | encodeRelAddress(pc - t - 8);
2036 t = n;
2037 }
2038 }
2039
Jack Palevich9f51a262009-07-29 16:22:26 -07002040 /* output a symbol and patch all calls to it */
2041 virtual void resolveForward(int t) {
2042 if (t) {
2043 int pc = getPC();
2044 *(int *) t = pc;
2045 }
2046 }
2047
Jack Palevich1cdef202009-05-22 12:06:27 -07002048 virtual int finishCompile() {
2049#if defined(__arm__)
2050 const long base = long(getBase());
2051 const long curr = long(getPC());
2052 int err = cacheflush(base, curr, 0);
2053 return err;
2054#else
2055 return 0;
2056#endif
2057 }
2058
Jack Palevich9eed7a22009-07-06 17:24:34 -07002059 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002060 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002061 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002062 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002063 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002064 case TY_CHAR:
2065 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002066 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002067 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002068 case TY_DOUBLE:
2069 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002070 case TY_ARRAY:
2071 return alignmentOf(pType->pHead);
2072 case TY_STRUCT:
2073 return pType->pHead->alignment & 0x7fffffff;
2074 case TY_FUNC:
2075 error("alignment of func not supported");
2076 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002077 default:
2078 return 4;
2079 }
2080 }
2081
2082 /**
2083 * Array element alignment (in bytes) for this type of data.
2084 */
2085 virtual size_t sizeOf(Type* pType){
2086 switch(pType->tag) {
2087 case TY_INT:
2088 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002089 case TY_SHORT:
2090 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002091 case TY_CHAR:
2092 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002093 case TY_FLOAT:
2094 return 4;
2095 case TY_DOUBLE:
2096 return 8;
2097 case TY_POINTER:
2098 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002099 case TY_ARRAY:
2100 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002101 case TY_STRUCT:
2102 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002103 default:
2104 error("Unsupported type %d", pType->tag);
2105 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002106 }
2107 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002108
Jack Palevich22305132009-05-13 10:58:45 -07002109 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002110
2111 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2112
2113 /** Encode a relative address that might also be
2114 * a label.
2115 */
2116 int encodeAddress(int value) {
2117 int base = getBase();
2118 if (value >= base && value <= getPC() ) {
2119 // This is a label, encode it relative to the base.
2120 value = value - base;
2121 }
2122 return encodeRelAddress(value);
2123 }
2124
2125 int encodeRelAddress(int value) {
2126 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2127 }
Jack Palevich22305132009-05-13 10:58:45 -07002128
Jack Palevichb7718b92009-07-09 22:00:24 -07002129 int calcRegArgCount(Type* pDecl) {
2130 int reg = 0;
2131 Type* pArgs = pDecl->pTail;
2132 while (pArgs && reg < 4) {
2133 Type* pArg = pArgs->pHead;
2134 if ( pArg->tag == TY_DOUBLE) {
2135 int evenReg = (reg + 1) & ~1;
2136 if (evenReg >= 4) {
2137 break;
2138 }
2139 reg = evenReg + 2;
2140 } else {
2141 reg++;
2142 }
2143 pArgs = pArgs->pTail;
2144 }
2145 return reg;
2146 }
2147
Jack Palevich58c30ee2009-07-17 16:35:23 -07002148 void setupIntPtrArgs() {
2149 o4(0xE8BD0002); // ldmfd sp!,{r1}
2150 mStackUse -= 4;
2151 popType();
2152 }
2153
Jack Palevich30321cb2009-08-20 15:34:23 -07002154 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002155 * Make sure both R0 and TOS are floats. (Could be ints)
2156 * We know that at least one of R0 and TOS is already a float
2157 */
2158 void setupFloatArgs() {
2159 Type* pR0Type = getR0Type();
2160 Type* pTOSType = getTOSType();
2161 TypeTag tagR0 = collapseType(pR0Type->tag);
2162 TypeTag tagTOS = collapseType(pTOSType->tag);
2163 if (tagR0 != TY_FLOAT) {
2164 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002165#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002166 o4(0xEE070A90); // fmsr s15, r0
2167 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002168#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002169 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002170#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002171 }
2172 if (tagTOS != TY_FLOAT) {
2173 assert(tagTOS == TY_INT);
2174 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002175#ifdef ARM_USE_VFP
2176 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002177 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002178#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002179 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2180 o4(0xE59D0004); // ldr r0, [sp, #4]
2181 callRuntime((void*) runtime_int_to_float);
2182 o4(0xE1A01000); // mov r1, r0
2183 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2184 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002185#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002186 } else {
2187 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002188#ifdef ARM_USE_VFP
2189 o4(0xECBD7A01); // fldmfds sp!, {s14}
2190
2191#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002192 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002193#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002194 }
2195 mStackUse -= 4;
2196 popType();
2197 }
2198
Jack Palevich30321cb2009-08-20 15:34:23 -07002199 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002200 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2201 * We know that at least one of R0 and TOS are already a double.
2202 */
2203
2204 void setupDoubleArgs() {
2205 Type* pR0Type = getR0Type();
2206 Type* pTOSType = getTOSType();
2207 TypeTag tagR0 = collapseType(pR0Type->tag);
2208 TypeTag tagTOS = collapseType(pTOSType->tag);
2209 if (tagR0 != TY_DOUBLE) {
2210 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002211#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002212 o4(0xEE070A90); // fmsr s15, r0
2213 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002214
2215#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002216 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002217#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002218 } else {
2219 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002220#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002221 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002222#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002223 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002224#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002225 }
2226 }
2227 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002228#ifdef ARM_USE_VFP
2229 if (tagTOS == TY_INT) {
2230 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002231 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002232 } else {
2233 assert(tagTOS == TY_FLOAT);
2234 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002235 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002236 }
2237#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002238 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2239 o4(0xE59D0008); // ldr r0, [sp, #8]
2240 if (tagTOS == TY_INT) {
2241 callRuntime((void*) runtime_int_to_double);
2242 } else {
2243 assert(tagTOS == TY_FLOAT);
2244 callRuntime((void*) runtime_float_to_double);
2245 }
2246 o4(0xE1A02000); // mov r2, r0
2247 o4(0xE1A03001); // mov r3, r1
2248 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2249 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002250#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002251 mStackUse -= 4;
2252 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002253#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002254 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002255#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002256 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002257#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002258 mStackUse -= 8;
2259 }
2260 popType();
2261 }
2262
Jack Palevicha8f427f2009-07-13 18:40:08 -07002263 void liReg(int t, int reg) {
2264 assert(reg >= 0 && reg < 16);
2265 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002266 size_t encodedImmediate;
2267 if (encode12BitImmediate(t, &encodedImmediate)) {
2268 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2269 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002270 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002271 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002272 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002273 o4(0xE51F0000 | rN); // ldr rN, .L3
2274 o4(0xEA000000); // b .L99
2275 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002276 // .L99:
2277 }
2278 }
2279
Jack Palevichc408bbf2009-09-08 12:07:32 -07002280 void incompatibleTypes(Type* pR0Type, Type* pType) {
2281 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2282 }
2283
Jack Palevichb7718b92009-07-09 22:00:24 -07002284 void callRuntime(void* fn) {
2285 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002286 o4(0xEA000000); // b .L99
2287 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002288 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002289 }
2290
Jack Palevichb7718b92009-07-09 22:00:24 -07002291 // Integer math:
2292
2293 static int runtime_DIV(int b, int a) {
2294 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002295 }
2296
Jack Palevichb7718b92009-07-09 22:00:24 -07002297 static int runtime_MOD(int b, int a) {
2298 return a % b;
2299 }
2300
Jack Palevich9221bcc2009-08-26 16:15:07 -07002301 static void runtime_structCopy(void* src, size_t size, void* dest) {
2302 memcpy(dest, src, size);
2303 }
2304
Jack Palevich30321cb2009-08-20 15:34:23 -07002305#ifndef ARM_USE_VFP
2306
Jack Palevichb7718b92009-07-09 22:00:24 -07002307 // Comparison to zero
2308
2309 static int runtime_is_non_zero_f(float a) {
2310 return a != 0;
2311 }
2312
2313 static int runtime_is_non_zero_d(double a) {
2314 return a != 0;
2315 }
2316
2317 // Comparison to zero
2318
2319 static int runtime_is_zero_f(float a) {
2320 return a == 0;
2321 }
2322
2323 static int runtime_is_zero_d(double a) {
2324 return a == 0;
2325 }
2326
2327 // Type conversion
2328
2329 static int runtime_float_to_int(float a) {
2330 return (int) a;
2331 }
2332
2333 static double runtime_float_to_double(float a) {
2334 return (double) a;
2335 }
2336
2337 static int runtime_double_to_int(double a) {
2338 return (int) a;
2339 }
2340
2341 static float runtime_double_to_float(double a) {
2342 return (float) a;
2343 }
2344
2345 static float runtime_int_to_float(int a) {
2346 return (float) a;
2347 }
2348
2349 static double runtime_int_to_double(int a) {
2350 return (double) a;
2351 }
2352
2353 // Comparisons float
2354
2355 static int runtime_cmp_eq_ff(float b, float a) {
2356 return a == b;
2357 }
2358
2359 static int runtime_cmp_ne_ff(float b, float a) {
2360 return a != b;
2361 }
2362
2363 static int runtime_cmp_lt_ff(float b, float a) {
2364 return a < b;
2365 }
2366
2367 static int runtime_cmp_le_ff(float b, float a) {
2368 return a <= b;
2369 }
2370
2371 static int runtime_cmp_ge_ff(float b, float a) {
2372 return a >= b;
2373 }
2374
2375 static int runtime_cmp_gt_ff(float b, float a) {
2376 return a > b;
2377 }
2378
2379 // Comparisons double
2380
2381 static int runtime_cmp_eq_dd(double b, double a) {
2382 return a == b;
2383 }
2384
2385 static int runtime_cmp_ne_dd(double b, double a) {
2386 return a != b;
2387 }
2388
2389 static int runtime_cmp_lt_dd(double b, double a) {
2390 return a < b;
2391 }
2392
2393 static int runtime_cmp_le_dd(double b, double a) {
2394 return a <= b;
2395 }
2396
2397 static int runtime_cmp_ge_dd(double b, double a) {
2398 return a >= b;
2399 }
2400
2401 static int runtime_cmp_gt_dd(double b, double a) {
2402 return a > b;
2403 }
2404
2405 // Math float
2406
2407 static float runtime_op_add_ff(float b, float a) {
2408 return a + b;
2409 }
2410
2411 static float runtime_op_sub_ff(float b, float a) {
2412 return a - b;
2413 }
2414
2415 static float runtime_op_mul_ff(float b, float a) {
2416 return a * b;
2417 }
2418
2419 static float runtime_op_div_ff(float b, float a) {
2420 return a / b;
2421 }
2422
2423 static float runtime_op_neg_f(float a) {
2424 return -a;
2425 }
2426
2427 // Math double
2428
2429 static double runtime_op_add_dd(double b, double a) {
2430 return a + b;
2431 }
2432
2433 static double runtime_op_sub_dd(double b, double a) {
2434 return a - b;
2435 }
2436
2437 static double runtime_op_mul_dd(double b, double a) {
2438 return a * b;
2439 }
2440
2441 static double runtime_op_div_dd(double b, double a) {
2442 return a / b;
2443 }
2444
2445 static double runtime_op_neg_d(double a) {
2446 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002447 }
-b master422972c2009-06-17 19:13:52 -07002448
Jack Palevich30321cb2009-08-20 15:34:23 -07002449#endif
2450
-b master422972c2009-06-17 19:13:52 -07002451 static const int STACK_ALIGNMENT = 8;
2452 int mStackUse;
2453 // This variable holds the amount we adjusted the stack in the most
2454 // recent endFunctionCallArguments call. It's examined by the
2455 // following adjustStackAfterCall call.
2456 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002457 };
2458
Jack Palevich09555c72009-05-27 12:25:55 -07002459#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002460
2461#ifdef PROVIDE_X86_CODEGEN
2462
Jack Palevich21a15a22009-05-11 14:49:29 -07002463 class X86CodeGenerator : public CodeGenerator {
2464 public:
2465 X86CodeGenerator() {}
2466 virtual ~X86CodeGenerator() {}
2467
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002468 /* returns address to patch with local variable size
2469 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002470 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002471 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2472 return oad(0xec81, 0); /* sub $xxx, %esp */
2473 }
2474
Jack Palevichb7718b92009-07-09 22:00:24 -07002475 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002476 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002477 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002478 }
2479
Jack Palevich21a15a22009-05-11 14:49:29 -07002480 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002481 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002482 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002483 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002484 }
2485
Jack Palevich1a539db2009-07-08 13:04:41 -07002486 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002487 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002488 switch (pType->tag) {
2489 case TY_FLOAT:
2490 oad(0x05D9, address); // flds
2491 break;
2492 case TY_DOUBLE:
2493 oad(0x05DD, address); // fldl
2494 break;
2495 default:
2496 assert(false);
2497 break;
2498 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002499 }
2500
Jack Palevich9221bcc2009-08-26 16:15:07 -07002501 virtual void addStructOffsetR0(int offset, Type* pType) {
2502 if (offset) {
2503 oad(0x05, offset); // addl offset, %eax
2504 }
2505 setR0Type(pType, ET_LVALUE);
2506 }
2507
Jack Palevich22305132009-05-13 10:58:45 -07002508 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002509 return psym(0xe9, t);
2510 }
2511
2512 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002513 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002514 Type* pR0Type = getR0Type();
2515 TypeTag tagR0 = pR0Type->tag;
2516 bool isFloatR0 = isFloatTag(tagR0);
2517 if (isFloatR0) {
2518 o(0xeed9); // fldz
2519 o(0xe9da); // fucompp
2520 o(0xe0df); // fnstsw %ax
2521 o(0x9e); // sahf
2522 } else {
2523 o(0xc085); // test %eax, %eax
2524 }
2525 // Use two output statements to generate one instruction.
2526 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002527 return psym(0x84 + l, t);
2528 }
2529
Jack Palevich58c30ee2009-07-17 16:35:23 -07002530 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002531 Type* pR0Type = getR0Type();
2532 Type* pTOSType = getTOSType();
2533 TypeTag tagR0 = pR0Type->tag;
2534 TypeTag tagTOS = pTOSType->tag;
2535 bool isFloatR0 = isFloatTag(tagR0);
2536 bool isFloatTOS = isFloatTag(tagTOS);
2537 if (!isFloatR0 && !isFloatTOS) {
2538 int t = decodeOp(op);
2539 o(0x59); /* pop %ecx */
2540 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002541 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002542 o(0x0f); /* setxx %al */
2543 o(t + 0x90);
2544 o(0xc0);
2545 popType();
2546 } else {
2547 setupFloatOperands();
2548 switch (op) {
2549 case OP_EQUALS:
2550 o(0xe9da); // fucompp
2551 o(0xe0df); // fnstsw %ax
2552 o(0x9e); // sahf
2553 o(0xc0940f); // sete %al
2554 o(0xc29b0f); // setnp %dl
2555 o(0xd021); // andl %edx, %eax
2556 break;
2557 case OP_NOT_EQUALS:
2558 o(0xe9da); // fucompp
2559 o(0xe0df); // fnstsw %ax
2560 o(0x9e); // sahf
2561 o(0xc0950f); // setne %al
2562 o(0xc29a0f); // setp %dl
2563 o(0xd009); // orl %edx, %eax
2564 break;
2565 case OP_GREATER_EQUAL:
2566 o(0xe9da); // fucompp
2567 o(0xe0df); // fnstsw %ax
2568 o(0x05c4f6); // testb $5, %ah
2569 o(0xc0940f); // sete %al
2570 break;
2571 case OP_LESS:
2572 o(0xc9d9); // fxch %st(1)
2573 o(0xe9da); // fucompp
2574 o(0xe0df); // fnstsw %ax
2575 o(0x9e); // sahf
2576 o(0xc0970f); // seta %al
2577 break;
2578 case OP_LESS_EQUAL:
2579 o(0xc9d9); // fxch %st(1)
2580 o(0xe9da); // fucompp
2581 o(0xe0df); // fnstsw %ax
2582 o(0x9e); // sahf
2583 o(0xc0930f); // setea %al
2584 break;
2585 case OP_GREATER:
2586 o(0xe9da); // fucompp
2587 o(0xe0df); // fnstsw %ax
2588 o(0x45c4f6); // testb $69, %ah
2589 o(0xc0940f); // sete %al
2590 break;
2591 default:
2592 error("Unknown comparison op");
2593 }
2594 o(0xc0b60f); // movzbl %al, %eax
2595 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002596 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002597 }
2598
Jack Palevich546b2242009-05-13 15:10:04 -07002599 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002600 Type* pR0Type = getR0Type();
2601 Type* pTOSType = getTOSType();
2602 TypeTag tagR0 = pR0Type->tag;
2603 TypeTag tagTOS = pTOSType->tag;
2604 bool isFloatR0 = isFloatTag(tagR0);
2605 bool isFloatTOS = isFloatTag(tagTOS);
2606 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002607 bool isPtrR0 = isPointerTag(tagR0);
2608 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002609 if (isPtrR0 || isPtrTOS) {
2610 if (isPtrR0 && isPtrTOS) {
2611 if (op != OP_MINUS) {
2612 error("Unsupported pointer-pointer operation %d.", op);
2613 }
2614 if (! typeEqual(pR0Type, pTOSType)) {
2615 error("Incompatible pointer types for subtraction.");
2616 }
2617 o(0x59); /* pop %ecx */
2618 o(decodeOp(op));
2619 popType();
2620 setR0Type(mkpInt);
2621 int size = sizeOf(pR0Type->pHead);
2622 if (size != 1) {
2623 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002624 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002625 // TODO: Optimize for power-of-two.
2626 genOp(OP_DIV);
2627 }
2628 } else {
2629 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2630 error("Unsupported pointer-scalar operation %d", op);
2631 }
Jack Palevichb6154502009-08-04 14:56:09 -07002632 Type* pPtrType = getPointerArithmeticResultType(
2633 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002634 o(0x59); /* pop %ecx */
2635 int size = sizeOf(pPtrType->pHead);
2636 if (size != 1) {
2637 // TODO: Optimize for power-of-two.
2638 if (isPtrR0) {
2639 oad(0xC969, size); // imull $size, %ecx
2640 } else {
2641 oad(0xC069, size); // mul $size, %eax
2642 }
2643 }
2644 o(decodeOp(op));
2645 popType();
2646 setR0Type(pPtrType);
2647 }
2648 } else {
2649 o(0x59); /* pop %ecx */
2650 o(decodeOp(op));
2651 if (op == OP_MOD)
2652 o(0x92); /* xchg %edx, %eax */
2653 popType();
2654 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002655 } else {
2656 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2657 setupFloatOperands();
2658 // Both float. x87 R0 == left hand, x87 R1 == right hand
2659 switch (op) {
2660 case OP_MUL:
2661 o(0xc9de); // fmulp
2662 break;
2663 case OP_DIV:
2664 o(0xf1de); // fdivp
2665 break;
2666 case OP_PLUS:
2667 o(0xc1de); // faddp
2668 break;
2669 case OP_MINUS:
2670 o(0xe1de); // fsubp
2671 break;
2672 default:
2673 error("Unsupported binary floating operation.");
2674 break;
2675 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002676 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002677 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002678 }
2679
Jack Palevich58c30ee2009-07-17 16:35:23 -07002680 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002681 if (op != OP_LOGICAL_NOT) {
2682 error("Unknown unary cmp %d", op);
2683 } else {
2684 Type* pR0Type = getR0Type();
2685 TypeTag tag = collapseType(pR0Type->tag);
2686 switch(tag) {
2687 case TY_INT: {
2688 oad(0xb9, 0); /* movl $0, %ecx */
2689 int t = decodeOp(op);
2690 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002691 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002692 o(0x0f); /* setxx %al */
2693 o(t + 0x90);
2694 o(0xc0);
2695 }
2696 break;
2697 case TY_FLOAT:
2698 case TY_DOUBLE:
2699 o(0xeed9); // fldz
2700 o(0xe9da); // fucompp
2701 o(0xe0df); // fnstsw %ax
2702 o(0x9e); // sahf
2703 o(0xc0950f); // setne %al
2704 o(0xc29a0f); // setp %dl
2705 o(0xd009); // orl %edx, %eax
2706 o(0xc0b60f); // movzbl %al, %eax
2707 o(0x01f083); // xorl $1, %eax
2708 break;
2709 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002710 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002711 break;
2712 }
2713 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002714 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002715 }
2716
2717 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002718 Type* pR0Type = getR0Type();
2719 TypeTag tag = collapseType(pR0Type->tag);
2720 switch(tag) {
2721 case TY_INT:
2722 oad(0xb9, 0); /* movl $0, %ecx */
2723 o(decodeOp(op));
2724 break;
2725 case TY_FLOAT:
2726 case TY_DOUBLE:
2727 switch (op) {
2728 case OP_MINUS:
2729 o(0xe0d9); // fchs
2730 break;
2731 case OP_BIT_NOT:
2732 error("Can't apply '~' operator to a float or double.");
2733 break;
2734 default:
2735 error("Unknown unary op %d\n", op);
2736 break;
2737 }
2738 break;
2739 default:
2740 error("genUnaryOp unsupported type");
2741 break;
2742 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002743 }
2744
Jack Palevich1cdef202009-05-22 12:06:27 -07002745 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002746 Type* pR0Type = getR0Type();
2747 TypeTag r0ct = collapseType(pR0Type->tag);
2748 switch(r0ct) {
2749 case TY_INT:
2750 o(0x50); /* push %eax */
2751 break;
2752 case TY_FLOAT:
2753 o(0x50); /* push %eax */
2754 o(0x241cd9); // fstps 0(%esp)
2755 break;
2756 case TY_DOUBLE:
2757 o(0x50); /* push %eax */
2758 o(0x50); /* push %eax */
2759 o(0x241cdd); // fstpl 0(%esp)
2760 break;
2761 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002762 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002763 break;
2764 }
Jack Palevich8df46192009-07-07 14:48:51 -07002765 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002766 }
2767
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002768 virtual void over() {
2769 // We know it's only used for int-ptr ops (++/--)
2770
2771 Type* pR0Type = getR0Type();
2772 TypeTag r0ct = collapseType(pR0Type->tag);
2773
2774 Type* pTOSType = getTOSType();
2775 TypeTag tosct = collapseType(pTOSType->tag);
2776
2777 assert (r0ct == TY_INT && tosct == TY_INT);
2778
2779 o(0x59); /* pop %ecx */
2780 o(0x50); /* push %eax */
2781 o(0x51); /* push %ecx */
2782
2783 overType();
2784 }
2785
Jack Palevich58c30ee2009-07-17 16:35:23 -07002786 virtual void popR0() {
2787 Type* pR0Type = getR0Type();
2788 TypeTag r0ct = collapseType(pR0Type->tag);
2789 switch(r0ct) {
2790 case TY_INT:
2791 o(0x58); /* popl %eax */
2792 break;
2793 case TY_FLOAT:
2794 o(0x2404d9); // flds (%esp)
2795 o(0x58); /* popl %eax */
2796 break;
2797 case TY_DOUBLE:
2798 o(0x2404dd); // fldl (%esp)
2799 o(0x58); /* popl %eax */
2800 o(0x58); /* popl %eax */
2801 break;
2802 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002803 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002804 break;
2805 }
2806 popType();
2807 }
2808
2809 virtual void storeR0ToTOS() {
2810 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002811 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002812 Type* pTargetType = pPointerType->pHead;
2813 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002814 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002815 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002816 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002817 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002818 case TY_INT:
2819 o(0x0189); /* movl %eax/%al, (%ecx) */
2820 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002821 case TY_SHORT:
2822 o(0x018966); /* movw %ax, (%ecx) */
2823 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002824 case TY_CHAR:
2825 o(0x0188); /* movl %eax/%al, (%ecx) */
2826 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002827 case TY_FLOAT:
2828 o(0x19d9); /* fstps (%ecx) */
2829 break;
2830 case TY_DOUBLE:
2831 o(0x19dd); /* fstpl (%ecx) */
2832 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002833 case TY_STRUCT:
2834 {
2835 // TODO: use alignment information to use movsw/movsl instead of movsb
2836 int size = sizeOf(pTargetType);
2837 if (size > 0) {
2838 o(0x9c); // pushf
2839 o(0x57); // pushl %edi
2840 o(0x56); // pushl %esi
2841 o(0xcf89); // movl %ecx, %edi
2842 o(0xc689); // movl %eax, %esi
2843 oad(0xb9, size); // mov #size, %ecx
2844 o(0xfc); // cld
2845 o(0xf3); // rep
2846 o(0xa4); // movsb
2847 o(0x5e); // popl %esi
2848 o(0x5f); // popl %edi
2849 o(0x9d); // popf
2850 }
2851 }
2852 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002853 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002854 error("storeR0ToTOS: unsupported type %d",
2855 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002856 break;
2857 }
Jack Palevich02effee2009-11-09 12:52:45 +08002858 setR0Type(pTargetType);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002859 }
2860
Jack Palevich58c30ee2009-07-17 16:35:23 -07002861 virtual void loadR0FromR0() {
2862 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002863 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002864 Type* pNewType = pPointerType->pHead;
2865 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002866 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002867 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002868 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002869 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002870 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002871 case TY_SHORT:
2872 o(0xbf0f); /* movswl (%eax), %eax */
2873 ob(0);
2874 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002875 case TY_CHAR:
2876 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002877 ob(0); /* add zero in code */
2878 break;
2879 case TY_FLOAT:
2880 o2(0x00d9); // flds (%eax)
2881 break;
2882 case TY_DOUBLE:
2883 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002884 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002885 case TY_ARRAY:
2886 pNewType = pNewType->pTail;
2887 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002888 case TY_STRUCT:
2889 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002890 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002891 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002892 break;
2893 }
Jack Palevich80e49722009-08-04 15:39:49 -07002894 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002895 }
2896
Jack Palevichb5e33312009-07-30 19:06:34 -07002897 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002898 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002899 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002900 }
2901
Jack Palevich9f51a262009-07-29 16:22:26 -07002902 virtual int leaForward(int ea, Type* pPointerType) {
2903 oad(0xb8, ea); /* mov $xx, %eax */
2904 setR0Type(pPointerType);
2905 return getPC() - 4;
2906 }
2907
Jack Palevichb6154502009-08-04 14:56:09 -07002908 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002909 Type* pR0Type = getR0Type();
2910 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002911 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002912 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002913 return;
2914 }
Jack Palevichb6154502009-08-04 14:56:09 -07002915 if (isPointerType(pType) && isPointerType(pR0Type)) {
2916 Type* pA = pR0Type;
2917 Type* pB = pType;
2918 // Array decays to pointer
2919 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2920 pA = pA->pTail;
2921 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002922 if (! (typeEqual(pA, pB)
2923 || pB->pHead->tag == TY_VOID
2924 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2925 )) {
2926 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002927 }
Jack Palevichb6154502009-08-04 14:56:09 -07002928 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002929 // do nothing special
2930 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2931 // do nothing special, both held in same register on x87.
2932 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002933 TypeTag r0Tag = collapseType(pR0Type->tag);
2934 TypeTag destTag = collapseType(pType->tag);
2935 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2936 // Convert R0 from int to float
2937 o(0x50); // push %eax
2938 o(0x2404DB); // fildl 0(%esp)
2939 o(0x58); // pop %eax
2940 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2941 // Convert R0 from float to int. Complicated because
2942 // need to save and restore the rounding mode.
2943 o(0x50); // push %eax
2944 o(0x50); // push %eax
2945 o(0x02247cD9); // fnstcw 2(%esp)
2946 o(0x2444b70f); // movzwl 2(%esp), %eax
2947 o(0x02);
2948 o(0x0cb4); // movb $12, %ah
2949 o(0x24048966); // movw %ax, 0(%esp)
2950 o(0x242cd9); // fldcw 0(%esp)
2951 o(0x04245cdb); // fistpl 4(%esp)
2952 o(0x02246cd9); // fldcw 2(%esp)
2953 o(0x58); // pop %eax
2954 o(0x58); // pop %eax
2955 } else {
2956 error("Incompatible types old: %d new: %d",
2957 pR0Type->tag, pType->tag);
2958 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002959 }
2960 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002961 }
2962
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002963 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002964 return oad(0xec81, 0); /* sub $xxx, %esp */
2965 }
2966
Jack Palevich8148c5b2009-07-16 18:24:47 -07002967 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2968 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002969 Type* pR0Type = getR0Type();
2970 TypeTag r0ct = collapseType(pR0Type->tag);
2971 switch(r0ct) {
2972 case TY_INT:
2973 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2974 return 4;
2975 case TY_FLOAT:
2976 oad(0x249CD9, l); /* fstps xxx(%esp) */
2977 return 4;
2978 case TY_DOUBLE:
2979 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2980 return 8;
2981 default:
2982 assert(false);
2983 return 0;
2984 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002985 }
2986
Jack Palevichb7718b92009-07-09 22:00:24 -07002987 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002988 * (int*) a = l;
2989 }
2990
Jack Palevich8df46192009-07-07 14:48:51 -07002991 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002992 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002993 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002994 return psym(0xe8, symbol); /* call xxx */
2995 }
2996
Jack Palevich8df46192009-07-07 14:48:51 -07002997 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002998 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002999 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07003000 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07003001 oad(0x2494ff, l); /* call *xxx(%esp) */
3002 }
3003
Jack Palevichb7718b92009-07-09 22:00:24 -07003004 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003005 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07003006 if (isIndirect) {
3007 l += 4;
3008 }
-b master422972c2009-06-17 19:13:52 -07003009 if (l > 0) {
3010 oad(0xc481, l); /* add $xxx, %esp */
3011 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003012 }
3013
Jack Palevicha6535612009-05-13 16:24:17 -07003014 virtual int jumpOffset() {
3015 return 5;
3016 }
3017
Jack Paleviche7b59062009-05-19 17:12:17 -07003018 /* output a symbol and patch all calls to it */
3019 virtual void gsym(int t) {
3020 int n;
3021 int pc = getPC();
3022 while (t) {
3023 n = *(int *) t; /* next value */
3024 *(int *) t = pc - t - 4;
3025 t = n;
3026 }
3027 }
3028
Jack Palevich9f51a262009-07-29 16:22:26 -07003029 /* output a symbol and patch all calls to it, using absolute address */
3030 virtual void resolveForward(int t) {
3031 int n;
3032 int pc = getPC();
3033 while (t) {
3034 n = *(int *) t; /* next value */
3035 *(int *) t = pc;
3036 t = n;
3037 }
3038 }
3039
Jack Palevich1cdef202009-05-22 12:06:27 -07003040 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003041 size_t pagesize = 4096;
3042 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3043 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3044 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3045 if (err) {
3046 error("mprotect() failed: %d", errno);
3047 }
3048 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003049 }
3050
Jack Palevich9eed7a22009-07-06 17:24:34 -07003051 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003052 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003053 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003054 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003055 switch (pType->tag) {
3056 case TY_CHAR:
3057 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003058 case TY_SHORT:
3059 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003060 case TY_ARRAY:
3061 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003062 case TY_STRUCT:
3063 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003064 case TY_FUNC:
3065 error("alignment of func not supported");
3066 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003067 default:
3068 return 4;
3069 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003070 }
3071
3072 /**
3073 * Array element alignment (in bytes) for this type of data.
3074 */
3075 virtual size_t sizeOf(Type* pType){
3076 switch(pType->tag) {
3077 case TY_INT:
3078 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003079 case TY_SHORT:
3080 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003081 case TY_CHAR:
3082 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003083 case TY_FLOAT:
3084 return 4;
3085 case TY_DOUBLE:
3086 return 8;
3087 case TY_POINTER:
3088 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003089 case TY_ARRAY:
3090 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003091 case TY_STRUCT:
3092 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003093 default:
3094 error("Unsupported type %d", pType->tag);
3095 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003096 }
3097 }
3098
Jack Palevich21a15a22009-05-11 14:49:29 -07003099 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003100
3101 /** Output 1 to 4 bytes.
3102 *
3103 */
3104 void o(int n) {
3105 /* cannot use unsigned, so we must do a hack */
3106 while (n && n != -1) {
3107 ob(n & 0xff);
3108 n = n >> 8;
3109 }
3110 }
3111
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003112 /* Output exactly 2 bytes
3113 */
3114 void o2(int n) {
3115 ob(n & 0xff);
3116 ob(0xff & (n >> 8));
3117 }
3118
Jack Paleviche7b59062009-05-19 17:12:17 -07003119 /* psym is used to put an instruction with a data field which is a
3120 reference to a symbol. It is in fact the same as oad ! */
3121 int psym(int n, int t) {
3122 return oad(n, t);
3123 }
3124
3125 /* instruction + address */
3126 int oad(int n, int t) {
3127 o(n);
3128 int result = getPC();
3129 o4(t);
3130 return result;
3131 }
3132
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003133 static const int operatorHelper[];
3134
3135 int decodeOp(int op) {
3136 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003137 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003138 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003139 }
3140 return operatorHelper[op];
3141 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003142
Jack Palevich546b2242009-05-13 15:10:04 -07003143 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003144 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003145 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003146 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003147
3148 void setupFloatOperands() {
3149 Type* pR0Type = getR0Type();
3150 Type* pTOSType = getTOSType();
3151 TypeTag tagR0 = pR0Type->tag;
3152 TypeTag tagTOS = pTOSType->tag;
3153 bool isFloatR0 = isFloatTag(tagR0);
3154 bool isFloatTOS = isFloatTag(tagTOS);
3155 if (! isFloatR0) {
3156 // Convert R0 from int to float
3157 o(0x50); // push %eax
3158 o(0x2404DB); // fildl 0(%esp)
3159 o(0x58); // pop %eax
3160 }
3161 if (! isFloatTOS){
3162 o(0x2404DB); // fildl 0(%esp);
3163 o(0x58); // pop %eax
3164 } else {
3165 if (tagTOS == TY_FLOAT) {
3166 o(0x2404d9); // flds (%esp)
3167 o(0x58); // pop %eax
3168 } else {
3169 o(0x2404dd); // fldl (%esp)
3170 o(0x58); // pop %eax
3171 o(0x58); // pop %eax
3172 }
3173 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003174 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003175 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003176 };
3177
Jack Paleviche7b59062009-05-19 17:12:17 -07003178#endif // PROVIDE_X86_CODEGEN
3179
Jack Palevichb67b18f2009-06-11 21:12:23 -07003180#ifdef PROVIDE_TRACE_CODEGEN
3181 class TraceCodeGenerator : public CodeGenerator {
3182 private:
3183 CodeGenerator* mpBase;
3184
3185 public:
3186 TraceCodeGenerator(CodeGenerator* pBase) {
3187 mpBase = pBase;
3188 }
3189
3190 virtual ~TraceCodeGenerator() {
3191 delete mpBase;
3192 }
3193
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003194 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003195 mpBase->init(pCodeBuf);
3196 }
3197
3198 void setErrorSink(ErrorSink* pErrorSink) {
3199 mpBase->setErrorSink(pErrorSink);
3200 }
3201
3202 /* returns address to patch with local variable size
3203 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003204 virtual int functionEntry(Type* pDecl) {
3205 int result = mpBase->functionEntry(pDecl);
3206 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003207 return result;
3208 }
3209
Jack Palevichb7718b92009-07-09 22:00:24 -07003210 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3211 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3212 localVariableAddress, localVariableSize);
3213 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003214 }
3215
3216 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003217 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003218 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003219 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003220 }
3221
Jack Palevich1a539db2009-07-08 13:04:41 -07003222 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003223 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003224 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003225 }
3226
Jack Palevich9221bcc2009-08-26 16:15:07 -07003227 virtual void addStructOffsetR0(int offset, Type* pType) {
3228 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3229 mpBase->addStructOffsetR0(offset, pType);
3230 }
3231
Jack Palevichb67b18f2009-06-11 21:12:23 -07003232 virtual int gjmp(int t) {
3233 int result = mpBase->gjmp(t);
3234 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3235 return result;
3236 }
3237
3238 /* l = 0: je, l == 1: jne */
3239 virtual int gtst(bool l, int t) {
3240 int result = mpBase->gtst(l, t);
3241 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3242 return result;
3243 }
3244
Jack Palevich58c30ee2009-07-17 16:35:23 -07003245 virtual void gcmp(int op) {
3246 fprintf(stderr, "gcmp(%d)\n", op);
3247 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003248 }
3249
3250 virtual void genOp(int op) {
3251 fprintf(stderr, "genOp(%d)\n", op);
3252 mpBase->genOp(op);
3253 }
3254
Jack Palevich9eed7a22009-07-06 17:24:34 -07003255
Jack Palevich58c30ee2009-07-17 16:35:23 -07003256 virtual void gUnaryCmp(int op) {
3257 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3258 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003259 }
3260
3261 virtual void genUnaryOp(int op) {
3262 fprintf(stderr, "genUnaryOp(%d)\n", op);
3263 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003264 }
3265
3266 virtual void pushR0() {
3267 fprintf(stderr, "pushR0()\n");
3268 mpBase->pushR0();
3269 }
3270
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003271 virtual void over() {
3272 fprintf(stderr, "over()\n");
3273 mpBase->over();
3274 }
3275
Jack Palevich58c30ee2009-07-17 16:35:23 -07003276 virtual void popR0() {
3277 fprintf(stderr, "popR0()\n");
3278 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003279 }
3280
Jack Palevich58c30ee2009-07-17 16:35:23 -07003281 virtual void storeR0ToTOS() {
3282 fprintf(stderr, "storeR0ToTOS()\n");
3283 mpBase->storeR0ToTOS();
3284 }
3285
3286 virtual void loadR0FromR0() {
3287 fprintf(stderr, "loadR0FromR0()\n");
3288 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003289 }
3290
Jack Palevichb5e33312009-07-30 19:06:34 -07003291 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3292 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3293 pPointerType->pHead->tag, et);
3294 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003295 }
3296
Jack Palevich9f51a262009-07-29 16:22:26 -07003297 virtual int leaForward(int ea, Type* pPointerType) {
3298 fprintf(stderr, "leaForward(%d)\n", ea);
3299 return mpBase->leaForward(ea, pPointerType);
3300 }
3301
Jack Palevich30321cb2009-08-20 15:34:23 -07003302 virtual void convertR0Imp(Type* pType, bool isCast){
3303 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3304 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003305 }
3306
3307 virtual int beginFunctionCallArguments() {
3308 int result = mpBase->beginFunctionCallArguments();
3309 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3310 return result;
3311 }
3312
Jack Palevich8148c5b2009-07-16 18:24:47 -07003313 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3314 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3315 pArgType->tag);
3316 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003317 }
3318
Jack Palevichb7718b92009-07-09 22:00:24 -07003319 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003320 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003321 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003322 }
3323
Jack Palevich8df46192009-07-07 14:48:51 -07003324 virtual int callForward(int symbol, Type* pFunc) {
3325 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003326 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3327 return result;
3328 }
3329
Jack Palevich8df46192009-07-07 14:48:51 -07003330 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003331 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3332 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003333 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003334 }
3335
Jack Palevichb7718b92009-07-09 22:00:24 -07003336 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3337 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3338 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003339 }
3340
3341 virtual int jumpOffset() {
3342 return mpBase->jumpOffset();
3343 }
3344
Jack Palevichb67b18f2009-06-11 21:12:23 -07003345 /* output a symbol and patch all calls to it */
3346 virtual void gsym(int t) {
3347 fprintf(stderr, "gsym(%d)\n", t);
3348 mpBase->gsym(t);
3349 }
3350
Jack Palevich9f51a262009-07-29 16:22:26 -07003351 virtual void resolveForward(int t) {
3352 mpBase->resolveForward(t);
3353 }
3354
Jack Palevichb67b18f2009-06-11 21:12:23 -07003355 virtual int finishCompile() {
3356 int result = mpBase->finishCompile();
3357 fprintf(stderr, "finishCompile() = %d\n", result);
3358 return result;
3359 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003360
3361 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003362 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003363 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003364 virtual size_t alignmentOf(Type* pType){
3365 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003366 }
3367
3368 /**
3369 * Array element alignment (in bytes) for this type of data.
3370 */
3371 virtual size_t sizeOf(Type* pType){
3372 return mpBase->sizeOf(pType);
3373 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003374
3375 virtual Type* getR0Type() {
3376 return mpBase->getR0Type();
3377 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003378
3379 virtual ExpressionType getR0ExpressionType() {
3380 return mpBase->getR0ExpressionType();
3381 }
3382
3383 virtual void setR0ExpressionType(ExpressionType et) {
3384 mpBase->setR0ExpressionType(et);
3385 }
3386
3387 virtual size_t getExpressionStackDepth() {
3388 return mpBase->getExpressionStackDepth();
3389 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003390
3391 virtual void forceR0RVal() {
3392 return mpBase->forceR0RVal();
3393 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003394 };
3395
3396#endif // PROVIDE_TRACE_CODEGEN
3397
Jack Palevich569f1352009-06-29 14:29:08 -07003398 class Arena {
3399 public:
3400 // Used to record a given allocation amount.
3401 // Used:
3402 // Mark mark = arena.mark();
3403 // ... lots of arena.allocate()
3404 // arena.free(mark);
3405
3406 struct Mark {
3407 size_t chunk;
3408 size_t offset;
3409 };
3410
3411 Arena() {
3412 mCurrentChunk = 0;
3413 Chunk start(CHUNK_SIZE);
3414 mData.push_back(start);
3415 }
3416
3417 ~Arena() {
3418 for(size_t i = 0; i < mData.size(); i++) {
3419 mData[i].free();
3420 }
3421 }
3422
3423 // Alloc using the standard alignment size safe for any variable
3424 void* alloc(size_t size) {
3425 return alloc(size, 8);
3426 }
3427
3428 Mark mark(){
3429 Mark result;
3430 result.chunk = mCurrentChunk;
3431 result.offset = mData[mCurrentChunk].mOffset;
3432 return result;
3433 }
3434
3435 void freeToMark(const Mark& mark) {
3436 mCurrentChunk = mark.chunk;
3437 mData[mCurrentChunk].mOffset = mark.offset;
3438 }
3439
3440 private:
3441 // Allocate memory aligned to a given size
3442 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3443 // Memory is not zero filled.
3444
3445 void* alloc(size_t size, size_t alignment) {
3446 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3447 if (mCurrentChunk + 1 < mData.size()) {
3448 mCurrentChunk++;
3449 } else {
3450 size_t allocSize = CHUNK_SIZE;
3451 if (allocSize < size + alignment - 1) {
3452 allocSize = size + alignment - 1;
3453 }
3454 Chunk chunk(allocSize);
3455 mData.push_back(chunk);
3456 mCurrentChunk++;
3457 }
3458 }
3459 return mData[mCurrentChunk].allocate(size, alignment);
3460 }
3461
3462 static const size_t CHUNK_SIZE = 128*1024;
3463 // Note: this class does not deallocate its
3464 // memory when it's destroyed. It depends upon
3465 // its parent to deallocate the memory.
3466 struct Chunk {
3467 Chunk() {
3468 mpData = 0;
3469 mSize = 0;
3470 mOffset = 0;
3471 }
3472
3473 Chunk(size_t size) {
3474 mSize = size;
3475 mpData = (char*) malloc(size);
3476 mOffset = 0;
3477 }
3478
3479 ~Chunk() {
3480 // Doesn't deallocate memory.
3481 }
3482
3483 void* allocate(size_t size, size_t alignment) {
3484 size_t alignedOffset = aligned(mOffset, alignment);
3485 void* result = mpData + alignedOffset;
3486 mOffset = alignedOffset + size;
3487 return result;
3488 }
3489
3490 void free() {
3491 if (mpData) {
3492 ::free(mpData);
3493 mpData = 0;
3494 }
3495 }
3496
3497 size_t remainingCapacity(size_t alignment) {
3498 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3499 }
3500
3501 // Assume alignment is a power of two
3502 inline size_t aligned(size_t v, size_t alignment) {
3503 size_t mask = alignment-1;
3504 return (v + mask) & ~mask;
3505 }
3506
3507 char* mpData;
3508 size_t mSize;
3509 size_t mOffset;
3510 };
3511
3512 size_t mCurrentChunk;
3513
3514 Vector<Chunk> mData;
3515 };
3516
Jack Palevich569f1352009-06-29 14:29:08 -07003517 struct VariableInfo;
3518
3519 struct Token {
3520 int hash;
3521 size_t length;
3522 char* pText;
3523 tokenid_t id;
3524
3525 // Current values for the token
3526 char* mpMacroDefinition;
3527 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003528 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003529 };
3530
3531 class TokenTable {
3532 public:
3533 // Don't use 0..0xff, allows characters and operators to be tokens too.
3534
3535 static const int TOKEN_BASE = 0x100;
3536 TokenTable() {
3537 mpMap = hashmapCreate(128, hashFn, equalsFn);
3538 }
3539
3540 ~TokenTable() {
3541 hashmapFree(mpMap);
3542 }
3543
3544 void setArena(Arena* pArena) {
3545 mpArena = pArena;
3546 }
3547
3548 // Returns a token for a given string of characters.
3549 tokenid_t intern(const char* pText, size_t length) {
3550 Token probe;
3551 int hash = hashmapHash((void*) pText, length);
3552 {
3553 Token probe;
3554 probe.hash = hash;
3555 probe.length = length;
3556 probe.pText = (char*) pText;
3557 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3558 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003559 return pValue->id;
3560 }
3561 }
3562
3563 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3564 memset(pToken, 0, sizeof(*pToken));
3565 pToken->hash = hash;
3566 pToken->length = length;
3567 pToken->pText = (char*) mpArena->alloc(length + 1);
3568 memcpy(pToken->pText, pText, length);
3569 pToken->pText[length] = 0;
3570 pToken->id = mTokens.size() + TOKEN_BASE;
3571 mTokens.push_back(pToken);
3572 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003573 return pToken->id;
3574 }
3575
3576 // Return the Token for a given tokenid.
3577 Token& operator[](tokenid_t id) {
3578 return *mTokens[id - TOKEN_BASE];
3579 }
3580
3581 inline size_t size() {
3582 return mTokens.size();
3583 }
3584
3585 private:
3586
3587 static int hashFn(void* pKey) {
3588 Token* pToken = (Token*) pKey;
3589 return pToken->hash;
3590 }
3591
3592 static bool equalsFn(void* keyA, void* keyB) {
3593 Token* pTokenA = (Token*) keyA;
3594 Token* pTokenB = (Token*) keyB;
3595 // Don't need to compare hash values, they should always be equal
3596 return pTokenA->length == pTokenB->length
3597 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3598 }
3599
3600 Hashmap* mpMap;
3601 Vector<Token*> mTokens;
3602 Arena* mpArena;
3603 };
3604
Jack Palevich1cdef202009-05-22 12:06:27 -07003605 class InputStream {
3606 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003607 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003608 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003609 };
3610
3611 class TextInputStream : public InputStream {
3612 public:
3613 TextInputStream(const char* text, size_t textLength)
3614 : pText(text), mTextLength(textLength), mPosition(0) {
3615 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003616
Jack Palevichdc456462009-07-16 16:50:56 -07003617 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003618 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3619 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003620
Jack Palevichdc456462009-07-16 16:50:56 -07003621 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003622 const char* pText;
3623 size_t mTextLength;
3624 size_t mPosition;
3625 };
3626
Jack Palevicheedf9d22009-06-04 16:23:40 -07003627 class String {
3628 public:
3629 String() {
3630 mpBase = 0;
3631 mUsed = 0;
3632 mSize = 0;
3633 }
3634
Jack Palevich303d8ff2009-06-11 19:06:24 -07003635 String(const char* item, int len, bool adopt) {
3636 if (len < 0) {
3637 len = strlen(item);
3638 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003639 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003640 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003641 mUsed = len;
3642 mSize = len + 1;
3643 } else {
3644 mpBase = 0;
3645 mUsed = 0;
3646 mSize = 0;
3647 appendBytes(item, len);
3648 }
3649 }
3650
Jack Palevich303d8ff2009-06-11 19:06:24 -07003651 String(const String& other) {
3652 mpBase = 0;
3653 mUsed = 0;
3654 mSize = 0;
3655 appendBytes(other.getUnwrapped(), other.len());
3656 }
3657
Jack Palevicheedf9d22009-06-04 16:23:40 -07003658 ~String() {
3659 if (mpBase) {
3660 free(mpBase);
3661 }
3662 }
3663
Jack Palevicha6baa232009-06-12 11:25:59 -07003664 String& operator=(const String& other) {
3665 clear();
3666 appendBytes(other.getUnwrapped(), other.len());
3667 return *this;
3668 }
3669
Jack Palevich303d8ff2009-06-11 19:06:24 -07003670 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003671 return mpBase;
3672 }
3673
Jack Palevich303d8ff2009-06-11 19:06:24 -07003674 void clear() {
3675 mUsed = 0;
3676 if (mSize > 0) {
3677 mpBase[0] = 0;
3678 }
3679 }
3680
Jack Palevicheedf9d22009-06-04 16:23:40 -07003681 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003682 appendBytes(s, strlen(s));
3683 }
3684
3685 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003686 memcpy(ensure(n), s, n + 1);
3687 }
3688
3689 void append(char c) {
3690 * ensure(1) = c;
3691 }
3692
Jack Palevich86351982009-06-30 18:09:56 -07003693 void append(String& other) {
3694 appendBytes(other.getUnwrapped(), other.len());
3695 }
3696
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003697 char* orphan() {
3698 char* result = mpBase;
3699 mpBase = 0;
3700 mUsed = 0;
3701 mSize = 0;
3702 return result;
3703 }
3704
Jack Palevicheedf9d22009-06-04 16:23:40 -07003705 void printf(const char* fmt,...) {
3706 va_list ap;
3707 va_start(ap, fmt);
3708 vprintf(fmt, ap);
3709 va_end(ap);
3710 }
3711
3712 void vprintf(const char* fmt, va_list ap) {
3713 char* temp;
3714 int numChars = vasprintf(&temp, fmt, ap);
3715 memcpy(ensure(numChars), temp, numChars+1);
3716 free(temp);
3717 }
3718
Jack Palevich303d8ff2009-06-11 19:06:24 -07003719 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003720 return mUsed;
3721 }
3722
3723 private:
3724 char* ensure(int n) {
3725 size_t newUsed = mUsed + n;
3726 if (newUsed > mSize) {
3727 size_t newSize = mSize * 2 + 10;
3728 if (newSize < newUsed) {
3729 newSize = newUsed;
3730 }
3731 mpBase = (char*) realloc(mpBase, newSize + 1);
3732 mSize = newSize;
3733 }
3734 mpBase[newUsed] = '\0';
3735 char* result = mpBase + mUsed;
3736 mUsed = newUsed;
3737 return result;
3738 }
3739
3740 char* mpBase;
3741 size_t mUsed;
3742 size_t mSize;
3743 };
3744
Jack Palevich569f1352009-06-29 14:29:08 -07003745 void internKeywords() {
3746 // Note: order has to match TOK_ constants
3747 static const char* keywords[] = {
3748 "int",
3749 "char",
3750 "void",
3751 "if",
3752 "else",
3753 "while",
3754 "break",
3755 "return",
3756 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003757 "auto",
3758 "case",
3759 "const",
3760 "continue",
3761 "default",
3762 "do",
3763 "double",
3764 "enum",
3765 "extern",
3766 "float",
3767 "goto",
3768 "long",
3769 "register",
3770 "short",
3771 "signed",
3772 "sizeof",
3773 "static",
3774 "struct",
3775 "switch",
3776 "typedef",
3777 "union",
3778 "unsigned",
3779 "volatile",
3780 "_Bool",
3781 "_Complex",
3782 "_Imaginary",
3783 "inline",
3784 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003785
3786 // predefined tokens that can also be symbols start here:
3787 "pragma",
3788 "define",
3789 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003790 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003791
Jack Palevich569f1352009-06-29 14:29:08 -07003792 for(int i = 0; keywords[i]; i++) {
3793 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003794 }
Jack Palevich569f1352009-06-29 14:29:08 -07003795 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003796
Jack Palevich36d94142009-06-08 15:55:32 -07003797 struct InputState {
3798 InputStream* pStream;
3799 int oldCh;
3800 };
3801
Jack Palevich2db168f2009-06-11 14:29:47 -07003802 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003803 void* pAddress;
3804 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003805 tokenid_t tok;
3806 size_t level;
3807 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003808 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003809 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003810 };
3811
Jack Palevich303d8ff2009-06-11 19:06:24 -07003812 class SymbolStack {
3813 public:
3814 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003815 mpArena = 0;
3816 mpTokenTable = 0;
3817 }
3818
3819 void setArena(Arena* pArena) {
3820 mpArena = pArena;
3821 }
3822
3823 void setTokenTable(TokenTable* pTokenTable) {
3824 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003825 }
3826
3827 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003828 Mark mark;
3829 mark.mArenaMark = mpArena->mark();
3830 mark.mSymbolHead = mStack.size();
3831 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003832 }
3833
3834 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003835 // Undo any shadowing that was done:
3836 Mark mark = mLevelStack.back();
3837 mLevelStack.pop_back();
3838 while (mStack.size() > mark.mSymbolHead) {
3839 VariableInfo* pV = mStack.back();
3840 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003841 if (pV->isStructTag) {
3842 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3843 } else {
3844 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3845 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003846 }
Jack Palevich569f1352009-06-29 14:29:08 -07003847 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003848 }
3849
Jack Palevich569f1352009-06-29 14:29:08 -07003850 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3851 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3852 return pV && pV->level == level();
3853 }
3854
Jack Palevich9221bcc2009-08-26 16:15:07 -07003855 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3856 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3857 return pV && pV->level == level();
3858 }
3859
Jack Palevich569f1352009-06-29 14:29:08 -07003860 VariableInfo* add(tokenid_t tok) {
3861 Token& token = (*mpTokenTable)[tok];
3862 VariableInfo* pOldV = token.mpVariableInfo;
3863 VariableInfo* pNewV =
3864 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3865 memset(pNewV, 0, sizeof(VariableInfo));
3866 pNewV->tok = tok;
3867 pNewV->level = level();
3868 pNewV->pOldDefinition = pOldV;
3869 token.mpVariableInfo = pNewV;
3870 mStack.push_back(pNewV);
3871 return pNewV;
3872 }
3873
Jack Palevich9221bcc2009-08-26 16:15:07 -07003874 VariableInfo* addStructTag(tokenid_t tok) {
3875 Token& token = (*mpTokenTable)[tok];
3876 VariableInfo* pOldS = token.mpStructInfo;
3877 VariableInfo* pNewS =
3878 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3879 memset(pNewS, 0, sizeof(VariableInfo));
3880 pNewS->tok = tok;
3881 pNewS->level = level();
3882 pNewS->isStructTag = true;
3883 pNewS->pOldDefinition = pOldS;
3884 token.mpStructInfo = pNewS;
3885 mStack.push_back(pNewS);
3886 return pNewS;
3887 }
3888
Jack Palevich86351982009-06-30 18:09:56 -07003889 VariableInfo* add(Type* pType) {
3890 VariableInfo* pVI = add(pType->id);
3891 pVI->pType = pType;
3892 return pVI;
3893 }
3894
Jack Palevich569f1352009-06-29 14:29:08 -07003895 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3896 for (size_t i = 0; i < mStack.size(); i++) {
3897 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003898 break;
3899 }
3900 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003901 }
3902
Jack Palevich303d8ff2009-06-11 19:06:24 -07003903 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003904 inline size_t level() {
3905 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003906 }
3907
Jack Palevich569f1352009-06-29 14:29:08 -07003908 struct Mark {
3909 Arena::Mark mArenaMark;
3910 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003911 };
3912
Jack Palevich569f1352009-06-29 14:29:08 -07003913 Arena* mpArena;
3914 TokenTable* mpTokenTable;
3915 Vector<VariableInfo*> mStack;
3916 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003917 };
Jack Palevich36d94142009-06-08 15:55:32 -07003918
Jack Palevich188a5a72009-10-27 17:23:20 -07003919 struct MacroState {
3920 tokenid_t name; // Name of the current macro we are expanding
3921 char* dptr; // point to macro text during macro playback
3922 int dch; // Saves old value of ch during a macro playback
3923 };
3924
3925#define MACRO_NESTING_MAX 32
3926 MacroState macroState[MACRO_NESTING_MAX];
3927 int macroLevel; // -1 means not playing any macro.
3928
Jack Palevich36d94142009-06-08 15:55:32 -07003929 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003930 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003931 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003932 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003933 int tokl; // token operator level
3934 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003935 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003936 intptr_t loc; // local variable index
3937 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003938 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003939 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003940 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003941 ACCSymbolLookupFn mpSymbolLookupFn;
3942 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003943
3944 // Arena for the duration of the compile
3945 Arena mGlobalArena;
3946 // Arena for data that's only needed when compiling a single function
3947 Arena mLocalArena;
3948
Jack Palevich2ff5c222009-07-23 15:11:22 -07003949 Arena* mpCurrentArena;
3950
Jack Palevich569f1352009-06-29 14:29:08 -07003951 TokenTable mTokenTable;
3952 SymbolStack mGlobals;
3953 SymbolStack mLocals;
3954
Jack Palevich9221bcc2009-08-26 16:15:07 -07003955 SymbolStack* mpCurrentSymbolStack;
3956
Jack Palevich40600de2009-07-01 15:32:35 -07003957 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003958 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003959 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003960 Type* mkpChar; // char
3961 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003962 Type* mkpFloat;
3963 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003964 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003965 Type* mkpIntPtr;
3966 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003967 Type* mkpFloatPtr;
3968 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003969 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003970
Jack Palevich36d94142009-06-08 15:55:32 -07003971 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003972 int mLineNumber;
3973 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003974
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003975 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003976 CodeGenerator* pGen;
3977
Jack Palevicheedf9d22009-06-04 16:23:40 -07003978 String mErrorBuf;
3979
Jack Palevicheedf9d22009-06-04 16:23:40 -07003980 String mPragmas;
3981 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003982 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003983
Jack Palevich21a15a22009-05-11 14:49:29 -07003984 static const int ALLOC_SIZE = 99999;
3985
Jack Palevich303d8ff2009-06-11 19:06:24 -07003986 static const int TOK_DUMMY = 1;
3987 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003988 static const int TOK_NUM_FLOAT = 3;
3989 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003990 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003991 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003992
3993 // 3..255 are character and/or operators
3994
Jack Palevich2db168f2009-06-11 14:29:47 -07003995 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003996 // Order has to match string list in "internKeywords".
3997 enum {
3998 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3999 TOK_INT = TOK_KEYWORD,
4000 TOK_CHAR,
4001 TOK_VOID,
4002 TOK_IF,
4003 TOK_ELSE,
4004 TOK_WHILE,
4005 TOK_BREAK,
4006 TOK_RETURN,
4007 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07004008 TOK_AUTO,
4009 TOK_CASE,
4010 TOK_CONST,
4011 TOK_CONTINUE,
4012 TOK_DEFAULT,
4013 TOK_DO,
4014 TOK_DOUBLE,
4015 TOK_ENUM,
4016 TOK_EXTERN,
4017 TOK_FLOAT,
4018 TOK_GOTO,
4019 TOK_LONG,
4020 TOK_REGISTER,
4021 TOK_SHORT,
4022 TOK_SIGNED,
4023 TOK_SIZEOF,
4024 TOK_STATIC,
4025 TOK_STRUCT,
4026 TOK_SWITCH,
4027 TOK_TYPEDEF,
4028 TOK_UNION,
4029 TOK_UNSIGNED,
4030 TOK_VOLATILE,
4031 TOK__BOOL,
4032 TOK__COMPLEX,
4033 TOK__IMAGINARY,
4034 TOK_INLINE,
4035 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004036
4037 // Symbols start after keywords
4038
4039 TOK_SYMBOL,
4040 TOK_PRAGMA = TOK_SYMBOL,
4041 TOK_DEFINE,
4042 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004043 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004044
4045 static const int LOCAL = 0x200;
4046
Jack Palevich21a15a22009-05-11 14:49:29 -07004047 /* tokens in string heap */
4048 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004049
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004050 static const int OP_INCREMENT = 0;
4051 static const int OP_DECREMENT = 1;
4052 static const int OP_MUL = 2;
4053 static const int OP_DIV = 3;
4054 static const int OP_MOD = 4;
4055 static const int OP_PLUS = 5;
4056 static const int OP_MINUS = 6;
4057 static const int OP_SHIFT_LEFT = 7;
4058 static const int OP_SHIFT_RIGHT = 8;
4059 static const int OP_LESS_EQUAL = 9;
4060 static const int OP_GREATER_EQUAL = 10;
4061 static const int OP_LESS = 11;
4062 static const int OP_GREATER = 12;
4063 static const int OP_EQUALS = 13;
4064 static const int OP_NOT_EQUALS = 14;
4065 static const int OP_LOGICAL_AND = 15;
4066 static const int OP_LOGICAL_OR = 16;
4067 static const int OP_BIT_AND = 17;
4068 static const int OP_BIT_XOR = 18;
4069 static const int OP_BIT_OR = 19;
4070 static const int OP_BIT_NOT = 20;
4071 static const int OP_LOGICAL_NOT = 21;
4072 static const int OP_COUNT = 22;
4073
4074 /* Operators are searched from front, the two-character operators appear
4075 * before the single-character operators with the same first character.
4076 * @ is used to pad out single-character operators.
4077 */
4078 static const char* operatorChars;
4079 static const char operatorLevel[];
4080
Jack Palevich569f1352009-06-29 14:29:08 -07004081 /* Called when we detect an internal problem. Does nothing in production.
4082 *
4083 */
4084 void internalError() {
4085 * (char*) 0 = 0;
4086 }
4087
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004088 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004089 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004090 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004091 internalError();
4092 }
Jack Palevich86351982009-06-30 18:09:56 -07004093 }
4094
Jack Palevich40600de2009-07-01 15:32:35 -07004095 bool isSymbol(tokenid_t t) {
4096 return t >= TOK_SYMBOL &&
4097 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4098 }
4099
4100 bool isSymbolOrKeyword(tokenid_t t) {
4101 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004102 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004103 }
4104
Jack Palevich86351982009-06-30 18:09:56 -07004105 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004106 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004107 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4108 if (pV && pV->tok != t) {
4109 internalError();
4110 }
4111 return pV;
4112 }
4113
4114 inline bool isDefined(tokenid_t t) {
4115 return t >= TOK_SYMBOL && VI(t) != 0;
4116 }
4117
Jack Palevich40600de2009-07-01 15:32:35 -07004118 const char* nameof(tokenid_t t) {
4119 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004120 return mTokenTable[t].pText;
4121 }
4122
Jack Palevich21a15a22009-05-11 14:49:29 -07004123 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004124 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004125 }
4126
4127 void inp() {
Jack Palevich188a5a72009-10-27 17:23:20 -07004128 // Close any totally empty macros. We leave them on the stack until now
4129 // so that we know which macros are being expanded when checking if the
4130 // last token in the macro is a macro that's already being expanded.
4131 while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
4132 macroLevel--;
4133 }
4134 if (macroLevel >= 0) {
4135 ch = *macroState[macroLevel].dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004136 if (ch == 0) {
Jack Palevich188a5a72009-10-27 17:23:20 -07004137 ch = macroState[macroLevel].dch;
4138 macroState[macroLevel].dptr = NULL; // This macro's done
Jack Palevich21a15a22009-05-11 14:49:29 -07004139 }
Jack Palevichdc456462009-07-16 16:50:56 -07004140 } else {
4141 if (mbBumpLine) {
4142 mLineNumber++;
4143 mbBumpLine = false;
4144 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004145 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004146 if (ch == '\n') {
4147 mbBumpLine = true;
4148 }
4149 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004150#if 0
4151 printf("ch='%c' 0x%x\n", ch, ch);
4152#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004153 }
4154
4155 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004156 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004157 }
4158
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004159 int decodeHex(int c) {
4160 if (isdigit(c)) {
4161 c -= '0';
4162 } else if (c <= 'F') {
4163 c = c - 'A' + 10;
4164 } else {
4165 c =c - 'a' + 10;
4166 }
4167 return c;
4168 }
4169
Jack Palevichb4758ff2009-06-12 12:49:14 -07004170 /* read a character constant, advances ch to after end of constant */
4171 int getq() {
4172 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004173 if (ch == '\\') {
4174 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004175 if (isoctal(ch)) {
4176 // 1 to 3 octal characters.
4177 val = 0;
4178 for(int i = 0; i < 3; i++) {
4179 if (isoctal(ch)) {
4180 val = (val << 3) + ch - '0';
4181 inp();
4182 }
4183 }
4184 return val;
4185 } else if (ch == 'x' || ch == 'X') {
4186 // N hex chars
4187 inp();
4188 if (! isxdigit(ch)) {
4189 error("'x' character escape requires at least one digit.");
4190 } else {
4191 val = 0;
4192 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004193 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004194 inp();
4195 }
4196 }
4197 } else {
4198 int val = ch;
4199 switch (ch) {
4200 case 'a':
4201 val = '\a';
4202 break;
4203 case 'b':
4204 val = '\b';
4205 break;
4206 case 'f':
4207 val = '\f';
4208 break;
4209 case 'n':
4210 val = '\n';
4211 break;
4212 case 'r':
4213 val = '\r';
4214 break;
4215 case 't':
4216 val = '\t';
4217 break;
4218 case 'v':
4219 val = '\v';
4220 break;
4221 case '\\':
4222 val = '\\';
4223 break;
4224 case '\'':
4225 val = '\'';
4226 break;
4227 case '"':
4228 val = '"';
4229 break;
4230 case '?':
4231 val = '?';
4232 break;
4233 default:
4234 error("Undefined character escape %c", ch);
4235 break;
4236 }
4237 inp();
4238 return val;
4239 }
4240 } else {
4241 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004242 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004243 return val;
4244 }
4245
4246 static bool isoctal(int ch) {
4247 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004248 }
4249
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004250 bool acceptCh(int c) {
4251 bool result = c == ch;
4252 if (result) {
4253 pdef(ch);
4254 inp();
4255 }
4256 return result;
4257 }
4258
4259 bool acceptDigitsCh() {
4260 bool result = false;
4261 while (isdigit(ch)) {
4262 result = true;
4263 pdef(ch);
4264 inp();
4265 }
4266 return result;
4267 }
4268
4269 void parseFloat() {
4270 tok = TOK_NUM_DOUBLE;
4271 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004272 if(mTokenString.len() == 0) {
4273 mTokenString.append('0');
4274 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004275 acceptCh('.');
4276 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004277 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004278 acceptCh('-') || acceptCh('+');
4279 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004280 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004281 if (ch == 'f' || ch == 'F') {
4282 tok = TOK_NUM_FLOAT;
4283 inp();
4284 } else if (ch == 'l' || ch == 'L') {
4285 inp();
4286 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004287 }
4288 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004289 char* pEnd = pText + strlen(pText);
4290 char* pEndPtr = 0;
4291 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004292 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004293 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004294 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004295 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004296 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004297 if (errno || pEndPtr != pEnd) {
4298 error("Can't parse constant: %s", pText);
4299 }
4300 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004301 }
4302
Jack Palevich188a5a72009-10-27 17:23:20 -07004303 bool currentlyBeingExpanded(tokenid_t id) {
4304 for (int i = 0; i <= macroLevel; i++) {
4305 if (macroState[macroLevel].name == id) {
4306 return true;
4307 }
4308 }
4309 return false;
4310 }
4311
Jack Palevich21a15a22009-05-11 14:49:29 -07004312 void next() {
4313 int l, a;
4314
Jack Palevich546b2242009-05-13 15:10:04 -07004315 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004316 if (ch == '#') {
4317 inp();
4318 next();
4319 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004320 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004321 } else if (tok == TOK_PRAGMA) {
4322 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004323 } else if (tok == TOK_LINE) {
4324 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004325 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004326 error("Unsupported preprocessor directive \"%s\"",
4327 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004328 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004329 }
4330 inp();
4331 }
4332 tokl = 0;
4333 tok = ch;
4334 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004335 if (isdigit(ch) || ch == '.') {
4336 // Start of a numeric constant. Could be integer, float, or
4337 // double, won't know until we look further.
4338 mTokenString.clear();
4339 pdef(ch);
4340 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004341 if (tok == '.' && !isdigit(ch)) {
4342 goto done;
4343 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004344 int base = 10;
4345 if (tok == '0') {
4346 if (ch == 'x' || ch == 'X') {
4347 base = 16;
4348 tok = TOK_NUM;
4349 tokc = 0;
4350 inp();
4351 while ( isxdigit(ch) ) {
4352 tokc = (tokc << 4) + decodeHex(ch);
4353 inp();
4354 }
4355 } else if (isoctal(ch)){
4356 base = 8;
4357 tok = TOK_NUM;
4358 tokc = 0;
4359 while ( isoctal(ch) ) {
4360 tokc = (tokc << 3) + (ch - '0');
4361 inp();
4362 }
4363 }
4364 } else if (isdigit(tok)){
4365 acceptDigitsCh();
4366 }
4367 if (base == 10) {
4368 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4369 parseFloat();
4370 } else {
4371 // It's an integer constant
4372 char* pText = mTokenString.getUnwrapped();
4373 char* pEnd = pText + strlen(pText);
4374 char* pEndPtr = 0;
4375 errno = 0;
4376 tokc = strtol(pText, &pEndPtr, base);
4377 if (errno || pEndPtr != pEnd) {
4378 error("Can't parse constant: %s %d %d", pText, base, errno);
4379 }
4380 tok = TOK_NUM;
4381 }
4382 }
4383 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004384 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004385 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004386 pdef(ch);
4387 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004388 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004389 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004390 if (! mbSuppressMacroExpansion) {
4391 // Is this a macro?
4392 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
Jack Palevich188a5a72009-10-27 17:23:20 -07004393 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
Jack Palevich815d8b82009-08-18 18:25:56 -07004394 // Yes, it is a macro
Jack Palevich188a5a72009-10-27 17:23:20 -07004395#if 0
4396 printf("Expanding macro %s -> %s",
4397 mTokenString.getUnwrapped(), pMacroDefinition);
4398#endif
4399 if (macroLevel >= MACRO_NESTING_MAX-1) {
4400 error("Too many levels of macro recursion.");
4401 } else {
4402 macroLevel++;
4403 macroState[macroLevel].name = tok;
4404 macroState[macroLevel].dptr = pMacroDefinition;
4405 macroState[macroLevel].dch = ch;
4406 inp();
4407 next();
4408 }
Jack Palevich815d8b82009-08-18 18:25:56 -07004409 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004410 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004411 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004412 inp();
4413 if (tok == '\'') {
4414 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004415 tokc = getq();
4416 if (ch != '\'') {
4417 error("Expected a ' character, got %c", ch);
4418 } else {
4419 inp();
4420 }
Jack Palevich546b2242009-05-13 15:10:04 -07004421 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004422 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004423 while (ch && ch != EOF) {
4424 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004425 inp();
4426 inp();
4427 if (ch == '/')
4428 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004429 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004430 if (ch == EOF) {
4431 error("End of file inside comment.");
4432 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004433 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004434 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004435 } else if ((tok == '/') & (ch == '/')) {
4436 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004437 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004438 inp();
4439 }
4440 inp();
4441 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004442 } else if ((tok == '-') & (ch == '>')) {
4443 inp();
4444 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004445 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004446 const char* t = operatorChars;
4447 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004448 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004449 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004450 tokl = operatorLevel[opIndex];
4451 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004452 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004453#if 0
4454 printf("%c%c -> tokl=%d tokc=0x%x\n",
4455 l, a, tokl, tokc);
4456#endif
4457 if (a == ch) {
4458 inp();
4459 tok = TOK_DUMMY; /* dummy token for double tokens */
4460 }
Jack Palevich0c017742009-07-31 12:00:39 -07004461 /* check for op=, valid for * / % + - << >> & ^ | */
4462 if (ch == '=' &&
4463 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004464 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004465 inp();
4466 tok = TOK_OP_ASSIGNMENT;
4467 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004468 break;
4469 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004470 opIndex++;
4471 }
4472 if (l == 0) {
4473 tokl = 0;
4474 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004475 }
4476 }
4477 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004478
4479 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004480#if 0
4481 {
Jack Palevich569f1352009-06-29 14:29:08 -07004482 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004483 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004484 fprintf(stderr, "%s\n", buf.getUnwrapped());
4485 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004486#endif
4487 }
4488
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004489 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004490 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004491 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004492 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004493 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004494 if (ch == '(') {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004495 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004496 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004497 }
4498 while (isspace(ch)) {
4499 inp();
4500 }
Jack Palevich569f1352009-06-29 14:29:08 -07004501 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004502 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004503 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004504 // Check for '//' comments.
4505 if (appendToValue && ch == '/') {
4506 inp();
4507 if (ch == '/') {
4508 appendToValue = false;
4509 } else {
4510 value.append('/');
4511 }
4512 }
4513 if (appendToValue && ch != EOF) {
4514 value.append(ch);
4515 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004516 inp();
4517 }
Jack Palevich569f1352009-06-29 14:29:08 -07004518 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4519 memcpy(pDefn, value.getUnwrapped(), value.len());
4520 pDefn[value.len()] = 0;
4521 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich188a5a72009-10-27 17:23:20 -07004522#if 0
4523 {
4524 String buf;
4525 decodeToken(buf, name, true);
4526 fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
4527 }
4528#endif
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004529 }
4530
Jack Palevicheedf9d22009-06-04 16:23:40 -07004531 void doPragma() {
4532 // # pragma name(val)
4533 int state = 0;
4534 while(ch != EOF && ch != '\n' && state < 10) {
4535 switch(state) {
4536 case 0:
4537 if (isspace(ch)) {
4538 inp();
4539 } else {
4540 state++;
4541 }
4542 break;
4543 case 1:
4544 if (isalnum(ch)) {
4545 mPragmas.append(ch);
4546 inp();
4547 } else if (ch == '(') {
4548 mPragmas.append(0);
4549 inp();
4550 state++;
4551 } else {
4552 state = 11;
4553 }
4554 break;
4555 case 2:
4556 if (isalnum(ch)) {
4557 mPragmas.append(ch);
4558 inp();
4559 } else if (ch == ')') {
4560 mPragmas.append(0);
4561 inp();
4562 state = 10;
4563 } else {
4564 state = 11;
4565 }
4566 break;
4567 }
4568 }
4569 if(state != 10) {
4570 error("Unexpected pragma syntax");
4571 }
4572 mPragmaStringCount += 2;
4573 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004574
Jack Palevichdc456462009-07-16 16:50:56 -07004575 void doLine() {
4576 // # line number { "filename "}
4577 next();
4578 if (tok != TOK_NUM) {
4579 error("Expected a line-number");
4580 } else {
4581 mLineNumber = tokc-1; // The end-of-line will increment it.
4582 }
4583 while(ch != EOF && ch != '\n') {
4584 inp();
4585 }
4586 }
4587
Jack Palevichac0e95e2009-05-29 13:53:44 -07004588 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004589 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004590 mErrorBuf.vprintf(fmt, ap);
4591 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004592 }
4593
Jack Palevich8b0624c2009-05-20 12:12:06 -07004594 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004595 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004596 error("'%c' expected", c);
4597 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004598 }
4599
Jack Palevich86351982009-06-30 18:09:56 -07004600 bool accept(intptr_t c) {
4601 if (tok == c) {
4602 next();
4603 return true;
4604 }
4605 return false;
4606 }
4607
Jack Palevich40600de2009-07-01 15:32:35 -07004608 bool acceptStringLiteral() {
4609 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004610 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004611 // This while loop merges multiple adjacent string constants.
4612 while (tok == '"') {
4613 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004614 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004615 }
4616 if (ch != '"') {
4617 error("Unterminated string constant.");
4618 }
4619 inp();
4620 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004621 }
Jack Palevich40600de2009-07-01 15:32:35 -07004622 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004623 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004624 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004625 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004626
4627 return true;
4628 }
4629 return false;
4630 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004631
Jack Palevichb1544ca2009-07-16 15:09:20 -07004632 void linkGlobal(tokenid_t t, bool isFunction) {
4633 VariableInfo* pVI = VI(t);
4634 void* n = NULL;
4635 if (mpSymbolLookupFn) {
4636 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4637 }
4638 if (pVI->pType == NULL) {
4639 if (isFunction) {
4640 pVI->pType = mkpIntFn;
4641 } else {
4642 pVI->pType = mkpInt;
4643 }
4644 }
4645 pVI->pAddress = n;
4646 }
4647
Jack Palevich29daf572009-07-30 19:38:55 -07004648 void unaryOrAssignment() {
4649 unary();
4650 if (accept('=')) {
4651 checkLVal();
4652 pGen->pushR0();
4653 expr();
4654 pGen->forceR0RVal();
4655 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004656 } else if (tok == TOK_OP_ASSIGNMENT) {
4657 int t = tokc;
4658 next();
4659 checkLVal();
4660 pGen->pushR0();
4661 pGen->forceR0RVal();
4662 pGen->pushR0();
4663 expr();
4664 pGen->forceR0RVal();
4665 pGen->genOp(t);
4666 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004667 }
4668 }
4669
Jack Palevich40600de2009-07-01 15:32:35 -07004670 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004671 */
Jack Palevich29daf572009-07-30 19:38:55 -07004672 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004673 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004674 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004675 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004676 if (acceptStringLiteral()) {
4677 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004678 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004679 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004680 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004681 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004682 t = tok;
4683 next();
4684 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004685 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004686 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004687 // Align to 4-byte boundary
4688 glo = (char*) (((intptr_t) glo + 3) & -4);
4689 * (float*) glo = (float) ad;
4690 pGen->loadFloat((int) glo, mkpFloat);
4691 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004692 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004693 // Align to 8-byte boundary
4694 glo = (char*) (((intptr_t) glo + 7) & -8);
4695 * (double*) glo = ad;
4696 pGen->loadFloat((int) glo, mkpDouble);
4697 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004698 } else if (c == 2) {
4699 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004700 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004701 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004702 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004703 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004704 else if (t == '+') {
4705 // ignore unary plus.
4706 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004707 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004708 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004709 } else if (c == 11) {
4710 // pre increment / pre decrement
4711 unary();
4712 doIncDec(a == OP_INCREMENT, 0);
4713 }
4714 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004715 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004716 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004717 if (pCast) {
4718 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004719 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004720 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004721 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004722 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004723 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004724 skip(')');
4725 }
4726 } else if (t == '*') {
4727 /* This is a pointer dereference.
4728 */
Jack Palevich29daf572009-07-30 19:38:55 -07004729 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004730 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004731 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004732 unary();
4733 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004734 } else if (t == EOF ) {
4735 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004736 } else if (t == ';') {
4737 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004738 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004739 // Don't have to do anything special here, the error
4740 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004741 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004742 if (!isDefined(t)) {
4743 mGlobals.add(t);
4744 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004745 }
Jack Palevich8df46192009-07-07 14:48:51 -07004746 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004747 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004748 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004749 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004750 linkGlobal(t, tok == '(');
4751 n = (intptr_t) pVI->pAddress;
4752 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004753 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004754 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004755 }
Jack Palevich29daf572009-07-30 19:38:55 -07004756 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004757 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004758 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004759 linkGlobal(t, false);
4760 n = (intptr_t) pVI->pAddress;
4761 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004762 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004763 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004764 }
Jack Palevich5b659092009-07-31 14:55:07 -07004765 }
4766 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004767 Type* pVal;
4768 ExpressionType et;
4769 if (pVI->pType->tag == TY_ARRAY) {
4770 pVal = pVI->pType;
4771 et = ET_RVALUE;
4772 } else {
4773 pVal = createPtrType(pVI->pType);
4774 et = ET_LVALUE;
4775 }
Jack Palevich5b659092009-07-31 14:55:07 -07004776 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004777 int tag = pVal->pHead->tag;
4778 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004779 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004780 }
Jack Palevich5b659092009-07-31 14:55:07 -07004781 pGen->leaR0(n, pVal, et);
4782 } else {
4783 pVI->pForward = (void*) pGen->leaForward(
4784 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004785 }
4786 }
4787 }
4788
Jack Palevich5b659092009-07-31 14:55:07 -07004789 /* Now handle postfix operators */
4790 for(;;) {
4791 if (tokl == 11) {
4792 // post inc / post dec
4793 doIncDec(tokc == OP_INCREMENT, true);
4794 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004795 } else if (accept('[')) {
4796 // Array reference
4797 pGen->forceR0RVal();
4798 pGen->pushR0();
4799 commaExpr();
4800 pGen->forceR0RVal();
4801 pGen->genOp(OP_PLUS);
4802 doPointer();
4803 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004804 } else if (accept('.')) {
4805 // struct element
4806 pGen->forceR0RVal();
4807 Type* pStruct = pGen->getR0Type();
4808 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004809 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004810 } else {
4811 error("expected a struct value to the left of '.'");
4812 }
4813 } else if (accept(TOK_OP_ARROW)) {
4814 pGen->forceR0RVal();
4815 Type* pPtr = pGen->getR0Type();
4816 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4817 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004818 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004819 } else {
4820 error("Expected a pointer to a struct to the left of '->'");
4821 }
Jack Palevich5b659092009-07-31 14:55:07 -07004822 } else if (accept('(')) {
4823 /* function call */
4824 Type* pDecl = NULL;
4825 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004826 Type* pFn = pGen->getR0Type();
Jack Palevich188a5a72009-10-27 17:23:20 -07004827 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
4828 pDecl = pFn->pHead;
4829 pGen->pushR0();
4830 Type* pArgList = pDecl->pTail;
4831 bool varArgs = pArgList == NULL;
4832 /* push args and invert order */
4833 a = pGen->beginFunctionCallArguments();
4834 int l = 0;
4835 int argCount = 0;
4836 while (tok != ')' && tok != EOF) {
4837 if (! varArgs && !pArgList) {
4838 error("Unexpected argument.");
Jack Palevich5b659092009-07-31 14:55:07 -07004839 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004840 expr();
4841 pGen->forceR0RVal();
4842 Type* pTargetType;
4843 if (pArgList) {
4844 pTargetType = pArgList->pHead;
4845 pArgList = pArgList->pTail;
4846 } else {
4847 // This is a ... function, just pass arguments in their
4848 // natural type.
4849 pTargetType = pGen->getR0Type();
4850 if (pTargetType->tag == TY_FLOAT) {
4851 pTargetType = mkpDouble;
4852 } else if (pTargetType->tag == TY_ARRAY) {
4853 // Pass arrays by pointer.
4854 pTargetType = pTargetType->pTail;
4855 }
4856 }
4857 if (pTargetType->tag == TY_VOID) {
4858 error("Can't pass void value for argument %d",
4859 argCount + 1);
4860 } else {
4861 l += pGen->storeR0ToArg(l, pTargetType);
4862 }
4863 if (accept(',')) {
4864 // fine
4865 } else if ( tok != ')') {
4866 error("Expected ',' or ')'");
4867 }
4868 argCount += 1;
Jack Palevich5b659092009-07-31 14:55:07 -07004869 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004870 if (! varArgs && pArgList) {
4871 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich5b659092009-07-31 14:55:07 -07004872 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004873 pGen->endFunctionCallArguments(pDecl, a, l);
4874 skip(')');
4875 pGen->callIndirect(l, pDecl);
4876 pGen->adjustStackAfterCall(pDecl, l, true);
4877 } else {
4878 error("Expected a function value to left of '('.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004879 }
Jack Palevich5b659092009-07-31 14:55:07 -07004880 } else {
4881 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004882 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004883 }
4884 }
4885
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004886 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004887 Type* pStructElement = lookupStructMember(pStruct, tok);
4888 if (pStructElement) {
4889 next();
4890 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4891 } else {
4892 String buf;
4893 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004894 error("Expected a struct member to the right of '%s', got %s",
4895 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004896 }
4897 }
4898
Jack Palevichaaac9282009-07-31 14:34:34 -07004899 void doIncDec(int isInc, int isPost) {
4900 // R0 already has the lval
4901 checkLVal();
4902 int lit = isInc ? 1 : -1;
4903 pGen->pushR0();
4904 pGen->loadR0FromR0();
4905 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004906 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4907 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004908 error("++/-- illegal for this type. %d", tag);
4909 }
4910 if (isPost) {
4911 pGen->over();
4912 pGen->pushR0();
4913 pGen->li(lit);
4914 pGen->genOp(OP_PLUS);
4915 pGen->storeR0ToTOS();
4916 pGen->popR0();
4917 } else {
4918 pGen->pushR0();
4919 pGen->li(lit);
4920 pGen->genOp(OP_PLUS);
4921 pGen->over();
4922 pGen->storeR0ToTOS();
4923 pGen->popR0();
4924 }
4925 }
4926
Jack Palevich47cbea92009-07-31 15:25:53 -07004927 void doPointer() {
4928 pGen->forceR0RVal();
4929 Type* pR0Type = pGen->getR0Type();
4930 if (pR0Type->tag != TY_POINTER) {
4931 error("Expected a pointer type.");
4932 } else {
4933 if (pR0Type->pHead->tag != TY_FUNC) {
4934 pGen->setR0ExpressionType(ET_LVALUE);
4935 }
4936 }
4937 }
4938
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004939 void doAddressOf() {
4940 Type* pR0 = pGen->getR0Type();
4941 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4942 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4943 error("Expected an lvalue");
4944 }
4945 Type* pR0Type = pGen->getR0Type();
4946 pGen->setR0ExpressionType(ET_RVALUE);
4947 }
4948
Jack Palevich40600de2009-07-01 15:32:35 -07004949 /* Recursive descent parser for binary operations.
4950 */
4951 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004952 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004953 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004954 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004955 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004956 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004957 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004958 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004959 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004960 t = tokc;
4961 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004962 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004963 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004964 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004965 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004966 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004967 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004968 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004969 // Check for syntax error.
4970 if (pGen->getR0Type() == NULL) {
4971 // We failed to parse a right-hand argument.
4972 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004973 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004974 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004975 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004976 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004977 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004978 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004979 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004980 }
4981 }
4982 }
4983 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004984 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004985 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004986 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004987 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004988 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004989 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004990 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004991 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004992 }
4993 }
4994 }
4995
Jack Palevich43aaee32009-07-31 14:01:37 -07004996 void commaExpr() {
4997 for(;;) {
4998 expr();
4999 if (!accept(',')) {
5000 break;
5001 }
5002 }
5003 }
5004
Jack Palevich21a15a22009-05-11 14:49:29 -07005005 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07005006 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07005007 }
5008
5009 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07005010 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005011 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005012 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07005013 }
5014
Jack Palevich46f2bd22009-10-29 17:56:56 -07005015 void block(intptr_t* breakLabel, intptr_t continueAddress, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07005016 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07005017
Jack Palevich95727a02009-07-06 12:07:15 -07005018 Type* pBaseType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005019 if ((pBaseType = acceptPrimitiveType(true))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07005020 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07005021 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005022 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005023 next();
5024 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07005025 a = test_expr();
5026 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005027 block(breakLabel, continueAddress, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07005028 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005029 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005030 n = pGen->gjmp(0); /* jmp */
5031 pGen->gsym(a);
Jack Palevichc951c592009-10-29 15:04:27 -07005032 block(breakLabel, continueAddress, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005033 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07005034 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005035 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005036 }
Jack Palevich546b2242009-05-13 15:10:04 -07005037 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07005038 t = tok;
5039 next();
5040 skip('(');
5041 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005042 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07005043 a = test_expr();
5044 } else {
5045 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005046 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005047 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005048 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07005049 a = 0;
5050 if (tok != ';')
5051 a = test_expr();
5052 skip(';');
5053 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005054 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005055 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005056 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005057 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005058 n = t + 4;
5059 }
5060 }
5061 skip(')');
Jack Palevichc951c592009-10-29 15:04:27 -07005062 block(&a, n, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005063 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005064 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005065 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005066 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005067 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005068 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005069 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005070 while (tok != '}' && tok != EOF)
Jack Palevichc951c592009-10-29 15:04:27 -07005071 block(breakLabel, continueAddress, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005072 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005073 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005074 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005075 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005076 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005077 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005078 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005079 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005080 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005081 if (pReturnType->tag == TY_VOID) {
5082 error("Must not return a value from a void function");
5083 } else {
5084 pGen->convertR0(pReturnType);
5085 }
5086 } else {
5087 if (pReturnType->tag != TY_VOID) {
5088 error("Must specify a value here");
5089 }
Jack Palevich8df46192009-07-07 14:48:51 -07005090 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005091 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005092 } else if (accept(TOK_BREAK)) {
Jack Palevichc951c592009-10-29 15:04:27 -07005093 if (breakLabel) {
5094 *breakLabel = pGen->gjmp(*breakLabel);
5095 } else {
5096 error("break statement must be within a for, do, while, or switch statement");
5097 }
5098 } else if (accept(TOK_CONTINUE)) {
5099 if (continueAddress) {
5100 pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset());
5101 } else {
5102 error("continue statement must be within a for, do, or while statement");
5103 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005104 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005105 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005106 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005107 }
5108 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005109
Jack Palevicha8f427f2009-07-13 18:40:08 -07005110 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005111 if (a == b) {
5112 return true;
5113 }
5114 if (a == NULL || b == NULL) {
5115 return false;
5116 }
5117 TypeTag at = a->tag;
5118 if (at != b->tag) {
5119 return false;
5120 }
5121 if (at == TY_POINTER) {
5122 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005123 } else if (at == TY_ARRAY) {
5124 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005125 } else if (at == TY_FUNC || at == TY_PARAM) {
5126 return typeEqual(a->pHead, b->pHead)
5127 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005128 } else if (at == TY_STRUCT) {
5129 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005130 }
5131 return true;
5132 }
5133
Jack Palevich2ff5c222009-07-23 15:11:22 -07005134 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005135 assert(tag >= TY_UNKNOWN && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005136 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005137 memset(pType, 0, sizeof(*pType));
Jack Palevichee1f8292009-10-28 16:10:17 -07005138 pType->storageClass = SC_DEFAULT;
Jack Palevich86351982009-06-30 18:09:56 -07005139 pType->tag = tag;
5140 pType->pHead = pHead;
5141 pType->pTail = pTail;
5142 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005143 }
5144
Jack Palevich2ff5c222009-07-23 15:11:22 -07005145 Type* createPtrType(Type* pType) {
5146 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005147 }
5148
5149 /**
5150 * Try to print a type in declaration order
5151 */
Jack Palevich86351982009-06-30 18:09:56 -07005152 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005153 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005154 if (pType == NULL) {
5155 buffer.appendCStr("null");
5156 return;
5157 }
Jack Palevich3f226492009-07-02 14:46:19 -07005158 decodeTypeImp(buffer, pType);
5159 }
5160
5161 void decodeTypeImp(String& buffer, Type* pType) {
5162 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005163 decodeId(buffer, pType->id);
5164 decodeTypeImpPostfix(buffer, pType);
5165 }
Jack Palevich3f226492009-07-02 14:46:19 -07005166
Jack Palevich9221bcc2009-08-26 16:15:07 -07005167 void decodeId(String& buffer, tokenid_t id) {
5168 if (id) {
5169 String temp;
5170 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005171 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005172 }
Jack Palevich3f226492009-07-02 14:46:19 -07005173 }
5174
5175 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5176 TypeTag tag = pType->tag;
5177
Jack Palevich9221bcc2009-08-26 16:15:07 -07005178 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005179 switch (tag) {
5180 case TY_INT:
5181 buffer.appendCStr("int");
5182 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005183 case TY_SHORT:
5184 buffer.appendCStr("short");
5185 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005186 case TY_CHAR:
5187 buffer.appendCStr("char");
5188 break;
5189 case TY_VOID:
5190 buffer.appendCStr("void");
5191 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005192 case TY_FLOAT:
5193 buffer.appendCStr("float");
5194 break;
5195 case TY_DOUBLE:
5196 buffer.appendCStr("double");
5197 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005198 case TY_STRUCT:
5199 {
5200 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5201 buffer.appendCStr(isStruct ? "struct" : "union");
5202 if (pType->pHead && pType->pHead->structTag) {
5203 buffer.append(' ');
5204 decodeId(buffer, pType->pHead->structTag);
5205 }
5206 }
5207 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005208 default:
5209 break;
5210 }
Jack Palevich86351982009-06-30 18:09:56 -07005211 buffer.append(' ');
5212 }
Jack Palevich3f226492009-07-02 14:46:19 -07005213
5214 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005215 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005216 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005217 case TY_SHORT:
5218 break;
Jack Palevich86351982009-06-30 18:09:56 -07005219 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005220 break;
5221 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005222 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005223 case TY_FLOAT:
5224 break;
5225 case TY_DOUBLE:
5226 break;
Jack Palevich86351982009-06-30 18:09:56 -07005227 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005228 decodeTypeImpPrefix(buffer, pType->pHead);
5229 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5230 buffer.append('(');
5231 }
5232 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005233 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005234 case TY_ARRAY:
5235 decodeTypeImpPrefix(buffer, pType->pHead);
5236 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005237 case TY_STRUCT:
5238 break;
Jack Palevich86351982009-06-30 18:09:56 -07005239 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005240 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005241 break;
5242 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005243 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005244 break;
5245 default:
5246 String temp;
5247 temp.printf("Unknown tag %d", pType->tag);
5248 buffer.append(temp);
5249 break;
5250 }
Jack Palevich3f226492009-07-02 14:46:19 -07005251 }
5252
5253 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5254 TypeTag tag = pType->tag;
5255
5256 switch(tag) {
5257 case TY_POINTER:
5258 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5259 buffer.append(')');
5260 }
5261 decodeTypeImpPostfix(buffer, pType->pHead);
5262 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005263 case TY_ARRAY:
5264 {
5265 String temp;
5266 temp.printf("[%d]", pType->length);
5267 buffer.append(temp);
5268 }
5269 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005270 case TY_STRUCT:
5271 if (pType->pHead->length >= 0) {
5272 buffer.appendCStr(" {");
5273 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5274 decodeTypeImp(buffer, pArg->pHead);
5275 buffer.appendCStr(";");
5276 }
5277 buffer.append('}');
5278 }
5279 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005280 case TY_FUNC:
5281 buffer.append('(');
5282 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5283 decodeTypeImp(buffer, pArg);
5284 if (pArg->pTail) {
5285 buffer.appendCStr(", ");
5286 }
5287 }
5288 buffer.append(')');
5289 break;
5290 default:
5291 break;
Jack Palevich86351982009-06-30 18:09:56 -07005292 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005293 }
5294
Jack Palevich86351982009-06-30 18:09:56 -07005295 void printType(Type* pType) {
5296 String buffer;
5297 decodeType(buffer, pType);
5298 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005299 }
5300
Jack Palevichee1f8292009-10-28 16:10:17 -07005301 void insertTypeSpecifier(Type** ppType, TypeTag tag) {
5302 if (! *ppType) {
5303 *ppType = createType(tag, NULL, NULL);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005304 } else {
Jack Palevichee1f8292009-10-28 16:10:17 -07005305 if ((*ppType)->tag != TY_UNKNOWN) {
5306 error("Only one type specifier allowed.");
5307 } else {
5308 (*ppType)->tag = tag;
5309 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005310 }
Jack Palevichee1f8292009-10-28 16:10:17 -07005311 }
5312
5313 void insertStorageClass(Type** ppType, StorageClass storageClass) {
5314 if (! *ppType) {
5315 *ppType = createType(TY_UNKNOWN, NULL, NULL);
5316 }
5317 if ((*ppType)->storageClass != SC_DEFAULT) {
5318 error("Only one storage class allowed.");
5319 } else {
5320 (*ppType)->storageClass = storageClass;
5321 }
5322 }
5323
5324 Type* acceptPrimitiveType(bool allowStorageClass) {
5325 Type* pType = NULL;
5326 for (bool keepGoing = true; keepGoing;) {
5327 switch(tok) {
5328 case TOK_AUTO:
5329 insertStorageClass(&pType, SC_AUTO);
5330 break;
5331 case TOK_REGISTER:
5332 insertStorageClass(&pType, SC_REGISTER);
5333 break;
5334 case TOK_STATIC:
5335 insertStorageClass(&pType, SC_STATIC);
5336 break;
5337 case TOK_EXTERN:
5338 insertStorageClass(&pType, SC_EXTERN);
5339 break;
5340 case TOK_TYPEDEF:
5341 insertStorageClass(&pType, SC_TYPEDEF);
5342 break;
5343 case TOK_INT:
5344 insertTypeSpecifier(&pType, TY_INT);
5345 break;
5346 case TOK_SHORT:
5347 insertTypeSpecifier(&pType, TY_SHORT);
5348 break;
5349 case TOK_CHAR:
5350 insertTypeSpecifier(&pType, TY_CHAR);
5351 break;
5352 case TOK_VOID:
5353 insertTypeSpecifier(&pType, TY_VOID);
5354 break;
5355 case TOK_FLOAT:
5356 insertTypeSpecifier(&pType, TY_FLOAT);
5357 break;
5358 case TOK_DOUBLE:
5359 insertTypeSpecifier(&pType, TY_DOUBLE);
5360 break;
5361 case TOK_STRUCT:
5362 case TOK_UNION:
5363 {
5364 insertTypeSpecifier(&pType, TY_STRUCT);
5365 bool isStruct = (tok == TOK_STRUCT);
5366 next();
5367 pType = acceptStruct(pType, isStruct);
5368 keepGoing = false;
5369 }
5370 break;
5371 default:
5372 // Is it a typedef?
5373 if (isSymbol(tok)) {
5374 VariableInfo* pV = VI(tok);
5375 if (pV && pV->pType->storageClass == SC_TYPEDEF) {
5376 if (! pType) {
5377 pType = createType(TY_UNKNOWN, NULL, NULL);
5378 }
5379 StorageClass storageClass = pType->storageClass;
5380 *pType = *pV->pType;
5381 pType->storageClass = storageClass;
5382 } else {
5383 keepGoing = false;
5384 }
5385 } else {
5386 keepGoing = false;
5387 }
5388 }
5389 if (keepGoing) {
5390 next();
5391 }
5392 }
5393 if (pType) {
5394 if (pType->tag == TY_UNKNOWN) {
5395 pType->tag = TY_INT;
5396 }
5397 if (allowStorageClass) {
5398 switch(pType->storageClass) {
5399 case SC_AUTO: error("auto not supported."); break;
5400 case SC_REGISTER: error("register not supported."); break;
5401 case SC_STATIC: error("static not supported."); break;
5402 case SC_EXTERN: error("extern not supported."); break;
5403 default: break;
5404 }
5405 } else {
5406 if (pType->storageClass != SC_DEFAULT) {
5407 error("An explicit storage class is not allowed in this type declaration");
5408 }
5409 }
5410 }
Jack Palevich86351982009-06-30 18:09:56 -07005411 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005412 }
5413
Jack Palevichee1f8292009-10-28 16:10:17 -07005414 Type* acceptStruct(Type* pStructType, bool isStruct) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005415 tokenid_t structTag = acceptSymbol();
5416 bool isDeclaration = accept('{');
5417 bool fail = false;
5418
Jack Palevich9221bcc2009-08-26 16:15:07 -07005419 if (structTag) {
5420 Token* pToken = &mTokenTable[structTag];
5421 VariableInfo* pStructInfo = pToken->mpStructInfo;
5422 bool needToDeclare = !pStructInfo;
5423 if (pStructInfo) {
5424 if (isDeclaration) {
5425 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5426 if (pStructInfo->pType->pHead->length == -1) {
5427 // we're filling in a forward declaration.
5428 needToDeclare = false;
5429 } else {
5430 error("A struct with the same name is already defined at this level.");
5431 fail = true;
5432 }
5433 } else {
5434 needToDeclare = true;
5435 }
5436 }
5437 if (!fail) {
5438 assert(pStructInfo->isStructTag);
5439 pStructType->pHead = pStructInfo->pType;
5440 pStructType->pTail = pStructType->pHead->pTail;
5441 }
5442 }
5443
5444 if (needToDeclare) {
5445 // This is a new struct name
5446 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
Jack Palevichee1f8292009-10-28 16:10:17 -07005447 StorageClass storageClass = pStructType->storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005448 pStructType = createType(TY_STRUCT, NULL, NULL);
5449 pStructType->structTag = structTag;
5450 pStructType->pHead = pStructType;
Jack Palevichee1f8292009-10-28 16:10:17 -07005451 pStructType->storageClass = storageClass;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005452 if (! isDeclaration) {
5453 // A forward declaration
5454 pStructType->length = -1;
5455 }
5456 pToken->mpStructInfo->pType = pStructType;
5457 }
5458 } else {
5459 // An anonymous struct
5460 pStructType->pHead = pStructType;
5461 }
5462
5463 if (isDeclaration) {
5464 size_t offset = 0;
5465 size_t structSize = 0;
5466 size_t structAlignment = 0;
5467 Type** pParamHolder = & pStructType->pHead->pTail;
5468 while (tok != '}' && tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005469 Type* pPrimitiveType = expectPrimitiveType(false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005470 if (pPrimitiveType) {
5471 while (tok != ';' && tok != EOF) {
5472 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5473 if (!pItem) {
5474 break;
5475 }
5476 if (lookupStructMember(pStructType, pItem->id)) {
5477 String buf;
5478 decodeToken(buf, pItem->id, false);
5479 error("Duplicate struct member %s", buf.getUnwrapped());
5480 }
5481 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5482 size_t alignment = pGen->alignmentOf(pItem);
5483 if (alignment > structAlignment) {
5484 structAlignment = alignment;
5485 }
5486 size_t alignmentMask = alignment - 1;
5487 offset = (offset + alignmentMask) & ~alignmentMask;
5488 pStructElement->length = offset;
5489 size_t size = pGen->sizeOf(pItem);
5490 if (isStruct) {
5491 offset += size;
5492 structSize = offset;
5493 } else {
5494 if (size >= structSize) {
5495 structSize = size;
5496 }
5497 }
5498 *pParamHolder = pStructElement;
5499 pParamHolder = &pStructElement->pTail;
5500 accept(',');
5501 }
5502 skip(';');
5503 } else {
5504 // Some sort of syntax error, skip token and keep trying
5505 next();
5506 }
5507 }
5508 if (!fail) {
5509 pStructType->pHead->length = structSize;
5510 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5511 }
5512 skip('}');
5513 }
5514 if (fail) {
5515 pStructType = NULL;
5516 }
5517 return pStructType;
5518 }
5519
5520 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5521 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5522 if (pStructElement->pHead->id == memberId) {
5523 return pStructElement;
5524 }
5525 }
5526 return NULL;
5527 }
5528
Jack Palevich2ff5c222009-07-23 15:11:22 -07005529 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005530 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005531 bool reportFailure = false;
Jack Palevichee1f8292009-10-28 16:10:17 -07005532 StorageClass storageClass = pType->storageClass;
Jack Palevich3f226492009-07-02 14:46:19 -07005533 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005534 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005535 if (declName) {
5536 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005537 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005538 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005539 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005540 pType->id = declName;
Jack Palevichee1f8292009-10-28 16:10:17 -07005541 pType->storageClass = storageClass;
Jack Palevichb6154502009-08-04 14:56:09 -07005542 } else if (nameRequired) {
5543 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005544 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005545#if 0
5546 fprintf(stderr, "Parsed a declaration: ");
5547 printType(pType);
5548#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005549 if (reportFailure) {
5550 return NULL;
5551 }
Jack Palevich86351982009-06-30 18:09:56 -07005552 return pType;
5553 }
5554
Jack Palevich2ff5c222009-07-23 15:11:22 -07005555 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005556 bool nameRequired = pBaseType->tag != TY_STRUCT;
5557 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005558 if (! pType) {
5559 error("Expected a declaration");
5560 }
5561 return pType;
5562 }
5563
Jack Palevich3f226492009-07-02 14:46:19 -07005564 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005565 Type* acceptCastTypeDeclaration() {
Jack Palevichee1f8292009-10-28 16:10:17 -07005566 Type* pType = acceptPrimitiveType(false);
Jack Palevich3f226492009-07-02 14:46:19 -07005567 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005568 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005569 }
Jack Palevich86351982009-06-30 18:09:56 -07005570 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005571 }
5572
Jack Palevich2ff5c222009-07-23 15:11:22 -07005573 Type* expectCastTypeDeclaration() {
5574 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005575 if (! pType) {
5576 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005577 }
Jack Palevich3f226492009-07-02 14:46:19 -07005578 return pType;
5579 }
5580
5581 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005582 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005583 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005584 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005585 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005586 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005587 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005588 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005589 return pType;
5590 }
5591
5592 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005593 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005594 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005595 // direct-dcl :
5596 // name
5597 // (dcl)
5598 // direct-dcl()
5599 // direct-dcl[]
5600 Type* pNewHead = NULL;
5601 if (accept('(')) {
5602 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005603 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005604 skip(')');
5605 } else if ((declName = acceptSymbol()) != 0) {
5606 if (nameAllowed == false && declName) {
5607 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005608 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005609 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005610 } else if (nameRequired && ! declName) {
5611 String temp;
5612 decodeToken(temp, tok, true);
5613 error("Expected name. Got %s", temp.getUnwrapped());
5614 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005615 }
Jack Palevichb6154502009-08-04 14:56:09 -07005616 for(;;) {
5617 if (accept('(')) {
5618 // Function declaration
5619 Type* pTail = acceptArgs(nameAllowed);
5620 pType = createType(TY_FUNC, pType, pTail);
5621 skip(')');
5622 } if (accept('[')) {
5623 if (tok != ']') {
5624 if (tok != TOK_NUM || tokc <= 0) {
5625 error("Expected positive integer constant");
5626 } else {
5627 Type* pDecayType = createPtrType(pType);
5628 pType = createType(TY_ARRAY, pType, pDecayType);
5629 pType->length = tokc;
5630 }
5631 next();
5632 }
5633 skip(']');
5634 } else {
5635 break;
5636 }
Jack Palevich86351982009-06-30 18:09:56 -07005637 }
Jack Palevich3f226492009-07-02 14:46:19 -07005638
5639 if (pNewHead) {
5640 Type* pA = pNewHead;
5641 while (pA->pHead) {
5642 pA = pA->pHead;
5643 }
5644 pA->pHead = pType;
5645 pType = pNewHead;
5646 }
Jack Palevich86351982009-06-30 18:09:56 -07005647 return pType;
5648 }
5649
Jack Palevich2ff5c222009-07-23 15:11:22 -07005650 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005651 Type* pHead = NULL;
5652 Type* pTail = NULL;
5653 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005654 Type* pBaseArg = acceptPrimitiveType(false);
Jack Palevich86351982009-06-30 18:09:56 -07005655 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005656 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005657 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005658 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005659 if (!pHead) {
5660 pHead = pParam;
5661 pTail = pParam;
5662 } else {
5663 pTail->pTail = pParam;
5664 pTail = pParam;
5665 }
5666 }
5667 }
5668 if (! accept(',')) {
5669 break;
5670 }
5671 }
5672 return pHead;
5673 }
5674
Jack Palevichee1f8292009-10-28 16:10:17 -07005675 Type* expectPrimitiveType(bool allowStorageClass) {
5676 Type* pType = acceptPrimitiveType(allowStorageClass);
Jack Palevich86351982009-06-30 18:09:56 -07005677 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005678 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005679 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005680 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005681 }
Jack Palevich86351982009-06-30 18:09:56 -07005682 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005683 }
5684
Jack Palevichb5e33312009-07-30 19:06:34 -07005685 void checkLVal() {
5686 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005687 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005688 }
5689 }
5690
Jack Palevich86351982009-06-30 18:09:56 -07005691 void addGlobalSymbol(Type* pDecl) {
5692 tokenid_t t = pDecl->id;
5693 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005694 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005695 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005696 }
Jack Palevich86351982009-06-30 18:09:56 -07005697 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005698 }
5699
Jack Palevich86351982009-06-30 18:09:56 -07005700 void reportDuplicate(tokenid_t t) {
5701 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005702 }
5703
Jack Palevich86351982009-06-30 18:09:56 -07005704 void addLocalSymbol(Type* pDecl) {
5705 tokenid_t t = pDecl->id;
5706 if (mLocals.isDefinedAtCurrentLevel(t)) {
5707 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005708 }
Jack Palevich86351982009-06-30 18:09:56 -07005709 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005710 }
5711
Jack Palevich61de31f2009-09-08 11:06:40 -07005712 bool checkUndeclaredStruct(Type* pBaseType) {
5713 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5714 String temp;
5715 decodeToken(temp, pBaseType->structTag, false);
5716 error("Undeclared struct %s", temp.getUnwrapped());
5717 return true;
5718 }
5719 return false;
5720 }
5721
Jack Palevich95727a02009-07-06 12:07:15 -07005722 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005723 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005724
Jack Palevich95727a02009-07-06 12:07:15 -07005725 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005726 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005727 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005728 if (!pDecl) {
5729 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005730 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005731 if (!pDecl->id) {
5732 break;
5733 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005734 if (checkUndeclaredStruct(pDecl)) {
5735 break;
5736 }
Jack Palevich86351982009-06-30 18:09:56 -07005737 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005738 if (pDecl->tag == TY_FUNC) {
5739 if (tok == '{') {
5740 error("Nested functions are not allowed. Did you forget a '}' ?");
5741 break;
5742 }
5743 // Else it's a forward declaration of a function.
Jack Palevichee1f8292009-10-28 16:10:17 -07005744 } else if (pDecl->storageClass != SC_TYPEDEF) {
Jack Palevich1c60e462009-09-18 15:03:03 -07005745 int variableAddress = 0;
5746 size_t alignment = pGen->alignmentOf(pDecl);
5747 assert(alignment > 0);
5748 size_t alignmentMask = ~ (alignment - 1);
5749 size_t sizeOf = pGen->sizeOf(pDecl);
5750 assert(sizeOf > 0);
5751 loc = (loc + alignment - 1) & alignmentMask;
5752 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5753 loc = loc + alignedSize;
5754 variableAddress = -loc;
5755 VI(pDecl->id)->pAddress = (void*) variableAddress;
5756 if (accept('=')) {
5757 /* assignment */
5758 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5759 pGen->pushR0();
5760 expr();
5761 pGen->forceR0RVal();
5762 pGen->storeR0ToTOS();
5763 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005764 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005765 if (tok == ',')
5766 next();
5767 }
5768 skip(';');
Jack Palevichee1f8292009-10-28 16:10:17 -07005769 pBaseType = acceptPrimitiveType(true);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005770 }
5771 }
5772
Jack Palevichf1728be2009-06-12 13:53:51 -07005773 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005774 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005775 }
5776
Jack Palevich37c54bd2009-07-14 18:35:36 -07005777 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005778 if (token == EOF ) {
5779 buffer.printf("EOF");
5780 } else if (token == TOK_NUM) {
Jack Palevich188a5a72009-10-27 17:23:20 -07005781 buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
5782 } else if (token == TOK_NUM_FLOAT) {
5783 buffer.printf("numeric constant float %g", tokd);
5784 } else if (token == TOK_NUM_DOUBLE) {
5785 buffer.printf("numeric constant double %g", tokd);
5786 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005787 if (token < 32) {
5788 buffer.printf("'\\x%02x'", token);
5789 } else {
5790 buffer.printf("'%c'", token);
5791 }
Jack Palevich569f1352009-06-29 14:29:08 -07005792 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005793 if (quote) {
5794 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5795 buffer.printf("keyword \"%s\"", nameof(token));
5796 } else {
5797 buffer.printf("symbol \"%s\"", nameof(token));
5798 }
5799 } else {
5800 buffer.printf("%s", nameof(token));
5801 }
Jack Palevich569f1352009-06-29 14:29:08 -07005802 }
5803 }
5804
Jack Palevich9221bcc2009-08-26 16:15:07 -07005805 void printToken(tokenid_t token) {
5806 String buffer;
5807 decodeToken(buffer, token, true);
5808 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5809 }
5810
Jack Palevich40600de2009-07-01 15:32:35 -07005811 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005812 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005813 if (!result) {
5814 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005815 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005816 error("Expected symbol. Got %s", temp.getUnwrapped());
5817 }
5818 return result;
5819 }
5820
Jack Palevich86351982009-06-30 18:09:56 -07005821 tokenid_t acceptSymbol() {
5822 tokenid_t result = 0;
5823 if (tok >= TOK_SYMBOL) {
5824 result = tok;
5825 next();
Jack Palevich86351982009-06-30 18:09:56 -07005826 }
5827 return result;
5828 }
5829
Jack Palevichb7c81e92009-06-04 19:56:13 -07005830 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005831 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005832 while (tok != EOF) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005833 Type* pBaseType = expectPrimitiveType(true);
Jack Palevich86351982009-06-30 18:09:56 -07005834 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005835 break;
5836 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005837 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005838 if (!pDecl) {
5839 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005840 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005841 if (!pDecl->id) {
5842 skip(';');
5843 continue;
5844 }
5845
Jack Palevich61de31f2009-09-08 11:06:40 -07005846 if (checkUndeclaredStruct(pDecl)) {
5847 skip(';');
5848 continue;
5849 }
Jack Palevich86351982009-06-30 18:09:56 -07005850 if (! isDefined(pDecl->id)) {
5851 addGlobalSymbol(pDecl);
5852 }
5853 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005854 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005855 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005856 }
Jack Palevich86351982009-06-30 18:09:56 -07005857 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005858 // it's a variable declaration
5859 for(;;) {
Jack Palevichee1f8292009-10-28 16:10:17 -07005860 if (pDecl->storageClass == SC_TYPEDEF) {
5861 // Do not allocate storage.
5862 } else {
5863 if (name && !name->pAddress) {
5864 name->pAddress = (int*) allocGlobalSpace(
5865 pGen->alignmentOf(name->pType),
5866 pGen->sizeOf(name->pType));
5867 }
5868 if (accept('=')) {
5869 if (tok == TOK_NUM) {
5870 if (name) {
5871 * (int*) name->pAddress = tokc;
5872 }
5873 next();
5874 } else {
5875 error("Expected an integer constant");
Jack Palevichd7461a72009-06-12 14:26:58 -07005876 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005877 }
5878 }
Jack Palevich86351982009-06-30 18:09:56 -07005879 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005880 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005881 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005882 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005883 if (!pDecl) {
5884 break;
5885 }
5886 if (! isDefined(pDecl->id)) {
5887 addGlobalSymbol(pDecl);
5888 }
5889 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005890 }
5891 skip(';');
5892 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005893 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005894 if (accept(';')) {
5895 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005896 } else if (tok != '{') {
5897 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005898 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005899 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005900 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005901 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005902 /* patch forward references */
5903 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005904 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005905 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005906 }
5907 // Calculate stack offsets for parameters
5908 mLocals.pushLevel();
5909 intptr_t a = 8;
5910 int argCount = 0;
5911 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5912 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005913 if (pArg->id) {
5914 addLocalSymbol(pArg);
5915 }
Jack Palevich95727a02009-07-06 12:07:15 -07005916 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005917 Type* pPassingType = passingType(pArg);
5918 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005919 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005920 if (pArg->id) {
5921 VI(pArg->id)->pAddress = (void*) a;
5922 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005923 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005924 argCount++;
5925 }
5926 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005927 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005928 a = pGen->functionEntry(pDecl);
Jack Palevichc951c592009-10-29 15:04:27 -07005929 block(0, 0, true);
Jack Palevich95727a02009-07-06 12:07:15 -07005930 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005931 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005932 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005933 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005934 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005935 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005936 }
5937 }
5938 }
5939
Jack Palevich9221bcc2009-08-26 16:15:07 -07005940 Type* passingType(Type* pType) {
5941 switch (pType->tag) {
5942 case TY_CHAR:
5943 case TY_SHORT:
5944 return mkpInt;
5945 default:
5946 return pType;
5947 }
5948 }
5949
Jack Palevich9cbd2262009-07-08 16:48:41 -07005950 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5951 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5952 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005953 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005954 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005955 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005956 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005957 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005958 char* result = (char*) base;
5959 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005960 return result;
5961 }
5962
Jack Palevich21a15a22009-05-11 14:49:29 -07005963 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005964 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005965 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005966 pGlobalBase = 0;
5967 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005968 if (pGen) {
5969 delete pGen;
5970 pGen = 0;
5971 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005972 if (pCodeBuf) {
5973 delete pCodeBuf;
5974 pCodeBuf = 0;
5975 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005976 if (file) {
5977 delete file;
5978 file = 0;
5979 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005980 }
5981
Jack Palevich8c246a92009-07-14 21:14:10 -07005982 // One-time initialization, when class is constructed.
5983 void init() {
5984 mpSymbolLookupFn = 0;
5985 mpSymbolLookupContext = 0;
5986 }
5987
Jack Palevich21a15a22009-05-11 14:49:29 -07005988 void clear() {
5989 tok = 0;
5990 tokc = 0;
5991 tokl = 0;
5992 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005993 rsym = 0;
5994 loc = 0;
5995 glo = 0;
Jack Palevich188a5a72009-10-27 17:23:20 -07005996 macroLevel = -1;
Jack Palevich21a15a22009-05-11 14:49:29 -07005997 file = 0;
5998 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005999 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07006000 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07006001 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07006002 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07006003 mLineNumber = 1;
6004 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07006005 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07006006 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006007
Jack Palevich22305132009-05-13 10:58:45 -07006008 void setArchitecture(const char* architecture) {
6009 delete pGen;
6010 pGen = 0;
6011
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006012 delete pCodeBuf;
6013 pCodeBuf = new CodeBuf();
6014
Jack Palevich22305132009-05-13 10:58:45 -07006015 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006016#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006017 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006018 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006019 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07006020 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006021#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07006022#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07006023 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07006024 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07006025 }
Jack Paleviche7b59062009-05-19 17:12:17 -07006026#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07006027 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006028 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07006029 }
6030 }
6031
6032 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07006033#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07006034 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006035 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07006036#elif defined(DEFAULT_X86_CODEGEN)
6037 pGen = new X86CodeGenerator();
6038#endif
6039 }
6040 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006041 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07006042 } else {
6043 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07006044 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07006045 }
6046 }
6047
Jack Palevich77ae76e2009-05-10 19:59:24 -07006048public:
Jack Palevich22305132009-05-13 10:58:45 -07006049 struct args {
6050 args() {
6051 architecture = 0;
6052 }
6053 const char* architecture;
6054 };
6055
Jack Paleviche7b59062009-05-19 17:12:17 -07006056 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07006057 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07006058 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07006059 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006060
Jack Paleviche7b59062009-05-19 17:12:17 -07006061 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07006062 cleanup();
6063 }
6064
Jack Palevich8c246a92009-07-14 21:14:10 -07006065 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6066 mpSymbolLookupFn = pFn;
6067 mpSymbolLookupContext = pContext;
6068 }
6069
Jack Palevich1cdef202009-05-22 12:06:27 -07006070 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006071 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07006072
Jack Palevich2ff5c222009-07-23 15:11:22 -07006073 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07006074 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07006075 cleanup();
6076 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07006077 mTokenTable.setArena(&mGlobalArena);
6078 mGlobals.setArena(&mGlobalArena);
6079 mGlobals.setTokenTable(&mTokenTable);
6080 mLocals.setArena(&mLocalArena);
6081 mLocals.setTokenTable(&mTokenTable);
6082
6083 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07006084 setArchitecture(NULL);
6085 if (!pGen) {
6086 return -1;
6087 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07006088#ifdef PROVIDE_TRACE_CODEGEN
6089 pGen = new TraceCodeGenerator(pGen);
6090#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006091 pGen->setErrorSink(this);
6092
6093 if (pCodeBuf) {
6094 pCodeBuf->init(ALLOC_SIZE);
6095 }
6096 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07006097 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07006098 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
6099 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07006100 inp();
6101 next();
6102 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07006103 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07006104 result = pGen->finishCompile();
6105 if (result == 0) {
6106 if (mErrorBuf.len()) {
6107 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006108 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07006109 }
Jack Palevichce105a92009-07-16 14:30:33 -07006110 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07006111 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07006112 }
6113
Jack Palevich86351982009-06-30 18:09:56 -07006114 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07006115 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07006116 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07006117 mkpChar = createType(TY_CHAR, NULL, NULL);
6118 mkpVoid = createType(TY_VOID, NULL, NULL);
6119 mkpFloat = createType(TY_FLOAT, NULL, NULL);
6120 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
6121 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
6122 mkpIntPtr = createPtrType(mkpInt);
6123 mkpCharPtr = createPtrType(mkpChar);
6124 mkpFloatPtr = createPtrType(mkpFloat);
6125 mkpDoublePtr = createPtrType(mkpDouble);
6126 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07006127 }
6128
Jack Palevicha6baa232009-06-12 11:25:59 -07006129 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07006130 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07006131 }
6132
Jack Palevich569f1352009-06-29 14:29:08 -07006133 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006134 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07006135 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07006136 }
6137
Jack Palevich569f1352009-06-29 14:29:08 -07006138 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006139 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07006140 error("Undefined forward reference: %s",
6141 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07006142 }
6143 return true;
6144 }
6145
Jack Palevich1cdef202009-05-22 12:06:27 -07006146 /* Look through the symbol table to find a symbol.
6147 * If found, return its value.
6148 */
6149 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07006150 if (mCompileResult == 0) {
6151 tokenid_t tok = mTokenTable.intern(name, strlen(name));
6152 VariableInfo* pVariableInfo = VI(tok);
6153 if (pVariableInfo) {
6154 return pVariableInfo->pAddress;
6155 }
Jack Palevich1cdef202009-05-22 12:06:27 -07006156 }
6157 return NULL;
6158 }
6159
Jack Palevicheedf9d22009-06-04 16:23:40 -07006160 void getPragmas(ACCsizei* actualStringCount,
6161 ACCsizei maxStringCount, ACCchar** strings) {
6162 int stringCount = mPragmaStringCount;
6163 if (actualStringCount) {
6164 *actualStringCount = stringCount;
6165 }
6166 if (stringCount > maxStringCount) {
6167 stringCount = maxStringCount;
6168 }
6169 if (strings) {
6170 char* pPragmas = mPragmas.getUnwrapped();
6171 while (stringCount-- > 0) {
6172 *strings++ = pPragmas;
6173 pPragmas += strlen(pPragmas) + 1;
6174 }
6175 }
6176 }
6177
Jack Palevichd5315572009-09-09 13:19:34 -07006178 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006179 *base = pCodeBuf->getBase();
6180 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006181 }
6182
Jack Palevichac0e95e2009-05-29 13:53:44 -07006183 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006184 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006185 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006186};
6187
Jack Paleviche7b59062009-05-19 17:12:17 -07006188const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006189 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6190
Jack Paleviche7b59062009-05-19 17:12:17 -07006191const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006192 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6193 5, 5, /* ==, != */
6194 9, 10, /* &&, || */
6195 6, 7, 8, /* & ^ | */
6196 2, 2 /* ~ ! */
6197 };
6198
Jack Palevich8b0624c2009-05-20 12:12:06 -07006199#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006200const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006201 0x1, // ++
6202 0xff, // --
6203 0xc1af0f, // *
6204 0xf9f79991, // /
6205 0xf9f79991, // % (With manual assist to swap results)
6206 0xc801, // +
6207 0xd8f7c829, // -
6208 0xe0d391, // <<
6209 0xf8d391, // >>
6210 0xe, // <=
6211 0xd, // >=
6212 0xc, // <
6213 0xf, // >
6214 0x4, // ==
6215 0x5, // !=
6216 0x0, // &&
6217 0x1, // ||
6218 0xc821, // &
6219 0xc831, // ^
6220 0xc809, // |
6221 0xd0f7, // ~
6222 0x4 // !
6223};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006224#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006225
Jack Palevich1cdef202009-05-22 12:06:27 -07006226struct ACCscript {
6227 ACCscript() {
6228 text = 0;
6229 textLength = 0;
6230 accError = ACC_NO_ERROR;
6231 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006232
Jack Palevich1cdef202009-05-22 12:06:27 -07006233 ~ACCscript() {
6234 delete text;
6235 }
Jack Palevich546b2242009-05-13 15:10:04 -07006236
Jack Palevich8c246a92009-07-14 21:14:10 -07006237 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6238 compiler.registerSymbolCallback(pFn, pContext);
6239 }
6240
Jack Palevich1cdef202009-05-22 12:06:27 -07006241 void setError(ACCenum error) {
6242 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6243 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006244 }
6245 }
6246
Jack Palevich1cdef202009-05-22 12:06:27 -07006247 ACCenum getError() {
6248 ACCenum result = accError;
6249 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006250 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006251 }
6252
Jack Palevich1cdef202009-05-22 12:06:27 -07006253 Compiler compiler;
6254 char* text;
6255 int textLength;
6256 ACCenum accError;
6257};
6258
6259
6260extern "C"
6261ACCscript* accCreateScript() {
6262 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006263}
Jack Palevich1cdef202009-05-22 12:06:27 -07006264
6265extern "C"
6266ACCenum accGetError( ACCscript* script ) {
6267 return script->getError();
6268}
6269
6270extern "C"
6271void accDeleteScript(ACCscript* script) {
6272 delete script;
6273}
6274
6275extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006276void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6277 ACCvoid* pContext) {
6278 script->registerSymbolCallback(pFn, pContext);
6279}
6280
6281extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006282void accScriptSource(ACCscript* script,
6283 ACCsizei count,
6284 const ACCchar ** string,
6285 const ACCint * length) {
6286 int totalLength = 0;
6287 for(int i = 0; i < count; i++) {
6288 int len = -1;
6289 const ACCchar* s = string[i];
6290 if (length) {
6291 len = length[i];
6292 }
6293 if (len < 0) {
6294 len = strlen(s);
6295 }
6296 totalLength += len;
6297 }
6298 delete script->text;
6299 char* text = new char[totalLength + 1];
6300 script->text = text;
6301 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006302 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006303 for(int i = 0; i < count; i++) {
6304 int len = -1;
6305 const ACCchar* s = string[i];
6306 if (length) {
6307 len = length[i];
6308 }
6309 if (len < 0) {
6310 len = strlen(s);
6311 }
Jack Palevich09555c72009-05-27 12:25:55 -07006312 memcpy(dest, s, len);
6313 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006314 }
6315 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006316
6317#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006318 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006319 int counter;
6320 char path[PATH_MAX];
6321 for (counter = 0; counter < 4096; counter++) {
6322 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6323 if(access(path, F_OK) != 0) {
6324 break;
6325 }
6326 }
6327 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006328 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006329 FILE* fd = fopen(path, "w");
6330 if (fd) {
6331 fwrite(text, totalLength, 1, fd);
6332 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006333 LOGD("Saved input to file %s", path);
6334 } else {
6335 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006336 }
6337 }
6338#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006339}
6340
6341extern "C"
6342void accCompileScript(ACCscript* script) {
6343 int result = script->compiler.compile(script->text, script->textLength);
6344 if (result) {
6345 script->setError(ACC_INVALID_OPERATION);
6346 }
6347}
6348
6349extern "C"
6350void accGetScriptiv(ACCscript* script,
6351 ACCenum pname,
6352 ACCint * params) {
6353 switch (pname) {
6354 case ACC_INFO_LOG_LENGTH:
6355 *params = 0;
6356 break;
6357 }
6358}
6359
6360extern "C"
6361void accGetScriptInfoLog(ACCscript* script,
6362 ACCsizei maxLength,
6363 ACCsizei * length,
6364 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006365 char* message = script->compiler.getErrorMessage();
6366 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006367 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006368 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006369 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006370 if (infoLog && maxLength > 0) {
6371 int trimmedLength = maxLength < messageLength ?
6372 maxLength : messageLength;
6373 memcpy(infoLog, message, trimmedLength);
6374 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006375 }
6376}
6377
6378extern "C"
6379void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6380 ACCvoid ** address) {
6381 void* value = script->compiler.lookup(name);
6382 if (value) {
6383 *address = value;
6384 } else {
6385 script->setError(ACC_INVALID_VALUE);
6386 }
6387}
6388
Jack Palevicheedf9d22009-06-04 16:23:40 -07006389extern "C"
6390void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6391 ACCsizei maxStringCount, ACCchar** strings){
6392 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6393}
6394
-b master422972c2009-06-17 19:13:52 -07006395extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006396void accGetProgramBinary(ACCscript* script,
6397 ACCvoid** base, ACCsizei* length) {
6398 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006399}
6400
Jack Palevicheedf9d22009-06-04 16:23:40 -07006401
Jack Palevich1cdef202009-05-22 12:06:27 -07006402} // namespace acc
6403