blob: 09ce64d16ba57f5b0043de5482039ee7fd46afc2 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070016#include <limits.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070017#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070018#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070020#include <stdlib.h>
21#include <string.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070022#include <unistd.h>
23
Jack Palevich2d11dfb2009-06-08 14:34:26 -070024#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070025
Jack Palevich8dc662e2009-06-09 22:53:47 +000026#if defined(__i386__)
27#include <sys/mman.h>
28#endif
29
Jack Palevich546b2242009-05-13 15:10:04 -070030
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Palevich30321cb2009-08-20 15:34:23 -070042#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
43#define ARM_USE_VFP
44#endif
45
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050
-b master422972c2009-06-17 19:13:52 -070051#define LOG_STACK(...) do {} while(0)
52// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
53
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichd30a2ce2009-09-09 19:08:54 -070056// Uncomment to disable ARM peephole optimizations
57// #define DISABLE_ARM_PEEPHOLE
58
Jack Palevich61de31f2009-09-08 11:06:40 -070059// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
60// #define DEBUG_SAVE_INPUT_TO_FILE
61
Jack Palevich9116bc42009-09-08 11:46:42 -070062#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070063#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070064#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070065#else
66#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
67#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070068#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070069
Jack Palevich7f5b1a22009-08-17 16:54:56 -070070#define assert(b) assertImpl(b, __LINE__)
71
Jack Palevichbbf8ab52009-05-11 11:54:30 -070072namespace acc {
73
Jack Palevich8df46192009-07-07 14:48:51 -070074// Subset of STL vector.
75template<class E> class Vector {
76 public:
77 Vector() {
78 mpBase = 0;
79 mUsed = 0;
80 mSize = 0;
81 }
82
83 ~Vector() {
84 if (mpBase) {
85 for(size_t i = 0; i < mUsed; i++) {
86 mpBase[mUsed].~E();
87 }
88 free(mpBase);
89 }
90 }
91
92 inline E& operator[](size_t i) {
93 return mpBase[i];
94 }
95
96 inline E& front() {
97 return mpBase[0];
98 }
99
100 inline E& back() {
101 return mpBase[mUsed - 1];
102 }
103
104 void pop_back() {
105 mUsed -= 1;
106 mpBase[mUsed].~E();
107 }
108
109 void push_back(const E& item) {
110 * ensure(1) = item;
111 }
112
113 size_t size() {
114 return mUsed;
115 }
116
117private:
118 E* ensure(int n) {
119 size_t newUsed = mUsed + n;
120 if (newUsed > mSize) {
121 size_t newSize = mSize * 2 + 10;
122 if (newSize < newUsed) {
123 newSize = newUsed;
124 }
125 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
126 mSize = newSize;
127 }
128 E* result = mpBase + mUsed;
129 mUsed = newUsed;
130 return result;
131 }
132
133 E* mpBase;
134 size_t mUsed;
135 size_t mSize;
136};
137
Jack Palevichac0e95e2009-05-29 13:53:44 -0700138class ErrorSink {
139public:
140 void error(const char *fmt, ...) {
141 va_list ap;
142 va_start(ap, fmt);
143 verror(fmt, ap);
144 va_end(ap);
145 }
146
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700147 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700148 virtual void verror(const char* fmt, va_list ap) = 0;
149};
150
151class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700152 typedef int tokenid_t;
153 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700154 TY_INT, // 0
155 TY_CHAR, // 1
156 TY_SHORT, // 2
157 TY_VOID, // 3
158 TY_FLOAT, // 4
159 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700160 TY_POINTER, // 6
161 TY_ARRAY, // 7
162 TY_STRUCT, // 8
163 TY_FUNC, // 9
164 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700165 };
166
167 struct Type {
168 TypeTag tag;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700169 tokenid_t id; // For function arguments, global vars, local vars, struct elements
170 tokenid_t structTag; // For structs the name of the struct
171 int length; // length of array, offset of struct element. -1 means struct is forward defined
172 int alignment; // for structs only
173 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700174 Type* pTail;
175 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700176
Jack Palevichba929a42009-07-17 10:20:32 -0700177 enum ExpressionType {
178 ET_RVALUE,
179 ET_LVALUE
180 };
181
182 struct ExpressionValue {
183 ExpressionValue() {
184 et = ET_RVALUE;
185 pType = NULL;
186 }
187 ExpressionType et;
188 Type* pType;
189 };
190
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700191 class ICodeBuf {
192 public:
193 virtual ~ICodeBuf() {}
194 virtual void init(int size) = 0;
195 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
196 virtual void o4(int n) = 0;
197 virtual void ob(int n) = 0;
198 virtual void* getBase() = 0;
199 virtual intptr_t getSize() = 0;
200 virtual intptr_t getPC() = 0;
201 // Call this before trying to modify code in the buffer.
202 virtual void flush() = 0;
203 };
204
205 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700206 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700207 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700208 ErrorSink* mErrorSink;
209 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700210 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700211
Jack Palevich21a15a22009-05-11 14:49:29 -0700212 void release() {
213 if (pProgramBase != 0) {
214 free(pProgramBase);
215 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700216 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 }
218
Jack Palevich0a280a02009-06-11 10:53:51 -0700219 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700220 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700221 bool overflow = newSize > mSize;
222 if (overflow && !mOverflowed) {
223 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700224 if (mErrorSink) {
225 mErrorSink->error("Code too large: %d bytes", newSize);
226 }
227 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700228 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 public:
232 CodeBuf() {
233 pProgramBase = 0;
234 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700235 mErrorSink = 0;
236 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700237 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700238 }
239
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700240 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 release();
242 }
243
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700244 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700245 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700246 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700247 pProgramBase = (char*) calloc(1, size);
248 ind = pProgramBase;
249 }
250
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700251 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700252 mErrorSink = pErrorSink;
253 }
254
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700255 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700256 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700257 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700258 }
Jack Palevich546b2242009-05-13 15:10:04 -0700259 * (int*) ind = n;
260 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700261 }
262
Jack Palevich21a15a22009-05-11 14:49:29 -0700263 /*
264 * Output a byte. Handles all values, 0..ff.
265 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700266 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700267 if(check(1)) {
268 return;
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 *ind++ = n;
271 }
272
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700273 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 return (void*) pProgramBase;
275 }
276
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700277 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700278 return ind - pProgramBase;
279 }
280
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700281 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700282 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700284
285 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700286 };
287
Jack Palevich1cdef202009-05-22 12:06:27 -0700288 /**
289 * A code generator creates an in-memory program, generating the code on
290 * the fly. There is one code generator implementation for each supported
291 * architecture.
292 *
293 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700294 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700295 * FP - a frame pointer for accessing function arguments and local
296 * variables.
297 * SP - a stack pointer for storing intermediate results while evaluating
298 * expressions. The stack pointer grows downwards.
299 *
300 * The function calling convention is that all arguments are placed on the
301 * stack such that the first argument has the lowest address.
302 * After the call, the result is in R0. The caller is responsible for
303 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700304 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700305 * FP and SP registers are saved.
306 */
307
Jack Palevich21a15a22009-05-11 14:49:29 -0700308 class CodeGenerator {
309 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700310 CodeGenerator() {
311 mErrorSink = 0;
312 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700313 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700314 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700315 virtual ~CodeGenerator() {}
316
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700317 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700318 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700319 pCodeBuf->setErrorSink(mErrorSink);
320 }
321
Jack Palevichb67b18f2009-06-11 21:12:23 -0700322 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700323 mErrorSink = pErrorSink;
324 if (pCodeBuf) {
325 pCodeBuf->setErrorSink(mErrorSink);
326 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700327 }
328
Jack Palevich58c30ee2009-07-17 16:35:23 -0700329 /* Give the code generator some utility types so it can
330 * use its own types as needed for the results of some
331 * operations like gcmp.
332 */
333
Jack Palevicha8f427f2009-07-13 18:40:08 -0700334 void setTypes(Type* pInt) {
335 mkpInt = pInt;
336 }
337
Jack Palevich1cdef202009-05-22 12:06:27 -0700338 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700339 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 * Save the old value of the FP.
341 * Set the new value of the FP.
342 * Convert from the native platform calling convention to
343 * our stack-based calling convention. This may require
344 * pushing arguments from registers to the stack.
345 * Allocate "N" bytes of stack space. N isn't known yet, so
346 * just emit the instructions for adjusting the stack, and return
347 * the address to patch up. The patching will be done in
348 * functionExit().
349 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700350 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700351 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700352
Jack Palevich1cdef202009-05-22 12:06:27 -0700353 /* Emit a function epilog.
354 * Restore the old SP and FP register values.
355 * Return to the calling function.
356 * argCount - the number of arguments to the function.
357 * localVariableAddress - returned from functionEntry()
358 * localVariableSize - the size in bytes of the local variables.
359 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700360 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700364 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700365
Jack Palevich1a539db2009-07-08 13:04:41 -0700366 /* Load floating point value from global address. */
367 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich9221bcc2009-08-26 16:15:07 -0700369 /* Add the struct offset in bytes to R0, change the type to pType */
370 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
371
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 /* Jump to a target, and return the address of the word that
373 * holds the target data, in case it needs to be fixed up later.
374 */
Jack Palevich22305132009-05-13 10:58:45 -0700375 virtual int gjmp(int t) = 0;
376
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 /* Test R0 and jump to a target if the test succeeds.
378 * l = 0: je, l == 1: jne
379 * Return the address of the word that holds the targed data, in
380 * case it needs to be fixed up later.
381 */
Jack Palevich22305132009-05-13 10:58:45 -0700382 virtual int gtst(bool l, int t) = 0;
383
Jack Palevich9eed7a22009-07-06 17:24:34 -0700384 /* Compare TOS against R0, and store the boolean result in R0.
385 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 * op specifies the comparison.
387 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700388 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich9eed7a22009-07-06 17:24:34 -0700390 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700392 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 */
Jack Palevich546b2242009-05-13 15:10:04 -0700394 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700395
Jack Palevich9eed7a22009-07-06 17:24:34 -0700396 /* Compare 0 against R0, and store the boolean result in R0.
397 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700398 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700399 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700400
401 /* Perform the arithmetic op specified by op. 0 is the
402 * left argument, R0 is the right argument.
403 */
404 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700406 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 */
408 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700410 /* Turn R0, TOS into R0 TOS R0 */
411
412 virtual void over() = 0;
413
414 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700415 */
416 virtual void popR0() = 0;
417
Jack Palevich9eed7a22009-07-06 17:24:34 -0700418 /* Store R0 to the address stored in TOS.
419 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700421 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700422
Jack Palevich1cdef202009-05-22 12:06:27 -0700423 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700424 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700425 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Load the absolute address of a variable to R0.
428 * If ea <= LOCAL, then this is a local variable, or an
429 * argument, addressed relative to FP.
430 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700431 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700432 * et is ET_RVALUE for things like string constants, ET_LVALUE for
433 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700435 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700436
Jack Palevich9f51a262009-07-29 16:22:26 -0700437 /* Load the pc-relative address of a forward-referenced variable to R0.
438 * Return the address of the 4-byte constant so that it can be filled
439 * in later.
440 */
441 virtual int leaForward(int ea, Type* pPointerType) = 0;
442
Jack Palevich8df46192009-07-07 14:48:51 -0700443 /**
444 * Convert R0 to the given type.
445 */
Jack Palevichb6154502009-08-04 14:56:09 -0700446
447 void convertR0(Type* pType) {
448 convertR0Imp(pType, false);
449 }
450
451 void castR0(Type* pType) {
452 convertR0Imp(pType, true);
453 }
454
455 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700456
Jack Palevich1cdef202009-05-22 12:06:27 -0700457 /* Emit code to adjust the stack for a function call. Return the
458 * label for the address of the instruction that adjusts the
459 * stack size. This will be passed as argument "a" to
460 * endFunctionCallArguments.
461 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700462 virtual int beginFunctionCallArguments() = 0;
463
Jack Palevich1cdef202009-05-22 12:06:27 -0700464 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700465 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700466 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700467 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700468
Jack Palevich1cdef202009-05-22 12:06:27 -0700469 /* Patch the function call preamble.
470 * a is the address returned from beginFunctionCallArguments
471 * l is the number of bytes the arguments took on the stack.
472 * Typically you would also emit code to convert the argument
473 * list into whatever the native function calling convention is.
474 * On ARM for example you would pop the first 5 arguments into
475 * R0..R4
476 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700477 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700478
Jack Palevich1cdef202009-05-22 12:06:27 -0700479 /* Emit a call to an unknown function. The argument "symbol" needs to
480 * be stored in the location where the address should go. It forms
481 * a chain. The address will be patched later.
482 * Return the address of the word that has to be patched.
483 */
Jack Palevich8df46192009-07-07 14:48:51 -0700484 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700485
Jack Palevich1cdef202009-05-22 12:06:27 -0700486 /* Call a function pointer. L is the number of bytes the arguments
487 * take on the stack. The address of the function is stored at
488 * location SP + l.
489 */
Jack Palevich8df46192009-07-07 14:48:51 -0700490 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700491
Jack Palevich1cdef202009-05-22 12:06:27 -0700492 /* Adjust SP after returning from a function call. l is the
493 * number of bytes of arguments stored on the stack. isIndirect
494 * is true if this was an indirect call. (In which case the
495 * address of the function is stored at location SP + l.)
496 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700497 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700498
Jack Palevich1cdef202009-05-22 12:06:27 -0700499 /* Generate a symbol at the current PC. t is the head of a
500 * linked list of addresses to patch.
501 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700502 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700503
Jack Palevich9f51a262009-07-29 16:22:26 -0700504 /* Resolve a forward reference function at the current PC.
505 * t is the head of a
506 * linked list of addresses to patch.
507 * (Like gsym, but using absolute address, not PC relative address.)
508 */
509 virtual void resolveForward(int t) = 0;
510
Jack Palevich1cdef202009-05-22 12:06:27 -0700511 /*
512 * Do any cleanup work required at the end of a compile.
513 * For example, an instruction cache might need to be
514 * invalidated.
515 * Return non-zero if there is an error.
516 */
517 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700518
Jack Palevicha6535612009-05-13 16:24:17 -0700519 /**
520 * Adjust relative branches by this amount.
521 */
522 virtual int jumpOffset() = 0;
523
Jack Palevich9eed7a22009-07-06 17:24:34 -0700524 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700525 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700526 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700527 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700528
529 /**
530 * Array element alignment (in bytes) for this type of data.
531 */
532 virtual size_t sizeOf(Type* type) = 0;
533
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700534 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700535 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700536 }
537
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700538 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700539 return mExpressionStack.back().et;
540 }
541
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700542 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700543 mExpressionStack.back().et = et;
544 }
545
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700546 virtual size_t getExpressionStackDepth() {
547 return mExpressionStack.size();
548 }
549
Jack Palevichb5e33312009-07-30 19:06:34 -0700550 virtual void forceR0RVal() {
551 if (getR0ExpressionType() == ET_LVALUE) {
552 loadR0FromR0();
553 }
554 }
555
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700557 /*
558 * Output a byte. Handles all values, 0..ff.
559 */
560 void ob(int n) {
561 pCodeBuf->ob(n);
562 }
563
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700564 void o4(int data) {
565 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700566 }
567
Jack Palevich8b0624c2009-05-20 12:12:06 -0700568 intptr_t getBase() {
569 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700570 }
571
Jack Palevich8b0624c2009-05-20 12:12:06 -0700572 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700573 return pCodeBuf->getPC();
574 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700575
576 intptr_t getSize() {
577 return pCodeBuf->getSize();
578 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700579
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700580 void flush() {
581 pCodeBuf->flush();
582 }
583
Jack Palevichac0e95e2009-05-29 13:53:44 -0700584 void error(const char* fmt,...) {
585 va_list ap;
586 va_start(ap, fmt);
587 mErrorSink->verror(fmt, ap);
588 va_end(ap);
589 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700590
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700591 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700592 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700593 error("code generator assertion failed at line %s:%d.", __FILE__, line);
594 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700595 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700596 }
597 }
Jack Palevich8df46192009-07-07 14:48:51 -0700598
599 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700600 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700601 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700602 mExpressionStack.back().et = ET_RVALUE;
603 }
604
605 void setR0Type(Type* pType, ExpressionType et) {
606 assert(pType != NULL);
607 mExpressionStack.back().pType = pType;
608 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700609 }
610
Jack Palevich8df46192009-07-07 14:48:51 -0700611 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700612 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700613 }
614
615 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700616 if (mExpressionStack.size()) {
617 mExpressionStack.push_back(mExpressionStack.back());
618 } else {
619 mExpressionStack.push_back(ExpressionValue());
620 }
621
Jack Palevich8df46192009-07-07 14:48:51 -0700622 }
623
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700624 void overType() {
625 size_t size = mExpressionStack.size();
626 if (size >= 2) {
627 mExpressionStack.push_back(mExpressionStack.back());
628 mExpressionStack[size-1] = mExpressionStack[size-2];
629 mExpressionStack[size-2] = mExpressionStack[size];
630 }
631 }
632
Jack Palevich8df46192009-07-07 14:48:51 -0700633 void popType() {
634 mExpressionStack.pop_back();
635 }
636
637 bool bitsSame(Type* pA, Type* pB) {
638 return collapseType(pA->tag) == collapseType(pB->tag);
639 }
640
641 TypeTag collapseType(TypeTag tag) {
642 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700643 TY_INT,
644 TY_INT,
645 TY_INT,
646 TY_VOID,
647 TY_FLOAT,
648 TY_DOUBLE,
649 TY_INT,
650 TY_INT,
651 TY_VOID,
652 TY_VOID,
653 TY_VOID
654 };
Jack Palevich8df46192009-07-07 14:48:51 -0700655 return collapsedTag[tag];
656 }
657
Jack Palevich1a539db2009-07-08 13:04:41 -0700658 TypeTag collapseTypeR0() {
659 return collapseType(getR0Type()->tag);
660 }
661
Jack Palevichb6154502009-08-04 14:56:09 -0700662 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700663 return isFloatTag(pType->tag);
664 }
665
Jack Palevichb6154502009-08-04 14:56:09 -0700666 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700667 return tag == TY_FLOAT || tag == TY_DOUBLE;
668 }
669
Jack Palevichb6154502009-08-04 14:56:09 -0700670 static bool isPointerType(Type* pType) {
671 return isPointerTag(pType->tag);
672 }
673
674 static bool isPointerTag(TypeTag tag) {
675 return tag == TY_POINTER || tag == TY_ARRAY;
676 }
677
678 Type* getPointerArithmeticResultType(Type* a, Type* b) {
679 TypeTag aTag = a->tag;
680 TypeTag bTag = b->tag;
681 if (aTag == TY_POINTER) {
682 return a;
683 }
684 if (bTag == TY_POINTER) {
685 return b;
686 }
687 if (aTag == TY_ARRAY) {
688 return a->pTail;
689 }
690 if (bTag == TY_ARRAY) {
691 return b->pTail;
692 }
693 return NULL;
694 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700695 Type* mkpInt;
696
Jack Palevich21a15a22009-05-11 14:49:29 -0700697 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700698 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700699 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700700 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700701 };
702
Jack Paleviche7b59062009-05-19 17:12:17 -0700703#ifdef PROVIDE_ARM_CODEGEN
704
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700705 static size_t rotateRight(size_t n, size_t rotate) {
706 return (n >> rotate) | (n << (32 - rotate));
707 }
708
709 static size_t rotateLeft(size_t n, size_t rotate) {
710 return (n << rotate) | (n >> (32 - rotate));
711 }
712
713 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
714 for(size_t i = 0; i < 16; i++) {
715 size_t rotate = i * 2;
716 size_t mask = rotateRight(0xff, rotate);
717 if ((immediate | mask) == mask) {
718 size_t bits8 = rotateLeft(immediate, rotate);
719 // assert(bits8 <= 0xff);
720 *pResult = (i << 8) | bits8;
721 return true;
722 }
723 }
724 return false;
725 }
726
727 static size_t decode12BitImmediate(size_t immediate) {
728 size_t data = immediate & 0xff;
729 size_t rotate = 2 * ((immediate >> 8) & 0xf);
730 return rotateRight(data, rotate);
731 }
732
Jack Palevich53f06582009-09-10 14:01:58 -0700733 static bool isPowerOfTwo(size_t n) {
734 return (n != 0) & ((n & (n-1)) == 0);
735 }
736
737 static size_t log2(size_t n) {
738 int result = 0;
739 while (n >>= 1) {
740 result++;
741 }
742 return result;
743 }
744
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700745 class ARMCodeBuf : public ICodeBuf {
746 ICodeBuf* mpBase;
747 ErrorSink* mErrorSink;
748
749 class CircularQueue {
750 static const int SIZE = 16; // Must be power of 2
751 static const int MASK = SIZE-1;
752 unsigned int mBuf[SIZE];
753 int mHead;
754 int mCount;
755
756 public:
757 CircularQueue() {
758 mHead = 0;
759 mCount = 0;
760 }
761
762 void pushBack(unsigned int data) {
763 mBuf[(mHead + mCount) & MASK] = data;
764 mCount += 1;
765 }
766
767 unsigned int popFront() {
768 unsigned int result = mBuf[mHead];
769 mHead = (mHead + 1) & MASK;
770 mCount -= 1;
771 return result;
772 }
773
774 void popBack(int n) {
775 mCount -= n;
776 }
777
778 inline int count() {
779 return mCount;
780 }
781
782 bool empty() {
783 return mCount == 0;
784 }
785
786 bool full() {
787 return mCount == SIZE;
788 }
789
790 // The valid indexes are 1 - count() to 0
791 unsigned int operator[](int i) {
792 return mBuf[(mHead + mCount + i) & MASK];
793 }
794 };
795
796 CircularQueue mQ;
797
798 void error(const char* fmt,...) {
799 va_list ap;
800 va_start(ap, fmt);
801 mErrorSink->verror(fmt, ap);
802 va_end(ap);
803 }
804
805 void flush() {
806 while (!mQ.empty()) {
807 mpBase->o4(mQ.popFront());
808 }
809 mpBase->flush();
810 }
811
812 public:
813 ARMCodeBuf(ICodeBuf* pBase) {
814 mpBase = pBase;
815 }
816
817 virtual ~ARMCodeBuf() {
818 delete mpBase;
819 }
820
821 void init(int size) {
822 mpBase->init(size);
823 }
824
825 void setErrorSink(ErrorSink* pErrorSink) {
826 mErrorSink = pErrorSink;
827 mpBase->setErrorSink(pErrorSink);
828 }
829
830 void o4(int n) {
831 if (mQ.full()) {
832 mpBase->o4(mQ.popFront());
833 }
834 mQ.pushBack(n);
835
836#ifndef DISABLE_ARM_PEEPHOLE
837 // Peephole check
838 bool didPeep;
839 do {
Jack Palevich53f06582009-09-10 14:01:58 -0700840 static const unsigned int opMask = 0x01e00000;
841 static const unsigned int immediateMask = 0x00000fff;
842 static const unsigned int BMask = 0x00400000;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700843 didPeep = false;
844 if (mQ.count() >= 4) {
845
846 // Operand by a small constant
847 // push;mov #imm;pop;op ==> op #imm
848
Jack Palevich1c60e462009-09-18 15:03:03 -0700849 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
850 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
851 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
852 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700853 unsigned int movConst = mQ[-3];
854 unsigned int op = mQ[-1];
855 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
856 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
857 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
858 mQ.popBack(4);
859 mQ.pushBack(combined);
860 didPeep = true;
861 } else {
862 mQ.popBack(4);
863 didPeep = true;
864 }
865 }
866 }
867
868 // Load local variable
Jack Palevich53f06582009-09-10 14:01:58 -0700869 // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm]
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700870 if (mQ.count() >= 2) {
Jack Palevich53f06582009-09-10 14:01:58 -0700871 if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
872 const unsigned int encodedImmediate = mQ[-2] & immediateMask;
873 const unsigned int ld = mQ[-1];
874 if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
875 unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
876 mQ.popBack(2);
877 mQ.pushBack(combined);
878 didPeep = true;
Jack Palevich1c60e462009-09-18 15:03:03 -0700879 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
Jack Palevich53f06582009-09-10 14:01:58 -0700880 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
881 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700882 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
Jack Palevich53f06582009-09-10 14:01:58 -0700883 mQ.popBack(2);
884 mQ.pushBack(combined);
885 didPeep = true;
886 }
887 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700888 }
889 }
890
891 // Constant array lookup
892
893 if (mQ.count() >= 6 &&
894 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
895 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
896 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
897 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
898 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
899 mQ[-1] == 0xe0810000) { // add r0, r1, r0
900 unsigned int mov1 = mQ[-5];
901 unsigned int mov2 = mQ[-3];
902 unsigned int const1 = decode12BitImmediate(mov1);
903 unsigned int const2 = decode12BitImmediate(mov2);
904 unsigned int comboConst = const1 * const2;
905 size_t immediate = 0;
906 if (encode12BitImmediate(comboConst, &immediate)) {
907 mQ.popBack(6);
908 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
909 if (comboConst) {
910 mQ.pushBack(add);
911 }
912 didPeep = true;
913 }
914 }
915
Jack Palevich53f06582009-09-10 14:01:58 -0700916 // Pointer arithmetic with a stride that is a power of two
917
918 if (mQ.count() >= 3 &&
Jack Palevich1c60e462009-09-18 15:03:03 -0700919 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
920 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
Jack Palevich53f06582009-09-10 14:01:58 -0700921 mQ[-1] == 0xe0810000) { // add r0, r1, r0
922 int stride = decode12BitImmediate(mQ[-3]);
923 if (isPowerOfTwo(stride)) {
924 mQ.popBack(3);
925 unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
926 mQ.pushBack(add);
927 didPeep = true;
928 }
929 }
930
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700931 } while (didPeep);
932#endif
933 }
934
935 void ob(int n) {
936 error("ob() not supported.");
937 }
938
939 void* getBase() {
940 flush();
941 return mpBase->getBase();
942 }
943
944 intptr_t getSize() {
945 flush();
946 return mpBase->getSize();
947 }
948
949 intptr_t getPC() {
950 flush();
951 return mpBase->getPC();
952 }
953 };
954
Jack Palevich22305132009-05-13 10:58:45 -0700955 class ARMCodeGenerator : public CodeGenerator {
956 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700957 ARMCodeGenerator() {
958#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700959 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700960#else
Jack Palevichd5315572009-09-09 13:19:34 -0700961 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700962#endif
963 }
-b master422972c2009-06-17 19:13:52 -0700964
Jack Palevich22305132009-05-13 10:58:45 -0700965 virtual ~ARMCodeGenerator() {}
966
967 /* returns address to patch with local variable size
968 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700969 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700970 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700971 // sp -> arg4 arg5 ...
972 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700973 int regArgCount = calcRegArgCount(pDecl);
974 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700975 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700976 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700977 }
978 // sp -> arg0 arg1 ...
979 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700980 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700981 // sp, fp -> oldfp, retadr, arg0 arg1 ....
982 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700983 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700984 int pc = getPC();
985 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700986 // We don't know how many local variables we are going to use,
987 // but we will round the allocation up to a multiple of
988 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700989 return pc;
Jack Palevich22305132009-05-13 10:58:45 -0700990 }
991
Jack Palevichb7718b92009-07-09 22:00:24 -0700992 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700993 // Round local variable size up to a multiple of stack alignment
994 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
995 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700996 // Patch local variable allocation code:
997 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700998 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700999 }
Jack Palevich69796b62009-05-14 15:42:26 -07001000 *(char*) (localVariableAddress) = localVariableSize;
1001
Jack Palevich30321cb2009-08-20 15:34:23 -07001002#ifdef ARM_USE_VFP
1003 {
Jack Palevichc0f25332009-08-25 12:23:43 -07001004 Type* pReturnType = pDecl->pHead;
1005 switch(pReturnType->tag) {
1006 case TY_FLOAT:
1007 o4(0xEE170A90); // fmrs r0, s15
1008 break;
1009 case TY_DOUBLE:
1010 o4(0xEC510B17); // fmrrd r0, r1, d7
1011 break;
1012 default:
1013 break;
1014 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001015 }
1016#endif
1017
Jack Palevich69796b62009-05-14 15:42:26 -07001018 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
1019 o4(0xE1A0E00B); // mov lr, fp
1020 o4(0xE59BB000); // ldr fp, [fp]
1021 o4(0xE28ED004); // add sp, lr, #4
1022 // sp -> retadr, arg0, ...
1023 o4(0xE8BD4000); // ldmfd sp!, {lr}
1024 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -07001025
1026 // We store the PC into the lr so we can adjust the sp before
1027 // returning. We need to pull off the registers we pushed
1028 // earlier. We don't need to actually store them anywhere,
1029 // just adjust the stack.
1030 int regArgCount = calcRegArgCount(pDecl);
1031 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -07001032 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
1033 }
1034 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -07001035 }
1036
1037 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001038 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001039 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001040 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001041 }
1042
Jack Palevich1a539db2009-07-08 13:04:41 -07001043 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001044 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 // Global, absolute address
1046 o4(0xE59F0000); // ldr r0, .L1
1047 o4(0xEA000000); // b .L99
1048 o4(address); // .L1: .word ea
1049 // .L99:
1050
1051 switch (pType->tag) {
1052 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001053#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001054 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001055#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001056 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001057#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001058 break;
1059 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001060#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001061 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001062#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001063 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001064#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001065 break;
1066 default:
1067 assert(false);
1068 break;
1069 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001070 }
1071
Jack Palevich9221bcc2009-08-26 16:15:07 -07001072
1073 virtual void addStructOffsetR0(int offset, Type* pType) {
1074 if (offset) {
1075 size_t immediate = 0;
1076 if (encode12BitImmediate(offset, &immediate)) {
1077 o4(0xE2800000 | immediate); // add r0, r0, #offset
1078 } else {
1079 error("structure offset out of range: %d", offset);
1080 }
1081 }
1082 setR0Type(pType, ET_LVALUE);
1083 }
1084
Jack Palevich22305132009-05-13 10:58:45 -07001085 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001086 int pc = getPC();
1087 o4(0xEA000000 | encodeAddress(t)); // b .L33
1088 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001089 }
1090
1091 /* l = 0: je, l == 1: jne */
1092 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001093 Type* pR0Type = getR0Type();
1094 TypeTag tagR0 = pR0Type->tag;
1095 switch(tagR0) {
1096 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001097#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001098 o4(0xEEF57A40); // fcmpzs s15
1099 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001100#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001101 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001102 o4(0xE3500000); // cmp r0,#0
1103#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 break;
1105 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001106#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001107 o4(0xEEB57B40); // fcmpzd d7
1108 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001109#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001110 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001111 o4(0xE3500000); // cmp r0,#0
1112#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001113 break;
1114 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001115 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001116 break;
1117 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001118 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001119 int pc = getPC();
1120 o4(branch | encodeAddress(t));
1121 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001122 }
1123
Jack Palevich58c30ee2009-07-17 16:35:23 -07001124 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001125 Type* pR0Type = getR0Type();
1126 Type* pTOSType = getTOSType();
1127 TypeTag tagR0 = collapseType(pR0Type->tag);
1128 TypeTag tagTOS = collapseType(pTOSType->tag);
1129 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001130 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001131 o4(0xE1510000); // cmp r1, r1
1132 switch(op) {
1133 case OP_EQUALS:
1134 o4(0x03A00001); // moveq r0,#1
1135 o4(0x13A00000); // movne r0,#0
1136 break;
1137 case OP_NOT_EQUALS:
1138 o4(0x03A00000); // moveq r0,#0
1139 o4(0x13A00001); // movne r0,#1
1140 break;
1141 case OP_LESS_EQUAL:
1142 o4(0xD3A00001); // movle r0,#1
1143 o4(0xC3A00000); // movgt r0,#0
1144 break;
1145 case OP_GREATER:
1146 o4(0xD3A00000); // movle r0,#0
1147 o4(0xC3A00001); // movgt r0,#1
1148 break;
1149 case OP_GREATER_EQUAL:
1150 o4(0xA3A00001); // movge r0,#1
1151 o4(0xB3A00000); // movlt r0,#0
1152 break;
1153 case OP_LESS:
1154 o4(0xA3A00000); // movge r0,#0
1155 o4(0xB3A00001); // movlt r0,#1
1156 break;
1157 default:
1158 error("Unknown comparison op %d", op);
1159 break;
1160 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001161 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1162 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001163#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001164 o4(0xEEB46BC7); // fcmped d6, d7
1165 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001166 switch(op) {
1167 case OP_EQUALS:
1168 o4(0x03A00001); // moveq r0,#1
1169 o4(0x13A00000); // movne r0,#0
1170 break;
1171 case OP_NOT_EQUALS:
1172 o4(0x03A00000); // moveq r0,#0
1173 o4(0x13A00001); // movne r0,#1
1174 break;
1175 case OP_LESS_EQUAL:
1176 o4(0xD3A00001); // movle r0,#1
1177 o4(0xC3A00000); // movgt r0,#0
1178 break;
1179 case OP_GREATER:
1180 o4(0xD3A00000); // movle r0,#0
1181 o4(0xC3A00001); // movgt r0,#1
1182 break;
1183 case OP_GREATER_EQUAL:
1184 o4(0xA3A00001); // movge r0,#1
1185 o4(0xB3A00000); // movlt r0,#0
1186 break;
1187 case OP_LESS:
1188 o4(0xA3A00000); // movge r0,#0
1189 o4(0xB3A00001); // movlt r0,#1
1190 break;
1191 default:
1192 error("Unknown comparison op %d", op);
1193 break;
1194 }
1195#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001196 switch(op) {
1197 case OP_EQUALS:
1198 callRuntime((void*) runtime_cmp_eq_dd);
1199 break;
1200 case OP_NOT_EQUALS:
1201 callRuntime((void*) runtime_cmp_ne_dd);
1202 break;
1203 case OP_LESS_EQUAL:
1204 callRuntime((void*) runtime_cmp_le_dd);
1205 break;
1206 case OP_GREATER:
1207 callRuntime((void*) runtime_cmp_gt_dd);
1208 break;
1209 case OP_GREATER_EQUAL:
1210 callRuntime((void*) runtime_cmp_ge_dd);
1211 break;
1212 case OP_LESS:
1213 callRuntime((void*) runtime_cmp_lt_dd);
1214 break;
1215 default:
1216 error("Unknown comparison op %d", op);
1217 break;
1218 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001219#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001220 } else {
1221 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001222#ifdef ARM_USE_VFP
1223 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001224 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001225 switch(op) {
1226 case OP_EQUALS:
1227 o4(0x03A00001); // moveq r0,#1
1228 o4(0x13A00000); // movne r0,#0
1229 break;
1230 case OP_NOT_EQUALS:
1231 o4(0x03A00000); // moveq r0,#0
1232 o4(0x13A00001); // movne r0,#1
1233 break;
1234 case OP_LESS_EQUAL:
1235 o4(0xD3A00001); // movle r0,#1
1236 o4(0xC3A00000); // movgt r0,#0
1237 break;
1238 case OP_GREATER:
1239 o4(0xD3A00000); // movle r0,#0
1240 o4(0xC3A00001); // movgt r0,#1
1241 break;
1242 case OP_GREATER_EQUAL:
1243 o4(0xA3A00001); // movge r0,#1
1244 o4(0xB3A00000); // movlt r0,#0
1245 break;
1246 case OP_LESS:
1247 o4(0xA3A00000); // movge r0,#0
1248 o4(0xB3A00001); // movlt r0,#1
1249 break;
1250 default:
1251 error("Unknown comparison op %d", op);
1252 break;
1253 }
1254#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001255 switch(op) {
1256 case OP_EQUALS:
1257 callRuntime((void*) runtime_cmp_eq_ff);
1258 break;
1259 case OP_NOT_EQUALS:
1260 callRuntime((void*) runtime_cmp_ne_ff);
1261 break;
1262 case OP_LESS_EQUAL:
1263 callRuntime((void*) runtime_cmp_le_ff);
1264 break;
1265 case OP_GREATER:
1266 callRuntime((void*) runtime_cmp_gt_ff);
1267 break;
1268 case OP_GREATER_EQUAL:
1269 callRuntime((void*) runtime_cmp_ge_ff);
1270 break;
1271 case OP_LESS:
1272 callRuntime((void*) runtime_cmp_lt_ff);
1273 break;
1274 default:
1275 error("Unknown comparison op %d", op);
1276 break;
1277 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001278#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001279 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001280 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001281 }
1282
Jack Palevich546b2242009-05-13 15:10:04 -07001283 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001284 Type* pR0Type = getR0Type();
1285 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001286 TypeTag tagR0 = pR0Type->tag;
1287 TypeTag tagTOS = pTOSType->tag;
1288 bool isFloatR0 = isFloatTag(tagR0);
1289 bool isFloatTOS = isFloatTag(tagTOS);
1290 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001291 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001292 bool isPtrR0 = isPointerTag(tagR0);
1293 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001294 if (isPtrR0 || isPtrTOS) {
1295 if (isPtrR0 && isPtrTOS) {
1296 if (op != OP_MINUS) {
1297 error("Unsupported pointer-pointer operation %d.", op);
1298 }
1299 if (! typeEqual(pR0Type, pTOSType)) {
1300 error("Incompatible pointer types for subtraction.");
1301 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001302 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001303 setR0Type(mkpInt);
1304 int size = sizeOf(pR0Type->pHead);
1305 if (size != 1) {
1306 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001307 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001308 // TODO: Optimize for power-of-two.
1309 genOp(OP_DIV);
1310 }
1311 } else {
1312 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1313 error("Unsupported pointer-scalar operation %d", op);
1314 }
Jack Palevichb6154502009-08-04 14:56:09 -07001315 Type* pPtrType = getPointerArithmeticResultType(
1316 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001317 int size = sizeOf(pPtrType->pHead);
1318 if (size != 1) {
1319 // TODO: Optimize for power-of-two.
1320 liReg(size, 2);
1321 if (isPtrR0) {
1322 o4(0x0E0010192); // mul r1,r2,r1
1323 } else {
1324 o4(0x0E0000092); // mul r0,r2,r0
1325 }
1326 }
1327 switch(op) {
1328 case OP_PLUS:
1329 o4(0xE0810000); // add r0,r1,r0
1330 break;
1331 case OP_MINUS:
1332 o4(0xE0410000); // sub r0,r1,r0
1333 break;
1334 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001335 setR0Type(pPtrType);
1336 }
1337 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001338 switch(op) {
1339 case OP_MUL:
1340 o4(0x0E0000091); // mul r0,r1,r0
1341 break;
1342 case OP_DIV:
1343 callRuntime((void*) runtime_DIV);
1344 break;
1345 case OP_MOD:
1346 callRuntime((void*) runtime_MOD);
1347 break;
1348 case OP_PLUS:
1349 o4(0xE0810000); // add r0,r1,r0
1350 break;
1351 case OP_MINUS:
1352 o4(0xE0410000); // sub r0,r1,r0
1353 break;
1354 case OP_SHIFT_LEFT:
1355 o4(0xE1A00011); // lsl r0,r1,r0
1356 break;
1357 case OP_SHIFT_RIGHT:
1358 o4(0xE1A00051); // asr r0,r1,r0
1359 break;
1360 case OP_BIT_AND:
1361 o4(0xE0010000); // and r0,r1,r0
1362 break;
1363 case OP_BIT_XOR:
1364 o4(0xE0210000); // eor r0,r1,r0
1365 break;
1366 case OP_BIT_OR:
1367 o4(0xE1810000); // orr r0,r1,r0
1368 break;
1369 case OP_BIT_NOT:
1370 o4(0xE1E00000); // mvn r0, r0
1371 break;
1372 default:
1373 error("Unimplemented op %d\n", op);
1374 break;
1375 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001376 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001377 } else {
1378 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1379 if (pResultType->tag == TY_DOUBLE) {
1380 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001381
Jack Palevichb7718b92009-07-09 22:00:24 -07001382 switch(op) {
1383 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001384#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001385 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001386#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001387 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001388#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001389 break;
1390 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001391#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001392 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001393#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001394 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001395#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001396 break;
1397 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001398#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001399 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001400#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001401 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001402#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001403 break;
1404 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001405#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001406 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001407#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001408 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001409#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001410 break;
1411 default:
1412 error("Unsupported binary floating operation %d\n", op);
1413 break;
1414 }
1415 } else {
1416 setupFloatArgs();
1417 switch(op) {
1418 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001419#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001420 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001421#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001422 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001423#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001424 break;
1425 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001426#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001427 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001428#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001429 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001430#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001431 break;
1432 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001433#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001434 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001435#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001436 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001437#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001438 break;
1439 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001440#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001441 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001442#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001443 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001444#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001445 break;
1446 default:
1447 error("Unsupported binary floating operation %d\n", op);
1448 break;
1449 }
1450 }
1451 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001452 }
Jack Palevich22305132009-05-13 10:58:45 -07001453 }
1454
Jack Palevich58c30ee2009-07-17 16:35:23 -07001455 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001456 if (op != OP_LOGICAL_NOT) {
1457 error("Unknown unary cmp %d", op);
1458 } else {
1459 Type* pR0Type = getR0Type();
1460 TypeTag tag = collapseType(pR0Type->tag);
1461 switch(tag) {
1462 case TY_INT:
1463 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001464 o4(0xE1510000); // cmp r1, r0
1465 o4(0x03A00001); // moveq r0,#1
1466 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001467 break;
1468 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001469#ifdef ARM_USE_VFP
1470 o4(0xEEF57A40); // fcmpzs s15
1471 o4(0xEEF1FA10); // fmstat
1472 o4(0x03A00001); // moveq r0,#1
1473 o4(0x13A00000); // movne r0,#0
1474#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001475 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001476#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001477 break;
1478 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001479#ifdef ARM_USE_VFP
1480 o4(0xEEB57B40); // fcmpzd d7
1481 o4(0xEEF1FA10); // fmstat
1482 o4(0x03A00001); // moveq r0,#1
1483 o4(0x13A00000); // movne r0,#0
1484#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001485 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001486#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001487 break;
1488 default:
1489 error("gUnaryCmp unsupported type");
1490 break;
1491 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001492 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001493 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001494 }
1495
1496 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001497 Type* pR0Type = getR0Type();
1498 TypeTag tag = collapseType(pR0Type->tag);
1499 switch(tag) {
1500 case TY_INT:
1501 switch(op) {
1502 case OP_MINUS:
1503 o4(0xE3A01000); // mov r1, #0
1504 o4(0xE0410000); // sub r0,r1,r0
1505 break;
1506 case OP_BIT_NOT:
1507 o4(0xE1E00000); // mvn r0, r0
1508 break;
1509 default:
1510 error("Unknown unary op %d\n", op);
1511 break;
1512 }
1513 break;
1514 case TY_FLOAT:
1515 case TY_DOUBLE:
1516 switch (op) {
1517 case OP_MINUS:
1518 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001519#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001520 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001521#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001522 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001523#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001524 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001525#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001526 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001527#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001528 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001529#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001530 }
1531 break;
1532 case OP_BIT_NOT:
1533 error("Can't apply '~' operator to a float or double.");
1534 break;
1535 default:
1536 error("Unknown unary op %d\n", op);
1537 break;
1538 }
1539 break;
1540 default:
1541 error("genUnaryOp unsupported type");
1542 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001543 }
Jack Palevich22305132009-05-13 10:58:45 -07001544 }
1545
Jack Palevich1cdef202009-05-22 12:06:27 -07001546 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 Type* pR0Type = getR0Type();
1548 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001549
1550#ifdef ARM_USE_VFP
1551 switch (r0ct ) {
1552 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001553 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001554 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001555 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001556 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001557 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001558 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001559 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001560 default:
1561 o4(0xE92D0001); // stmfd sp!,{r0}
1562 mStackUse += 4;
1563 }
1564#else
1565
Jack Palevichb7718b92009-07-09 22:00:24 -07001566 if (r0ct != TY_DOUBLE) {
1567 o4(0xE92D0001); // stmfd sp!,{r0}
1568 mStackUse += 4;
1569 } else {
1570 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1571 mStackUse += 8;
1572 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001573#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001574 pushType();
-b master422972c2009-06-17 19:13:52 -07001575 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001576 }
1577
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001578 virtual void over() {
1579 // We know it's only used for int-ptr ops (++/--)
1580
1581 Type* pR0Type = getR0Type();
1582 TypeTag r0ct = collapseType(pR0Type->tag);
1583
1584 Type* pTOSType = getTOSType();
1585 TypeTag tosct = collapseType(pTOSType->tag);
1586
1587 assert (r0ct == TY_INT && tosct == TY_INT);
1588
1589 o4(0xE8BD0002); // ldmfd sp!,{r1}
1590 o4(0xE92D0001); // stmfd sp!,{r0}
1591 o4(0xE92D0002); // stmfd sp!,{r1}
1592 overType();
1593 mStackUse += 4;
1594 }
1595
Jack Palevich58c30ee2009-07-17 16:35:23 -07001596 virtual void popR0() {
1597 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001598 TypeTag tosct = collapseType(pTOSType->tag);
1599#ifdef ARM_USE_VFP
1600 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001601 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001602 }
1603#endif
1604 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001605 case TY_INT:
1606 case TY_FLOAT:
1607 o4(0xE8BD0001); // ldmfd sp!,{r0}
1608 mStackUse -= 4;
1609 break;
1610 case TY_DOUBLE:
1611 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1612 mStackUse -= 8;
1613 break;
1614 default:
1615 error("Can't pop this type.");
1616 break;
1617 }
1618 popType();
1619 LOG_STACK("popR0: %d\n", mStackUse);
1620 }
1621
1622 virtual void storeR0ToTOS() {
1623 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001624 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001625 Type* pDestType = pPointerType->pHead;
1626 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001627 o4(0xE8BD0004); // ldmfd sp!,{r2}
1628 popType();
-b master422972c2009-06-17 19:13:52 -07001629 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001630 switch (pDestType->tag) {
1631 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001632 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001633 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001634 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001635 case TY_FLOAT:
1636#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001637 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001638#else
1639 o4(0xE5820000); // str r0, [r2]
1640#endif
1641 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001642 case TY_SHORT:
1643 o4(0xE1C200B0); // strh r0, [r2]
1644 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001645 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001646 o4(0xE5C20000); // strb r0, [r2]
1647 break;
1648 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001649#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001650 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001651#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001652 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001653#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001654 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001655 case TY_STRUCT:
1656 {
1657 int size = sizeOf(pDestType);
1658 if (size > 0) {
1659 liReg(size, 1);
1660 callRuntime((void*) runtime_structCopy);
1661 }
1662 }
1663 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001664 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001665 error("storeR0ToTOS: unimplemented type %d",
1666 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001667 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001668 }
Jack Palevich22305132009-05-13 10:58:45 -07001669 }
1670
Jack Palevich58c30ee2009-07-17 16:35:23 -07001671 virtual void loadR0FromR0() {
1672 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001673 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001674 Type* pNewType = pPointerType->pHead;
1675 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001676 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001677 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001678 case TY_INT:
1679 o4(0xE5900000); // ldr r0, [r0]
1680 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001681 case TY_FLOAT:
1682#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001683 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001684#else
1685 o4(0xE5900000); // ldr r0, [r0]
1686#endif
1687 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001688 case TY_SHORT:
1689 o4(0xE1D000F0); // ldrsh r0, [r0]
1690 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001691 case TY_CHAR:
1692 o4(0xE5D00000); // ldrb r0, [r0]
1693 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001694 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001695#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001696 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001697#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001698 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001699#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001700 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001701 case TY_ARRAY:
1702 pNewType = pNewType->pTail;
1703 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001704 case TY_STRUCT:
1705 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001706 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001707 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001708 break;
1709 }
Jack Palevich80e49722009-08-04 15:39:49 -07001710 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001711 }
1712
Jack Palevichb5e33312009-07-30 19:06:34 -07001713 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001714 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001715 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001716
1717 size_t immediate = 0;
1718 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001719 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001720 inRange = encode12BitImmediate(-ea, &immediate);
1721 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001722 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001723 inRange = encode12BitImmediate(ea, &immediate);
1724 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1725 }
1726 if (! inRange) {
1727 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001728 }
Jack Palevichbd894902009-05-14 19:35:31 -07001729 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001730 // Global, absolute.
1731 o4(0xE59F0000); // ldr r0, .L1
1732 o4(0xEA000000); // b .L99
1733 o4(ea); // .L1: .word 0
1734 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001735 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001736 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001737 }
1738
Jack Palevich9f51a262009-07-29 16:22:26 -07001739 virtual int leaForward(int ea, Type* pPointerType) {
1740 setR0Type(pPointerType);
1741 int result = ea;
1742 int pc = getPC();
1743 int offset = 0;
1744 if (ea) {
1745 offset = (pc - ea - 8) >> 2;
1746 if ((offset & 0xffff) != offset) {
1747 error("function forward reference out of bounds");
1748 }
1749 } else {
1750 offset = 0;
1751 }
1752 o4(0xE59F0000 | offset); // ldr r0, .L1
1753
1754 if (ea == 0) {
1755 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001756 result = getPC();
1757 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001758 // .L99:
1759 }
1760 return result;
1761 }
1762
Jack Palevichb6154502009-08-04 14:56:09 -07001763 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001764 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001765 if (isPointerType(pType) && isPointerType(pR0Type)) {
1766 Type* pA = pR0Type;
1767 Type* pB = pType;
1768 // Array decays to pointer
1769 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1770 pA = pA->pTail;
1771 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001772 if (! (typeEqual(pA, pB)
1773 || pB->pHead->tag == TY_VOID
1774 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1775 )) {
1776 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001777 }
Jack Palevichb6154502009-08-04 14:56:09 -07001778 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001779 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001780 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001781 TypeTag r0Tag = collapseType(pR0Type->tag);
1782 TypeTag destTag = collapseType(pType->tag);
1783 if (r0Tag == TY_INT) {
1784 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001785#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001786 o4(0xEE070A90); // fmsr s15, r0
1787 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001788
1789#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001790 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001791#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001792 } else {
1793 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001794#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001795 o4(0xEE070A90); // fmsr s15, r0
1796 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001797
1798#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001799 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001800#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001801 }
1802 } else if (r0Tag == TY_FLOAT) {
1803 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001804#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001805 o4(0xEEFD7AE7); // ftosizs s15, s15
1806 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001807#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001808 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001809#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001810 } else {
1811 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001812#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001813 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001814#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001815 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001816#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001817 }
1818 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001819 if (r0Tag == TY_DOUBLE) {
1820 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001821#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001822 o4(0xEEFD7BC7); // ftosizd s15, d7
1823 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001824#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001825 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001826#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001827 } else {
1828 if(destTag == TY_FLOAT) {
1829#ifdef ARM_USE_VFP
1830 o4(0xEEF77BC7); // fcvtsd s15, d7
1831#else
1832 callRuntime((void*) runtime_double_to_float);
1833#endif
1834 } else {
1835 incompatibleTypes(pR0Type, pType);
1836 }
1837 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001838 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001839 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001840 }
1841 }
Jack Palevich8df46192009-07-07 14:48:51 -07001842 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001843 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001844 }
1845
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001846 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001847 int pc = getPC();
1848 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1849 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001850 }
1851
Jack Palevich8148c5b2009-07-16 18:24:47 -07001852 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001853 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001854 Type* pR0Type = getR0Type();
1855 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001856#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001857 switch(r0ct) {
1858 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001859 if (l < 0 || l > 4096-4) {
1860 error("l out of range for stack offset: 0x%08x", l);
1861 }
1862 o4(0xE58D0000 | l); // str r0, [sp, #l]
1863 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001864 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001865 if (l < 0 || l > 1020 || (l & 3)) {
1866 error("l out of range for stack offset: 0x%08x", l);
1867 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001868 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001869 return 4;
1870 case TY_DOUBLE: {
1871 // Align to 8 byte boundary
1872 int l2 = (l + 7) & ~7;
1873 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1874 error("l out of range for stack offset: 0x%08x", l);
1875 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001876 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001877 return (l2 - l) + 8;
1878 }
1879 default:
1880 assert(false);
1881 return 0;
1882 }
1883#else
1884 switch(r0ct) {
1885 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001886 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001887 if (l < 0 || l > 4096-4) {
1888 error("l out of range for stack offset: 0x%08x", l);
1889 }
1890 o4(0xE58D0000 + l); // str r0, [sp, #l]
1891 return 4;
1892 case TY_DOUBLE: {
1893 // Align to 8 byte boundary
1894 int l2 = (l + 7) & ~7;
1895 if (l2 < 0 || l2 > 4096-8) {
1896 error("l out of range for stack offset: 0x%08x", l);
1897 }
1898 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1899 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1900 return (l2 - l) + 8;
1901 }
1902 default:
1903 assert(false);
1904 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001905 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001906#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001907 }
1908
Jack Palevichb7718b92009-07-09 22:00:24 -07001909 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001910 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001911 // Have to calculate register arg count from actual stack size,
1912 // in order to properly handle ... functions.
1913 int regArgCount = l >> 2;
1914 if (regArgCount > 4) {
1915 regArgCount = 4;
1916 }
1917 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001918 argumentStackUse -= regArgCount * 4;
1919 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1920 }
1921 mStackUse += argumentStackUse;
1922
1923 // Align stack.
1924 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1925 * STACK_ALIGNMENT);
1926 mStackAlignmentAdjustment = 0;
1927 if (missalignment > 0) {
1928 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1929 }
1930 l += mStackAlignmentAdjustment;
1931
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001932 if (l < 0 || l > 0x3FC) {
1933 error("L out of range for stack adjustment: 0x%08x", l);
1934 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001935 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001936 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001937 mStackUse += mStackAlignmentAdjustment;
1938 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1939 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001940 }
1941
Jack Palevich8df46192009-07-07 14:48:51 -07001942 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001943 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001944 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001945 int pc = getPC();
1946 o4(0xEB000000 | encodeAddress(symbol));
1947 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001948 }
1949
Jack Palevich8df46192009-07-07 14:48:51 -07001950 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001951 assert(pFunc->tag == TY_FUNC);
1952 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001953 int argCount = l >> 2;
1954 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001955 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001956 if (adjustedL < 0 || adjustedL > 4096-4) {
1957 error("l out of range for stack offset: 0x%08x", l);
1958 }
1959 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1960 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001961 Type* pReturnType = pFunc->pHead;
1962 setR0Type(pReturnType);
1963#ifdef ARM_USE_VFP
1964 switch(pReturnType->tag) {
1965 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001966 o4(0xEE070A90); // fmsr s15, r0
1967 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001968 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001969 o4(0xEC410B17); // fmdrr d7, r0, r1
1970 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001971 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001972 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001973 }
1974#endif
Jack Palevich22305132009-05-13 10:58:45 -07001975 }
1976
Jack Palevichb7718b92009-07-09 22:00:24 -07001977 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001978 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001979 // Have to calculate register arg count from actual stack size,
1980 // in order to properly handle ... functions.
1981 int regArgCount = l >> 2;
1982 if (regArgCount > 4) {
1983 regArgCount = 4;
1984 }
1985 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001986 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1987 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001988 if (stackUse) {
1989 if (stackUse < 0 || stackUse > 255) {
1990 error("L out of range for stack adjustment: 0x%08x", l);
1991 }
1992 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001993 mStackUse -= stackUse * 4;
1994 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001995 }
Jack Palevich22305132009-05-13 10:58:45 -07001996 }
1997
Jack Palevicha6535612009-05-13 16:24:17 -07001998 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001999 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002000 }
2001
2002 /* output a symbol and patch all calls to it */
2003 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002004 int n;
2005 int base = getBase();
2006 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002007 while (t) {
2008 int data = * (int*) t;
2009 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2010 if (decodedOffset == 0) {
2011 n = 0;
2012 } else {
2013 n = base + decodedOffset; /* next value */
2014 }
2015 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2016 | encodeRelAddress(pc - t - 8);
2017 t = n;
2018 }
2019 }
2020
Jack Palevich9f51a262009-07-29 16:22:26 -07002021 /* output a symbol and patch all calls to it */
2022 virtual void resolveForward(int t) {
2023 if (t) {
2024 int pc = getPC();
2025 *(int *) t = pc;
2026 }
2027 }
2028
Jack Palevich1cdef202009-05-22 12:06:27 -07002029 virtual int finishCompile() {
2030#if defined(__arm__)
2031 const long base = long(getBase());
2032 const long curr = long(getPC());
2033 int err = cacheflush(base, curr, 0);
2034 return err;
2035#else
2036 return 0;
2037#endif
2038 }
2039
Jack Palevich9eed7a22009-07-06 17:24:34 -07002040 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002041 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002042 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002043 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002044 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002045 case TY_CHAR:
2046 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002047 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002048 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002049 case TY_DOUBLE:
2050 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002051 case TY_ARRAY:
2052 return alignmentOf(pType->pHead);
2053 case TY_STRUCT:
2054 return pType->pHead->alignment & 0x7fffffff;
2055 case TY_FUNC:
2056 error("alignment of func not supported");
2057 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002058 default:
2059 return 4;
2060 }
2061 }
2062
2063 /**
2064 * Array element alignment (in bytes) for this type of data.
2065 */
2066 virtual size_t sizeOf(Type* pType){
2067 switch(pType->tag) {
2068 case TY_INT:
2069 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002070 case TY_SHORT:
2071 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002072 case TY_CHAR:
2073 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002074 case TY_FLOAT:
2075 return 4;
2076 case TY_DOUBLE:
2077 return 8;
2078 case TY_POINTER:
2079 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002080 case TY_ARRAY:
2081 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002082 case TY_STRUCT:
2083 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002084 default:
2085 error("Unsupported type %d", pType->tag);
2086 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002087 }
2088 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002089
Jack Palevich22305132009-05-13 10:58:45 -07002090 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002091
2092 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2093
2094 /** Encode a relative address that might also be
2095 * a label.
2096 */
2097 int encodeAddress(int value) {
2098 int base = getBase();
2099 if (value >= base && value <= getPC() ) {
2100 // This is a label, encode it relative to the base.
2101 value = value - base;
2102 }
2103 return encodeRelAddress(value);
2104 }
2105
2106 int encodeRelAddress(int value) {
2107 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2108 }
Jack Palevich22305132009-05-13 10:58:45 -07002109
Jack Palevichb7718b92009-07-09 22:00:24 -07002110 int calcRegArgCount(Type* pDecl) {
2111 int reg = 0;
2112 Type* pArgs = pDecl->pTail;
2113 while (pArgs && reg < 4) {
2114 Type* pArg = pArgs->pHead;
2115 if ( pArg->tag == TY_DOUBLE) {
2116 int evenReg = (reg + 1) & ~1;
2117 if (evenReg >= 4) {
2118 break;
2119 }
2120 reg = evenReg + 2;
2121 } else {
2122 reg++;
2123 }
2124 pArgs = pArgs->pTail;
2125 }
2126 return reg;
2127 }
2128
Jack Palevich58c30ee2009-07-17 16:35:23 -07002129 void setupIntPtrArgs() {
2130 o4(0xE8BD0002); // ldmfd sp!,{r1}
2131 mStackUse -= 4;
2132 popType();
2133 }
2134
Jack Palevich30321cb2009-08-20 15:34:23 -07002135 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002136 * Make sure both R0 and TOS are floats. (Could be ints)
2137 * We know that at least one of R0 and TOS is already a float
2138 */
2139 void setupFloatArgs() {
2140 Type* pR0Type = getR0Type();
2141 Type* pTOSType = getTOSType();
2142 TypeTag tagR0 = collapseType(pR0Type->tag);
2143 TypeTag tagTOS = collapseType(pTOSType->tag);
2144 if (tagR0 != TY_FLOAT) {
2145 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002146#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002147 o4(0xEE070A90); // fmsr s15, r0
2148 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002149#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002150 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002151#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002152 }
2153 if (tagTOS != TY_FLOAT) {
2154 assert(tagTOS == TY_INT);
2155 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002156#ifdef ARM_USE_VFP
2157 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002158 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002159#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002160 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2161 o4(0xE59D0004); // ldr r0, [sp, #4]
2162 callRuntime((void*) runtime_int_to_float);
2163 o4(0xE1A01000); // mov r1, r0
2164 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2165 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002166#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002167 } else {
2168 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002169#ifdef ARM_USE_VFP
2170 o4(0xECBD7A01); // fldmfds sp!, {s14}
2171
2172#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002173 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002174#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002175 }
2176 mStackUse -= 4;
2177 popType();
2178 }
2179
Jack Palevich30321cb2009-08-20 15:34:23 -07002180 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002181 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2182 * We know that at least one of R0 and TOS are already a double.
2183 */
2184
2185 void setupDoubleArgs() {
2186 Type* pR0Type = getR0Type();
2187 Type* pTOSType = getTOSType();
2188 TypeTag tagR0 = collapseType(pR0Type->tag);
2189 TypeTag tagTOS = collapseType(pTOSType->tag);
2190 if (tagR0 != TY_DOUBLE) {
2191 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002192#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002193 o4(0xEE070A90); // fmsr s15, r0
2194 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002195
2196#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002197 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002198#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002199 } else {
2200 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002201#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002202 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002203#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002204 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002205#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002206 }
2207 }
2208 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002209#ifdef ARM_USE_VFP
2210 if (tagTOS == TY_INT) {
2211 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002212 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002213 } else {
2214 assert(tagTOS == TY_FLOAT);
2215 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002216 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002217 }
2218#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002219 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2220 o4(0xE59D0008); // ldr r0, [sp, #8]
2221 if (tagTOS == TY_INT) {
2222 callRuntime((void*) runtime_int_to_double);
2223 } else {
2224 assert(tagTOS == TY_FLOAT);
2225 callRuntime((void*) runtime_float_to_double);
2226 }
2227 o4(0xE1A02000); // mov r2, r0
2228 o4(0xE1A03001); // mov r3, r1
2229 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2230 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002231#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002232 mStackUse -= 4;
2233 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002234#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002235 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002236#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002237 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002238#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002239 mStackUse -= 8;
2240 }
2241 popType();
2242 }
2243
Jack Palevicha8f427f2009-07-13 18:40:08 -07002244 void liReg(int t, int reg) {
2245 assert(reg >= 0 && reg < 16);
2246 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002247 size_t encodedImmediate;
2248 if (encode12BitImmediate(t, &encodedImmediate)) {
2249 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2250 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002251 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002252 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002253 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002254 o4(0xE51F0000 | rN); // ldr rN, .L3
2255 o4(0xEA000000); // b .L99
2256 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002257 // .L99:
2258 }
2259 }
2260
Jack Palevichc408bbf2009-09-08 12:07:32 -07002261 void incompatibleTypes(Type* pR0Type, Type* pType) {
2262 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2263 }
2264
Jack Palevichb7718b92009-07-09 22:00:24 -07002265 void callRuntime(void* fn) {
2266 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002267 o4(0xEA000000); // b .L99
2268 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002269 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002270 }
2271
Jack Palevichb7718b92009-07-09 22:00:24 -07002272 // Integer math:
2273
2274 static int runtime_DIV(int b, int a) {
2275 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002276 }
2277
Jack Palevichb7718b92009-07-09 22:00:24 -07002278 static int runtime_MOD(int b, int a) {
2279 return a % b;
2280 }
2281
Jack Palevich9221bcc2009-08-26 16:15:07 -07002282 static void runtime_structCopy(void* src, size_t size, void* dest) {
2283 memcpy(dest, src, size);
2284 }
2285
Jack Palevich30321cb2009-08-20 15:34:23 -07002286#ifndef ARM_USE_VFP
2287
Jack Palevichb7718b92009-07-09 22:00:24 -07002288 // Comparison to zero
2289
2290 static int runtime_is_non_zero_f(float a) {
2291 return a != 0;
2292 }
2293
2294 static int runtime_is_non_zero_d(double a) {
2295 return a != 0;
2296 }
2297
2298 // Comparison to zero
2299
2300 static int runtime_is_zero_f(float a) {
2301 return a == 0;
2302 }
2303
2304 static int runtime_is_zero_d(double a) {
2305 return a == 0;
2306 }
2307
2308 // Type conversion
2309
2310 static int runtime_float_to_int(float a) {
2311 return (int) a;
2312 }
2313
2314 static double runtime_float_to_double(float a) {
2315 return (double) a;
2316 }
2317
2318 static int runtime_double_to_int(double a) {
2319 return (int) a;
2320 }
2321
2322 static float runtime_double_to_float(double a) {
2323 return (float) a;
2324 }
2325
2326 static float runtime_int_to_float(int a) {
2327 return (float) a;
2328 }
2329
2330 static double runtime_int_to_double(int a) {
2331 return (double) a;
2332 }
2333
2334 // Comparisons float
2335
2336 static int runtime_cmp_eq_ff(float b, float a) {
2337 return a == b;
2338 }
2339
2340 static int runtime_cmp_ne_ff(float b, float a) {
2341 return a != b;
2342 }
2343
2344 static int runtime_cmp_lt_ff(float b, float a) {
2345 return a < b;
2346 }
2347
2348 static int runtime_cmp_le_ff(float b, float a) {
2349 return a <= b;
2350 }
2351
2352 static int runtime_cmp_ge_ff(float b, float a) {
2353 return a >= b;
2354 }
2355
2356 static int runtime_cmp_gt_ff(float b, float a) {
2357 return a > b;
2358 }
2359
2360 // Comparisons double
2361
2362 static int runtime_cmp_eq_dd(double b, double a) {
2363 return a == b;
2364 }
2365
2366 static int runtime_cmp_ne_dd(double b, double a) {
2367 return a != b;
2368 }
2369
2370 static int runtime_cmp_lt_dd(double b, double a) {
2371 return a < b;
2372 }
2373
2374 static int runtime_cmp_le_dd(double b, double a) {
2375 return a <= b;
2376 }
2377
2378 static int runtime_cmp_ge_dd(double b, double a) {
2379 return a >= b;
2380 }
2381
2382 static int runtime_cmp_gt_dd(double b, double a) {
2383 return a > b;
2384 }
2385
2386 // Math float
2387
2388 static float runtime_op_add_ff(float b, float a) {
2389 return a + b;
2390 }
2391
2392 static float runtime_op_sub_ff(float b, float a) {
2393 return a - b;
2394 }
2395
2396 static float runtime_op_mul_ff(float b, float a) {
2397 return a * b;
2398 }
2399
2400 static float runtime_op_div_ff(float b, float a) {
2401 return a / b;
2402 }
2403
2404 static float runtime_op_neg_f(float a) {
2405 return -a;
2406 }
2407
2408 // Math double
2409
2410 static double runtime_op_add_dd(double b, double a) {
2411 return a + b;
2412 }
2413
2414 static double runtime_op_sub_dd(double b, double a) {
2415 return a - b;
2416 }
2417
2418 static double runtime_op_mul_dd(double b, double a) {
2419 return a * b;
2420 }
2421
2422 static double runtime_op_div_dd(double b, double a) {
2423 return a / b;
2424 }
2425
2426 static double runtime_op_neg_d(double a) {
2427 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002428 }
-b master422972c2009-06-17 19:13:52 -07002429
Jack Palevich30321cb2009-08-20 15:34:23 -07002430#endif
2431
-b master422972c2009-06-17 19:13:52 -07002432 static const int STACK_ALIGNMENT = 8;
2433 int mStackUse;
2434 // This variable holds the amount we adjusted the stack in the most
2435 // recent endFunctionCallArguments call. It's examined by the
2436 // following adjustStackAfterCall call.
2437 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002438 };
2439
Jack Palevich09555c72009-05-27 12:25:55 -07002440#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002441
2442#ifdef PROVIDE_X86_CODEGEN
2443
Jack Palevich21a15a22009-05-11 14:49:29 -07002444 class X86CodeGenerator : public CodeGenerator {
2445 public:
2446 X86CodeGenerator() {}
2447 virtual ~X86CodeGenerator() {}
2448
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002449 /* returns address to patch with local variable size
2450 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002451 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002452 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2453 return oad(0xec81, 0); /* sub $xxx, %esp */
2454 }
2455
Jack Palevichb7718b92009-07-09 22:00:24 -07002456 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002457 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002458 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002459 }
2460
Jack Palevich21a15a22009-05-11 14:49:29 -07002461 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002462 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002463 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002464 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002465 }
2466
Jack Palevich1a539db2009-07-08 13:04:41 -07002467 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002468 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002469 switch (pType->tag) {
2470 case TY_FLOAT:
2471 oad(0x05D9, address); // flds
2472 break;
2473 case TY_DOUBLE:
2474 oad(0x05DD, address); // fldl
2475 break;
2476 default:
2477 assert(false);
2478 break;
2479 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002480 }
2481
Jack Palevich9221bcc2009-08-26 16:15:07 -07002482 virtual void addStructOffsetR0(int offset, Type* pType) {
2483 if (offset) {
2484 oad(0x05, offset); // addl offset, %eax
2485 }
2486 setR0Type(pType, ET_LVALUE);
2487 }
2488
Jack Palevich22305132009-05-13 10:58:45 -07002489 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002490 return psym(0xe9, t);
2491 }
2492
2493 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002494 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002495 Type* pR0Type = getR0Type();
2496 TypeTag tagR0 = pR0Type->tag;
2497 bool isFloatR0 = isFloatTag(tagR0);
2498 if (isFloatR0) {
2499 o(0xeed9); // fldz
2500 o(0xe9da); // fucompp
2501 o(0xe0df); // fnstsw %ax
2502 o(0x9e); // sahf
2503 } else {
2504 o(0xc085); // test %eax, %eax
2505 }
2506 // Use two output statements to generate one instruction.
2507 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002508 return psym(0x84 + l, t);
2509 }
2510
Jack Palevich58c30ee2009-07-17 16:35:23 -07002511 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002512 Type* pR0Type = getR0Type();
2513 Type* pTOSType = getTOSType();
2514 TypeTag tagR0 = pR0Type->tag;
2515 TypeTag tagTOS = pTOSType->tag;
2516 bool isFloatR0 = isFloatTag(tagR0);
2517 bool isFloatTOS = isFloatTag(tagTOS);
2518 if (!isFloatR0 && !isFloatTOS) {
2519 int t = decodeOp(op);
2520 o(0x59); /* pop %ecx */
2521 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002522 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002523 o(0x0f); /* setxx %al */
2524 o(t + 0x90);
2525 o(0xc0);
2526 popType();
2527 } else {
2528 setupFloatOperands();
2529 switch (op) {
2530 case OP_EQUALS:
2531 o(0xe9da); // fucompp
2532 o(0xe0df); // fnstsw %ax
2533 o(0x9e); // sahf
2534 o(0xc0940f); // sete %al
2535 o(0xc29b0f); // setnp %dl
2536 o(0xd021); // andl %edx, %eax
2537 break;
2538 case OP_NOT_EQUALS:
2539 o(0xe9da); // fucompp
2540 o(0xe0df); // fnstsw %ax
2541 o(0x9e); // sahf
2542 o(0xc0950f); // setne %al
2543 o(0xc29a0f); // setp %dl
2544 o(0xd009); // orl %edx, %eax
2545 break;
2546 case OP_GREATER_EQUAL:
2547 o(0xe9da); // fucompp
2548 o(0xe0df); // fnstsw %ax
2549 o(0x05c4f6); // testb $5, %ah
2550 o(0xc0940f); // sete %al
2551 break;
2552 case OP_LESS:
2553 o(0xc9d9); // fxch %st(1)
2554 o(0xe9da); // fucompp
2555 o(0xe0df); // fnstsw %ax
2556 o(0x9e); // sahf
2557 o(0xc0970f); // seta %al
2558 break;
2559 case OP_LESS_EQUAL:
2560 o(0xc9d9); // fxch %st(1)
2561 o(0xe9da); // fucompp
2562 o(0xe0df); // fnstsw %ax
2563 o(0x9e); // sahf
2564 o(0xc0930f); // setea %al
2565 break;
2566 case OP_GREATER:
2567 o(0xe9da); // fucompp
2568 o(0xe0df); // fnstsw %ax
2569 o(0x45c4f6); // testb $69, %ah
2570 o(0xc0940f); // sete %al
2571 break;
2572 default:
2573 error("Unknown comparison op");
2574 }
2575 o(0xc0b60f); // movzbl %al, %eax
2576 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002577 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002578 }
2579
Jack Palevich546b2242009-05-13 15:10:04 -07002580 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002581 Type* pR0Type = getR0Type();
2582 Type* pTOSType = getTOSType();
2583 TypeTag tagR0 = pR0Type->tag;
2584 TypeTag tagTOS = pTOSType->tag;
2585 bool isFloatR0 = isFloatTag(tagR0);
2586 bool isFloatTOS = isFloatTag(tagTOS);
2587 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002588 bool isPtrR0 = isPointerTag(tagR0);
2589 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002590 if (isPtrR0 || isPtrTOS) {
2591 if (isPtrR0 && isPtrTOS) {
2592 if (op != OP_MINUS) {
2593 error("Unsupported pointer-pointer operation %d.", op);
2594 }
2595 if (! typeEqual(pR0Type, pTOSType)) {
2596 error("Incompatible pointer types for subtraction.");
2597 }
2598 o(0x59); /* pop %ecx */
2599 o(decodeOp(op));
2600 popType();
2601 setR0Type(mkpInt);
2602 int size = sizeOf(pR0Type->pHead);
2603 if (size != 1) {
2604 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002605 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002606 // TODO: Optimize for power-of-two.
2607 genOp(OP_DIV);
2608 }
2609 } else {
2610 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2611 error("Unsupported pointer-scalar operation %d", op);
2612 }
Jack Palevichb6154502009-08-04 14:56:09 -07002613 Type* pPtrType = getPointerArithmeticResultType(
2614 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002615 o(0x59); /* pop %ecx */
2616 int size = sizeOf(pPtrType->pHead);
2617 if (size != 1) {
2618 // TODO: Optimize for power-of-two.
2619 if (isPtrR0) {
2620 oad(0xC969, size); // imull $size, %ecx
2621 } else {
2622 oad(0xC069, size); // mul $size, %eax
2623 }
2624 }
2625 o(decodeOp(op));
2626 popType();
2627 setR0Type(pPtrType);
2628 }
2629 } else {
2630 o(0x59); /* pop %ecx */
2631 o(decodeOp(op));
2632 if (op == OP_MOD)
2633 o(0x92); /* xchg %edx, %eax */
2634 popType();
2635 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002636 } else {
2637 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2638 setupFloatOperands();
2639 // Both float. x87 R0 == left hand, x87 R1 == right hand
2640 switch (op) {
2641 case OP_MUL:
2642 o(0xc9de); // fmulp
2643 break;
2644 case OP_DIV:
2645 o(0xf1de); // fdivp
2646 break;
2647 case OP_PLUS:
2648 o(0xc1de); // faddp
2649 break;
2650 case OP_MINUS:
2651 o(0xe1de); // fsubp
2652 break;
2653 default:
2654 error("Unsupported binary floating operation.");
2655 break;
2656 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002657 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002658 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002659 }
2660
Jack Palevich58c30ee2009-07-17 16:35:23 -07002661 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002662 if (op != OP_LOGICAL_NOT) {
2663 error("Unknown unary cmp %d", op);
2664 } else {
2665 Type* pR0Type = getR0Type();
2666 TypeTag tag = collapseType(pR0Type->tag);
2667 switch(tag) {
2668 case TY_INT: {
2669 oad(0xb9, 0); /* movl $0, %ecx */
2670 int t = decodeOp(op);
2671 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002672 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002673 o(0x0f); /* setxx %al */
2674 o(t + 0x90);
2675 o(0xc0);
2676 }
2677 break;
2678 case TY_FLOAT:
2679 case TY_DOUBLE:
2680 o(0xeed9); // fldz
2681 o(0xe9da); // fucompp
2682 o(0xe0df); // fnstsw %ax
2683 o(0x9e); // sahf
2684 o(0xc0950f); // setne %al
2685 o(0xc29a0f); // setp %dl
2686 o(0xd009); // orl %edx, %eax
2687 o(0xc0b60f); // movzbl %al, %eax
2688 o(0x01f083); // xorl $1, %eax
2689 break;
2690 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002691 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002692 break;
2693 }
2694 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002695 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002696 }
2697
2698 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002699 Type* pR0Type = getR0Type();
2700 TypeTag tag = collapseType(pR0Type->tag);
2701 switch(tag) {
2702 case TY_INT:
2703 oad(0xb9, 0); /* movl $0, %ecx */
2704 o(decodeOp(op));
2705 break;
2706 case TY_FLOAT:
2707 case TY_DOUBLE:
2708 switch (op) {
2709 case OP_MINUS:
2710 o(0xe0d9); // fchs
2711 break;
2712 case OP_BIT_NOT:
2713 error("Can't apply '~' operator to a float or double.");
2714 break;
2715 default:
2716 error("Unknown unary op %d\n", op);
2717 break;
2718 }
2719 break;
2720 default:
2721 error("genUnaryOp unsupported type");
2722 break;
2723 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002724 }
2725
Jack Palevich1cdef202009-05-22 12:06:27 -07002726 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002727 Type* pR0Type = getR0Type();
2728 TypeTag r0ct = collapseType(pR0Type->tag);
2729 switch(r0ct) {
2730 case TY_INT:
2731 o(0x50); /* push %eax */
2732 break;
2733 case TY_FLOAT:
2734 o(0x50); /* push %eax */
2735 o(0x241cd9); // fstps 0(%esp)
2736 break;
2737 case TY_DOUBLE:
2738 o(0x50); /* push %eax */
2739 o(0x50); /* push %eax */
2740 o(0x241cdd); // fstpl 0(%esp)
2741 break;
2742 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002743 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002744 break;
2745 }
Jack Palevich8df46192009-07-07 14:48:51 -07002746 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002747 }
2748
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002749 virtual void over() {
2750 // We know it's only used for int-ptr ops (++/--)
2751
2752 Type* pR0Type = getR0Type();
2753 TypeTag r0ct = collapseType(pR0Type->tag);
2754
2755 Type* pTOSType = getTOSType();
2756 TypeTag tosct = collapseType(pTOSType->tag);
2757
2758 assert (r0ct == TY_INT && tosct == TY_INT);
2759
2760 o(0x59); /* pop %ecx */
2761 o(0x50); /* push %eax */
2762 o(0x51); /* push %ecx */
2763
2764 overType();
2765 }
2766
Jack Palevich58c30ee2009-07-17 16:35:23 -07002767 virtual void popR0() {
2768 Type* pR0Type = getR0Type();
2769 TypeTag r0ct = collapseType(pR0Type->tag);
2770 switch(r0ct) {
2771 case TY_INT:
2772 o(0x58); /* popl %eax */
2773 break;
2774 case TY_FLOAT:
2775 o(0x2404d9); // flds (%esp)
2776 o(0x58); /* popl %eax */
2777 break;
2778 case TY_DOUBLE:
2779 o(0x2404dd); // fldl (%esp)
2780 o(0x58); /* popl %eax */
2781 o(0x58); /* popl %eax */
2782 break;
2783 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002784 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002785 break;
2786 }
2787 popType();
2788 }
2789
2790 virtual void storeR0ToTOS() {
2791 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002792 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002793 Type* pTargetType = pPointerType->pHead;
2794 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002795 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002796 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002797 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002798 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002799 case TY_INT:
2800 o(0x0189); /* movl %eax/%al, (%ecx) */
2801 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002802 case TY_SHORT:
2803 o(0x018966); /* movw %ax, (%ecx) */
2804 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002805 case TY_CHAR:
2806 o(0x0188); /* movl %eax/%al, (%ecx) */
2807 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002808 case TY_FLOAT:
2809 o(0x19d9); /* fstps (%ecx) */
2810 break;
2811 case TY_DOUBLE:
2812 o(0x19dd); /* fstpl (%ecx) */
2813 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002814 case TY_STRUCT:
2815 {
2816 // TODO: use alignment information to use movsw/movsl instead of movsb
2817 int size = sizeOf(pTargetType);
2818 if (size > 0) {
2819 o(0x9c); // pushf
2820 o(0x57); // pushl %edi
2821 o(0x56); // pushl %esi
2822 o(0xcf89); // movl %ecx, %edi
2823 o(0xc689); // movl %eax, %esi
2824 oad(0xb9, size); // mov #size, %ecx
2825 o(0xfc); // cld
2826 o(0xf3); // rep
2827 o(0xa4); // movsb
2828 o(0x5e); // popl %esi
2829 o(0x5f); // popl %edi
2830 o(0x9d); // popf
2831 }
2832 }
2833 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002834 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002835 error("storeR0ToTOS: unsupported type %d",
2836 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002837 break;
2838 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002839 }
2840
Jack Palevich58c30ee2009-07-17 16:35:23 -07002841 virtual void loadR0FromR0() {
2842 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002843 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002844 Type* pNewType = pPointerType->pHead;
2845 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002846 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002847 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002848 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002849 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002850 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002851 case TY_SHORT:
2852 o(0xbf0f); /* movswl (%eax), %eax */
2853 ob(0);
2854 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002855 case TY_CHAR:
2856 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002857 ob(0); /* add zero in code */
2858 break;
2859 case TY_FLOAT:
2860 o2(0x00d9); // flds (%eax)
2861 break;
2862 case TY_DOUBLE:
2863 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002864 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002865 case TY_ARRAY:
2866 pNewType = pNewType->pTail;
2867 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002868 case TY_STRUCT:
2869 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002870 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002871 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002872 break;
2873 }
Jack Palevich80e49722009-08-04 15:39:49 -07002874 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002875 }
2876
Jack Palevichb5e33312009-07-30 19:06:34 -07002877 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002878 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002879 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002880 }
2881
Jack Palevich9f51a262009-07-29 16:22:26 -07002882 virtual int leaForward(int ea, Type* pPointerType) {
2883 oad(0xb8, ea); /* mov $xx, %eax */
2884 setR0Type(pPointerType);
2885 return getPC() - 4;
2886 }
2887
Jack Palevichb6154502009-08-04 14:56:09 -07002888 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002889 Type* pR0Type = getR0Type();
2890 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002891 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002892 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002893 return;
2894 }
Jack Palevichb6154502009-08-04 14:56:09 -07002895 if (isPointerType(pType) && isPointerType(pR0Type)) {
2896 Type* pA = pR0Type;
2897 Type* pB = pType;
2898 // Array decays to pointer
2899 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2900 pA = pA->pTail;
2901 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002902 if (! (typeEqual(pA, pB)
2903 || pB->pHead->tag == TY_VOID
2904 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2905 )) {
2906 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002907 }
Jack Palevichb6154502009-08-04 14:56:09 -07002908 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002909 // do nothing special
2910 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2911 // do nothing special, both held in same register on x87.
2912 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002913 TypeTag r0Tag = collapseType(pR0Type->tag);
2914 TypeTag destTag = collapseType(pType->tag);
2915 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2916 // Convert R0 from int to float
2917 o(0x50); // push %eax
2918 o(0x2404DB); // fildl 0(%esp)
2919 o(0x58); // pop %eax
2920 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2921 // Convert R0 from float to int. Complicated because
2922 // need to save and restore the rounding mode.
2923 o(0x50); // push %eax
2924 o(0x50); // push %eax
2925 o(0x02247cD9); // fnstcw 2(%esp)
2926 o(0x2444b70f); // movzwl 2(%esp), %eax
2927 o(0x02);
2928 o(0x0cb4); // movb $12, %ah
2929 o(0x24048966); // movw %ax, 0(%esp)
2930 o(0x242cd9); // fldcw 0(%esp)
2931 o(0x04245cdb); // fistpl 4(%esp)
2932 o(0x02246cd9); // fldcw 2(%esp)
2933 o(0x58); // pop %eax
2934 o(0x58); // pop %eax
2935 } else {
2936 error("Incompatible types old: %d new: %d",
2937 pR0Type->tag, pType->tag);
2938 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002939 }
2940 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002941 }
2942
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002943 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002944 return oad(0xec81, 0); /* sub $xxx, %esp */
2945 }
2946
Jack Palevich8148c5b2009-07-16 18:24:47 -07002947 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2948 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002949 Type* pR0Type = getR0Type();
2950 TypeTag r0ct = collapseType(pR0Type->tag);
2951 switch(r0ct) {
2952 case TY_INT:
2953 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2954 return 4;
2955 case TY_FLOAT:
2956 oad(0x249CD9, l); /* fstps xxx(%esp) */
2957 return 4;
2958 case TY_DOUBLE:
2959 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2960 return 8;
2961 default:
2962 assert(false);
2963 return 0;
2964 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002965 }
2966
Jack Palevichb7718b92009-07-09 22:00:24 -07002967 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002968 * (int*) a = l;
2969 }
2970
Jack Palevich8df46192009-07-07 14:48:51 -07002971 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002972 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002973 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002974 return psym(0xe8, symbol); /* call xxx */
2975 }
2976
Jack Palevich8df46192009-07-07 14:48:51 -07002977 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002978 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002979 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002980 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002981 oad(0x2494ff, l); /* call *xxx(%esp) */
2982 }
2983
Jack Palevichb7718b92009-07-09 22:00:24 -07002984 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002985 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002986 if (isIndirect) {
2987 l += 4;
2988 }
-b master422972c2009-06-17 19:13:52 -07002989 if (l > 0) {
2990 oad(0xc481, l); /* add $xxx, %esp */
2991 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002992 }
2993
Jack Palevicha6535612009-05-13 16:24:17 -07002994 virtual int jumpOffset() {
2995 return 5;
2996 }
2997
Jack Paleviche7b59062009-05-19 17:12:17 -07002998 /* output a symbol and patch all calls to it */
2999 virtual void gsym(int t) {
3000 int n;
3001 int pc = getPC();
3002 while (t) {
3003 n = *(int *) t; /* next value */
3004 *(int *) t = pc - t - 4;
3005 t = n;
3006 }
3007 }
3008
Jack Palevich9f51a262009-07-29 16:22:26 -07003009 /* output a symbol and patch all calls to it, using absolute address */
3010 virtual void resolveForward(int t) {
3011 int n;
3012 int pc = getPC();
3013 while (t) {
3014 n = *(int *) t; /* next value */
3015 *(int *) t = pc;
3016 t = n;
3017 }
3018 }
3019
Jack Palevich1cdef202009-05-22 12:06:27 -07003020 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003021 size_t pagesize = 4096;
3022 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3023 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3024 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3025 if (err) {
3026 error("mprotect() failed: %d", errno);
3027 }
3028 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003029 }
3030
Jack Palevich9eed7a22009-07-06 17:24:34 -07003031 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003032 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003033 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003034 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003035 switch (pType->tag) {
3036 case TY_CHAR:
3037 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003038 case TY_SHORT:
3039 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003040 case TY_ARRAY:
3041 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003042 case TY_STRUCT:
3043 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003044 case TY_FUNC:
3045 error("alignment of func not supported");
3046 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003047 default:
3048 return 4;
3049 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003050 }
3051
3052 /**
3053 * Array element alignment (in bytes) for this type of data.
3054 */
3055 virtual size_t sizeOf(Type* pType){
3056 switch(pType->tag) {
3057 case TY_INT:
3058 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003059 case TY_SHORT:
3060 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003061 case TY_CHAR:
3062 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003063 case TY_FLOAT:
3064 return 4;
3065 case TY_DOUBLE:
3066 return 8;
3067 case TY_POINTER:
3068 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003069 case TY_ARRAY:
3070 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003071 case TY_STRUCT:
3072 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003073 default:
3074 error("Unsupported type %d", pType->tag);
3075 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003076 }
3077 }
3078
Jack Palevich21a15a22009-05-11 14:49:29 -07003079 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003080
3081 /** Output 1 to 4 bytes.
3082 *
3083 */
3084 void o(int n) {
3085 /* cannot use unsigned, so we must do a hack */
3086 while (n && n != -1) {
3087 ob(n & 0xff);
3088 n = n >> 8;
3089 }
3090 }
3091
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003092 /* Output exactly 2 bytes
3093 */
3094 void o2(int n) {
3095 ob(n & 0xff);
3096 ob(0xff & (n >> 8));
3097 }
3098
Jack Paleviche7b59062009-05-19 17:12:17 -07003099 /* psym is used to put an instruction with a data field which is a
3100 reference to a symbol. It is in fact the same as oad ! */
3101 int psym(int n, int t) {
3102 return oad(n, t);
3103 }
3104
3105 /* instruction + address */
3106 int oad(int n, int t) {
3107 o(n);
3108 int result = getPC();
3109 o4(t);
3110 return result;
3111 }
3112
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003113 static const int operatorHelper[];
3114
3115 int decodeOp(int op) {
3116 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003117 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003118 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003119 }
3120 return operatorHelper[op];
3121 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003122
Jack Palevich546b2242009-05-13 15:10:04 -07003123 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003124 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003125 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003126 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003127
3128 void setupFloatOperands() {
3129 Type* pR0Type = getR0Type();
3130 Type* pTOSType = getTOSType();
3131 TypeTag tagR0 = pR0Type->tag;
3132 TypeTag tagTOS = pTOSType->tag;
3133 bool isFloatR0 = isFloatTag(tagR0);
3134 bool isFloatTOS = isFloatTag(tagTOS);
3135 if (! isFloatR0) {
3136 // Convert R0 from int to float
3137 o(0x50); // push %eax
3138 o(0x2404DB); // fildl 0(%esp)
3139 o(0x58); // pop %eax
3140 }
3141 if (! isFloatTOS){
3142 o(0x2404DB); // fildl 0(%esp);
3143 o(0x58); // pop %eax
3144 } else {
3145 if (tagTOS == TY_FLOAT) {
3146 o(0x2404d9); // flds (%esp)
3147 o(0x58); // pop %eax
3148 } else {
3149 o(0x2404dd); // fldl (%esp)
3150 o(0x58); // pop %eax
3151 o(0x58); // pop %eax
3152 }
3153 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003154 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003155 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003156 };
3157
Jack Paleviche7b59062009-05-19 17:12:17 -07003158#endif // PROVIDE_X86_CODEGEN
3159
Jack Palevichb67b18f2009-06-11 21:12:23 -07003160#ifdef PROVIDE_TRACE_CODEGEN
3161 class TraceCodeGenerator : public CodeGenerator {
3162 private:
3163 CodeGenerator* mpBase;
3164
3165 public:
3166 TraceCodeGenerator(CodeGenerator* pBase) {
3167 mpBase = pBase;
3168 }
3169
3170 virtual ~TraceCodeGenerator() {
3171 delete mpBase;
3172 }
3173
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003174 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003175 mpBase->init(pCodeBuf);
3176 }
3177
3178 void setErrorSink(ErrorSink* pErrorSink) {
3179 mpBase->setErrorSink(pErrorSink);
3180 }
3181
3182 /* returns address to patch with local variable size
3183 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003184 virtual int functionEntry(Type* pDecl) {
3185 int result = mpBase->functionEntry(pDecl);
3186 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003187 return result;
3188 }
3189
Jack Palevichb7718b92009-07-09 22:00:24 -07003190 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3191 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3192 localVariableAddress, localVariableSize);
3193 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003194 }
3195
3196 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003197 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003198 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003199 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003200 }
3201
Jack Palevich1a539db2009-07-08 13:04:41 -07003202 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003203 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003204 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003205 }
3206
Jack Palevich9221bcc2009-08-26 16:15:07 -07003207 virtual void addStructOffsetR0(int offset, Type* pType) {
3208 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3209 mpBase->addStructOffsetR0(offset, pType);
3210 }
3211
Jack Palevichb67b18f2009-06-11 21:12:23 -07003212 virtual int gjmp(int t) {
3213 int result = mpBase->gjmp(t);
3214 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3215 return result;
3216 }
3217
3218 /* l = 0: je, l == 1: jne */
3219 virtual int gtst(bool l, int t) {
3220 int result = mpBase->gtst(l, t);
3221 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3222 return result;
3223 }
3224
Jack Palevich58c30ee2009-07-17 16:35:23 -07003225 virtual void gcmp(int op) {
3226 fprintf(stderr, "gcmp(%d)\n", op);
3227 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003228 }
3229
3230 virtual void genOp(int op) {
3231 fprintf(stderr, "genOp(%d)\n", op);
3232 mpBase->genOp(op);
3233 }
3234
Jack Palevich9eed7a22009-07-06 17:24:34 -07003235
Jack Palevich58c30ee2009-07-17 16:35:23 -07003236 virtual void gUnaryCmp(int op) {
3237 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3238 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003239 }
3240
3241 virtual void genUnaryOp(int op) {
3242 fprintf(stderr, "genUnaryOp(%d)\n", op);
3243 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003244 }
3245
3246 virtual void pushR0() {
3247 fprintf(stderr, "pushR0()\n");
3248 mpBase->pushR0();
3249 }
3250
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003251 virtual void over() {
3252 fprintf(stderr, "over()\n");
3253 mpBase->over();
3254 }
3255
Jack Palevich58c30ee2009-07-17 16:35:23 -07003256 virtual void popR0() {
3257 fprintf(stderr, "popR0()\n");
3258 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003259 }
3260
Jack Palevich58c30ee2009-07-17 16:35:23 -07003261 virtual void storeR0ToTOS() {
3262 fprintf(stderr, "storeR0ToTOS()\n");
3263 mpBase->storeR0ToTOS();
3264 }
3265
3266 virtual void loadR0FromR0() {
3267 fprintf(stderr, "loadR0FromR0()\n");
3268 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003269 }
3270
Jack Palevichb5e33312009-07-30 19:06:34 -07003271 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3272 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3273 pPointerType->pHead->tag, et);
3274 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003275 }
3276
Jack Palevich9f51a262009-07-29 16:22:26 -07003277 virtual int leaForward(int ea, Type* pPointerType) {
3278 fprintf(stderr, "leaForward(%d)\n", ea);
3279 return mpBase->leaForward(ea, pPointerType);
3280 }
3281
Jack Palevich30321cb2009-08-20 15:34:23 -07003282 virtual void convertR0Imp(Type* pType, bool isCast){
3283 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3284 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003285 }
3286
3287 virtual int beginFunctionCallArguments() {
3288 int result = mpBase->beginFunctionCallArguments();
3289 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3290 return result;
3291 }
3292
Jack Palevich8148c5b2009-07-16 18:24:47 -07003293 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3294 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3295 pArgType->tag);
3296 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003297 }
3298
Jack Palevichb7718b92009-07-09 22:00:24 -07003299 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003300 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003301 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003302 }
3303
Jack Palevich8df46192009-07-07 14:48:51 -07003304 virtual int callForward(int symbol, Type* pFunc) {
3305 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003306 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3307 return result;
3308 }
3309
Jack Palevich8df46192009-07-07 14:48:51 -07003310 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003311 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3312 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003313 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003314 }
3315
Jack Palevichb7718b92009-07-09 22:00:24 -07003316 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3317 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3318 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003319 }
3320
3321 virtual int jumpOffset() {
3322 return mpBase->jumpOffset();
3323 }
3324
Jack Palevichb67b18f2009-06-11 21:12:23 -07003325 /* output a symbol and patch all calls to it */
3326 virtual void gsym(int t) {
3327 fprintf(stderr, "gsym(%d)\n", t);
3328 mpBase->gsym(t);
3329 }
3330
Jack Palevich9f51a262009-07-29 16:22:26 -07003331 virtual void resolveForward(int t) {
3332 mpBase->resolveForward(t);
3333 }
3334
Jack Palevichb67b18f2009-06-11 21:12:23 -07003335 virtual int finishCompile() {
3336 int result = mpBase->finishCompile();
3337 fprintf(stderr, "finishCompile() = %d\n", result);
3338 return result;
3339 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003340
3341 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003342 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003343 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003344 virtual size_t alignmentOf(Type* pType){
3345 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003346 }
3347
3348 /**
3349 * Array element alignment (in bytes) for this type of data.
3350 */
3351 virtual size_t sizeOf(Type* pType){
3352 return mpBase->sizeOf(pType);
3353 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003354
3355 virtual Type* getR0Type() {
3356 return mpBase->getR0Type();
3357 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003358
3359 virtual ExpressionType getR0ExpressionType() {
3360 return mpBase->getR0ExpressionType();
3361 }
3362
3363 virtual void setR0ExpressionType(ExpressionType et) {
3364 mpBase->setR0ExpressionType(et);
3365 }
3366
3367 virtual size_t getExpressionStackDepth() {
3368 return mpBase->getExpressionStackDepth();
3369 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003370
3371 virtual void forceR0RVal() {
3372 return mpBase->forceR0RVal();
3373 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003374 };
3375
3376#endif // PROVIDE_TRACE_CODEGEN
3377
Jack Palevich569f1352009-06-29 14:29:08 -07003378 class Arena {
3379 public:
3380 // Used to record a given allocation amount.
3381 // Used:
3382 // Mark mark = arena.mark();
3383 // ... lots of arena.allocate()
3384 // arena.free(mark);
3385
3386 struct Mark {
3387 size_t chunk;
3388 size_t offset;
3389 };
3390
3391 Arena() {
3392 mCurrentChunk = 0;
3393 Chunk start(CHUNK_SIZE);
3394 mData.push_back(start);
3395 }
3396
3397 ~Arena() {
3398 for(size_t i = 0; i < mData.size(); i++) {
3399 mData[i].free();
3400 }
3401 }
3402
3403 // Alloc using the standard alignment size safe for any variable
3404 void* alloc(size_t size) {
3405 return alloc(size, 8);
3406 }
3407
3408 Mark mark(){
3409 Mark result;
3410 result.chunk = mCurrentChunk;
3411 result.offset = mData[mCurrentChunk].mOffset;
3412 return result;
3413 }
3414
3415 void freeToMark(const Mark& mark) {
3416 mCurrentChunk = mark.chunk;
3417 mData[mCurrentChunk].mOffset = mark.offset;
3418 }
3419
3420 private:
3421 // Allocate memory aligned to a given size
3422 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3423 // Memory is not zero filled.
3424
3425 void* alloc(size_t size, size_t alignment) {
3426 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3427 if (mCurrentChunk + 1 < mData.size()) {
3428 mCurrentChunk++;
3429 } else {
3430 size_t allocSize = CHUNK_SIZE;
3431 if (allocSize < size + alignment - 1) {
3432 allocSize = size + alignment - 1;
3433 }
3434 Chunk chunk(allocSize);
3435 mData.push_back(chunk);
3436 mCurrentChunk++;
3437 }
3438 }
3439 return mData[mCurrentChunk].allocate(size, alignment);
3440 }
3441
3442 static const size_t CHUNK_SIZE = 128*1024;
3443 // Note: this class does not deallocate its
3444 // memory when it's destroyed. It depends upon
3445 // its parent to deallocate the memory.
3446 struct Chunk {
3447 Chunk() {
3448 mpData = 0;
3449 mSize = 0;
3450 mOffset = 0;
3451 }
3452
3453 Chunk(size_t size) {
3454 mSize = size;
3455 mpData = (char*) malloc(size);
3456 mOffset = 0;
3457 }
3458
3459 ~Chunk() {
3460 // Doesn't deallocate memory.
3461 }
3462
3463 void* allocate(size_t size, size_t alignment) {
3464 size_t alignedOffset = aligned(mOffset, alignment);
3465 void* result = mpData + alignedOffset;
3466 mOffset = alignedOffset + size;
3467 return result;
3468 }
3469
3470 void free() {
3471 if (mpData) {
3472 ::free(mpData);
3473 mpData = 0;
3474 }
3475 }
3476
3477 size_t remainingCapacity(size_t alignment) {
3478 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3479 }
3480
3481 // Assume alignment is a power of two
3482 inline size_t aligned(size_t v, size_t alignment) {
3483 size_t mask = alignment-1;
3484 return (v + mask) & ~mask;
3485 }
3486
3487 char* mpData;
3488 size_t mSize;
3489 size_t mOffset;
3490 };
3491
3492 size_t mCurrentChunk;
3493
3494 Vector<Chunk> mData;
3495 };
3496
Jack Palevich569f1352009-06-29 14:29:08 -07003497 struct VariableInfo;
3498
3499 struct Token {
3500 int hash;
3501 size_t length;
3502 char* pText;
3503 tokenid_t id;
3504
3505 // Current values for the token
3506 char* mpMacroDefinition;
3507 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003508 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003509 };
3510
3511 class TokenTable {
3512 public:
3513 // Don't use 0..0xff, allows characters and operators to be tokens too.
3514
3515 static const int TOKEN_BASE = 0x100;
3516 TokenTable() {
3517 mpMap = hashmapCreate(128, hashFn, equalsFn);
3518 }
3519
3520 ~TokenTable() {
3521 hashmapFree(mpMap);
3522 }
3523
3524 void setArena(Arena* pArena) {
3525 mpArena = pArena;
3526 }
3527
3528 // Returns a token for a given string of characters.
3529 tokenid_t intern(const char* pText, size_t length) {
3530 Token probe;
3531 int hash = hashmapHash((void*) pText, length);
3532 {
3533 Token probe;
3534 probe.hash = hash;
3535 probe.length = length;
3536 probe.pText = (char*) pText;
3537 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3538 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003539 return pValue->id;
3540 }
3541 }
3542
3543 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3544 memset(pToken, 0, sizeof(*pToken));
3545 pToken->hash = hash;
3546 pToken->length = length;
3547 pToken->pText = (char*) mpArena->alloc(length + 1);
3548 memcpy(pToken->pText, pText, length);
3549 pToken->pText[length] = 0;
3550 pToken->id = mTokens.size() + TOKEN_BASE;
3551 mTokens.push_back(pToken);
3552 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003553 return pToken->id;
3554 }
3555
3556 // Return the Token for a given tokenid.
3557 Token& operator[](tokenid_t id) {
3558 return *mTokens[id - TOKEN_BASE];
3559 }
3560
3561 inline size_t size() {
3562 return mTokens.size();
3563 }
3564
3565 private:
3566
3567 static int hashFn(void* pKey) {
3568 Token* pToken = (Token*) pKey;
3569 return pToken->hash;
3570 }
3571
3572 static bool equalsFn(void* keyA, void* keyB) {
3573 Token* pTokenA = (Token*) keyA;
3574 Token* pTokenB = (Token*) keyB;
3575 // Don't need to compare hash values, they should always be equal
3576 return pTokenA->length == pTokenB->length
3577 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3578 }
3579
3580 Hashmap* mpMap;
3581 Vector<Token*> mTokens;
3582 Arena* mpArena;
3583 };
3584
Jack Palevich1cdef202009-05-22 12:06:27 -07003585 class InputStream {
3586 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003587 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003588 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003589 };
3590
3591 class TextInputStream : public InputStream {
3592 public:
3593 TextInputStream(const char* text, size_t textLength)
3594 : pText(text), mTextLength(textLength), mPosition(0) {
3595 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003596
Jack Palevichdc456462009-07-16 16:50:56 -07003597 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003598 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3599 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003600
Jack Palevichdc456462009-07-16 16:50:56 -07003601 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003602 const char* pText;
3603 size_t mTextLength;
3604 size_t mPosition;
3605 };
3606
Jack Palevicheedf9d22009-06-04 16:23:40 -07003607 class String {
3608 public:
3609 String() {
3610 mpBase = 0;
3611 mUsed = 0;
3612 mSize = 0;
3613 }
3614
Jack Palevich303d8ff2009-06-11 19:06:24 -07003615 String(const char* item, int len, bool adopt) {
3616 if (len < 0) {
3617 len = strlen(item);
3618 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003619 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003620 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003621 mUsed = len;
3622 mSize = len + 1;
3623 } else {
3624 mpBase = 0;
3625 mUsed = 0;
3626 mSize = 0;
3627 appendBytes(item, len);
3628 }
3629 }
3630
Jack Palevich303d8ff2009-06-11 19:06:24 -07003631 String(const String& other) {
3632 mpBase = 0;
3633 mUsed = 0;
3634 mSize = 0;
3635 appendBytes(other.getUnwrapped(), other.len());
3636 }
3637
Jack Palevicheedf9d22009-06-04 16:23:40 -07003638 ~String() {
3639 if (mpBase) {
3640 free(mpBase);
3641 }
3642 }
3643
Jack Palevicha6baa232009-06-12 11:25:59 -07003644 String& operator=(const String& other) {
3645 clear();
3646 appendBytes(other.getUnwrapped(), other.len());
3647 return *this;
3648 }
3649
Jack Palevich303d8ff2009-06-11 19:06:24 -07003650 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003651 return mpBase;
3652 }
3653
Jack Palevich303d8ff2009-06-11 19:06:24 -07003654 void clear() {
3655 mUsed = 0;
3656 if (mSize > 0) {
3657 mpBase[0] = 0;
3658 }
3659 }
3660
Jack Palevicheedf9d22009-06-04 16:23:40 -07003661 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003662 appendBytes(s, strlen(s));
3663 }
3664
3665 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003666 memcpy(ensure(n), s, n + 1);
3667 }
3668
3669 void append(char c) {
3670 * ensure(1) = c;
3671 }
3672
Jack Palevich86351982009-06-30 18:09:56 -07003673 void append(String& other) {
3674 appendBytes(other.getUnwrapped(), other.len());
3675 }
3676
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003677 char* orphan() {
3678 char* result = mpBase;
3679 mpBase = 0;
3680 mUsed = 0;
3681 mSize = 0;
3682 return result;
3683 }
3684
Jack Palevicheedf9d22009-06-04 16:23:40 -07003685 void printf(const char* fmt,...) {
3686 va_list ap;
3687 va_start(ap, fmt);
3688 vprintf(fmt, ap);
3689 va_end(ap);
3690 }
3691
3692 void vprintf(const char* fmt, va_list ap) {
3693 char* temp;
3694 int numChars = vasprintf(&temp, fmt, ap);
3695 memcpy(ensure(numChars), temp, numChars+1);
3696 free(temp);
3697 }
3698
Jack Palevich303d8ff2009-06-11 19:06:24 -07003699 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003700 return mUsed;
3701 }
3702
3703 private:
3704 char* ensure(int n) {
3705 size_t newUsed = mUsed + n;
3706 if (newUsed > mSize) {
3707 size_t newSize = mSize * 2 + 10;
3708 if (newSize < newUsed) {
3709 newSize = newUsed;
3710 }
3711 mpBase = (char*) realloc(mpBase, newSize + 1);
3712 mSize = newSize;
3713 }
3714 mpBase[newUsed] = '\0';
3715 char* result = mpBase + mUsed;
3716 mUsed = newUsed;
3717 return result;
3718 }
3719
3720 char* mpBase;
3721 size_t mUsed;
3722 size_t mSize;
3723 };
3724
Jack Palevich569f1352009-06-29 14:29:08 -07003725 void internKeywords() {
3726 // Note: order has to match TOK_ constants
3727 static const char* keywords[] = {
3728 "int",
3729 "char",
3730 "void",
3731 "if",
3732 "else",
3733 "while",
3734 "break",
3735 "return",
3736 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003737 "auto",
3738 "case",
3739 "const",
3740 "continue",
3741 "default",
3742 "do",
3743 "double",
3744 "enum",
3745 "extern",
3746 "float",
3747 "goto",
3748 "long",
3749 "register",
3750 "short",
3751 "signed",
3752 "sizeof",
3753 "static",
3754 "struct",
3755 "switch",
3756 "typedef",
3757 "union",
3758 "unsigned",
3759 "volatile",
3760 "_Bool",
3761 "_Complex",
3762 "_Imaginary",
3763 "inline",
3764 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003765
3766 // predefined tokens that can also be symbols start here:
3767 "pragma",
3768 "define",
3769 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003770 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003771
Jack Palevich569f1352009-06-29 14:29:08 -07003772 for(int i = 0; keywords[i]; i++) {
3773 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003774 }
Jack Palevich569f1352009-06-29 14:29:08 -07003775 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003776
Jack Palevich36d94142009-06-08 15:55:32 -07003777 struct InputState {
3778 InputStream* pStream;
3779 int oldCh;
3780 };
3781
Jack Palevich2db168f2009-06-11 14:29:47 -07003782 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003783 void* pAddress;
3784 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003785 tokenid_t tok;
3786 size_t level;
3787 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003788 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003789 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003790 };
3791
Jack Palevich303d8ff2009-06-11 19:06:24 -07003792 class SymbolStack {
3793 public:
3794 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003795 mpArena = 0;
3796 mpTokenTable = 0;
3797 }
3798
3799 void setArena(Arena* pArena) {
3800 mpArena = pArena;
3801 }
3802
3803 void setTokenTable(TokenTable* pTokenTable) {
3804 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003805 }
3806
3807 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003808 Mark mark;
3809 mark.mArenaMark = mpArena->mark();
3810 mark.mSymbolHead = mStack.size();
3811 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003812 }
3813
3814 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003815 // Undo any shadowing that was done:
3816 Mark mark = mLevelStack.back();
3817 mLevelStack.pop_back();
3818 while (mStack.size() > mark.mSymbolHead) {
3819 VariableInfo* pV = mStack.back();
3820 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003821 if (pV->isStructTag) {
3822 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3823 } else {
3824 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3825 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003826 }
Jack Palevich569f1352009-06-29 14:29:08 -07003827 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003828 }
3829
Jack Palevich569f1352009-06-29 14:29:08 -07003830 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3831 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3832 return pV && pV->level == level();
3833 }
3834
Jack Palevich9221bcc2009-08-26 16:15:07 -07003835 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3836 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3837 return pV && pV->level == level();
3838 }
3839
Jack Palevich569f1352009-06-29 14:29:08 -07003840 VariableInfo* add(tokenid_t tok) {
3841 Token& token = (*mpTokenTable)[tok];
3842 VariableInfo* pOldV = token.mpVariableInfo;
3843 VariableInfo* pNewV =
3844 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3845 memset(pNewV, 0, sizeof(VariableInfo));
3846 pNewV->tok = tok;
3847 pNewV->level = level();
3848 pNewV->pOldDefinition = pOldV;
3849 token.mpVariableInfo = pNewV;
3850 mStack.push_back(pNewV);
3851 return pNewV;
3852 }
3853
Jack Palevich9221bcc2009-08-26 16:15:07 -07003854 VariableInfo* addStructTag(tokenid_t tok) {
3855 Token& token = (*mpTokenTable)[tok];
3856 VariableInfo* pOldS = token.mpStructInfo;
3857 VariableInfo* pNewS =
3858 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3859 memset(pNewS, 0, sizeof(VariableInfo));
3860 pNewS->tok = tok;
3861 pNewS->level = level();
3862 pNewS->isStructTag = true;
3863 pNewS->pOldDefinition = pOldS;
3864 token.mpStructInfo = pNewS;
3865 mStack.push_back(pNewS);
3866 return pNewS;
3867 }
3868
Jack Palevich86351982009-06-30 18:09:56 -07003869 VariableInfo* add(Type* pType) {
3870 VariableInfo* pVI = add(pType->id);
3871 pVI->pType = pType;
3872 return pVI;
3873 }
3874
Jack Palevich569f1352009-06-29 14:29:08 -07003875 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3876 for (size_t i = 0; i < mStack.size(); i++) {
3877 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003878 break;
3879 }
3880 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003881 }
3882
Jack Palevich303d8ff2009-06-11 19:06:24 -07003883 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003884 inline size_t level() {
3885 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003886 }
3887
Jack Palevich569f1352009-06-29 14:29:08 -07003888 struct Mark {
3889 Arena::Mark mArenaMark;
3890 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003891 };
3892
Jack Palevich569f1352009-06-29 14:29:08 -07003893 Arena* mpArena;
3894 TokenTable* mpTokenTable;
3895 Vector<VariableInfo*> mStack;
3896 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003897 };
Jack Palevich36d94142009-06-08 15:55:32 -07003898
Jack Palevich188a5a72009-10-27 17:23:20 -07003899 struct MacroState {
3900 tokenid_t name; // Name of the current macro we are expanding
3901 char* dptr; // point to macro text during macro playback
3902 int dch; // Saves old value of ch during a macro playback
3903 };
3904
3905#define MACRO_NESTING_MAX 32
3906 MacroState macroState[MACRO_NESTING_MAX];
3907 int macroLevel; // -1 means not playing any macro.
3908
Jack Palevich36d94142009-06-08 15:55:32 -07003909 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003910 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003911 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003912 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003913 int tokl; // token operator level
3914 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003915 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003916 intptr_t loc; // local variable index
3917 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003918 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003919 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003920 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003921 ACCSymbolLookupFn mpSymbolLookupFn;
3922 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003923
3924 // Arena for the duration of the compile
3925 Arena mGlobalArena;
3926 // Arena for data that's only needed when compiling a single function
3927 Arena mLocalArena;
3928
Jack Palevich2ff5c222009-07-23 15:11:22 -07003929 Arena* mpCurrentArena;
3930
Jack Palevich569f1352009-06-29 14:29:08 -07003931 TokenTable mTokenTable;
3932 SymbolStack mGlobals;
3933 SymbolStack mLocals;
3934
Jack Palevich9221bcc2009-08-26 16:15:07 -07003935 SymbolStack* mpCurrentSymbolStack;
3936
Jack Palevich40600de2009-07-01 15:32:35 -07003937 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003938 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003939 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003940 Type* mkpChar; // char
3941 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003942 Type* mkpFloat;
3943 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003944 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003945 Type* mkpIntPtr;
3946 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003947 Type* mkpFloatPtr;
3948 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003949 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003950
Jack Palevich36d94142009-06-08 15:55:32 -07003951 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003952 int mLineNumber;
3953 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003954
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003955 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003956 CodeGenerator* pGen;
3957
Jack Palevicheedf9d22009-06-04 16:23:40 -07003958 String mErrorBuf;
3959
Jack Palevicheedf9d22009-06-04 16:23:40 -07003960 String mPragmas;
3961 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003962 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003963
Jack Palevich21a15a22009-05-11 14:49:29 -07003964 static const int ALLOC_SIZE = 99999;
3965
Jack Palevich303d8ff2009-06-11 19:06:24 -07003966 static const int TOK_DUMMY = 1;
3967 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003968 static const int TOK_NUM_FLOAT = 3;
3969 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003970 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003971 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003972
3973 // 3..255 are character and/or operators
3974
Jack Palevich2db168f2009-06-11 14:29:47 -07003975 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003976 // Order has to match string list in "internKeywords".
3977 enum {
3978 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3979 TOK_INT = TOK_KEYWORD,
3980 TOK_CHAR,
3981 TOK_VOID,
3982 TOK_IF,
3983 TOK_ELSE,
3984 TOK_WHILE,
3985 TOK_BREAK,
3986 TOK_RETURN,
3987 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003988 TOK_AUTO,
3989 TOK_CASE,
3990 TOK_CONST,
3991 TOK_CONTINUE,
3992 TOK_DEFAULT,
3993 TOK_DO,
3994 TOK_DOUBLE,
3995 TOK_ENUM,
3996 TOK_EXTERN,
3997 TOK_FLOAT,
3998 TOK_GOTO,
3999 TOK_LONG,
4000 TOK_REGISTER,
4001 TOK_SHORT,
4002 TOK_SIGNED,
4003 TOK_SIZEOF,
4004 TOK_STATIC,
4005 TOK_STRUCT,
4006 TOK_SWITCH,
4007 TOK_TYPEDEF,
4008 TOK_UNION,
4009 TOK_UNSIGNED,
4010 TOK_VOLATILE,
4011 TOK__BOOL,
4012 TOK__COMPLEX,
4013 TOK__IMAGINARY,
4014 TOK_INLINE,
4015 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004016
4017 // Symbols start after keywords
4018
4019 TOK_SYMBOL,
4020 TOK_PRAGMA = TOK_SYMBOL,
4021 TOK_DEFINE,
4022 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004023 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004024
4025 static const int LOCAL = 0x200;
4026
Jack Palevich21a15a22009-05-11 14:49:29 -07004027 /* tokens in string heap */
4028 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004029
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004030 static const int OP_INCREMENT = 0;
4031 static const int OP_DECREMENT = 1;
4032 static const int OP_MUL = 2;
4033 static const int OP_DIV = 3;
4034 static const int OP_MOD = 4;
4035 static const int OP_PLUS = 5;
4036 static const int OP_MINUS = 6;
4037 static const int OP_SHIFT_LEFT = 7;
4038 static const int OP_SHIFT_RIGHT = 8;
4039 static const int OP_LESS_EQUAL = 9;
4040 static const int OP_GREATER_EQUAL = 10;
4041 static const int OP_LESS = 11;
4042 static const int OP_GREATER = 12;
4043 static const int OP_EQUALS = 13;
4044 static const int OP_NOT_EQUALS = 14;
4045 static const int OP_LOGICAL_AND = 15;
4046 static const int OP_LOGICAL_OR = 16;
4047 static const int OP_BIT_AND = 17;
4048 static const int OP_BIT_XOR = 18;
4049 static const int OP_BIT_OR = 19;
4050 static const int OP_BIT_NOT = 20;
4051 static const int OP_LOGICAL_NOT = 21;
4052 static const int OP_COUNT = 22;
4053
4054 /* Operators are searched from front, the two-character operators appear
4055 * before the single-character operators with the same first character.
4056 * @ is used to pad out single-character operators.
4057 */
4058 static const char* operatorChars;
4059 static const char operatorLevel[];
4060
Jack Palevich569f1352009-06-29 14:29:08 -07004061 /* Called when we detect an internal problem. Does nothing in production.
4062 *
4063 */
4064 void internalError() {
4065 * (char*) 0 = 0;
4066 }
4067
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004068 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004069 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004070 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004071 internalError();
4072 }
Jack Palevich86351982009-06-30 18:09:56 -07004073 }
4074
Jack Palevich40600de2009-07-01 15:32:35 -07004075 bool isSymbol(tokenid_t t) {
4076 return t >= TOK_SYMBOL &&
4077 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4078 }
4079
4080 bool isSymbolOrKeyword(tokenid_t t) {
4081 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004082 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004083 }
4084
Jack Palevich86351982009-06-30 18:09:56 -07004085 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004086 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004087 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4088 if (pV && pV->tok != t) {
4089 internalError();
4090 }
4091 return pV;
4092 }
4093
4094 inline bool isDefined(tokenid_t t) {
4095 return t >= TOK_SYMBOL && VI(t) != 0;
4096 }
4097
Jack Palevich40600de2009-07-01 15:32:35 -07004098 const char* nameof(tokenid_t t) {
4099 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004100 return mTokenTable[t].pText;
4101 }
4102
Jack Palevich21a15a22009-05-11 14:49:29 -07004103 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004104 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004105 }
4106
4107 void inp() {
Jack Palevich188a5a72009-10-27 17:23:20 -07004108 // Close any totally empty macros. We leave them on the stack until now
4109 // so that we know which macros are being expanded when checking if the
4110 // last token in the macro is a macro that's already being expanded.
4111 while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) {
4112 macroLevel--;
4113 }
4114 if (macroLevel >= 0) {
4115 ch = *macroState[macroLevel].dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004116 if (ch == 0) {
Jack Palevich188a5a72009-10-27 17:23:20 -07004117 ch = macroState[macroLevel].dch;
4118 macroState[macroLevel].dptr = NULL; // This macro's done
Jack Palevich21a15a22009-05-11 14:49:29 -07004119 }
Jack Palevichdc456462009-07-16 16:50:56 -07004120 } else {
4121 if (mbBumpLine) {
4122 mLineNumber++;
4123 mbBumpLine = false;
4124 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004125 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004126 if (ch == '\n') {
4127 mbBumpLine = true;
4128 }
4129 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004130#if 0
4131 printf("ch='%c' 0x%x\n", ch, ch);
4132#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 }
4134
4135 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004136 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004137 }
4138
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004139 int decodeHex(int c) {
4140 if (isdigit(c)) {
4141 c -= '0';
4142 } else if (c <= 'F') {
4143 c = c - 'A' + 10;
4144 } else {
4145 c =c - 'a' + 10;
4146 }
4147 return c;
4148 }
4149
Jack Palevichb4758ff2009-06-12 12:49:14 -07004150 /* read a character constant, advances ch to after end of constant */
4151 int getq() {
4152 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004153 if (ch == '\\') {
4154 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004155 if (isoctal(ch)) {
4156 // 1 to 3 octal characters.
4157 val = 0;
4158 for(int i = 0; i < 3; i++) {
4159 if (isoctal(ch)) {
4160 val = (val << 3) + ch - '0';
4161 inp();
4162 }
4163 }
4164 return val;
4165 } else if (ch == 'x' || ch == 'X') {
4166 // N hex chars
4167 inp();
4168 if (! isxdigit(ch)) {
4169 error("'x' character escape requires at least one digit.");
4170 } else {
4171 val = 0;
4172 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004173 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004174 inp();
4175 }
4176 }
4177 } else {
4178 int val = ch;
4179 switch (ch) {
4180 case 'a':
4181 val = '\a';
4182 break;
4183 case 'b':
4184 val = '\b';
4185 break;
4186 case 'f':
4187 val = '\f';
4188 break;
4189 case 'n':
4190 val = '\n';
4191 break;
4192 case 'r':
4193 val = '\r';
4194 break;
4195 case 't':
4196 val = '\t';
4197 break;
4198 case 'v':
4199 val = '\v';
4200 break;
4201 case '\\':
4202 val = '\\';
4203 break;
4204 case '\'':
4205 val = '\'';
4206 break;
4207 case '"':
4208 val = '"';
4209 break;
4210 case '?':
4211 val = '?';
4212 break;
4213 default:
4214 error("Undefined character escape %c", ch);
4215 break;
4216 }
4217 inp();
4218 return val;
4219 }
4220 } else {
4221 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004222 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004223 return val;
4224 }
4225
4226 static bool isoctal(int ch) {
4227 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004228 }
4229
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004230 bool acceptCh(int c) {
4231 bool result = c == ch;
4232 if (result) {
4233 pdef(ch);
4234 inp();
4235 }
4236 return result;
4237 }
4238
4239 bool acceptDigitsCh() {
4240 bool result = false;
4241 while (isdigit(ch)) {
4242 result = true;
4243 pdef(ch);
4244 inp();
4245 }
4246 return result;
4247 }
4248
4249 void parseFloat() {
4250 tok = TOK_NUM_DOUBLE;
4251 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004252 if(mTokenString.len() == 0) {
4253 mTokenString.append('0');
4254 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004255 acceptCh('.');
4256 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004257 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004258 acceptCh('-') || acceptCh('+');
4259 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004260 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004261 if (ch == 'f' || ch == 'F') {
4262 tok = TOK_NUM_FLOAT;
4263 inp();
4264 } else if (ch == 'l' || ch == 'L') {
4265 inp();
4266 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004267 }
4268 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004269 char* pEnd = pText + strlen(pText);
4270 char* pEndPtr = 0;
4271 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004272 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004273 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004274 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004275 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004276 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004277 if (errno || pEndPtr != pEnd) {
4278 error("Can't parse constant: %s", pText);
4279 }
4280 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004281 }
4282
Jack Palevich188a5a72009-10-27 17:23:20 -07004283 bool currentlyBeingExpanded(tokenid_t id) {
4284 for (int i = 0; i <= macroLevel; i++) {
4285 if (macroState[macroLevel].name == id) {
4286 return true;
4287 }
4288 }
4289 return false;
4290 }
4291
Jack Palevich21a15a22009-05-11 14:49:29 -07004292 void next() {
4293 int l, a;
4294
Jack Palevich546b2242009-05-13 15:10:04 -07004295 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004296 if (ch == '#') {
4297 inp();
4298 next();
4299 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004300 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004301 } else if (tok == TOK_PRAGMA) {
4302 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004303 } else if (tok == TOK_LINE) {
4304 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004305 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004306 error("Unsupported preprocessor directive \"%s\"",
4307 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004308 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004309 }
4310 inp();
4311 }
4312 tokl = 0;
4313 tok = ch;
4314 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004315 if (isdigit(ch) || ch == '.') {
4316 // Start of a numeric constant. Could be integer, float, or
4317 // double, won't know until we look further.
4318 mTokenString.clear();
4319 pdef(ch);
4320 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004321 if (tok == '.' && !isdigit(ch)) {
4322 goto done;
4323 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004324 int base = 10;
4325 if (tok == '0') {
4326 if (ch == 'x' || ch == 'X') {
4327 base = 16;
4328 tok = TOK_NUM;
4329 tokc = 0;
4330 inp();
4331 while ( isxdigit(ch) ) {
4332 tokc = (tokc << 4) + decodeHex(ch);
4333 inp();
4334 }
4335 } else if (isoctal(ch)){
4336 base = 8;
4337 tok = TOK_NUM;
4338 tokc = 0;
4339 while ( isoctal(ch) ) {
4340 tokc = (tokc << 3) + (ch - '0');
4341 inp();
4342 }
4343 }
4344 } else if (isdigit(tok)){
4345 acceptDigitsCh();
4346 }
4347 if (base == 10) {
4348 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4349 parseFloat();
4350 } else {
4351 // It's an integer constant
4352 char* pText = mTokenString.getUnwrapped();
4353 char* pEnd = pText + strlen(pText);
4354 char* pEndPtr = 0;
4355 errno = 0;
4356 tokc = strtol(pText, &pEndPtr, base);
4357 if (errno || pEndPtr != pEnd) {
4358 error("Can't parse constant: %s %d %d", pText, base, errno);
4359 }
4360 tok = TOK_NUM;
4361 }
4362 }
4363 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004364 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004365 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004366 pdef(ch);
4367 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004368 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004369 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004370 if (! mbSuppressMacroExpansion) {
4371 // Is this a macro?
4372 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
Jack Palevich188a5a72009-10-27 17:23:20 -07004373 if (pMacroDefinition && !currentlyBeingExpanded(tok)) {
Jack Palevich815d8b82009-08-18 18:25:56 -07004374 // Yes, it is a macro
Jack Palevich188a5a72009-10-27 17:23:20 -07004375#if 0
4376 printf("Expanding macro %s -> %s",
4377 mTokenString.getUnwrapped(), pMacroDefinition);
4378#endif
4379 if (macroLevel >= MACRO_NESTING_MAX-1) {
4380 error("Too many levels of macro recursion.");
4381 } else {
4382 macroLevel++;
4383 macroState[macroLevel].name = tok;
4384 macroState[macroLevel].dptr = pMacroDefinition;
4385 macroState[macroLevel].dch = ch;
4386 inp();
4387 next();
4388 }
Jack Palevich815d8b82009-08-18 18:25:56 -07004389 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004390 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004391 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004392 inp();
4393 if (tok == '\'') {
4394 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004395 tokc = getq();
4396 if (ch != '\'') {
4397 error("Expected a ' character, got %c", ch);
4398 } else {
4399 inp();
4400 }
Jack Palevich546b2242009-05-13 15:10:04 -07004401 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004402 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004403 while (ch && ch != EOF) {
4404 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004405 inp();
4406 inp();
4407 if (ch == '/')
4408 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004409 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004410 if (ch == EOF) {
4411 error("End of file inside comment.");
4412 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004413 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004414 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004415 } else if ((tok == '/') & (ch == '/')) {
4416 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004417 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004418 inp();
4419 }
4420 inp();
4421 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004422 } else if ((tok == '-') & (ch == '>')) {
4423 inp();
4424 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004425 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004426 const char* t = operatorChars;
4427 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004428 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004429 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004430 tokl = operatorLevel[opIndex];
4431 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004432 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004433#if 0
4434 printf("%c%c -> tokl=%d tokc=0x%x\n",
4435 l, a, tokl, tokc);
4436#endif
4437 if (a == ch) {
4438 inp();
4439 tok = TOK_DUMMY; /* dummy token for double tokens */
4440 }
Jack Palevich0c017742009-07-31 12:00:39 -07004441 /* check for op=, valid for * / % + - << >> & ^ | */
4442 if (ch == '=' &&
4443 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004444 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004445 inp();
4446 tok = TOK_OP_ASSIGNMENT;
4447 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004448 break;
4449 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004450 opIndex++;
4451 }
4452 if (l == 0) {
4453 tokl = 0;
4454 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004455 }
4456 }
4457 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004458
4459 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004460#if 0
4461 {
Jack Palevich569f1352009-06-29 14:29:08 -07004462 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004463 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004464 fprintf(stderr, "%s\n", buf.getUnwrapped());
4465 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004466#endif
4467 }
4468
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004469 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004470 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004471 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004472 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004473 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004474 if (ch == '(') {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004475 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004476 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004477 }
4478 while (isspace(ch)) {
4479 inp();
4480 }
Jack Palevich569f1352009-06-29 14:29:08 -07004481 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004482 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004483 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004484 // Check for '//' comments.
4485 if (appendToValue && ch == '/') {
4486 inp();
4487 if (ch == '/') {
4488 appendToValue = false;
4489 } else {
4490 value.append('/');
4491 }
4492 }
4493 if (appendToValue && ch != EOF) {
4494 value.append(ch);
4495 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004496 inp();
4497 }
Jack Palevich569f1352009-06-29 14:29:08 -07004498 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4499 memcpy(pDefn, value.getUnwrapped(), value.len());
4500 pDefn[value.len()] = 0;
4501 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich188a5a72009-10-27 17:23:20 -07004502#if 0
4503 {
4504 String buf;
4505 decodeToken(buf, name, true);
4506 fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn);
4507 }
4508#endif
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004509 }
4510
Jack Palevicheedf9d22009-06-04 16:23:40 -07004511 void doPragma() {
4512 // # pragma name(val)
4513 int state = 0;
4514 while(ch != EOF && ch != '\n' && state < 10) {
4515 switch(state) {
4516 case 0:
4517 if (isspace(ch)) {
4518 inp();
4519 } else {
4520 state++;
4521 }
4522 break;
4523 case 1:
4524 if (isalnum(ch)) {
4525 mPragmas.append(ch);
4526 inp();
4527 } else if (ch == '(') {
4528 mPragmas.append(0);
4529 inp();
4530 state++;
4531 } else {
4532 state = 11;
4533 }
4534 break;
4535 case 2:
4536 if (isalnum(ch)) {
4537 mPragmas.append(ch);
4538 inp();
4539 } else if (ch == ')') {
4540 mPragmas.append(0);
4541 inp();
4542 state = 10;
4543 } else {
4544 state = 11;
4545 }
4546 break;
4547 }
4548 }
4549 if(state != 10) {
4550 error("Unexpected pragma syntax");
4551 }
4552 mPragmaStringCount += 2;
4553 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004554
Jack Palevichdc456462009-07-16 16:50:56 -07004555 void doLine() {
4556 // # line number { "filename "}
4557 next();
4558 if (tok != TOK_NUM) {
4559 error("Expected a line-number");
4560 } else {
4561 mLineNumber = tokc-1; // The end-of-line will increment it.
4562 }
4563 while(ch != EOF && ch != '\n') {
4564 inp();
4565 }
4566 }
4567
Jack Palevichac0e95e2009-05-29 13:53:44 -07004568 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004569 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004570 mErrorBuf.vprintf(fmt, ap);
4571 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004572 }
4573
Jack Palevich8b0624c2009-05-20 12:12:06 -07004574 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004575 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004576 error("'%c' expected", c);
4577 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004578 }
4579
Jack Palevich86351982009-06-30 18:09:56 -07004580 bool accept(intptr_t c) {
4581 if (tok == c) {
4582 next();
4583 return true;
4584 }
4585 return false;
4586 }
4587
Jack Palevich40600de2009-07-01 15:32:35 -07004588 bool acceptStringLiteral() {
4589 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004590 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004591 // This while loop merges multiple adjacent string constants.
4592 while (tok == '"') {
4593 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004594 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004595 }
4596 if (ch != '"') {
4597 error("Unterminated string constant.");
4598 }
4599 inp();
4600 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004601 }
Jack Palevich40600de2009-07-01 15:32:35 -07004602 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004603 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004604 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004605 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004606
4607 return true;
4608 }
4609 return false;
4610 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004611
Jack Palevichb1544ca2009-07-16 15:09:20 -07004612 void linkGlobal(tokenid_t t, bool isFunction) {
4613 VariableInfo* pVI = VI(t);
4614 void* n = NULL;
4615 if (mpSymbolLookupFn) {
4616 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4617 }
4618 if (pVI->pType == NULL) {
4619 if (isFunction) {
4620 pVI->pType = mkpIntFn;
4621 } else {
4622 pVI->pType = mkpInt;
4623 }
4624 }
4625 pVI->pAddress = n;
4626 }
4627
Jack Palevich29daf572009-07-30 19:38:55 -07004628 void unaryOrAssignment() {
4629 unary();
4630 if (accept('=')) {
4631 checkLVal();
4632 pGen->pushR0();
4633 expr();
4634 pGen->forceR0RVal();
4635 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004636 } else if (tok == TOK_OP_ASSIGNMENT) {
4637 int t = tokc;
4638 next();
4639 checkLVal();
4640 pGen->pushR0();
4641 pGen->forceR0RVal();
4642 pGen->pushR0();
4643 expr();
4644 pGen->forceR0RVal();
4645 pGen->genOp(t);
4646 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004647 }
4648 }
4649
Jack Palevich40600de2009-07-01 15:32:35 -07004650 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004651 */
Jack Palevich29daf572009-07-30 19:38:55 -07004652 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004653 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004654 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004655 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004656 if (acceptStringLiteral()) {
4657 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004658 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004659 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004660 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004661 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004662 t = tok;
4663 next();
4664 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004665 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004666 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004667 // Align to 4-byte boundary
4668 glo = (char*) (((intptr_t) glo + 3) & -4);
4669 * (float*) glo = (float) ad;
4670 pGen->loadFloat((int) glo, mkpFloat);
4671 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004672 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004673 // Align to 8-byte boundary
4674 glo = (char*) (((intptr_t) glo + 7) & -8);
4675 * (double*) glo = ad;
4676 pGen->loadFloat((int) glo, mkpDouble);
4677 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004678 } else if (c == 2) {
4679 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004680 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004681 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004682 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004683 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004684 else if (t == '+') {
4685 // ignore unary plus.
4686 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004687 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004688 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004689 } else if (c == 11) {
4690 // pre increment / pre decrement
4691 unary();
4692 doIncDec(a == OP_INCREMENT, 0);
4693 }
4694 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004695 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004696 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004697 if (pCast) {
4698 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004699 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004700 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004701 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004702 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004703 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004704 skip(')');
4705 }
4706 } else if (t == '*') {
4707 /* This is a pointer dereference.
4708 */
Jack Palevich29daf572009-07-30 19:38:55 -07004709 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004710 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004711 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004712 unary();
4713 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004714 } else if (t == EOF ) {
4715 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004716 } else if (t == ';') {
4717 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004718 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004719 // Don't have to do anything special here, the error
4720 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004721 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004722 if (!isDefined(t)) {
4723 mGlobals.add(t);
4724 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004725 }
Jack Palevich8df46192009-07-07 14:48:51 -07004726 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004727 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004728 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004729 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004730 linkGlobal(t, tok == '(');
4731 n = (intptr_t) pVI->pAddress;
4732 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004733 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004734 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004735 }
Jack Palevich29daf572009-07-30 19:38:55 -07004736 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004737 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004738 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004739 linkGlobal(t, false);
4740 n = (intptr_t) pVI->pAddress;
4741 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004742 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004743 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004744 }
Jack Palevich5b659092009-07-31 14:55:07 -07004745 }
4746 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004747 Type* pVal;
4748 ExpressionType et;
4749 if (pVI->pType->tag == TY_ARRAY) {
4750 pVal = pVI->pType;
4751 et = ET_RVALUE;
4752 } else {
4753 pVal = createPtrType(pVI->pType);
4754 et = ET_LVALUE;
4755 }
Jack Palevich5b659092009-07-31 14:55:07 -07004756 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004757 int tag = pVal->pHead->tag;
4758 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004759 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004760 }
Jack Palevich5b659092009-07-31 14:55:07 -07004761 pGen->leaR0(n, pVal, et);
4762 } else {
4763 pVI->pForward = (void*) pGen->leaForward(
4764 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004765 }
4766 }
4767 }
4768
Jack Palevich5b659092009-07-31 14:55:07 -07004769 /* Now handle postfix operators */
4770 for(;;) {
4771 if (tokl == 11) {
4772 // post inc / post dec
4773 doIncDec(tokc == OP_INCREMENT, true);
4774 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004775 } else if (accept('[')) {
4776 // Array reference
4777 pGen->forceR0RVal();
4778 pGen->pushR0();
4779 commaExpr();
4780 pGen->forceR0RVal();
4781 pGen->genOp(OP_PLUS);
4782 doPointer();
4783 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004784 } else if (accept('.')) {
4785 // struct element
4786 pGen->forceR0RVal();
4787 Type* pStruct = pGen->getR0Type();
4788 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004789 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004790 } else {
4791 error("expected a struct value to the left of '.'");
4792 }
4793 } else if (accept(TOK_OP_ARROW)) {
4794 pGen->forceR0RVal();
4795 Type* pPtr = pGen->getR0Type();
4796 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4797 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004798 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004799 } else {
4800 error("Expected a pointer to a struct to the left of '->'");
4801 }
Jack Palevich5b659092009-07-31 14:55:07 -07004802 } else if (accept('(')) {
4803 /* function call */
4804 Type* pDecl = NULL;
4805 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004806 Type* pFn = pGen->getR0Type();
Jack Palevich188a5a72009-10-27 17:23:20 -07004807 if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) {
4808 pDecl = pFn->pHead;
4809 pGen->pushR0();
4810 Type* pArgList = pDecl->pTail;
4811 bool varArgs = pArgList == NULL;
4812 /* push args and invert order */
4813 a = pGen->beginFunctionCallArguments();
4814 int l = 0;
4815 int argCount = 0;
4816 while (tok != ')' && tok != EOF) {
4817 if (! varArgs && !pArgList) {
4818 error("Unexpected argument.");
Jack Palevich5b659092009-07-31 14:55:07 -07004819 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004820 expr();
4821 pGen->forceR0RVal();
4822 Type* pTargetType;
4823 if (pArgList) {
4824 pTargetType = pArgList->pHead;
4825 pArgList = pArgList->pTail;
4826 } else {
4827 // This is a ... function, just pass arguments in their
4828 // natural type.
4829 pTargetType = pGen->getR0Type();
4830 if (pTargetType->tag == TY_FLOAT) {
4831 pTargetType = mkpDouble;
4832 } else if (pTargetType->tag == TY_ARRAY) {
4833 // Pass arrays by pointer.
4834 pTargetType = pTargetType->pTail;
4835 }
4836 }
4837 if (pTargetType->tag == TY_VOID) {
4838 error("Can't pass void value for argument %d",
4839 argCount + 1);
4840 } else {
4841 l += pGen->storeR0ToArg(l, pTargetType);
4842 }
4843 if (accept(',')) {
4844 // fine
4845 } else if ( tok != ')') {
4846 error("Expected ',' or ')'");
4847 }
4848 argCount += 1;
Jack Palevich5b659092009-07-31 14:55:07 -07004849 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004850 if (! varArgs && pArgList) {
4851 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich5b659092009-07-31 14:55:07 -07004852 }
Jack Palevich188a5a72009-10-27 17:23:20 -07004853 pGen->endFunctionCallArguments(pDecl, a, l);
4854 skip(')');
4855 pGen->callIndirect(l, pDecl);
4856 pGen->adjustStackAfterCall(pDecl, l, true);
4857 } else {
4858 error("Expected a function value to left of '('.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004859 }
Jack Palevich5b659092009-07-31 14:55:07 -07004860 } else {
4861 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004862 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004863 }
4864 }
4865
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004866 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004867 Type* pStructElement = lookupStructMember(pStruct, tok);
4868 if (pStructElement) {
4869 next();
4870 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4871 } else {
4872 String buf;
4873 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004874 error("Expected a struct member to the right of '%s', got %s",
4875 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004876 }
4877 }
4878
Jack Palevichaaac9282009-07-31 14:34:34 -07004879 void doIncDec(int isInc, int isPost) {
4880 // R0 already has the lval
4881 checkLVal();
4882 int lit = isInc ? 1 : -1;
4883 pGen->pushR0();
4884 pGen->loadR0FromR0();
4885 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004886 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4887 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004888 error("++/-- illegal for this type. %d", tag);
4889 }
4890 if (isPost) {
4891 pGen->over();
4892 pGen->pushR0();
4893 pGen->li(lit);
4894 pGen->genOp(OP_PLUS);
4895 pGen->storeR0ToTOS();
4896 pGen->popR0();
4897 } else {
4898 pGen->pushR0();
4899 pGen->li(lit);
4900 pGen->genOp(OP_PLUS);
4901 pGen->over();
4902 pGen->storeR0ToTOS();
4903 pGen->popR0();
4904 }
4905 }
4906
Jack Palevich47cbea92009-07-31 15:25:53 -07004907 void doPointer() {
4908 pGen->forceR0RVal();
4909 Type* pR0Type = pGen->getR0Type();
4910 if (pR0Type->tag != TY_POINTER) {
4911 error("Expected a pointer type.");
4912 } else {
4913 if (pR0Type->pHead->tag != TY_FUNC) {
4914 pGen->setR0ExpressionType(ET_LVALUE);
4915 }
4916 }
4917 }
4918
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004919 void doAddressOf() {
4920 Type* pR0 = pGen->getR0Type();
4921 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4922 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4923 error("Expected an lvalue");
4924 }
4925 Type* pR0Type = pGen->getR0Type();
4926 pGen->setR0ExpressionType(ET_RVALUE);
4927 }
4928
Jack Palevich40600de2009-07-01 15:32:35 -07004929 /* Recursive descent parser for binary operations.
4930 */
4931 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004932 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004933 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004934 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004935 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004936 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004937 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004938 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004939 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004940 t = tokc;
4941 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004942 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004943 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004944 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004945 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004946 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004947 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004948 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004949 // Check for syntax error.
4950 if (pGen->getR0Type() == NULL) {
4951 // We failed to parse a right-hand argument.
4952 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004953 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004954 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004955 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004956 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004957 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004958 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004959 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004960 }
4961 }
4962 }
4963 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004964 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004965 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004966 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004967 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004968 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004969 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004970 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004971 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004972 }
4973 }
4974 }
4975
Jack Palevich43aaee32009-07-31 14:01:37 -07004976 void commaExpr() {
4977 for(;;) {
4978 expr();
4979 if (!accept(',')) {
4980 break;
4981 }
4982 }
4983 }
4984
Jack Palevich21a15a22009-05-11 14:49:29 -07004985 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004986 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004987 }
4988
4989 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004990 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004991 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004992 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004993 }
4994
Jack Palevicha6baa232009-06-12 11:25:59 -07004995 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004996 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004997
Jack Palevich95727a02009-07-06 12:07:15 -07004998 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004999 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07005000 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07005001 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005002 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005003 next();
5004 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07005005 a = test_expr();
5006 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07005007 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07005008 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005009 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005010 n = pGen->gjmp(0); /* jmp */
5011 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07005012 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005013 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07005014 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005015 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005016 }
Jack Palevich546b2242009-05-13 15:10:04 -07005017 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07005018 t = tok;
5019 next();
5020 skip('(');
5021 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005022 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07005023 a = test_expr();
5024 } else {
5025 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005026 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005027 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005028 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07005029 a = 0;
5030 if (tok != ';')
5031 a = test_expr();
5032 skip(';');
5033 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005034 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005035 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005036 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005037 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005038 n = t + 4;
5039 }
5040 }
5041 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07005042 block((intptr_t) &a, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005043 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005044 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005045 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005046 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005047 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005048 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005049 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005050 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07005051 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005052 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005053 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005054 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005055 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005056 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005057 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005058 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005059 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005060 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005061 if (pReturnType->tag == TY_VOID) {
5062 error("Must not return a value from a void function");
5063 } else {
5064 pGen->convertR0(pReturnType);
5065 }
5066 } else {
5067 if (pReturnType->tag != TY_VOID) {
5068 error("Must specify a value here");
5069 }
Jack Palevich8df46192009-07-07 14:48:51 -07005070 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005071 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005072 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005073 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07005074 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005075 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005076 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005077 }
5078 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005079
Jack Palevicha8f427f2009-07-13 18:40:08 -07005080 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005081 if (a == b) {
5082 return true;
5083 }
5084 if (a == NULL || b == NULL) {
5085 return false;
5086 }
5087 TypeTag at = a->tag;
5088 if (at != b->tag) {
5089 return false;
5090 }
5091 if (at == TY_POINTER) {
5092 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005093 } else if (at == TY_ARRAY) {
5094 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005095 } else if (at == TY_FUNC || at == TY_PARAM) {
5096 return typeEqual(a->pHead, b->pHead)
5097 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005098 } else if (at == TY_STRUCT) {
5099 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005100 }
5101 return true;
5102 }
5103
Jack Palevich2ff5c222009-07-23 15:11:22 -07005104 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07005105 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005106 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005107 memset(pType, 0, sizeof(*pType));
5108 pType->tag = tag;
5109 pType->pHead = pHead;
5110 pType->pTail = pTail;
5111 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005112 }
5113
Jack Palevich2ff5c222009-07-23 15:11:22 -07005114 Type* createPtrType(Type* pType) {
5115 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005116 }
5117
5118 /**
5119 * Try to print a type in declaration order
5120 */
Jack Palevich86351982009-06-30 18:09:56 -07005121 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005122 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005123 if (pType == NULL) {
5124 buffer.appendCStr("null");
5125 return;
5126 }
Jack Palevich3f226492009-07-02 14:46:19 -07005127 decodeTypeImp(buffer, pType);
5128 }
5129
5130 void decodeTypeImp(String& buffer, Type* pType) {
5131 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005132 decodeId(buffer, pType->id);
5133 decodeTypeImpPostfix(buffer, pType);
5134 }
Jack Palevich3f226492009-07-02 14:46:19 -07005135
Jack Palevich9221bcc2009-08-26 16:15:07 -07005136 void decodeId(String& buffer, tokenid_t id) {
5137 if (id) {
5138 String temp;
5139 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005140 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005141 }
Jack Palevich3f226492009-07-02 14:46:19 -07005142 }
5143
5144 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5145 TypeTag tag = pType->tag;
5146
Jack Palevich9221bcc2009-08-26 16:15:07 -07005147 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005148 switch (tag) {
5149 case TY_INT:
5150 buffer.appendCStr("int");
5151 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005152 case TY_SHORT:
5153 buffer.appendCStr("short");
5154 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005155 case TY_CHAR:
5156 buffer.appendCStr("char");
5157 break;
5158 case TY_VOID:
5159 buffer.appendCStr("void");
5160 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005161 case TY_FLOAT:
5162 buffer.appendCStr("float");
5163 break;
5164 case TY_DOUBLE:
5165 buffer.appendCStr("double");
5166 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005167 case TY_STRUCT:
5168 {
5169 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5170 buffer.appendCStr(isStruct ? "struct" : "union");
5171 if (pType->pHead && pType->pHead->structTag) {
5172 buffer.append(' ');
5173 decodeId(buffer, pType->pHead->structTag);
5174 }
5175 }
5176 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005177 default:
5178 break;
5179 }
Jack Palevich86351982009-06-30 18:09:56 -07005180 buffer.append(' ');
5181 }
Jack Palevich3f226492009-07-02 14:46:19 -07005182
5183 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005184 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005185 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005186 case TY_SHORT:
5187 break;
Jack Palevich86351982009-06-30 18:09:56 -07005188 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005189 break;
5190 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005191 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005192 case TY_FLOAT:
5193 break;
5194 case TY_DOUBLE:
5195 break;
Jack Palevich86351982009-06-30 18:09:56 -07005196 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005197 decodeTypeImpPrefix(buffer, pType->pHead);
5198 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5199 buffer.append('(');
5200 }
5201 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005202 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005203 case TY_ARRAY:
5204 decodeTypeImpPrefix(buffer, pType->pHead);
5205 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005206 case TY_STRUCT:
5207 break;
Jack Palevich86351982009-06-30 18:09:56 -07005208 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005209 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005210 break;
5211 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005212 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005213 break;
5214 default:
5215 String temp;
5216 temp.printf("Unknown tag %d", pType->tag);
5217 buffer.append(temp);
5218 break;
5219 }
Jack Palevich3f226492009-07-02 14:46:19 -07005220 }
5221
5222 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5223 TypeTag tag = pType->tag;
5224
5225 switch(tag) {
5226 case TY_POINTER:
5227 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5228 buffer.append(')');
5229 }
5230 decodeTypeImpPostfix(buffer, pType->pHead);
5231 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005232 case TY_ARRAY:
5233 {
5234 String temp;
5235 temp.printf("[%d]", pType->length);
5236 buffer.append(temp);
5237 }
5238 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005239 case TY_STRUCT:
5240 if (pType->pHead->length >= 0) {
5241 buffer.appendCStr(" {");
5242 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5243 decodeTypeImp(buffer, pArg->pHead);
5244 buffer.appendCStr(";");
5245 }
5246 buffer.append('}');
5247 }
5248 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005249 case TY_FUNC:
5250 buffer.append('(');
5251 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5252 decodeTypeImp(buffer, pArg);
5253 if (pArg->pTail) {
5254 buffer.appendCStr(", ");
5255 }
5256 }
5257 buffer.append(')');
5258 break;
5259 default:
5260 break;
Jack Palevich86351982009-06-30 18:09:56 -07005261 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005262 }
5263
Jack Palevich86351982009-06-30 18:09:56 -07005264 void printType(Type* pType) {
5265 String buffer;
5266 decodeType(buffer, pType);
5267 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005268 }
5269
Jack Palevich2ff5c222009-07-23 15:11:22 -07005270 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005271 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005272 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005273 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005274 } else if (tok == TOK_SHORT) {
5275 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005276 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005277 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005278 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005279 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005280 } else if (tok == TOK_FLOAT) {
5281 pType = mkpFloat;
5282 } else if (tok == TOK_DOUBLE) {
5283 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005284 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5285 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005286 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005287 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005288 }
5289 next();
Jack Palevich86351982009-06-30 18:09:56 -07005290 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005291 }
5292
Jack Palevich9221bcc2009-08-26 16:15:07 -07005293 Type* acceptStruct() {
5294 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5295 bool isStruct = tok == TOK_STRUCT;
5296 next();
5297 tokenid_t structTag = acceptSymbol();
5298 bool isDeclaration = accept('{');
5299 bool fail = false;
5300
5301 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5302 if (structTag) {
5303 Token* pToken = &mTokenTable[structTag];
5304 VariableInfo* pStructInfo = pToken->mpStructInfo;
5305 bool needToDeclare = !pStructInfo;
5306 if (pStructInfo) {
5307 if (isDeclaration) {
5308 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5309 if (pStructInfo->pType->pHead->length == -1) {
5310 // we're filling in a forward declaration.
5311 needToDeclare = false;
5312 } else {
5313 error("A struct with the same name is already defined at this level.");
5314 fail = true;
5315 }
5316 } else {
5317 needToDeclare = true;
5318 }
5319 }
5320 if (!fail) {
5321 assert(pStructInfo->isStructTag);
5322 pStructType->pHead = pStructInfo->pType;
5323 pStructType->pTail = pStructType->pHead->pTail;
5324 }
5325 }
5326
5327 if (needToDeclare) {
5328 // This is a new struct name
5329 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5330 pStructType = createType(TY_STRUCT, NULL, NULL);
5331 pStructType->structTag = structTag;
5332 pStructType->pHead = pStructType;
5333 if (! isDeclaration) {
5334 // A forward declaration
5335 pStructType->length = -1;
5336 }
5337 pToken->mpStructInfo->pType = pStructType;
5338 }
5339 } else {
5340 // An anonymous struct
5341 pStructType->pHead = pStructType;
5342 }
5343
5344 if (isDeclaration) {
5345 size_t offset = 0;
5346 size_t structSize = 0;
5347 size_t structAlignment = 0;
5348 Type** pParamHolder = & pStructType->pHead->pTail;
5349 while (tok != '}' && tok != EOF) {
5350 Type* pPrimitiveType = expectPrimitiveType();
5351 if (pPrimitiveType) {
5352 while (tok != ';' && tok != EOF) {
5353 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5354 if (!pItem) {
5355 break;
5356 }
5357 if (lookupStructMember(pStructType, pItem->id)) {
5358 String buf;
5359 decodeToken(buf, pItem->id, false);
5360 error("Duplicate struct member %s", buf.getUnwrapped());
5361 }
5362 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5363 size_t alignment = pGen->alignmentOf(pItem);
5364 if (alignment > structAlignment) {
5365 structAlignment = alignment;
5366 }
5367 size_t alignmentMask = alignment - 1;
5368 offset = (offset + alignmentMask) & ~alignmentMask;
5369 pStructElement->length = offset;
5370 size_t size = pGen->sizeOf(pItem);
5371 if (isStruct) {
5372 offset += size;
5373 structSize = offset;
5374 } else {
5375 if (size >= structSize) {
5376 structSize = size;
5377 }
5378 }
5379 *pParamHolder = pStructElement;
5380 pParamHolder = &pStructElement->pTail;
5381 accept(',');
5382 }
5383 skip(';');
5384 } else {
5385 // Some sort of syntax error, skip token and keep trying
5386 next();
5387 }
5388 }
5389 if (!fail) {
5390 pStructType->pHead->length = structSize;
5391 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5392 }
5393 skip('}');
5394 }
5395 if (fail) {
5396 pStructType = NULL;
5397 }
5398 return pStructType;
5399 }
5400
5401 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5402 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5403 if (pStructElement->pHead->id == memberId) {
5404 return pStructElement;
5405 }
5406 }
5407 return NULL;
5408 }
5409
Jack Palevich2ff5c222009-07-23 15:11:22 -07005410 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005411 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005412 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005413 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005414 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005415 if (declName) {
5416 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005417 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005418 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005419 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005420 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005421 } else if (nameRequired) {
5422 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005423 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005424#if 0
5425 fprintf(stderr, "Parsed a declaration: ");
5426 printType(pType);
5427#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005428 if (reportFailure) {
5429 return NULL;
5430 }
Jack Palevich86351982009-06-30 18:09:56 -07005431 return pType;
5432 }
5433
Jack Palevich2ff5c222009-07-23 15:11:22 -07005434 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005435 bool nameRequired = pBaseType->tag != TY_STRUCT;
5436 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005437 if (! pType) {
5438 error("Expected a declaration");
5439 }
5440 return pType;
5441 }
5442
Jack Palevich3f226492009-07-02 14:46:19 -07005443 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005444 Type* acceptCastTypeDeclaration() {
5445 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005446 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005447 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005448 }
Jack Palevich86351982009-06-30 18:09:56 -07005449 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005450 }
5451
Jack Palevich2ff5c222009-07-23 15:11:22 -07005452 Type* expectCastTypeDeclaration() {
5453 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005454 if (! pType) {
5455 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005456 }
Jack Palevich3f226492009-07-02 14:46:19 -07005457 return pType;
5458 }
5459
5460 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005461 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005462 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005463 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005464 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005465 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005466 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005467 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005468 return pType;
5469 }
5470
5471 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005472 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005473 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005474 // direct-dcl :
5475 // name
5476 // (dcl)
5477 // direct-dcl()
5478 // direct-dcl[]
5479 Type* pNewHead = NULL;
5480 if (accept('(')) {
5481 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005482 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005483 skip(')');
5484 } else if ((declName = acceptSymbol()) != 0) {
5485 if (nameAllowed == false && declName) {
5486 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005487 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005488 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005489 } else if (nameRequired && ! declName) {
5490 String temp;
5491 decodeToken(temp, tok, true);
5492 error("Expected name. Got %s", temp.getUnwrapped());
5493 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005494 }
Jack Palevichb6154502009-08-04 14:56:09 -07005495 for(;;) {
5496 if (accept('(')) {
5497 // Function declaration
5498 Type* pTail = acceptArgs(nameAllowed);
5499 pType = createType(TY_FUNC, pType, pTail);
5500 skip(')');
5501 } if (accept('[')) {
5502 if (tok != ']') {
5503 if (tok != TOK_NUM || tokc <= 0) {
5504 error("Expected positive integer constant");
5505 } else {
5506 Type* pDecayType = createPtrType(pType);
5507 pType = createType(TY_ARRAY, pType, pDecayType);
5508 pType->length = tokc;
5509 }
5510 next();
5511 }
5512 skip(']');
5513 } else {
5514 break;
5515 }
Jack Palevich86351982009-06-30 18:09:56 -07005516 }
Jack Palevich3f226492009-07-02 14:46:19 -07005517
5518 if (pNewHead) {
5519 Type* pA = pNewHead;
5520 while (pA->pHead) {
5521 pA = pA->pHead;
5522 }
5523 pA->pHead = pType;
5524 pType = pNewHead;
5525 }
Jack Palevich86351982009-06-30 18:09:56 -07005526 return pType;
5527 }
5528
Jack Palevich2ff5c222009-07-23 15:11:22 -07005529 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005530 Type* pHead = NULL;
5531 Type* pTail = NULL;
5532 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005533 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005534 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005535 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005536 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005537 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005538 if (!pHead) {
5539 pHead = pParam;
5540 pTail = pParam;
5541 } else {
5542 pTail->pTail = pParam;
5543 pTail = pParam;
5544 }
5545 }
5546 }
5547 if (! accept(',')) {
5548 break;
5549 }
5550 }
5551 return pHead;
5552 }
5553
Jack Palevich2ff5c222009-07-23 15:11:22 -07005554 Type* expectPrimitiveType() {
5555 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005556 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005557 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005558 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005559 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005560 }
Jack Palevich86351982009-06-30 18:09:56 -07005561 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005562 }
5563
Jack Palevichb5e33312009-07-30 19:06:34 -07005564 void checkLVal() {
5565 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005566 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005567 }
5568 }
5569
Jack Palevich86351982009-06-30 18:09:56 -07005570 void addGlobalSymbol(Type* pDecl) {
5571 tokenid_t t = pDecl->id;
5572 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005573 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005574 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005575 }
Jack Palevich86351982009-06-30 18:09:56 -07005576 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005577 }
5578
Jack Palevich86351982009-06-30 18:09:56 -07005579 void reportDuplicate(tokenid_t t) {
5580 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005581 }
5582
Jack Palevich86351982009-06-30 18:09:56 -07005583 void addLocalSymbol(Type* pDecl) {
5584 tokenid_t t = pDecl->id;
5585 if (mLocals.isDefinedAtCurrentLevel(t)) {
5586 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005587 }
Jack Palevich86351982009-06-30 18:09:56 -07005588 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005589 }
5590
Jack Palevich61de31f2009-09-08 11:06:40 -07005591 bool checkUndeclaredStruct(Type* pBaseType) {
5592 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5593 String temp;
5594 decodeToken(temp, pBaseType->structTag, false);
5595 error("Undeclared struct %s", temp.getUnwrapped());
5596 return true;
5597 }
5598 return false;
5599 }
5600
Jack Palevich95727a02009-07-06 12:07:15 -07005601 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005602 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005603
Jack Palevich95727a02009-07-06 12:07:15 -07005604 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005605 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005606 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005607 if (!pDecl) {
5608 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005609 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005610 if (!pDecl->id) {
5611 break;
5612 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005613 if (checkUndeclaredStruct(pDecl)) {
5614 break;
5615 }
Jack Palevich86351982009-06-30 18:09:56 -07005616 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005617 if (pDecl->tag == TY_FUNC) {
5618 if (tok == '{') {
5619 error("Nested functions are not allowed. Did you forget a '}' ?");
5620 break;
5621 }
5622 // Else it's a forward declaration of a function.
5623 } else {
5624 int variableAddress = 0;
5625 size_t alignment = pGen->alignmentOf(pDecl);
5626 assert(alignment > 0);
5627 size_t alignmentMask = ~ (alignment - 1);
5628 size_t sizeOf = pGen->sizeOf(pDecl);
5629 assert(sizeOf > 0);
5630 loc = (loc + alignment - 1) & alignmentMask;
5631 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5632 loc = loc + alignedSize;
5633 variableAddress = -loc;
5634 VI(pDecl->id)->pAddress = (void*) variableAddress;
5635 if (accept('=')) {
5636 /* assignment */
5637 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5638 pGen->pushR0();
5639 expr();
5640 pGen->forceR0RVal();
5641 pGen->storeR0ToTOS();
5642 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005643 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005644 if (tok == ',')
5645 next();
5646 }
5647 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005648 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005649 }
5650 }
5651
Jack Palevichf1728be2009-06-12 13:53:51 -07005652 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005653 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005654 }
5655
Jack Palevich37c54bd2009-07-14 18:35:36 -07005656 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005657 if (token == EOF ) {
5658 buffer.printf("EOF");
5659 } else if (token == TOK_NUM) {
Jack Palevich188a5a72009-10-27 17:23:20 -07005660 buffer.printf("numeric constant %d(0x%x)", tokc, tokc);
5661 } else if (token == TOK_NUM_FLOAT) {
5662 buffer.printf("numeric constant float %g", tokd);
5663 } else if (token == TOK_NUM_DOUBLE) {
5664 buffer.printf("numeric constant double %g", tokd);
5665 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005666 if (token < 32) {
5667 buffer.printf("'\\x%02x'", token);
5668 } else {
5669 buffer.printf("'%c'", token);
5670 }
Jack Palevich569f1352009-06-29 14:29:08 -07005671 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005672 if (quote) {
5673 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5674 buffer.printf("keyword \"%s\"", nameof(token));
5675 } else {
5676 buffer.printf("symbol \"%s\"", nameof(token));
5677 }
5678 } else {
5679 buffer.printf("%s", nameof(token));
5680 }
Jack Palevich569f1352009-06-29 14:29:08 -07005681 }
5682 }
5683
Jack Palevich9221bcc2009-08-26 16:15:07 -07005684 void printToken(tokenid_t token) {
5685 String buffer;
5686 decodeToken(buffer, token, true);
5687 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5688 }
5689
Jack Palevich40600de2009-07-01 15:32:35 -07005690 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005691 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005692 if (!result) {
5693 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005694 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005695 error("Expected symbol. Got %s", temp.getUnwrapped());
5696 }
5697 return result;
5698 }
5699
Jack Palevich86351982009-06-30 18:09:56 -07005700 tokenid_t acceptSymbol() {
5701 tokenid_t result = 0;
5702 if (tok >= TOK_SYMBOL) {
5703 result = tok;
5704 next();
Jack Palevich86351982009-06-30 18:09:56 -07005705 }
5706 return result;
5707 }
5708
Jack Palevichb7c81e92009-06-04 19:56:13 -07005709 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005710 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005711 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005712 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005713 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005714 break;
5715 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005716 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005717 if (!pDecl) {
5718 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005719 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005720 if (!pDecl->id) {
5721 skip(';');
5722 continue;
5723 }
5724
Jack Palevich61de31f2009-09-08 11:06:40 -07005725 if (checkUndeclaredStruct(pDecl)) {
5726 skip(';');
5727 continue;
5728 }
5729
Jack Palevich86351982009-06-30 18:09:56 -07005730 if (! isDefined(pDecl->id)) {
5731 addGlobalSymbol(pDecl);
5732 }
5733 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005734 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005735 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005736 }
Jack Palevich86351982009-06-30 18:09:56 -07005737 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005738 // it's a variable declaration
5739 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005740 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005741 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005742 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005743 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005744 }
Jack Palevich86351982009-06-30 18:09:56 -07005745 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005746 if (tok == TOK_NUM) {
5747 if (name) {
5748 * (int*) name->pAddress = tokc;
5749 }
5750 next();
5751 } else {
5752 error("Expected an integer constant");
5753 }
5754 }
Jack Palevich86351982009-06-30 18:09:56 -07005755 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005756 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005757 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005758 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005759 if (!pDecl) {
5760 break;
5761 }
5762 if (! isDefined(pDecl->id)) {
5763 addGlobalSymbol(pDecl);
5764 }
5765 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005766 }
5767 skip(';');
5768 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005769 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005770 if (accept(';')) {
5771 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005772 } else if (tok != '{') {
5773 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005774 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005775 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005776 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005777 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005778 /* patch forward references */
5779 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005780 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005781 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005782 }
5783 // Calculate stack offsets for parameters
5784 mLocals.pushLevel();
5785 intptr_t a = 8;
5786 int argCount = 0;
5787 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5788 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005789 if (pArg->id) {
5790 addLocalSymbol(pArg);
5791 }
Jack Palevich95727a02009-07-06 12:07:15 -07005792 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005793 Type* pPassingType = passingType(pArg);
5794 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005795 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005796 if (pArg->id) {
5797 VI(pArg->id)->pAddress = (void*) a;
5798 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005799 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005800 argCount++;
5801 }
5802 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005803 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005804 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005805 block(0, true);
5806 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005807 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005808 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005809 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005810 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005811 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005812 }
5813 }
5814 }
5815
Jack Palevich9221bcc2009-08-26 16:15:07 -07005816 Type* passingType(Type* pType) {
5817 switch (pType->tag) {
5818 case TY_CHAR:
5819 case TY_SHORT:
5820 return mkpInt;
5821 default:
5822 return pType;
5823 }
5824 }
5825
Jack Palevich9cbd2262009-07-08 16:48:41 -07005826 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5827 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5828 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005829 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005830 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005831 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005832 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005833 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005834 char* result = (char*) base;
5835 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005836 return result;
5837 }
5838
Jack Palevich21a15a22009-05-11 14:49:29 -07005839 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005840 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005841 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005842 pGlobalBase = 0;
5843 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005844 if (pGen) {
5845 delete pGen;
5846 pGen = 0;
5847 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005848 if (pCodeBuf) {
5849 delete pCodeBuf;
5850 pCodeBuf = 0;
5851 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005852 if (file) {
5853 delete file;
5854 file = 0;
5855 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005856 }
5857
Jack Palevich8c246a92009-07-14 21:14:10 -07005858 // One-time initialization, when class is constructed.
5859 void init() {
5860 mpSymbolLookupFn = 0;
5861 mpSymbolLookupContext = 0;
5862 }
5863
Jack Palevich21a15a22009-05-11 14:49:29 -07005864 void clear() {
5865 tok = 0;
5866 tokc = 0;
5867 tokl = 0;
5868 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005869 rsym = 0;
5870 loc = 0;
5871 glo = 0;
Jack Palevich188a5a72009-10-27 17:23:20 -07005872 macroLevel = -1;
Jack Palevich21a15a22009-05-11 14:49:29 -07005873 file = 0;
5874 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005875 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005876 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005877 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005878 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005879 mLineNumber = 1;
5880 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005881 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005882 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005883
Jack Palevich22305132009-05-13 10:58:45 -07005884 void setArchitecture(const char* architecture) {
5885 delete pGen;
5886 pGen = 0;
5887
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005888 delete pCodeBuf;
5889 pCodeBuf = new CodeBuf();
5890
Jack Palevich22305132009-05-13 10:58:45 -07005891 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005892#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005893 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005894 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005895 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07005896 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005897#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005898#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005899 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005900 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005901 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005902#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005903 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005904 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005905 }
5906 }
5907
5908 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005909#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005910 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005911 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07005912#elif defined(DEFAULT_X86_CODEGEN)
5913 pGen = new X86CodeGenerator();
5914#endif
5915 }
5916 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005917 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005918 } else {
5919 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005920 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005921 }
5922 }
5923
Jack Palevich77ae76e2009-05-10 19:59:24 -07005924public:
Jack Palevich22305132009-05-13 10:58:45 -07005925 struct args {
5926 args() {
5927 architecture = 0;
5928 }
5929 const char* architecture;
5930 };
5931
Jack Paleviche7b59062009-05-19 17:12:17 -07005932 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005933 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005934 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005935 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005936
Jack Paleviche7b59062009-05-19 17:12:17 -07005937 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005938 cleanup();
5939 }
5940
Jack Palevich8c246a92009-07-14 21:14:10 -07005941 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5942 mpSymbolLookupFn = pFn;
5943 mpSymbolLookupContext = pContext;
5944 }
5945
Jack Palevich1cdef202009-05-22 12:06:27 -07005946 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005947 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005948
Jack Palevich2ff5c222009-07-23 15:11:22 -07005949 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005950 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005951 cleanup();
5952 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005953 mTokenTable.setArena(&mGlobalArena);
5954 mGlobals.setArena(&mGlobalArena);
5955 mGlobals.setTokenTable(&mTokenTable);
5956 mLocals.setArena(&mLocalArena);
5957 mLocals.setTokenTable(&mTokenTable);
5958
5959 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005960 setArchitecture(NULL);
5961 if (!pGen) {
5962 return -1;
5963 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005964#ifdef PROVIDE_TRACE_CODEGEN
5965 pGen = new TraceCodeGenerator(pGen);
5966#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005967 pGen->setErrorSink(this);
5968
5969 if (pCodeBuf) {
5970 pCodeBuf->init(ALLOC_SIZE);
5971 }
5972 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07005973 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005974 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5975 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005976 inp();
5977 next();
5978 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005979 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005980 result = pGen->finishCompile();
5981 if (result == 0) {
5982 if (mErrorBuf.len()) {
5983 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005984 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005985 }
Jack Palevichce105a92009-07-16 14:30:33 -07005986 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005987 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005988 }
5989
Jack Palevich86351982009-06-30 18:09:56 -07005990 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005991 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005992 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005993 mkpChar = createType(TY_CHAR, NULL, NULL);
5994 mkpVoid = createType(TY_VOID, NULL, NULL);
5995 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5996 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5997 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5998 mkpIntPtr = createPtrType(mkpInt);
5999 mkpCharPtr = createPtrType(mkpChar);
6000 mkpFloatPtr = createPtrType(mkpFloat);
6001 mkpDoublePtr = createPtrType(mkpDouble);
6002 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07006003 }
6004
Jack Palevicha6baa232009-06-12 11:25:59 -07006005 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07006006 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07006007 }
6008
Jack Palevich569f1352009-06-29 14:29:08 -07006009 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006010 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07006011 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07006012 }
6013
Jack Palevich569f1352009-06-29 14:29:08 -07006014 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07006015 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07006016 error("Undefined forward reference: %s",
6017 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07006018 }
6019 return true;
6020 }
6021
Jack Palevich1cdef202009-05-22 12:06:27 -07006022 /* Look through the symbol table to find a symbol.
6023 * If found, return its value.
6024 */
6025 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07006026 if (mCompileResult == 0) {
6027 tokenid_t tok = mTokenTable.intern(name, strlen(name));
6028 VariableInfo* pVariableInfo = VI(tok);
6029 if (pVariableInfo) {
6030 return pVariableInfo->pAddress;
6031 }
Jack Palevich1cdef202009-05-22 12:06:27 -07006032 }
6033 return NULL;
6034 }
6035
Jack Palevicheedf9d22009-06-04 16:23:40 -07006036 void getPragmas(ACCsizei* actualStringCount,
6037 ACCsizei maxStringCount, ACCchar** strings) {
6038 int stringCount = mPragmaStringCount;
6039 if (actualStringCount) {
6040 *actualStringCount = stringCount;
6041 }
6042 if (stringCount > maxStringCount) {
6043 stringCount = maxStringCount;
6044 }
6045 if (strings) {
6046 char* pPragmas = mPragmas.getUnwrapped();
6047 while (stringCount-- > 0) {
6048 *strings++ = pPragmas;
6049 pPragmas += strlen(pPragmas) + 1;
6050 }
6051 }
6052 }
6053
Jack Palevichd5315572009-09-09 13:19:34 -07006054 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006055 *base = pCodeBuf->getBase();
6056 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006057 }
6058
Jack Palevichac0e95e2009-05-29 13:53:44 -07006059 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006060 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006061 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006062};
6063
Jack Paleviche7b59062009-05-19 17:12:17 -07006064const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006065 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6066
Jack Paleviche7b59062009-05-19 17:12:17 -07006067const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006068 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6069 5, 5, /* ==, != */
6070 9, 10, /* &&, || */
6071 6, 7, 8, /* & ^ | */
6072 2, 2 /* ~ ! */
6073 };
6074
Jack Palevich8b0624c2009-05-20 12:12:06 -07006075#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006076const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006077 0x1, // ++
6078 0xff, // --
6079 0xc1af0f, // *
6080 0xf9f79991, // /
6081 0xf9f79991, // % (With manual assist to swap results)
6082 0xc801, // +
6083 0xd8f7c829, // -
6084 0xe0d391, // <<
6085 0xf8d391, // >>
6086 0xe, // <=
6087 0xd, // >=
6088 0xc, // <
6089 0xf, // >
6090 0x4, // ==
6091 0x5, // !=
6092 0x0, // &&
6093 0x1, // ||
6094 0xc821, // &
6095 0xc831, // ^
6096 0xc809, // |
6097 0xd0f7, // ~
6098 0x4 // !
6099};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006100#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006101
Jack Palevich1cdef202009-05-22 12:06:27 -07006102struct ACCscript {
6103 ACCscript() {
6104 text = 0;
6105 textLength = 0;
6106 accError = ACC_NO_ERROR;
6107 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006108
Jack Palevich1cdef202009-05-22 12:06:27 -07006109 ~ACCscript() {
6110 delete text;
6111 }
Jack Palevich546b2242009-05-13 15:10:04 -07006112
Jack Palevich8c246a92009-07-14 21:14:10 -07006113 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6114 compiler.registerSymbolCallback(pFn, pContext);
6115 }
6116
Jack Palevich1cdef202009-05-22 12:06:27 -07006117 void setError(ACCenum error) {
6118 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6119 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006120 }
6121 }
6122
Jack Palevich1cdef202009-05-22 12:06:27 -07006123 ACCenum getError() {
6124 ACCenum result = accError;
6125 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006126 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006127 }
6128
Jack Palevich1cdef202009-05-22 12:06:27 -07006129 Compiler compiler;
6130 char* text;
6131 int textLength;
6132 ACCenum accError;
6133};
6134
6135
6136extern "C"
6137ACCscript* accCreateScript() {
6138 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006139}
Jack Palevich1cdef202009-05-22 12:06:27 -07006140
6141extern "C"
6142ACCenum accGetError( ACCscript* script ) {
6143 return script->getError();
6144}
6145
6146extern "C"
6147void accDeleteScript(ACCscript* script) {
6148 delete script;
6149}
6150
6151extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006152void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6153 ACCvoid* pContext) {
6154 script->registerSymbolCallback(pFn, pContext);
6155}
6156
6157extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006158void accScriptSource(ACCscript* script,
6159 ACCsizei count,
6160 const ACCchar ** string,
6161 const ACCint * length) {
6162 int totalLength = 0;
6163 for(int i = 0; i < count; i++) {
6164 int len = -1;
6165 const ACCchar* s = string[i];
6166 if (length) {
6167 len = length[i];
6168 }
6169 if (len < 0) {
6170 len = strlen(s);
6171 }
6172 totalLength += len;
6173 }
6174 delete script->text;
6175 char* text = new char[totalLength + 1];
6176 script->text = text;
6177 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006178 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006179 for(int i = 0; i < count; i++) {
6180 int len = -1;
6181 const ACCchar* s = string[i];
6182 if (length) {
6183 len = length[i];
6184 }
6185 if (len < 0) {
6186 len = strlen(s);
6187 }
Jack Palevich09555c72009-05-27 12:25:55 -07006188 memcpy(dest, s, len);
6189 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006190 }
6191 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006192
6193#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006194 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006195 int counter;
6196 char path[PATH_MAX];
6197 for (counter = 0; counter < 4096; counter++) {
6198 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6199 if(access(path, F_OK) != 0) {
6200 break;
6201 }
6202 }
6203 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006204 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006205 FILE* fd = fopen(path, "w");
6206 if (fd) {
6207 fwrite(text, totalLength, 1, fd);
6208 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006209 LOGD("Saved input to file %s", path);
6210 } else {
6211 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006212 }
6213 }
6214#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006215}
6216
6217extern "C"
6218void accCompileScript(ACCscript* script) {
6219 int result = script->compiler.compile(script->text, script->textLength);
6220 if (result) {
6221 script->setError(ACC_INVALID_OPERATION);
6222 }
6223}
6224
6225extern "C"
6226void accGetScriptiv(ACCscript* script,
6227 ACCenum pname,
6228 ACCint * params) {
6229 switch (pname) {
6230 case ACC_INFO_LOG_LENGTH:
6231 *params = 0;
6232 break;
6233 }
6234}
6235
6236extern "C"
6237void accGetScriptInfoLog(ACCscript* script,
6238 ACCsizei maxLength,
6239 ACCsizei * length,
6240 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006241 char* message = script->compiler.getErrorMessage();
6242 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006243 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006244 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006245 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006246 if (infoLog && maxLength > 0) {
6247 int trimmedLength = maxLength < messageLength ?
6248 maxLength : messageLength;
6249 memcpy(infoLog, message, trimmedLength);
6250 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006251 }
6252}
6253
6254extern "C"
6255void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6256 ACCvoid ** address) {
6257 void* value = script->compiler.lookup(name);
6258 if (value) {
6259 *address = value;
6260 } else {
6261 script->setError(ACC_INVALID_VALUE);
6262 }
6263}
6264
Jack Palevicheedf9d22009-06-04 16:23:40 -07006265extern "C"
6266void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6267 ACCsizei maxStringCount, ACCchar** strings){
6268 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6269}
6270
-b master422972c2009-06-17 19:13:52 -07006271extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006272void accGetProgramBinary(ACCscript* script,
6273 ACCvoid** base, ACCsizei* length) {
6274 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006275}
6276
Jack Palevicheedf9d22009-06-04 16:23:40 -07006277
Jack Palevich1cdef202009-05-22 12:06:27 -07006278} // namespace acc
6279