blob: 6dccc5b639e2310a9502adf5ee4e7ddb8c0f2b96 [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
849 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
853 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;
879 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
880 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
881 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
882 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
883 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 &&
919 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
920 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
921 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
3899 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003900 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003901 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003902 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003903 int tokl; // token operator level
3904 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003905 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003906 intptr_t loc; // local variable index
3907 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003908 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003909 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003910 char* dptr; // Macro state: Points to macro text during macro playback.
3911 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003912 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003913 ACCSymbolLookupFn mpSymbolLookupFn;
3914 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003915
3916 // Arena for the duration of the compile
3917 Arena mGlobalArena;
3918 // Arena for data that's only needed when compiling a single function
3919 Arena mLocalArena;
3920
Jack Palevich2ff5c222009-07-23 15:11:22 -07003921 Arena* mpCurrentArena;
3922
Jack Palevich569f1352009-06-29 14:29:08 -07003923 TokenTable mTokenTable;
3924 SymbolStack mGlobals;
3925 SymbolStack mLocals;
3926
Jack Palevich9221bcc2009-08-26 16:15:07 -07003927 SymbolStack* mpCurrentSymbolStack;
3928
Jack Palevich40600de2009-07-01 15:32:35 -07003929 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003930 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003931 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003932 Type* mkpChar; // char
3933 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003934 Type* mkpFloat;
3935 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003936 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003937 Type* mkpIntPtr;
3938 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003939 Type* mkpFloatPtr;
3940 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003941 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003942
Jack Palevich36d94142009-06-08 15:55:32 -07003943 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003944 int mLineNumber;
3945 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003946
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003947 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003948 CodeGenerator* pGen;
3949
Jack Palevicheedf9d22009-06-04 16:23:40 -07003950 String mErrorBuf;
3951
Jack Palevicheedf9d22009-06-04 16:23:40 -07003952 String mPragmas;
3953 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003954 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003955
Jack Palevich21a15a22009-05-11 14:49:29 -07003956 static const int ALLOC_SIZE = 99999;
3957
Jack Palevich303d8ff2009-06-11 19:06:24 -07003958 static const int TOK_DUMMY = 1;
3959 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003960 static const int TOK_NUM_FLOAT = 3;
3961 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003962 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003963 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003964
3965 // 3..255 are character and/or operators
3966
Jack Palevich2db168f2009-06-11 14:29:47 -07003967 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003968 // Order has to match string list in "internKeywords".
3969 enum {
3970 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3971 TOK_INT = TOK_KEYWORD,
3972 TOK_CHAR,
3973 TOK_VOID,
3974 TOK_IF,
3975 TOK_ELSE,
3976 TOK_WHILE,
3977 TOK_BREAK,
3978 TOK_RETURN,
3979 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003980 TOK_AUTO,
3981 TOK_CASE,
3982 TOK_CONST,
3983 TOK_CONTINUE,
3984 TOK_DEFAULT,
3985 TOK_DO,
3986 TOK_DOUBLE,
3987 TOK_ENUM,
3988 TOK_EXTERN,
3989 TOK_FLOAT,
3990 TOK_GOTO,
3991 TOK_LONG,
3992 TOK_REGISTER,
3993 TOK_SHORT,
3994 TOK_SIGNED,
3995 TOK_SIZEOF,
3996 TOK_STATIC,
3997 TOK_STRUCT,
3998 TOK_SWITCH,
3999 TOK_TYPEDEF,
4000 TOK_UNION,
4001 TOK_UNSIGNED,
4002 TOK_VOLATILE,
4003 TOK__BOOL,
4004 TOK__COMPLEX,
4005 TOK__IMAGINARY,
4006 TOK_INLINE,
4007 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004008
4009 // Symbols start after keywords
4010
4011 TOK_SYMBOL,
4012 TOK_PRAGMA = TOK_SYMBOL,
4013 TOK_DEFINE,
4014 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004015 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004016
4017 static const int LOCAL = 0x200;
4018
4019 static const int SYM_FORWARD = 0;
4020 static const int SYM_DEFINE = 1;
4021
4022 /* tokens in string heap */
4023 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004024
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004025 static const int OP_INCREMENT = 0;
4026 static const int OP_DECREMENT = 1;
4027 static const int OP_MUL = 2;
4028 static const int OP_DIV = 3;
4029 static const int OP_MOD = 4;
4030 static const int OP_PLUS = 5;
4031 static const int OP_MINUS = 6;
4032 static const int OP_SHIFT_LEFT = 7;
4033 static const int OP_SHIFT_RIGHT = 8;
4034 static const int OP_LESS_EQUAL = 9;
4035 static const int OP_GREATER_EQUAL = 10;
4036 static const int OP_LESS = 11;
4037 static const int OP_GREATER = 12;
4038 static const int OP_EQUALS = 13;
4039 static const int OP_NOT_EQUALS = 14;
4040 static const int OP_LOGICAL_AND = 15;
4041 static const int OP_LOGICAL_OR = 16;
4042 static const int OP_BIT_AND = 17;
4043 static const int OP_BIT_XOR = 18;
4044 static const int OP_BIT_OR = 19;
4045 static const int OP_BIT_NOT = 20;
4046 static const int OP_LOGICAL_NOT = 21;
4047 static const int OP_COUNT = 22;
4048
4049 /* Operators are searched from front, the two-character operators appear
4050 * before the single-character operators with the same first character.
4051 * @ is used to pad out single-character operators.
4052 */
4053 static const char* operatorChars;
4054 static const char operatorLevel[];
4055
Jack Palevich569f1352009-06-29 14:29:08 -07004056 /* Called when we detect an internal problem. Does nothing in production.
4057 *
4058 */
4059 void internalError() {
4060 * (char*) 0 = 0;
4061 }
4062
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004063 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004064 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004065 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004066 internalError();
4067 }
Jack Palevich86351982009-06-30 18:09:56 -07004068 }
4069
Jack Palevich40600de2009-07-01 15:32:35 -07004070 bool isSymbol(tokenid_t t) {
4071 return t >= TOK_SYMBOL &&
4072 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4073 }
4074
4075 bool isSymbolOrKeyword(tokenid_t t) {
4076 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004077 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004078 }
4079
Jack Palevich86351982009-06-30 18:09:56 -07004080 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004081 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004082 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4083 if (pV && pV->tok != t) {
4084 internalError();
4085 }
4086 return pV;
4087 }
4088
4089 inline bool isDefined(tokenid_t t) {
4090 return t >= TOK_SYMBOL && VI(t) != 0;
4091 }
4092
Jack Palevich40600de2009-07-01 15:32:35 -07004093 const char* nameof(tokenid_t t) {
4094 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004095 return mTokenTable[t].pText;
4096 }
4097
Jack Palevich21a15a22009-05-11 14:49:29 -07004098 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004099 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004100 }
4101
4102 void inp() {
4103 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07004104 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004105 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004106 dptr = 0;
4107 ch = dch;
4108 }
Jack Palevichdc456462009-07-16 16:50:56 -07004109 } else {
4110 if (mbBumpLine) {
4111 mLineNumber++;
4112 mbBumpLine = false;
4113 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004114 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004115 if (ch == '\n') {
4116 mbBumpLine = true;
4117 }
4118 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004119#if 0
4120 printf("ch='%c' 0x%x\n", ch, ch);
4121#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004122 }
4123
4124 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004125 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004126 }
4127
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004128 int decodeHex(int c) {
4129 if (isdigit(c)) {
4130 c -= '0';
4131 } else if (c <= 'F') {
4132 c = c - 'A' + 10;
4133 } else {
4134 c =c - 'a' + 10;
4135 }
4136 return c;
4137 }
4138
Jack Palevichb4758ff2009-06-12 12:49:14 -07004139 /* read a character constant, advances ch to after end of constant */
4140 int getq() {
4141 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004142 if (ch == '\\') {
4143 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004144 if (isoctal(ch)) {
4145 // 1 to 3 octal characters.
4146 val = 0;
4147 for(int i = 0; i < 3; i++) {
4148 if (isoctal(ch)) {
4149 val = (val << 3) + ch - '0';
4150 inp();
4151 }
4152 }
4153 return val;
4154 } else if (ch == 'x' || ch == 'X') {
4155 // N hex chars
4156 inp();
4157 if (! isxdigit(ch)) {
4158 error("'x' character escape requires at least one digit.");
4159 } else {
4160 val = 0;
4161 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004162 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004163 inp();
4164 }
4165 }
4166 } else {
4167 int val = ch;
4168 switch (ch) {
4169 case 'a':
4170 val = '\a';
4171 break;
4172 case 'b':
4173 val = '\b';
4174 break;
4175 case 'f':
4176 val = '\f';
4177 break;
4178 case 'n':
4179 val = '\n';
4180 break;
4181 case 'r':
4182 val = '\r';
4183 break;
4184 case 't':
4185 val = '\t';
4186 break;
4187 case 'v':
4188 val = '\v';
4189 break;
4190 case '\\':
4191 val = '\\';
4192 break;
4193 case '\'':
4194 val = '\'';
4195 break;
4196 case '"':
4197 val = '"';
4198 break;
4199 case '?':
4200 val = '?';
4201 break;
4202 default:
4203 error("Undefined character escape %c", ch);
4204 break;
4205 }
4206 inp();
4207 return val;
4208 }
4209 } else {
4210 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004211 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004212 return val;
4213 }
4214
4215 static bool isoctal(int ch) {
4216 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004217 }
4218
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004219 bool acceptCh(int c) {
4220 bool result = c == ch;
4221 if (result) {
4222 pdef(ch);
4223 inp();
4224 }
4225 return result;
4226 }
4227
4228 bool acceptDigitsCh() {
4229 bool result = false;
4230 while (isdigit(ch)) {
4231 result = true;
4232 pdef(ch);
4233 inp();
4234 }
4235 return result;
4236 }
4237
4238 void parseFloat() {
4239 tok = TOK_NUM_DOUBLE;
4240 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004241 if(mTokenString.len() == 0) {
4242 mTokenString.append('0');
4243 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004244 acceptCh('.');
4245 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004246 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004247 acceptCh('-') || acceptCh('+');
4248 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004249 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004250 if (ch == 'f' || ch == 'F') {
4251 tok = TOK_NUM_FLOAT;
4252 inp();
4253 } else if (ch == 'l' || ch == 'L') {
4254 inp();
4255 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004256 }
4257 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004258 char* pEnd = pText + strlen(pText);
4259 char* pEndPtr = 0;
4260 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004261 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004262 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004263 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004264 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004265 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004266 if (errno || pEndPtr != pEnd) {
4267 error("Can't parse constant: %s", pText);
4268 }
4269 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004270 }
4271
Jack Palevich21a15a22009-05-11 14:49:29 -07004272 void next() {
4273 int l, a;
4274
Jack Palevich546b2242009-05-13 15:10:04 -07004275 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004276 if (ch == '#') {
4277 inp();
4278 next();
4279 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004280 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004281 } else if (tok == TOK_PRAGMA) {
4282 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004283 } else if (tok == TOK_LINE) {
4284 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004285 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004286 error("Unsupported preprocessor directive \"%s\"",
4287 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004288 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004289 }
4290 inp();
4291 }
4292 tokl = 0;
4293 tok = ch;
4294 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004295 if (isdigit(ch) || ch == '.') {
4296 // Start of a numeric constant. Could be integer, float, or
4297 // double, won't know until we look further.
4298 mTokenString.clear();
4299 pdef(ch);
4300 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004301 if (tok == '.' && !isdigit(ch)) {
4302 goto done;
4303 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004304 int base = 10;
4305 if (tok == '0') {
4306 if (ch == 'x' || ch == 'X') {
4307 base = 16;
4308 tok = TOK_NUM;
4309 tokc = 0;
4310 inp();
4311 while ( isxdigit(ch) ) {
4312 tokc = (tokc << 4) + decodeHex(ch);
4313 inp();
4314 }
4315 } else if (isoctal(ch)){
4316 base = 8;
4317 tok = TOK_NUM;
4318 tokc = 0;
4319 while ( isoctal(ch) ) {
4320 tokc = (tokc << 3) + (ch - '0');
4321 inp();
4322 }
4323 }
4324 } else if (isdigit(tok)){
4325 acceptDigitsCh();
4326 }
4327 if (base == 10) {
4328 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4329 parseFloat();
4330 } else {
4331 // It's an integer constant
4332 char* pText = mTokenString.getUnwrapped();
4333 char* pEnd = pText + strlen(pText);
4334 char* pEndPtr = 0;
4335 errno = 0;
4336 tokc = strtol(pText, &pEndPtr, base);
4337 if (errno || pEndPtr != pEnd) {
4338 error("Can't parse constant: %s %d %d", pText, base, errno);
4339 }
4340 tok = TOK_NUM;
4341 }
4342 }
4343 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004344 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004345 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004346 pdef(ch);
4347 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004348 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004349 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004350 if (! mbSuppressMacroExpansion) {
4351 // Is this a macro?
4352 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4353 if (pMacroDefinition) {
4354 // Yes, it is a macro
4355 dptr = pMacroDefinition;
4356 dch = ch;
4357 inp();
4358 next();
4359 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004360 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004361 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004362 inp();
4363 if (tok == '\'') {
4364 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004365 tokc = getq();
4366 if (ch != '\'') {
4367 error("Expected a ' character, got %c", ch);
4368 } else {
4369 inp();
4370 }
Jack Palevich546b2242009-05-13 15:10:04 -07004371 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004372 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004373 while (ch && ch != EOF) {
4374 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004375 inp();
4376 inp();
4377 if (ch == '/')
4378 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004379 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004380 if (ch == EOF) {
4381 error("End of file inside comment.");
4382 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004383 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004384 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004385 } else if ((tok == '/') & (ch == '/')) {
4386 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004387 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004388 inp();
4389 }
4390 inp();
4391 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004392 } else if ((tok == '-') & (ch == '>')) {
4393 inp();
4394 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004395 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004396 const char* t = operatorChars;
4397 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004398 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004399 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004400 tokl = operatorLevel[opIndex];
4401 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004402 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004403#if 0
4404 printf("%c%c -> tokl=%d tokc=0x%x\n",
4405 l, a, tokl, tokc);
4406#endif
4407 if (a == ch) {
4408 inp();
4409 tok = TOK_DUMMY; /* dummy token for double tokens */
4410 }
Jack Palevich0c017742009-07-31 12:00:39 -07004411 /* check for op=, valid for * / % + - << >> & ^ | */
4412 if (ch == '=' &&
4413 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004414 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004415 inp();
4416 tok = TOK_OP_ASSIGNMENT;
4417 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004418 break;
4419 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004420 opIndex++;
4421 }
4422 if (l == 0) {
4423 tokl = 0;
4424 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004425 }
4426 }
4427 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004428
4429 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004430#if 0
4431 {
Jack Palevich569f1352009-06-29 14:29:08 -07004432 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004433 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004434 fprintf(stderr, "%s\n", buf.getUnwrapped());
4435 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004436#endif
4437 }
4438
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004439 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004440 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004441 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004442 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004443 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004444 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004445 if (ch == '(') {
4446 delete pName;
4447 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004448 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004449 }
4450 while (isspace(ch)) {
4451 inp();
4452 }
Jack Palevich569f1352009-06-29 14:29:08 -07004453 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004454 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004455 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004456 // Check for '//' comments.
4457 if (appendToValue && ch == '/') {
4458 inp();
4459 if (ch == '/') {
4460 appendToValue = false;
4461 } else {
4462 value.append('/');
4463 }
4464 }
4465 if (appendToValue && ch != EOF) {
4466 value.append(ch);
4467 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004468 inp();
4469 }
Jack Palevich569f1352009-06-29 14:29:08 -07004470 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4471 memcpy(pDefn, value.getUnwrapped(), value.len());
4472 pDefn[value.len()] = 0;
4473 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004474 }
4475
Jack Palevicheedf9d22009-06-04 16:23:40 -07004476 void doPragma() {
4477 // # pragma name(val)
4478 int state = 0;
4479 while(ch != EOF && ch != '\n' && state < 10) {
4480 switch(state) {
4481 case 0:
4482 if (isspace(ch)) {
4483 inp();
4484 } else {
4485 state++;
4486 }
4487 break;
4488 case 1:
4489 if (isalnum(ch)) {
4490 mPragmas.append(ch);
4491 inp();
4492 } else if (ch == '(') {
4493 mPragmas.append(0);
4494 inp();
4495 state++;
4496 } else {
4497 state = 11;
4498 }
4499 break;
4500 case 2:
4501 if (isalnum(ch)) {
4502 mPragmas.append(ch);
4503 inp();
4504 } else if (ch == ')') {
4505 mPragmas.append(0);
4506 inp();
4507 state = 10;
4508 } else {
4509 state = 11;
4510 }
4511 break;
4512 }
4513 }
4514 if(state != 10) {
4515 error("Unexpected pragma syntax");
4516 }
4517 mPragmaStringCount += 2;
4518 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004519
Jack Palevichdc456462009-07-16 16:50:56 -07004520 void doLine() {
4521 // # line number { "filename "}
4522 next();
4523 if (tok != TOK_NUM) {
4524 error("Expected a line-number");
4525 } else {
4526 mLineNumber = tokc-1; // The end-of-line will increment it.
4527 }
4528 while(ch != EOF && ch != '\n') {
4529 inp();
4530 }
4531 }
4532
Jack Palevichac0e95e2009-05-29 13:53:44 -07004533 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004534 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004535 mErrorBuf.vprintf(fmt, ap);
4536 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004537 }
4538
Jack Palevich8b0624c2009-05-20 12:12:06 -07004539 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004540 if (tok != c) {
4541 error("'%c' expected", c);
4542 }
4543 next();
4544 }
4545
Jack Palevich86351982009-06-30 18:09:56 -07004546 bool accept(intptr_t c) {
4547 if (tok == c) {
4548 next();
4549 return true;
4550 }
4551 return false;
4552 }
4553
Jack Palevich40600de2009-07-01 15:32:35 -07004554 bool acceptStringLiteral() {
4555 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004556 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004557 // This while loop merges multiple adjacent string constants.
4558 while (tok == '"') {
4559 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004560 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004561 }
4562 if (ch != '"') {
4563 error("Unterminated string constant.");
4564 }
4565 inp();
4566 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004567 }
Jack Palevich40600de2009-07-01 15:32:35 -07004568 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004569 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004570 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004571 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004572
4573 return true;
4574 }
4575 return false;
4576 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004577
Jack Palevichb1544ca2009-07-16 15:09:20 -07004578 void linkGlobal(tokenid_t t, bool isFunction) {
4579 VariableInfo* pVI = VI(t);
4580 void* n = NULL;
4581 if (mpSymbolLookupFn) {
4582 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4583 }
4584 if (pVI->pType == NULL) {
4585 if (isFunction) {
4586 pVI->pType = mkpIntFn;
4587 } else {
4588 pVI->pType = mkpInt;
4589 }
4590 }
4591 pVI->pAddress = n;
4592 }
4593
Jack Palevich29daf572009-07-30 19:38:55 -07004594 void unaryOrAssignment() {
4595 unary();
4596 if (accept('=')) {
4597 checkLVal();
4598 pGen->pushR0();
4599 expr();
4600 pGen->forceR0RVal();
4601 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004602 } else if (tok == TOK_OP_ASSIGNMENT) {
4603 int t = tokc;
4604 next();
4605 checkLVal();
4606 pGen->pushR0();
4607 pGen->forceR0RVal();
4608 pGen->pushR0();
4609 expr();
4610 pGen->forceR0RVal();
4611 pGen->genOp(t);
4612 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004613 }
4614 }
4615
Jack Palevich40600de2009-07-01 15:32:35 -07004616 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004617 */
Jack Palevich29daf572009-07-30 19:38:55 -07004618 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004619 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004620 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004621 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004622 if (acceptStringLiteral()) {
4623 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004624 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004625 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004626 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004627 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004628 t = tok;
4629 next();
4630 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004631 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004632 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004633 // Align to 4-byte boundary
4634 glo = (char*) (((intptr_t) glo + 3) & -4);
4635 * (float*) glo = (float) ad;
4636 pGen->loadFloat((int) glo, mkpFloat);
4637 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004638 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004639 // Align to 8-byte boundary
4640 glo = (char*) (((intptr_t) glo + 7) & -8);
4641 * (double*) glo = ad;
4642 pGen->loadFloat((int) glo, mkpDouble);
4643 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004644 } else if (c == 2) {
4645 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004646 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004647 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004648 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004649 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004650 else if (t == '+') {
4651 // ignore unary plus.
4652 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004653 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004654 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004655 } else if (c == 11) {
4656 // pre increment / pre decrement
4657 unary();
4658 doIncDec(a == OP_INCREMENT, 0);
4659 }
4660 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004661 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004662 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004663 if (pCast) {
4664 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004665 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004666 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004667 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004668 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004669 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004670 skip(')');
4671 }
4672 } else if (t == '*') {
4673 /* This is a pointer dereference.
4674 */
Jack Palevich29daf572009-07-30 19:38:55 -07004675 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004676 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004677 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004678 unary();
4679 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004680 } else if (t == EOF ) {
4681 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004682 } else if (t == ';') {
4683 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004684 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004685 // Don't have to do anything special here, the error
4686 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004687 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004688 if (!isDefined(t)) {
4689 mGlobals.add(t);
4690 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004691 }
Jack Palevich8df46192009-07-07 14:48:51 -07004692 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004693 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004694 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004695 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004696 linkGlobal(t, tok == '(');
4697 n = (intptr_t) pVI->pAddress;
4698 if (!n && tok != '(') {
4699 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004700 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004701 }
Jack Palevich29daf572009-07-30 19:38:55 -07004702 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004703 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004704 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004705 linkGlobal(t, false);
4706 n = (intptr_t) pVI->pAddress;
4707 if (!n) {
4708 error("Undeclared variable %s\n", nameof(t));
4709 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004710 }
Jack Palevich5b659092009-07-31 14:55:07 -07004711 }
4712 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004713 Type* pVal;
4714 ExpressionType et;
4715 if (pVI->pType->tag == TY_ARRAY) {
4716 pVal = pVI->pType;
4717 et = ET_RVALUE;
4718 } else {
4719 pVal = createPtrType(pVI->pType);
4720 et = ET_LVALUE;
4721 }
Jack Palevich5b659092009-07-31 14:55:07 -07004722 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004723 int tag = pVal->pHead->tag;
4724 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004725 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004726 }
Jack Palevich5b659092009-07-31 14:55:07 -07004727 pGen->leaR0(n, pVal, et);
4728 } else {
4729 pVI->pForward = (void*) pGen->leaForward(
4730 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004731 }
4732 }
4733 }
4734
Jack Palevich5b659092009-07-31 14:55:07 -07004735 /* Now handle postfix operators */
4736 for(;;) {
4737 if (tokl == 11) {
4738 // post inc / post dec
4739 doIncDec(tokc == OP_INCREMENT, true);
4740 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004741 } else if (accept('[')) {
4742 // Array reference
4743 pGen->forceR0RVal();
4744 pGen->pushR0();
4745 commaExpr();
4746 pGen->forceR0RVal();
4747 pGen->genOp(OP_PLUS);
4748 doPointer();
4749 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004750 } else if (accept('.')) {
4751 // struct element
4752 pGen->forceR0RVal();
4753 Type* pStruct = pGen->getR0Type();
4754 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004755 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004756 } else {
4757 error("expected a struct value to the left of '.'");
4758 }
4759 } else if (accept(TOK_OP_ARROW)) {
4760 pGen->forceR0RVal();
4761 Type* pPtr = pGen->getR0Type();
4762 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4763 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004764 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004765 } else {
4766 error("Expected a pointer to a struct to the left of '->'");
4767 }
Jack Palevich5b659092009-07-31 14:55:07 -07004768 } else if (accept('(')) {
4769 /* function call */
4770 Type* pDecl = NULL;
4771 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004772 Type* pFn = pGen->getR0Type();
4773 assert(pFn->tag == TY_POINTER);
4774 assert(pFn->pHead->tag == TY_FUNC);
4775 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004776 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004777 Type* pArgList = pDecl->pTail;
4778 bool varArgs = pArgList == NULL;
4779 /* push args and invert order */
4780 a = pGen->beginFunctionCallArguments();
4781 int l = 0;
4782 int argCount = 0;
4783 while (tok != ')' && tok != EOF) {
4784 if (! varArgs && !pArgList) {
4785 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004786 }
Jack Palevich5b659092009-07-31 14:55:07 -07004787 expr();
4788 pGen->forceR0RVal();
4789 Type* pTargetType;
4790 if (pArgList) {
4791 pTargetType = pArgList->pHead;
4792 pArgList = pArgList->pTail;
4793 } else {
4794 // This is a ... function, just pass arguments in their
4795 // natural type.
4796 pTargetType = pGen->getR0Type();
4797 if (pTargetType->tag == TY_FLOAT) {
4798 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004799 } else if (pTargetType->tag == TY_ARRAY) {
4800 // Pass arrays by pointer.
4801 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004802 }
4803 }
4804 if (pTargetType->tag == TY_VOID) {
4805 error("Can't pass void value for argument %d",
4806 argCount + 1);
4807 } else {
4808 l += pGen->storeR0ToArg(l, pTargetType);
4809 }
4810 if (accept(',')) {
4811 // fine
4812 } else if ( tok != ')') {
4813 error("Expected ',' or ')'");
4814 }
4815 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004816 }
Jack Palevich5b659092009-07-31 14:55:07 -07004817 if (! varArgs && pArgList) {
4818 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004819 }
Jack Palevich5b659092009-07-31 14:55:07 -07004820 pGen->endFunctionCallArguments(pDecl, a, l);
4821 skip(')');
4822 pGen->callIndirect(l, pDecl);
4823 pGen->adjustStackAfterCall(pDecl, l, true);
4824 } else {
4825 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004826 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004827 }
4828 }
4829
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004830 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004831 Type* pStructElement = lookupStructMember(pStruct, tok);
4832 if (pStructElement) {
4833 next();
4834 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4835 } else {
4836 String buf;
4837 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004838 error("Expected a struct member to the right of '%s', got %s",
4839 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004840 }
4841 }
4842
Jack Palevichaaac9282009-07-31 14:34:34 -07004843 void doIncDec(int isInc, int isPost) {
4844 // R0 already has the lval
4845 checkLVal();
4846 int lit = isInc ? 1 : -1;
4847 pGen->pushR0();
4848 pGen->loadR0FromR0();
4849 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004850 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4851 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004852 error("++/-- illegal for this type. %d", tag);
4853 }
4854 if (isPost) {
4855 pGen->over();
4856 pGen->pushR0();
4857 pGen->li(lit);
4858 pGen->genOp(OP_PLUS);
4859 pGen->storeR0ToTOS();
4860 pGen->popR0();
4861 } else {
4862 pGen->pushR0();
4863 pGen->li(lit);
4864 pGen->genOp(OP_PLUS);
4865 pGen->over();
4866 pGen->storeR0ToTOS();
4867 pGen->popR0();
4868 }
4869 }
4870
Jack Palevich47cbea92009-07-31 15:25:53 -07004871 void doPointer() {
4872 pGen->forceR0RVal();
4873 Type* pR0Type = pGen->getR0Type();
4874 if (pR0Type->tag != TY_POINTER) {
4875 error("Expected a pointer type.");
4876 } else {
4877 if (pR0Type->pHead->tag != TY_FUNC) {
4878 pGen->setR0ExpressionType(ET_LVALUE);
4879 }
4880 }
4881 }
4882
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004883 void doAddressOf() {
4884 Type* pR0 = pGen->getR0Type();
4885 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4886 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4887 error("Expected an lvalue");
4888 }
4889 Type* pR0Type = pGen->getR0Type();
4890 pGen->setR0ExpressionType(ET_RVALUE);
4891 }
4892
Jack Palevich40600de2009-07-01 15:32:35 -07004893 /* Recursive descent parser for binary operations.
4894 */
4895 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004896 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004897 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004898 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004899 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004900 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004901 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004902 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004903 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004904 t = tokc;
4905 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004906 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004907 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004908 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004909 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004910 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004911 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004912 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004913 // Check for syntax error.
4914 if (pGen->getR0Type() == NULL) {
4915 // We failed to parse a right-hand argument.
4916 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004917 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004918 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004919 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004920 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004921 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004922 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004923 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004924 }
4925 }
4926 }
4927 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004928 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004929 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004930 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004931 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004932 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004933 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004934 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004935 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004936 }
4937 }
4938 }
4939
Jack Palevich43aaee32009-07-31 14:01:37 -07004940 void commaExpr() {
4941 for(;;) {
4942 expr();
4943 if (!accept(',')) {
4944 break;
4945 }
4946 }
4947 }
4948
Jack Palevich21a15a22009-05-11 14:49:29 -07004949 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004950 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004951 }
4952
4953 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004954 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004955 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004956 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004957 }
4958
Jack Palevicha6baa232009-06-12 11:25:59 -07004959 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004960 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004961
Jack Palevich95727a02009-07-06 12:07:15 -07004962 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004963 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004964 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004965 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004966 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004967 next();
4968 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004969 a = test_expr();
4970 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004971 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004972 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004973 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004974 n = pGen->gjmp(0); /* jmp */
4975 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004976 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004977 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004978 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004979 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004980 }
Jack Palevich546b2242009-05-13 15:10:04 -07004981 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004982 t = tok;
4983 next();
4984 skip('(');
4985 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004986 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004987 a = test_expr();
4988 } else {
4989 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004990 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004991 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004992 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07004993 a = 0;
4994 if (tok != ';')
4995 a = test_expr();
4996 skip(';');
4997 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004998 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004999 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005000 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005001 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005002 n = t + 4;
5003 }
5004 }
5005 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07005006 block((intptr_t) &a, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005007 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005008 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005009 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005010 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005011 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005012 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005013 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005014 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07005015 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005016 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005017 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005018 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005019 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005020 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005021 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005022 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005023 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005024 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005025 if (pReturnType->tag == TY_VOID) {
5026 error("Must not return a value from a void function");
5027 } else {
5028 pGen->convertR0(pReturnType);
5029 }
5030 } else {
5031 if (pReturnType->tag != TY_VOID) {
5032 error("Must specify a value here");
5033 }
Jack Palevich8df46192009-07-07 14:48:51 -07005034 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005035 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005036 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005037 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07005038 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005039 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005040 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005041 }
5042 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005043
Jack Palevicha8f427f2009-07-13 18:40:08 -07005044 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005045 if (a == b) {
5046 return true;
5047 }
5048 if (a == NULL || b == NULL) {
5049 return false;
5050 }
5051 TypeTag at = a->tag;
5052 if (at != b->tag) {
5053 return false;
5054 }
5055 if (at == TY_POINTER) {
5056 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005057 } else if (at == TY_ARRAY) {
5058 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005059 } else if (at == TY_FUNC || at == TY_PARAM) {
5060 return typeEqual(a->pHead, b->pHead)
5061 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005062 } else if (at == TY_STRUCT) {
5063 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005064 }
5065 return true;
5066 }
5067
Jack Palevich2ff5c222009-07-23 15:11:22 -07005068 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07005069 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005070 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005071 memset(pType, 0, sizeof(*pType));
5072 pType->tag = tag;
5073 pType->pHead = pHead;
5074 pType->pTail = pTail;
5075 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005076 }
5077
Jack Palevich2ff5c222009-07-23 15:11:22 -07005078 Type* createPtrType(Type* pType) {
5079 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005080 }
5081
5082 /**
5083 * Try to print a type in declaration order
5084 */
Jack Palevich86351982009-06-30 18:09:56 -07005085 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005086 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005087 if (pType == NULL) {
5088 buffer.appendCStr("null");
5089 return;
5090 }
Jack Palevich3f226492009-07-02 14:46:19 -07005091 decodeTypeImp(buffer, pType);
5092 }
5093
5094 void decodeTypeImp(String& buffer, Type* pType) {
5095 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005096 decodeId(buffer, pType->id);
5097 decodeTypeImpPostfix(buffer, pType);
5098 }
Jack Palevich3f226492009-07-02 14:46:19 -07005099
Jack Palevich9221bcc2009-08-26 16:15:07 -07005100 void decodeId(String& buffer, tokenid_t id) {
5101 if (id) {
5102 String temp;
5103 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005104 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005105 }
Jack Palevich3f226492009-07-02 14:46:19 -07005106 }
5107
5108 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5109 TypeTag tag = pType->tag;
5110
Jack Palevich9221bcc2009-08-26 16:15:07 -07005111 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005112 switch (tag) {
5113 case TY_INT:
5114 buffer.appendCStr("int");
5115 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005116 case TY_SHORT:
5117 buffer.appendCStr("short");
5118 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005119 case TY_CHAR:
5120 buffer.appendCStr("char");
5121 break;
5122 case TY_VOID:
5123 buffer.appendCStr("void");
5124 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005125 case TY_FLOAT:
5126 buffer.appendCStr("float");
5127 break;
5128 case TY_DOUBLE:
5129 buffer.appendCStr("double");
5130 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005131 case TY_STRUCT:
5132 {
5133 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5134 buffer.appendCStr(isStruct ? "struct" : "union");
5135 if (pType->pHead && pType->pHead->structTag) {
5136 buffer.append(' ');
5137 decodeId(buffer, pType->pHead->structTag);
5138 }
5139 }
5140 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005141 default:
5142 break;
5143 }
Jack Palevich86351982009-06-30 18:09:56 -07005144 buffer.append(' ');
5145 }
Jack Palevich3f226492009-07-02 14:46:19 -07005146
5147 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005148 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005149 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005150 case TY_SHORT:
5151 break;
Jack Palevich86351982009-06-30 18:09:56 -07005152 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005153 break;
5154 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005155 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005156 case TY_FLOAT:
5157 break;
5158 case TY_DOUBLE:
5159 break;
Jack Palevich86351982009-06-30 18:09:56 -07005160 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005161 decodeTypeImpPrefix(buffer, pType->pHead);
5162 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5163 buffer.append('(');
5164 }
5165 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005166 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005167 case TY_ARRAY:
5168 decodeTypeImpPrefix(buffer, pType->pHead);
5169 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005170 case TY_STRUCT:
5171 break;
Jack Palevich86351982009-06-30 18:09:56 -07005172 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005173 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005174 break;
5175 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005176 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005177 break;
5178 default:
5179 String temp;
5180 temp.printf("Unknown tag %d", pType->tag);
5181 buffer.append(temp);
5182 break;
5183 }
Jack Palevich3f226492009-07-02 14:46:19 -07005184 }
5185
5186 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5187 TypeTag tag = pType->tag;
5188
5189 switch(tag) {
5190 case TY_POINTER:
5191 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5192 buffer.append(')');
5193 }
5194 decodeTypeImpPostfix(buffer, pType->pHead);
5195 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005196 case TY_ARRAY:
5197 {
5198 String temp;
5199 temp.printf("[%d]", pType->length);
5200 buffer.append(temp);
5201 }
5202 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005203 case TY_STRUCT:
5204 if (pType->pHead->length >= 0) {
5205 buffer.appendCStr(" {");
5206 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5207 decodeTypeImp(buffer, pArg->pHead);
5208 buffer.appendCStr(";");
5209 }
5210 buffer.append('}');
5211 }
5212 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005213 case TY_FUNC:
5214 buffer.append('(');
5215 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5216 decodeTypeImp(buffer, pArg);
5217 if (pArg->pTail) {
5218 buffer.appendCStr(", ");
5219 }
5220 }
5221 buffer.append(')');
5222 break;
5223 default:
5224 break;
Jack Palevich86351982009-06-30 18:09:56 -07005225 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005226 }
5227
Jack Palevich86351982009-06-30 18:09:56 -07005228 void printType(Type* pType) {
5229 String buffer;
5230 decodeType(buffer, pType);
5231 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005232 }
5233
Jack Palevich2ff5c222009-07-23 15:11:22 -07005234 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005235 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005236 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005237 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005238 } else if (tok == TOK_SHORT) {
5239 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005240 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005241 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005242 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005243 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005244 } else if (tok == TOK_FLOAT) {
5245 pType = mkpFloat;
5246 } else if (tok == TOK_DOUBLE) {
5247 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005248 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5249 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005250 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005251 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005252 }
5253 next();
Jack Palevich86351982009-06-30 18:09:56 -07005254 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005255 }
5256
Jack Palevich9221bcc2009-08-26 16:15:07 -07005257 Type* acceptStruct() {
5258 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5259 bool isStruct = tok == TOK_STRUCT;
5260 next();
5261 tokenid_t structTag = acceptSymbol();
5262 bool isDeclaration = accept('{');
5263 bool fail = false;
5264
5265 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5266 if (structTag) {
5267 Token* pToken = &mTokenTable[structTag];
5268 VariableInfo* pStructInfo = pToken->mpStructInfo;
5269 bool needToDeclare = !pStructInfo;
5270 if (pStructInfo) {
5271 if (isDeclaration) {
5272 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5273 if (pStructInfo->pType->pHead->length == -1) {
5274 // we're filling in a forward declaration.
5275 needToDeclare = false;
5276 } else {
5277 error("A struct with the same name is already defined at this level.");
5278 fail = true;
5279 }
5280 } else {
5281 needToDeclare = true;
5282 }
5283 }
5284 if (!fail) {
5285 assert(pStructInfo->isStructTag);
5286 pStructType->pHead = pStructInfo->pType;
5287 pStructType->pTail = pStructType->pHead->pTail;
5288 }
5289 }
5290
5291 if (needToDeclare) {
5292 // This is a new struct name
5293 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5294 pStructType = createType(TY_STRUCT, NULL, NULL);
5295 pStructType->structTag = structTag;
5296 pStructType->pHead = pStructType;
5297 if (! isDeclaration) {
5298 // A forward declaration
5299 pStructType->length = -1;
5300 }
5301 pToken->mpStructInfo->pType = pStructType;
5302 }
5303 } else {
5304 // An anonymous struct
5305 pStructType->pHead = pStructType;
5306 }
5307
5308 if (isDeclaration) {
5309 size_t offset = 0;
5310 size_t structSize = 0;
5311 size_t structAlignment = 0;
5312 Type** pParamHolder = & pStructType->pHead->pTail;
5313 while (tok != '}' && tok != EOF) {
5314 Type* pPrimitiveType = expectPrimitiveType();
5315 if (pPrimitiveType) {
5316 while (tok != ';' && tok != EOF) {
5317 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5318 if (!pItem) {
5319 break;
5320 }
5321 if (lookupStructMember(pStructType, pItem->id)) {
5322 String buf;
5323 decodeToken(buf, pItem->id, false);
5324 error("Duplicate struct member %s", buf.getUnwrapped());
5325 }
5326 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5327 size_t alignment = pGen->alignmentOf(pItem);
5328 if (alignment > structAlignment) {
5329 structAlignment = alignment;
5330 }
5331 size_t alignmentMask = alignment - 1;
5332 offset = (offset + alignmentMask) & ~alignmentMask;
5333 pStructElement->length = offset;
5334 size_t size = pGen->sizeOf(pItem);
5335 if (isStruct) {
5336 offset += size;
5337 structSize = offset;
5338 } else {
5339 if (size >= structSize) {
5340 structSize = size;
5341 }
5342 }
5343 *pParamHolder = pStructElement;
5344 pParamHolder = &pStructElement->pTail;
5345 accept(',');
5346 }
5347 skip(';');
5348 } else {
5349 // Some sort of syntax error, skip token and keep trying
5350 next();
5351 }
5352 }
5353 if (!fail) {
5354 pStructType->pHead->length = structSize;
5355 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5356 }
5357 skip('}');
5358 }
5359 if (fail) {
5360 pStructType = NULL;
5361 }
5362 return pStructType;
5363 }
5364
5365 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5366 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5367 if (pStructElement->pHead->id == memberId) {
5368 return pStructElement;
5369 }
5370 }
5371 return NULL;
5372 }
5373
Jack Palevich2ff5c222009-07-23 15:11:22 -07005374 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005375 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005376 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005377 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005378 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005379 if (declName) {
5380 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005381 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005382 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005383 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005384 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005385 } else if (nameRequired) {
5386 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005387 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005388#if 0
5389 fprintf(stderr, "Parsed a declaration: ");
5390 printType(pType);
5391#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005392 if (reportFailure) {
5393 return NULL;
5394 }
Jack Palevich86351982009-06-30 18:09:56 -07005395 return pType;
5396 }
5397
Jack Palevich2ff5c222009-07-23 15:11:22 -07005398 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005399 bool nameRequired = pBaseType->tag != TY_STRUCT;
5400 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005401 if (! pType) {
5402 error("Expected a declaration");
5403 }
5404 return pType;
5405 }
5406
Jack Palevich3f226492009-07-02 14:46:19 -07005407 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005408 Type* acceptCastTypeDeclaration() {
5409 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005410 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005411 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005412 }
Jack Palevich86351982009-06-30 18:09:56 -07005413 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005414 }
5415
Jack Palevich2ff5c222009-07-23 15:11:22 -07005416 Type* expectCastTypeDeclaration() {
5417 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005418 if (! pType) {
5419 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005420 }
Jack Palevich3f226492009-07-02 14:46:19 -07005421 return pType;
5422 }
5423
5424 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005425 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005426 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005427 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005428 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005429 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005430 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005431 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005432 return pType;
5433 }
5434
5435 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005436 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005437 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005438 // direct-dcl :
5439 // name
5440 // (dcl)
5441 // direct-dcl()
5442 // direct-dcl[]
5443 Type* pNewHead = NULL;
5444 if (accept('(')) {
5445 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005446 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005447 skip(')');
5448 } else if ((declName = acceptSymbol()) != 0) {
5449 if (nameAllowed == false && declName) {
5450 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005451 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005452 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005453 } else if (nameRequired && ! declName) {
5454 String temp;
5455 decodeToken(temp, tok, true);
5456 error("Expected name. Got %s", temp.getUnwrapped());
5457 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005458 }
Jack Palevichb6154502009-08-04 14:56:09 -07005459 for(;;) {
5460 if (accept('(')) {
5461 // Function declaration
5462 Type* pTail = acceptArgs(nameAllowed);
5463 pType = createType(TY_FUNC, pType, pTail);
5464 skip(')');
5465 } if (accept('[')) {
5466 if (tok != ']') {
5467 if (tok != TOK_NUM || tokc <= 0) {
5468 error("Expected positive integer constant");
5469 } else {
5470 Type* pDecayType = createPtrType(pType);
5471 pType = createType(TY_ARRAY, pType, pDecayType);
5472 pType->length = tokc;
5473 }
5474 next();
5475 }
5476 skip(']');
5477 } else {
5478 break;
5479 }
Jack Palevich86351982009-06-30 18:09:56 -07005480 }
Jack Palevich3f226492009-07-02 14:46:19 -07005481
5482 if (pNewHead) {
5483 Type* pA = pNewHead;
5484 while (pA->pHead) {
5485 pA = pA->pHead;
5486 }
5487 pA->pHead = pType;
5488 pType = pNewHead;
5489 }
Jack Palevich86351982009-06-30 18:09:56 -07005490 return pType;
5491 }
5492
Jack Palevich2ff5c222009-07-23 15:11:22 -07005493 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005494 Type* pHead = NULL;
5495 Type* pTail = NULL;
5496 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005497 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005498 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005499 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005500 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005501 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005502 if (!pHead) {
5503 pHead = pParam;
5504 pTail = pParam;
5505 } else {
5506 pTail->pTail = pParam;
5507 pTail = pParam;
5508 }
5509 }
5510 }
5511 if (! accept(',')) {
5512 break;
5513 }
5514 }
5515 return pHead;
5516 }
5517
Jack Palevich2ff5c222009-07-23 15:11:22 -07005518 Type* expectPrimitiveType() {
5519 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005520 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005521 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005522 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005523 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005524 }
Jack Palevich86351982009-06-30 18:09:56 -07005525 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005526 }
5527
Jack Palevichb5e33312009-07-30 19:06:34 -07005528 void checkLVal() {
5529 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005530 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005531 }
5532 }
5533
Jack Palevich86351982009-06-30 18:09:56 -07005534 void addGlobalSymbol(Type* pDecl) {
5535 tokenid_t t = pDecl->id;
5536 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005537 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005538 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005539 }
Jack Palevich86351982009-06-30 18:09:56 -07005540 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005541 }
5542
Jack Palevich86351982009-06-30 18:09:56 -07005543 void reportDuplicate(tokenid_t t) {
5544 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005545 }
5546
Jack Palevich86351982009-06-30 18:09:56 -07005547 void addLocalSymbol(Type* pDecl) {
5548 tokenid_t t = pDecl->id;
5549 if (mLocals.isDefinedAtCurrentLevel(t)) {
5550 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005551 }
Jack Palevich86351982009-06-30 18:09:56 -07005552 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005553 }
5554
Jack Palevich61de31f2009-09-08 11:06:40 -07005555 bool checkUndeclaredStruct(Type* pBaseType) {
5556 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5557 String temp;
5558 decodeToken(temp, pBaseType->structTag, false);
5559 error("Undeclared struct %s", temp.getUnwrapped());
5560 return true;
5561 }
5562 return false;
5563 }
5564
Jack Palevich95727a02009-07-06 12:07:15 -07005565 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005566 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005567
Jack Palevich95727a02009-07-06 12:07:15 -07005568 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005569 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005570 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005571 if (!pDecl) {
5572 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005573 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005574 if (!pDecl->id) {
5575 break;
5576 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005577 if (checkUndeclaredStruct(pDecl)) {
5578 break;
5579 }
Jack Palevich86351982009-06-30 18:09:56 -07005580 int variableAddress = 0;
5581 addLocalSymbol(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005582 size_t alignment = pGen->alignmentOf(pDecl);
5583 assert(alignment > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005584 size_t alignmentMask = ~ (alignment - 1);
5585 size_t sizeOf = pGen->sizeOf(pDecl);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005586 assert(sizeOf > 0);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07005587 loc = (loc + alignment - 1) & alignmentMask;
5588 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5589 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07005590 variableAddress = -loc;
5591 VI(pDecl->id)->pAddress = (void*) variableAddress;
5592 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005593 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07005594 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07005595 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07005596 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005597 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07005598 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07005599 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005600 if (tok == ',')
5601 next();
5602 }
5603 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005604 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005605 }
5606 }
5607
Jack Palevichf1728be2009-06-12 13:53:51 -07005608 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005609 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005610 }
5611
Jack Palevich37c54bd2009-07-14 18:35:36 -07005612 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005613 if (token == EOF ) {
5614 buffer.printf("EOF");
5615 } else if (token == TOK_NUM) {
5616 buffer.printf("numeric constant");
5617 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005618 if (token < 32) {
5619 buffer.printf("'\\x%02x'", token);
5620 } else {
5621 buffer.printf("'%c'", token);
5622 }
Jack Palevich569f1352009-06-29 14:29:08 -07005623 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005624 if (quote) {
5625 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5626 buffer.printf("keyword \"%s\"", nameof(token));
5627 } else {
5628 buffer.printf("symbol \"%s\"", nameof(token));
5629 }
5630 } else {
5631 buffer.printf("%s", nameof(token));
5632 }
Jack Palevich569f1352009-06-29 14:29:08 -07005633 }
5634 }
5635
Jack Palevich9221bcc2009-08-26 16:15:07 -07005636 void printToken(tokenid_t token) {
5637 String buffer;
5638 decodeToken(buffer, token, true);
5639 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5640 }
5641
Jack Palevich40600de2009-07-01 15:32:35 -07005642 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005643 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005644 if (!result) {
5645 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005646 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005647 error("Expected symbol. Got %s", temp.getUnwrapped());
5648 }
5649 return result;
5650 }
5651
Jack Palevich86351982009-06-30 18:09:56 -07005652 tokenid_t acceptSymbol() {
5653 tokenid_t result = 0;
5654 if (tok >= TOK_SYMBOL) {
5655 result = tok;
5656 next();
Jack Palevich86351982009-06-30 18:09:56 -07005657 }
5658 return result;
5659 }
5660
Jack Palevichb7c81e92009-06-04 19:56:13 -07005661 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005662 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005663 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005664 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005665 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005666 break;
5667 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005668 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005669 if (!pDecl) {
5670 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005671 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005672 if (!pDecl->id) {
5673 skip(';');
5674 continue;
5675 }
5676
Jack Palevich61de31f2009-09-08 11:06:40 -07005677 if (checkUndeclaredStruct(pDecl)) {
5678 skip(';');
5679 continue;
5680 }
5681
Jack Palevich86351982009-06-30 18:09:56 -07005682 if (! isDefined(pDecl->id)) {
5683 addGlobalSymbol(pDecl);
5684 }
5685 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005686 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005687 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005688 }
Jack Palevich86351982009-06-30 18:09:56 -07005689 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005690 // it's a variable declaration
5691 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005692 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005693 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005694 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005695 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005696 }
Jack Palevich86351982009-06-30 18:09:56 -07005697 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005698 if (tok == TOK_NUM) {
5699 if (name) {
5700 * (int*) name->pAddress = tokc;
5701 }
5702 next();
5703 } else {
5704 error("Expected an integer constant");
5705 }
5706 }
Jack Palevich86351982009-06-30 18:09:56 -07005707 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005708 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005709 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005710 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005711 if (!pDecl) {
5712 break;
5713 }
5714 if (! isDefined(pDecl->id)) {
5715 addGlobalSymbol(pDecl);
5716 }
5717 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005718 }
5719 skip(';');
5720 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005721 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005722 if (accept(';')) {
5723 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005724 } else if (tok != '{') {
5725 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005726 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005727 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005728 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005729 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005730 /* patch forward references */
5731 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005732 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005733 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005734 }
5735 // Calculate stack offsets for parameters
5736 mLocals.pushLevel();
5737 intptr_t a = 8;
5738 int argCount = 0;
5739 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5740 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005741 if (pArg->id) {
5742 addLocalSymbol(pArg);
5743 }
Jack Palevich95727a02009-07-06 12:07:15 -07005744 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005745 Type* pPassingType = passingType(pArg);
5746 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005747 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005748 if (pArg->id) {
5749 VI(pArg->id)->pAddress = (void*) a;
5750 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005751 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005752 argCount++;
5753 }
5754 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005755 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005756 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005757 block(0, true);
5758 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005759 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005760 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005761 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005762 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005763 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005764 }
5765 }
5766 }
5767
Jack Palevich9221bcc2009-08-26 16:15:07 -07005768 Type* passingType(Type* pType) {
5769 switch (pType->tag) {
5770 case TY_CHAR:
5771 case TY_SHORT:
5772 return mkpInt;
5773 default:
5774 return pType;
5775 }
5776 }
5777
Jack Palevich9cbd2262009-07-08 16:48:41 -07005778 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5779 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5780 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005781 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005782 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005783 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005784 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005785 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005786 char* result = (char*) base;
5787 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005788 return result;
5789 }
5790
Jack Palevich21a15a22009-05-11 14:49:29 -07005791 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005792 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005793 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005794 pGlobalBase = 0;
5795 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005796 if (pGen) {
5797 delete pGen;
5798 pGen = 0;
5799 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005800 if (pCodeBuf) {
5801 delete pCodeBuf;
5802 pCodeBuf = 0;
5803 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005804 if (file) {
5805 delete file;
5806 file = 0;
5807 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005808 }
5809
Jack Palevich8c246a92009-07-14 21:14:10 -07005810 // One-time initialization, when class is constructed.
5811 void init() {
5812 mpSymbolLookupFn = 0;
5813 mpSymbolLookupContext = 0;
5814 }
5815
Jack Palevich21a15a22009-05-11 14:49:29 -07005816 void clear() {
5817 tok = 0;
5818 tokc = 0;
5819 tokl = 0;
5820 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005821 rsym = 0;
5822 loc = 0;
5823 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005824 dptr = 0;
5825 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005826 file = 0;
5827 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005828 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005829 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005830 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005831 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005832 mLineNumber = 1;
5833 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005834 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005835 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005836
Jack Palevich22305132009-05-13 10:58:45 -07005837 void setArchitecture(const char* architecture) {
5838 delete pGen;
5839 pGen = 0;
5840
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005841 delete pCodeBuf;
5842 pCodeBuf = new CodeBuf();
5843
Jack Palevich22305132009-05-13 10:58:45 -07005844 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005845#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005846 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005847 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005848 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07005849 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005850#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005851#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005852 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005853 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005854 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005855#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005856 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005857 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005858 }
5859 }
5860
5861 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005862#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005863 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005864 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07005865#elif defined(DEFAULT_X86_CODEGEN)
5866 pGen = new X86CodeGenerator();
5867#endif
5868 }
5869 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005870 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005871 } else {
5872 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005873 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005874 }
5875 }
5876
Jack Palevich77ae76e2009-05-10 19:59:24 -07005877public:
Jack Palevich22305132009-05-13 10:58:45 -07005878 struct args {
5879 args() {
5880 architecture = 0;
5881 }
5882 const char* architecture;
5883 };
5884
Jack Paleviche7b59062009-05-19 17:12:17 -07005885 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005886 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005887 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005888 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005889
Jack Paleviche7b59062009-05-19 17:12:17 -07005890 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005891 cleanup();
5892 }
5893
Jack Palevich8c246a92009-07-14 21:14:10 -07005894 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5895 mpSymbolLookupFn = pFn;
5896 mpSymbolLookupContext = pContext;
5897 }
5898
Jack Palevich1cdef202009-05-22 12:06:27 -07005899 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005900 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005901
Jack Palevich2ff5c222009-07-23 15:11:22 -07005902 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005903 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005904 cleanup();
5905 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005906 mTokenTable.setArena(&mGlobalArena);
5907 mGlobals.setArena(&mGlobalArena);
5908 mGlobals.setTokenTable(&mTokenTable);
5909 mLocals.setArena(&mLocalArena);
5910 mLocals.setTokenTable(&mTokenTable);
5911
5912 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005913 setArchitecture(NULL);
5914 if (!pGen) {
5915 return -1;
5916 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005917#ifdef PROVIDE_TRACE_CODEGEN
5918 pGen = new TraceCodeGenerator(pGen);
5919#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005920 pGen->setErrorSink(this);
5921
5922 if (pCodeBuf) {
5923 pCodeBuf->init(ALLOC_SIZE);
5924 }
5925 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07005926 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005927 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5928 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005929 inp();
5930 next();
5931 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005932 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005933 result = pGen->finishCompile();
5934 if (result == 0) {
5935 if (mErrorBuf.len()) {
5936 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005937 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005938 }
Jack Palevichce105a92009-07-16 14:30:33 -07005939 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005940 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005941 }
5942
Jack Palevich86351982009-06-30 18:09:56 -07005943 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005944 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005945 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005946 mkpChar = createType(TY_CHAR, NULL, NULL);
5947 mkpVoid = createType(TY_VOID, NULL, NULL);
5948 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5949 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5950 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5951 mkpIntPtr = createPtrType(mkpInt);
5952 mkpCharPtr = createPtrType(mkpChar);
5953 mkpFloatPtr = createPtrType(mkpFloat);
5954 mkpDoublePtr = createPtrType(mkpDouble);
5955 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005956 }
5957
Jack Palevicha6baa232009-06-12 11:25:59 -07005958 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005959 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005960 }
5961
Jack Palevich569f1352009-06-29 14:29:08 -07005962 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005963 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005964 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005965 }
5966
Jack Palevich569f1352009-06-29 14:29:08 -07005967 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005968 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005969 error("Undefined forward reference: %s",
5970 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005971 }
5972 return true;
5973 }
5974
Jack Palevich1cdef202009-05-22 12:06:27 -07005975 /* Look through the symbol table to find a symbol.
5976 * If found, return its value.
5977 */
5978 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005979 if (mCompileResult == 0) {
5980 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5981 VariableInfo* pVariableInfo = VI(tok);
5982 if (pVariableInfo) {
5983 return pVariableInfo->pAddress;
5984 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005985 }
5986 return NULL;
5987 }
5988
Jack Palevicheedf9d22009-06-04 16:23:40 -07005989 void getPragmas(ACCsizei* actualStringCount,
5990 ACCsizei maxStringCount, ACCchar** strings) {
5991 int stringCount = mPragmaStringCount;
5992 if (actualStringCount) {
5993 *actualStringCount = stringCount;
5994 }
5995 if (stringCount > maxStringCount) {
5996 stringCount = maxStringCount;
5997 }
5998 if (strings) {
5999 char* pPragmas = mPragmas.getUnwrapped();
6000 while (stringCount-- > 0) {
6001 *strings++ = pPragmas;
6002 pPragmas += strlen(pPragmas) + 1;
6003 }
6004 }
6005 }
6006
Jack Palevichd5315572009-09-09 13:19:34 -07006007 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006008 *base = pCodeBuf->getBase();
6009 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006010 }
6011
Jack Palevichac0e95e2009-05-29 13:53:44 -07006012 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006013 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006014 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006015};
6016
Jack Paleviche7b59062009-05-19 17:12:17 -07006017const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006018 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6019
Jack Paleviche7b59062009-05-19 17:12:17 -07006020const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006021 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6022 5, 5, /* ==, != */
6023 9, 10, /* &&, || */
6024 6, 7, 8, /* & ^ | */
6025 2, 2 /* ~ ! */
6026 };
6027
Jack Palevich8b0624c2009-05-20 12:12:06 -07006028#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006029const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006030 0x1, // ++
6031 0xff, // --
6032 0xc1af0f, // *
6033 0xf9f79991, // /
6034 0xf9f79991, // % (With manual assist to swap results)
6035 0xc801, // +
6036 0xd8f7c829, // -
6037 0xe0d391, // <<
6038 0xf8d391, // >>
6039 0xe, // <=
6040 0xd, // >=
6041 0xc, // <
6042 0xf, // >
6043 0x4, // ==
6044 0x5, // !=
6045 0x0, // &&
6046 0x1, // ||
6047 0xc821, // &
6048 0xc831, // ^
6049 0xc809, // |
6050 0xd0f7, // ~
6051 0x4 // !
6052};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006053#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006054
Jack Palevich1cdef202009-05-22 12:06:27 -07006055struct ACCscript {
6056 ACCscript() {
6057 text = 0;
6058 textLength = 0;
6059 accError = ACC_NO_ERROR;
6060 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006061
Jack Palevich1cdef202009-05-22 12:06:27 -07006062 ~ACCscript() {
6063 delete text;
6064 }
Jack Palevich546b2242009-05-13 15:10:04 -07006065
Jack Palevich8c246a92009-07-14 21:14:10 -07006066 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6067 compiler.registerSymbolCallback(pFn, pContext);
6068 }
6069
Jack Palevich1cdef202009-05-22 12:06:27 -07006070 void setError(ACCenum error) {
6071 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6072 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006073 }
6074 }
6075
Jack Palevich1cdef202009-05-22 12:06:27 -07006076 ACCenum getError() {
6077 ACCenum result = accError;
6078 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006079 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006080 }
6081
Jack Palevich1cdef202009-05-22 12:06:27 -07006082 Compiler compiler;
6083 char* text;
6084 int textLength;
6085 ACCenum accError;
6086};
6087
6088
6089extern "C"
6090ACCscript* accCreateScript() {
6091 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006092}
Jack Palevich1cdef202009-05-22 12:06:27 -07006093
6094extern "C"
6095ACCenum accGetError( ACCscript* script ) {
6096 return script->getError();
6097}
6098
6099extern "C"
6100void accDeleteScript(ACCscript* script) {
6101 delete script;
6102}
6103
6104extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006105void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6106 ACCvoid* pContext) {
6107 script->registerSymbolCallback(pFn, pContext);
6108}
6109
6110extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006111void accScriptSource(ACCscript* script,
6112 ACCsizei count,
6113 const ACCchar ** string,
6114 const ACCint * length) {
6115 int totalLength = 0;
6116 for(int i = 0; i < count; i++) {
6117 int len = -1;
6118 const ACCchar* s = string[i];
6119 if (length) {
6120 len = length[i];
6121 }
6122 if (len < 0) {
6123 len = strlen(s);
6124 }
6125 totalLength += len;
6126 }
6127 delete script->text;
6128 char* text = new char[totalLength + 1];
6129 script->text = text;
6130 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006131 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006132 for(int i = 0; i < count; i++) {
6133 int len = -1;
6134 const ACCchar* s = string[i];
6135 if (length) {
6136 len = length[i];
6137 }
6138 if (len < 0) {
6139 len = strlen(s);
6140 }
Jack Palevich09555c72009-05-27 12:25:55 -07006141 memcpy(dest, s, len);
6142 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006143 }
6144 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006145
6146#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006147 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006148 int counter;
6149 char path[PATH_MAX];
6150 for (counter = 0; counter < 4096; counter++) {
6151 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6152 if(access(path, F_OK) != 0) {
6153 break;
6154 }
6155 }
6156 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006157 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006158 FILE* fd = fopen(path, "w");
6159 if (fd) {
6160 fwrite(text, totalLength, 1, fd);
6161 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006162 LOGD("Saved input to file %s", path);
6163 } else {
6164 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006165 }
6166 }
6167#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006168}
6169
6170extern "C"
6171void accCompileScript(ACCscript* script) {
6172 int result = script->compiler.compile(script->text, script->textLength);
6173 if (result) {
6174 script->setError(ACC_INVALID_OPERATION);
6175 }
6176}
6177
6178extern "C"
6179void accGetScriptiv(ACCscript* script,
6180 ACCenum pname,
6181 ACCint * params) {
6182 switch (pname) {
6183 case ACC_INFO_LOG_LENGTH:
6184 *params = 0;
6185 break;
6186 }
6187}
6188
6189extern "C"
6190void accGetScriptInfoLog(ACCscript* script,
6191 ACCsizei maxLength,
6192 ACCsizei * length,
6193 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006194 char* message = script->compiler.getErrorMessage();
6195 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006196 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006197 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006198 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006199 if (infoLog && maxLength > 0) {
6200 int trimmedLength = maxLength < messageLength ?
6201 maxLength : messageLength;
6202 memcpy(infoLog, message, trimmedLength);
6203 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006204 }
6205}
6206
6207extern "C"
6208void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6209 ACCvoid ** address) {
6210 void* value = script->compiler.lookup(name);
6211 if (value) {
6212 *address = value;
6213 } else {
6214 script->setError(ACC_INVALID_VALUE);
6215 }
6216}
6217
Jack Palevicheedf9d22009-06-04 16:23:40 -07006218extern "C"
6219void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6220 ACCsizei maxStringCount, ACCchar** strings){
6221 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6222}
6223
-b master422972c2009-06-17 19:13:52 -07006224extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006225void accGetProgramBinary(ACCscript* script,
6226 ACCvoid** base, ACCsizei* length) {
6227 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006228}
6229
Jack Palevicheedf9d22009-06-04 16:23:40 -07006230
Jack Palevich1cdef202009-05-22 12:06:27 -07006231} // namespace acc
6232