blob: 808752e3070b03e833e3f9d7472f52c85a903483 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070016#include <limits.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070017#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070018#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070020#include <stdlib.h>
21#include <string.h>
Jack Palevich61de31f2009-09-08 11:06:40 -070022#include <unistd.h>
23
Jack Palevich2d11dfb2009-06-08 14:34:26 -070024#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070025
Jack Palevich8dc662e2009-06-09 22:53:47 +000026#if defined(__i386__)
27#include <sys/mman.h>
28#endif
29
Jack Palevich546b2242009-05-13 15:10:04 -070030
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Palevich30321cb2009-08-20 15:34:23 -070042#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
43#define ARM_USE_VFP
44#endif
45
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050
-b master422972c2009-06-17 19:13:52 -070051#define LOG_STACK(...) do {} while(0)
52// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
53
Jack Palevichb67b18f2009-06-11 21:12:23 -070054// #define PROVIDE_TRACE_CODEGEN
55
Jack Palevichd30a2ce2009-09-09 19:08:54 -070056// Uncomment to disable ARM peephole optimizations
57// #define DISABLE_ARM_PEEPHOLE
58
Jack Palevich61de31f2009-09-08 11:06:40 -070059// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
60// #define DEBUG_SAVE_INPUT_TO_FILE
61
Jack Palevich9116bc42009-09-08 11:46:42 -070062#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich61de31f2009-09-08 11:06:40 -070063#ifdef ARM_USE_VFP
Jack Palevich9116bc42009-09-08 11:46:42 -070064#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c"
Jack Palevich61de31f2009-09-08 11:06:40 -070065#else
66#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
67#endif
Jack Palevich9116bc42009-09-08 11:46:42 -070068#endif
Jack Palevich61de31f2009-09-08 11:06:40 -070069
Jack Palevich7f5b1a22009-08-17 16:54:56 -070070#define assert(b) assertImpl(b, __LINE__)
71
Jack Palevichbbf8ab52009-05-11 11:54:30 -070072namespace acc {
73
Jack Palevich8df46192009-07-07 14:48:51 -070074// Subset of STL vector.
75template<class E> class Vector {
76 public:
77 Vector() {
78 mpBase = 0;
79 mUsed = 0;
80 mSize = 0;
81 }
82
83 ~Vector() {
84 if (mpBase) {
85 for(size_t i = 0; i < mUsed; i++) {
86 mpBase[mUsed].~E();
87 }
88 free(mpBase);
89 }
90 }
91
92 inline E& operator[](size_t i) {
93 return mpBase[i];
94 }
95
96 inline E& front() {
97 return mpBase[0];
98 }
99
100 inline E& back() {
101 return mpBase[mUsed - 1];
102 }
103
104 void pop_back() {
105 mUsed -= 1;
106 mpBase[mUsed].~E();
107 }
108
109 void push_back(const E& item) {
110 * ensure(1) = item;
111 }
112
113 size_t size() {
114 return mUsed;
115 }
116
117private:
118 E* ensure(int n) {
119 size_t newUsed = mUsed + n;
120 if (newUsed > mSize) {
121 size_t newSize = mSize * 2 + 10;
122 if (newSize < newUsed) {
123 newSize = newUsed;
124 }
125 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
126 mSize = newSize;
127 }
128 E* result = mpBase + mUsed;
129 mUsed = newUsed;
130 return result;
131 }
132
133 E* mpBase;
134 size_t mUsed;
135 size_t mSize;
136};
137
Jack Palevichac0e95e2009-05-29 13:53:44 -0700138class ErrorSink {
139public:
140 void error(const char *fmt, ...) {
141 va_list ap;
142 va_start(ap, fmt);
143 verror(fmt, ap);
144 va_end(ap);
145 }
146
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700147 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700148 virtual void verror(const char* fmt, va_list ap) = 0;
149};
150
151class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700152 typedef int tokenid_t;
153 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700154 TY_INT, // 0
155 TY_CHAR, // 1
156 TY_SHORT, // 2
157 TY_VOID, // 3
158 TY_FLOAT, // 4
159 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700160 TY_POINTER, // 6
161 TY_ARRAY, // 7
162 TY_STRUCT, // 8
163 TY_FUNC, // 9
164 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700165 };
166
167 struct Type {
168 TypeTag tag;
Jack Palevich9221bcc2009-08-26 16:15:07 -0700169 tokenid_t id; // For function arguments, global vars, local vars, struct elements
170 tokenid_t structTag; // For structs the name of the struct
171 int length; // length of array, offset of struct element. -1 means struct is forward defined
172 int alignment; // for structs only
173 Type* pHead; // For a struct this is the prototype struct.
Jack Palevich8df46192009-07-07 14:48:51 -0700174 Type* pTail;
175 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700176
Jack Palevichba929a42009-07-17 10:20:32 -0700177 enum ExpressionType {
178 ET_RVALUE,
179 ET_LVALUE
180 };
181
182 struct ExpressionValue {
183 ExpressionValue() {
184 et = ET_RVALUE;
185 pType = NULL;
186 }
187 ExpressionType et;
188 Type* pType;
189 };
190
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700191 class ICodeBuf {
192 public:
193 virtual ~ICodeBuf() {}
194 virtual void init(int size) = 0;
195 virtual void setErrorSink(ErrorSink* pErrorSink) = 0;
196 virtual void o4(int n) = 0;
197 virtual void ob(int n) = 0;
198 virtual void* getBase() = 0;
199 virtual intptr_t getSize() = 0;
200 virtual intptr_t getPC() = 0;
201 // Call this before trying to modify code in the buffer.
202 virtual void flush() = 0;
203 };
204
205 class CodeBuf : public ICodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700206 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700207 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700208 ErrorSink* mErrorSink;
209 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700210 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700211
Jack Palevich21a15a22009-05-11 14:49:29 -0700212 void release() {
213 if (pProgramBase != 0) {
214 free(pProgramBase);
215 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700216 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 }
218
Jack Palevich0a280a02009-06-11 10:53:51 -0700219 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700220 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700221 bool overflow = newSize > mSize;
222 if (overflow && !mOverflowed) {
223 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700224 if (mErrorSink) {
225 mErrorSink->error("Code too large: %d bytes", newSize);
226 }
227 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700228 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 public:
232 CodeBuf() {
233 pProgramBase = 0;
234 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700235 mErrorSink = 0;
236 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700237 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700238 }
239
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700240 virtual ~CodeBuf() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 release();
242 }
243
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700244 virtual void init(int size) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700245 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700246 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700247 pProgramBase = (char*) calloc(1, size);
248 ind = pProgramBase;
249 }
250
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700251 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700252 mErrorSink = pErrorSink;
253 }
254
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700255 virtual void o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700256 if(check(4)) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700257 return;
Jack Palevich0a280a02009-06-11 10:53:51 -0700258 }
Jack Palevich546b2242009-05-13 15:10:04 -0700259 * (int*) ind = n;
260 ind += 4;
Jack Palevich546b2242009-05-13 15:10:04 -0700261 }
262
Jack Palevich21a15a22009-05-11 14:49:29 -0700263 /*
264 * Output a byte. Handles all values, 0..ff.
265 */
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700266 virtual void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700267 if(check(1)) {
268 return;
269 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700270 *ind++ = n;
271 }
272
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700273 virtual void* getBase() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 return (void*) pProgramBase;
275 }
276
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700277 virtual intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700278 return ind - pProgramBase;
279 }
280
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700281 virtual intptr_t getPC() {
Jack Palevich8b0624c2009-05-20 12:12:06 -0700282 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700284
285 virtual void flush() {}
Jack Palevich21a15a22009-05-11 14:49:29 -0700286 };
287
Jack Palevich1cdef202009-05-22 12:06:27 -0700288 /**
289 * A code generator creates an in-memory program, generating the code on
290 * the fly. There is one code generator implementation for each supported
291 * architecture.
292 *
293 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700294 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700295 * FP - a frame pointer for accessing function arguments and local
296 * variables.
297 * SP - a stack pointer for storing intermediate results while evaluating
298 * expressions. The stack pointer grows downwards.
299 *
300 * The function calling convention is that all arguments are placed on the
301 * stack such that the first argument has the lowest address.
302 * After the call, the result is in R0. The caller is responsible for
303 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700304 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700305 * FP and SP registers are saved.
306 */
307
Jack Palevich21a15a22009-05-11 14:49:29 -0700308 class CodeGenerator {
309 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700310 CodeGenerator() {
311 mErrorSink = 0;
312 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700313 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700314 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700315 virtual ~CodeGenerator() {}
316
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700317 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700318 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700319 pCodeBuf->setErrorSink(mErrorSink);
320 }
321
Jack Palevichb67b18f2009-06-11 21:12:23 -0700322 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700323 mErrorSink = pErrorSink;
324 if (pCodeBuf) {
325 pCodeBuf->setErrorSink(mErrorSink);
326 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700327 }
328
Jack Palevich58c30ee2009-07-17 16:35:23 -0700329 /* Give the code generator some utility types so it can
330 * use its own types as needed for the results of some
331 * operations like gcmp.
332 */
333
Jack Palevicha8f427f2009-07-13 18:40:08 -0700334 void setTypes(Type* pInt) {
335 mkpInt = pInt;
336 }
337
Jack Palevich1cdef202009-05-22 12:06:27 -0700338 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700339 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 * Save the old value of the FP.
341 * Set the new value of the FP.
342 * Convert from the native platform calling convention to
343 * our stack-based calling convention. This may require
344 * pushing arguments from registers to the stack.
345 * Allocate "N" bytes of stack space. N isn't known yet, so
346 * just emit the instructions for adjusting the stack, and return
347 * the address to patch up. The patching will be done in
348 * functionExit().
349 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700350 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700351 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700352
Jack Palevich1cdef202009-05-22 12:06:27 -0700353 /* Emit a function epilog.
354 * Restore the old SP and FP register values.
355 * Return to the calling function.
356 * argCount - the number of arguments to the function.
357 * localVariableAddress - returned from functionEntry()
358 * localVariableSize - the size in bytes of the local variables.
359 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700360 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700362
Jack Palevich1cdef202009-05-22 12:06:27 -0700363 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700364 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700365
Jack Palevich1a539db2009-07-08 13:04:41 -0700366 /* Load floating point value from global address. */
367 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich9221bcc2009-08-26 16:15:07 -0700369 /* Add the struct offset in bytes to R0, change the type to pType */
370 virtual void addStructOffsetR0(int offset, Type* pType) = 0;
371
Jack Palevich1cdef202009-05-22 12:06:27 -0700372 /* Jump to a target, and return the address of the word that
373 * holds the target data, in case it needs to be fixed up later.
374 */
Jack Palevich22305132009-05-13 10:58:45 -0700375 virtual int gjmp(int t) = 0;
376
Jack Palevich1cdef202009-05-22 12:06:27 -0700377 /* Test R0 and jump to a target if the test succeeds.
378 * l = 0: je, l == 1: jne
379 * Return the address of the word that holds the targed data, in
380 * case it needs to be fixed up later.
381 */
Jack Palevich22305132009-05-13 10:58:45 -0700382 virtual int gtst(bool l, int t) = 0;
383
Jack Palevich9eed7a22009-07-06 17:24:34 -0700384 /* Compare TOS against R0, and store the boolean result in R0.
385 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 * op specifies the comparison.
387 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700388 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich9eed7a22009-07-06 17:24:34 -0700390 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700392 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 */
Jack Palevich546b2242009-05-13 15:10:04 -0700394 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700395
Jack Palevich9eed7a22009-07-06 17:24:34 -0700396 /* Compare 0 against R0, and store the boolean result in R0.
397 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700398 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700399 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700400
401 /* Perform the arithmetic op specified by op. 0 is the
402 * left argument, R0 is the right argument.
403 */
404 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700406 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700407 */
408 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700410 /* Turn R0, TOS into R0 TOS R0 */
411
412 virtual void over() = 0;
413
414 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700415 */
416 virtual void popR0() = 0;
417
Jack Palevich9eed7a22009-07-06 17:24:34 -0700418 /* Store R0 to the address stored in TOS.
419 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700421 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700422
Jack Palevich1cdef202009-05-22 12:06:27 -0700423 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700424 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700425 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Load the absolute address of a variable to R0.
428 * If ea <= LOCAL, then this is a local variable, or an
429 * argument, addressed relative to FP.
430 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700431 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700432 * et is ET_RVALUE for things like string constants, ET_LVALUE for
433 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700435 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700436
Jack Palevich9f51a262009-07-29 16:22:26 -0700437 /* Load the pc-relative address of a forward-referenced variable to R0.
438 * Return the address of the 4-byte constant so that it can be filled
439 * in later.
440 */
441 virtual int leaForward(int ea, Type* pPointerType) = 0;
442
Jack Palevich8df46192009-07-07 14:48:51 -0700443 /**
444 * Convert R0 to the given type.
445 */
Jack Palevichb6154502009-08-04 14:56:09 -0700446
447 void convertR0(Type* pType) {
448 convertR0Imp(pType, false);
449 }
450
451 void castR0(Type* pType) {
452 convertR0Imp(pType, true);
453 }
454
455 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700456
Jack Palevich1cdef202009-05-22 12:06:27 -0700457 /* Emit code to adjust the stack for a function call. Return the
458 * label for the address of the instruction that adjusts the
459 * stack size. This will be passed as argument "a" to
460 * endFunctionCallArguments.
461 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700462 virtual int beginFunctionCallArguments() = 0;
463
Jack Palevich1cdef202009-05-22 12:06:27 -0700464 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700465 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700466 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700467 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700468
Jack Palevich1cdef202009-05-22 12:06:27 -0700469 /* Patch the function call preamble.
470 * a is the address returned from beginFunctionCallArguments
471 * l is the number of bytes the arguments took on the stack.
472 * Typically you would also emit code to convert the argument
473 * list into whatever the native function calling convention is.
474 * On ARM for example you would pop the first 5 arguments into
475 * R0..R4
476 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700477 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700478
Jack Palevich1cdef202009-05-22 12:06:27 -0700479 /* Emit a call to an unknown function. The argument "symbol" needs to
480 * be stored in the location where the address should go. It forms
481 * a chain. The address will be patched later.
482 * Return the address of the word that has to be patched.
483 */
Jack Palevich8df46192009-07-07 14:48:51 -0700484 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700485
Jack Palevich1cdef202009-05-22 12:06:27 -0700486 /* Call a function pointer. L is the number of bytes the arguments
487 * take on the stack. The address of the function is stored at
488 * location SP + l.
489 */
Jack Palevich8df46192009-07-07 14:48:51 -0700490 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700491
Jack Palevich1cdef202009-05-22 12:06:27 -0700492 /* Adjust SP after returning from a function call. l is the
493 * number of bytes of arguments stored on the stack. isIndirect
494 * is true if this was an indirect call. (In which case the
495 * address of the function is stored at location SP + l.)
496 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700497 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700498
Jack Palevich1cdef202009-05-22 12:06:27 -0700499 /* Generate a symbol at the current PC. t is the head of a
500 * linked list of addresses to patch.
501 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700502 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700503
Jack Palevich9f51a262009-07-29 16:22:26 -0700504 /* Resolve a forward reference function at the current PC.
505 * t is the head of a
506 * linked list of addresses to patch.
507 * (Like gsym, but using absolute address, not PC relative address.)
508 */
509 virtual void resolveForward(int t) = 0;
510
Jack Palevich1cdef202009-05-22 12:06:27 -0700511 /*
512 * Do any cleanup work required at the end of a compile.
513 * For example, an instruction cache might need to be
514 * invalidated.
515 * Return non-zero if there is an error.
516 */
517 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700518
Jack Palevicha6535612009-05-13 16:24:17 -0700519 /**
520 * Adjust relative branches by this amount.
521 */
522 virtual int jumpOffset() = 0;
523
Jack Palevich9eed7a22009-07-06 17:24:34 -0700524 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700525 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700526 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700527 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700528
529 /**
530 * Array element alignment (in bytes) for this type of data.
531 */
532 virtual size_t sizeOf(Type* type) = 0;
533
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700534 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700535 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700536 }
537
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700538 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700539 return mExpressionStack.back().et;
540 }
541
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700542 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700543 mExpressionStack.back().et = et;
544 }
545
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700546 virtual size_t getExpressionStackDepth() {
547 return mExpressionStack.size();
548 }
549
Jack Palevichb5e33312009-07-30 19:06:34 -0700550 virtual void forceR0RVal() {
551 if (getR0ExpressionType() == ET_LVALUE) {
552 loadR0FromR0();
553 }
554 }
555
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700557 /*
558 * Output a byte. Handles all values, 0..ff.
559 */
560 void ob(int n) {
561 pCodeBuf->ob(n);
562 }
563
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700564 void o4(int data) {
565 pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700566 }
567
Jack Palevich8b0624c2009-05-20 12:12:06 -0700568 intptr_t getBase() {
569 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700570 }
571
Jack Palevich8b0624c2009-05-20 12:12:06 -0700572 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700573 return pCodeBuf->getPC();
574 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700575
576 intptr_t getSize() {
577 return pCodeBuf->getSize();
578 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700579
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700580 void flush() {
581 pCodeBuf->flush();
582 }
583
Jack Palevichac0e95e2009-05-29 13:53:44 -0700584 void error(const char* fmt,...) {
585 va_list ap;
586 va_start(ap, fmt);
587 mErrorSink->verror(fmt, ap);
588 va_end(ap);
589 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700590
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700591 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700592 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700593 error("code generator assertion failed at line %s:%d.", __FILE__, line);
594 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700595 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700596 }
597 }
Jack Palevich8df46192009-07-07 14:48:51 -0700598
599 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700600 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700601 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700602 mExpressionStack.back().et = ET_RVALUE;
603 }
604
605 void setR0Type(Type* pType, ExpressionType et) {
606 assert(pType != NULL);
607 mExpressionStack.back().pType = pType;
608 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700609 }
610
Jack Palevich8df46192009-07-07 14:48:51 -0700611 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700612 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700613 }
614
615 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700616 if (mExpressionStack.size()) {
617 mExpressionStack.push_back(mExpressionStack.back());
618 } else {
619 mExpressionStack.push_back(ExpressionValue());
620 }
621
Jack Palevich8df46192009-07-07 14:48:51 -0700622 }
623
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700624 void overType() {
625 size_t size = mExpressionStack.size();
626 if (size >= 2) {
627 mExpressionStack.push_back(mExpressionStack.back());
628 mExpressionStack[size-1] = mExpressionStack[size-2];
629 mExpressionStack[size-2] = mExpressionStack[size];
630 }
631 }
632
Jack Palevich8df46192009-07-07 14:48:51 -0700633 void popType() {
634 mExpressionStack.pop_back();
635 }
636
637 bool bitsSame(Type* pA, Type* pB) {
638 return collapseType(pA->tag) == collapseType(pB->tag);
639 }
640
641 TypeTag collapseType(TypeTag tag) {
642 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700643 TY_INT,
644 TY_INT,
645 TY_INT,
646 TY_VOID,
647 TY_FLOAT,
648 TY_DOUBLE,
649 TY_INT,
650 TY_INT,
651 TY_VOID,
652 TY_VOID,
653 TY_VOID
654 };
Jack Palevich8df46192009-07-07 14:48:51 -0700655 return collapsedTag[tag];
656 }
657
Jack Palevich1a539db2009-07-08 13:04:41 -0700658 TypeTag collapseTypeR0() {
659 return collapseType(getR0Type()->tag);
660 }
661
Jack Palevichb6154502009-08-04 14:56:09 -0700662 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700663 return isFloatTag(pType->tag);
664 }
665
Jack Palevichb6154502009-08-04 14:56:09 -0700666 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700667 return tag == TY_FLOAT || tag == TY_DOUBLE;
668 }
669
Jack Palevichb6154502009-08-04 14:56:09 -0700670 static bool isPointerType(Type* pType) {
671 return isPointerTag(pType->tag);
672 }
673
674 static bool isPointerTag(TypeTag tag) {
675 return tag == TY_POINTER || tag == TY_ARRAY;
676 }
677
678 Type* getPointerArithmeticResultType(Type* a, Type* b) {
679 TypeTag aTag = a->tag;
680 TypeTag bTag = b->tag;
681 if (aTag == TY_POINTER) {
682 return a;
683 }
684 if (bTag == TY_POINTER) {
685 return b;
686 }
687 if (aTag == TY_ARRAY) {
688 return a->pTail;
689 }
690 if (bTag == TY_ARRAY) {
691 return b->pTail;
692 }
693 return NULL;
694 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700695 Type* mkpInt;
696
Jack Palevich21a15a22009-05-11 14:49:29 -0700697 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700698 Vector<ExpressionValue> mExpressionStack;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700699 ICodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700700 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700701 };
702
Jack Paleviche7b59062009-05-19 17:12:17 -0700703#ifdef PROVIDE_ARM_CODEGEN
704
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700705 static size_t rotateRight(size_t n, size_t rotate) {
706 return (n >> rotate) | (n << (32 - rotate));
707 }
708
709 static size_t rotateLeft(size_t n, size_t rotate) {
710 return (n << rotate) | (n >> (32 - rotate));
711 }
712
713 static bool encode12BitImmediate(size_t immediate, size_t* pResult) {
714 for(size_t i = 0; i < 16; i++) {
715 size_t rotate = i * 2;
716 size_t mask = rotateRight(0xff, rotate);
717 if ((immediate | mask) == mask) {
718 size_t bits8 = rotateLeft(immediate, rotate);
719 // assert(bits8 <= 0xff);
720 *pResult = (i << 8) | bits8;
721 return true;
722 }
723 }
724 return false;
725 }
726
727 static size_t decode12BitImmediate(size_t immediate) {
728 size_t data = immediate & 0xff;
729 size_t rotate = 2 * ((immediate >> 8) & 0xf);
730 return rotateRight(data, rotate);
731 }
732
Jack Palevich53f06582009-09-10 14:01:58 -0700733 static bool isPowerOfTwo(size_t n) {
734 return (n != 0) & ((n & (n-1)) == 0);
735 }
736
737 static size_t log2(size_t n) {
738 int result = 0;
739 while (n >>= 1) {
740 result++;
741 }
742 return result;
743 }
744
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700745 class ARMCodeBuf : public ICodeBuf {
746 ICodeBuf* mpBase;
747 ErrorSink* mErrorSink;
748
749 class CircularQueue {
750 static const int SIZE = 16; // Must be power of 2
751 static const int MASK = SIZE-1;
752 unsigned int mBuf[SIZE];
753 int mHead;
754 int mCount;
755
756 public:
757 CircularQueue() {
758 mHead = 0;
759 mCount = 0;
760 }
761
762 void pushBack(unsigned int data) {
763 mBuf[(mHead + mCount) & MASK] = data;
764 mCount += 1;
765 }
766
767 unsigned int popFront() {
768 unsigned int result = mBuf[mHead];
769 mHead = (mHead + 1) & MASK;
770 mCount -= 1;
771 return result;
772 }
773
774 void popBack(int n) {
775 mCount -= n;
776 }
777
778 inline int count() {
779 return mCount;
780 }
781
782 bool empty() {
783 return mCount == 0;
784 }
785
786 bool full() {
787 return mCount == SIZE;
788 }
789
790 // The valid indexes are 1 - count() to 0
791 unsigned int operator[](int i) {
792 return mBuf[(mHead + mCount + i) & MASK];
793 }
794 };
795
796 CircularQueue mQ;
797
798 void error(const char* fmt,...) {
799 va_list ap;
800 va_start(ap, fmt);
801 mErrorSink->verror(fmt, ap);
802 va_end(ap);
803 }
804
805 void flush() {
806 while (!mQ.empty()) {
807 mpBase->o4(mQ.popFront());
808 }
809 mpBase->flush();
810 }
811
812 public:
813 ARMCodeBuf(ICodeBuf* pBase) {
814 mpBase = pBase;
815 }
816
817 virtual ~ARMCodeBuf() {
818 delete mpBase;
819 }
820
821 void init(int size) {
822 mpBase->init(size);
823 }
824
825 void setErrorSink(ErrorSink* pErrorSink) {
826 mErrorSink = pErrorSink;
827 mpBase->setErrorSink(pErrorSink);
828 }
829
830 void o4(int n) {
831 if (mQ.full()) {
832 mpBase->o4(mQ.popFront());
833 }
834 mQ.pushBack(n);
835
836#ifndef DISABLE_ARM_PEEPHOLE
837 // Peephole check
838 bool didPeep;
839 do {
Jack Palevich53f06582009-09-10 14:01:58 -0700840 static const unsigned int opMask = 0x01e00000;
841 static const unsigned int immediateMask = 0x00000fff;
842 static const unsigned int BMask = 0x00400000;
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700843 didPeep = false;
844 if (mQ.count() >= 4) {
845
846 // Operand by a small constant
847 // push;mov #imm;pop;op ==> op #imm
848
Jack Palevich1c60e462009-09-18 15:03:03 -0700849 if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0}
850 (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X
851 mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1}
852 (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700853 unsigned int movConst = mQ[-3];
854 unsigned int op = mQ[-1];
855 unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask);
856 // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined);
857 if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0
858 mQ.popBack(4);
859 mQ.pushBack(combined);
860 didPeep = true;
861 } else {
862 mQ.popBack(4);
863 didPeep = true;
864 }
865 }
866 }
867
868 // Load local variable
Jack Palevich53f06582009-09-10 14:01:58 -0700869 // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm]
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700870 if (mQ.count() >= 2) {
Jack Palevich53f06582009-09-10 14:01:58 -0700871 if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm
872 const unsigned int encodedImmediate = mQ[-2] & immediateMask;
873 const unsigned int ld = mQ[-1];
874 if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0]
875 unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0]
876 mQ.popBack(2);
877 mQ.pushBack(combined);
878 didPeep = true;
Jack Palevich1c60e462009-09-18 15:03:03 -0700879 } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000]
Jack Palevich53f06582009-09-10 14:01:58 -0700880 unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate);
881 if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) {
Jack Palevich1c60e462009-09-18 15:03:03 -0700882 unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0]
Jack Palevich53f06582009-09-10 14:01:58 -0700883 mQ.popBack(2);
884 mQ.pushBack(combined);
885 didPeep = true;
886 }
887 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700888 }
889 }
890
891 // Constant array lookup
892
893 if (mQ.count() >= 6 &&
894 mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0}
895 (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001
896 mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1}
897 (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004
898 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
899 mQ[-1] == 0xe0810000) { // add r0, r1, r0
900 unsigned int mov1 = mQ[-5];
901 unsigned int mov2 = mQ[-3];
902 unsigned int const1 = decode12BitImmediate(mov1);
903 unsigned int const2 = decode12BitImmediate(mov2);
904 unsigned int comboConst = const1 * const2;
905 size_t immediate = 0;
906 if (encode12BitImmediate(comboConst, &immediate)) {
907 mQ.popBack(6);
908 unsigned int add = immediate | 0xE2800000; // add r0, r0, #n
909 if (comboConst) {
910 mQ.pushBack(add);
911 }
912 didPeep = true;
913 }
914 }
915
Jack Palevich53f06582009-09-10 14:01:58 -0700916 // Pointer arithmetic with a stride that is a power of two
917
918 if (mQ.count() >= 3 &&
Jack Palevich1c60e462009-09-18 15:03:03 -0700919 (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride
920 mQ[-2] == 0xe0000092 && // mul r0, r2, r0
Jack Palevich53f06582009-09-10 14:01:58 -0700921 mQ[-1] == 0xe0810000) { // add r0, r1, r0
922 int stride = decode12BitImmediate(mQ[-3]);
923 if (isPowerOfTwo(stride)) {
924 mQ.popBack(3);
925 unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride)
926 mQ.pushBack(add);
927 didPeep = true;
928 }
929 }
930
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700931 } while (didPeep);
932#endif
933 }
934
935 void ob(int n) {
936 error("ob() not supported.");
937 }
938
939 void* getBase() {
940 flush();
941 return mpBase->getBase();
942 }
943
944 intptr_t getSize() {
945 flush();
946 return mpBase->getSize();
947 }
948
949 intptr_t getPC() {
950 flush();
951 return mpBase->getPC();
952 }
953 };
954
Jack Palevich22305132009-05-13 10:58:45 -0700955 class ARMCodeGenerator : public CodeGenerator {
956 public:
Jack Palevich30321cb2009-08-20 15:34:23 -0700957 ARMCodeGenerator() {
958#ifdef ARM_USE_VFP
Jack Palevichd5315572009-09-09 13:19:34 -0700959 // LOGD("Using ARM VFP hardware floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700960#else
Jack Palevichd5315572009-09-09 13:19:34 -0700961 // LOGD("Using ARM soft floating point.");
Jack Palevich30321cb2009-08-20 15:34:23 -0700962#endif
963 }
-b master422972c2009-06-17 19:13:52 -0700964
Jack Palevich22305132009-05-13 10:58:45 -0700965 virtual ~ARMCodeGenerator() {}
966
967 /* returns address to patch with local variable size
968 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700969 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700970 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700971 // sp -> arg4 arg5 ...
972 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700973 int regArgCount = calcRegArgCount(pDecl);
974 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700975 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700976 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700977 }
978 // sp -> arg0 arg1 ...
979 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700980 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700981 // sp, fp -> oldfp, retadr, arg0 arg1 ....
982 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700983 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700984 int pc = getPC();
985 o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700986 // We don't know how many local variables we are going to use,
987 // but we will round the allocation up to a multiple of
988 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevichd30a2ce2009-09-09 19:08:54 -0700989 return pc;
Jack Palevich22305132009-05-13 10:58:45 -0700990 }
991
Jack Palevichb7718b92009-07-09 22:00:24 -0700992 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700993 // Round local variable size up to a multiple of stack alignment
994 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
995 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700996 // Patch local variable allocation code:
997 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700998 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700999 }
Jack Palevich69796b62009-05-14 15:42:26 -07001000 *(char*) (localVariableAddress) = localVariableSize;
1001
Jack Palevich30321cb2009-08-20 15:34:23 -07001002#ifdef ARM_USE_VFP
1003 {
Jack Palevichc0f25332009-08-25 12:23:43 -07001004 Type* pReturnType = pDecl->pHead;
1005 switch(pReturnType->tag) {
1006 case TY_FLOAT:
1007 o4(0xEE170A90); // fmrs r0, s15
1008 break;
1009 case TY_DOUBLE:
1010 o4(0xEC510B17); // fmrrd r0, r1, d7
1011 break;
1012 default:
1013 break;
1014 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001015 }
1016#endif
1017
Jack Palevich69796b62009-05-14 15:42:26 -07001018 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
1019 o4(0xE1A0E00B); // mov lr, fp
1020 o4(0xE59BB000); // ldr fp, [fp]
1021 o4(0xE28ED004); // add sp, lr, #4
1022 // sp -> retadr, arg0, ...
1023 o4(0xE8BD4000); // ldmfd sp!, {lr}
1024 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -07001025
1026 // We store the PC into the lr so we can adjust the sp before
1027 // returning. We need to pull off the registers we pushed
1028 // earlier. We don't need to actually store them anywhere,
1029 // just adjust the stack.
1030 int regArgCount = calcRegArgCount(pDecl);
1031 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -07001032 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
1033 }
1034 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -07001035 }
1036
1037 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001038 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001039 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -07001040 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001041 }
1042
Jack Palevich1a539db2009-07-08 13:04:41 -07001043 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001044 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 // Global, absolute address
1046 o4(0xE59F0000); // ldr r0, .L1
1047 o4(0xEA000000); // b .L99
1048 o4(address); // .L1: .word ea
1049 // .L99:
1050
1051 switch (pType->tag) {
1052 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001053#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001054 o4(0xEDD07A00); // flds s15, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001055#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001056 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001057#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001058 break;
1059 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001060#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001061 o4(0xED907B00); // fldd d7, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001062#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001063 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001064#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001065 break;
1066 default:
1067 assert(false);
1068 break;
1069 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001070 }
1071
Jack Palevich9221bcc2009-08-26 16:15:07 -07001072
1073 virtual void addStructOffsetR0(int offset, Type* pType) {
1074 if (offset) {
1075 size_t immediate = 0;
1076 if (encode12BitImmediate(offset, &immediate)) {
1077 o4(0xE2800000 | immediate); // add r0, r0, #offset
1078 } else {
1079 error("structure offset out of range: %d", offset);
1080 }
1081 }
1082 setR0Type(pType, ET_LVALUE);
1083 }
1084
Jack Palevich22305132009-05-13 10:58:45 -07001085 virtual int gjmp(int t) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001086 int pc = getPC();
1087 o4(0xEA000000 | encodeAddress(t)); // b .L33
1088 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001089 }
1090
1091 /* l = 0: je, l == 1: jne */
1092 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001093 Type* pR0Type = getR0Type();
1094 TypeTag tagR0 = pR0Type->tag;
1095 switch(tagR0) {
1096 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001097#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001098 o4(0xEEF57A40); // fcmpzs s15
1099 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001100#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001101 callRuntime((void*) runtime_is_non_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001102 o4(0xE3500000); // cmp r0,#0
1103#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001104 break;
1105 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001106#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001107 o4(0xEEB57B40); // fcmpzd d7
1108 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001109#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001110 callRuntime((void*) runtime_is_non_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001111 o4(0xE3500000); // cmp r0,#0
1112#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001113 break;
1114 default:
Jack Palevich30321cb2009-08-20 15:34:23 -07001115 o4(0xE3500000); // cmp r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001116 break;
1117 }
Jack Palevich8de461d2009-05-14 17:21:45 -07001118 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001119 int pc = getPC();
1120 o4(branch | encodeAddress(t));
1121 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001122 }
1123
Jack Palevich58c30ee2009-07-17 16:35:23 -07001124 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001125 Type* pR0Type = getR0Type();
1126 Type* pTOSType = getTOSType();
1127 TypeTag tagR0 = collapseType(pR0Type->tag);
1128 TypeTag tagTOS = collapseType(pTOSType->tag);
1129 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001130 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -07001131 o4(0xE1510000); // cmp r1, r1
1132 switch(op) {
1133 case OP_EQUALS:
1134 o4(0x03A00001); // moveq r0,#1
1135 o4(0x13A00000); // movne r0,#0
1136 break;
1137 case OP_NOT_EQUALS:
1138 o4(0x03A00000); // moveq r0,#0
1139 o4(0x13A00001); // movne r0,#1
1140 break;
1141 case OP_LESS_EQUAL:
1142 o4(0xD3A00001); // movle r0,#1
1143 o4(0xC3A00000); // movgt r0,#0
1144 break;
1145 case OP_GREATER:
1146 o4(0xD3A00000); // movle r0,#0
1147 o4(0xC3A00001); // movgt r0,#1
1148 break;
1149 case OP_GREATER_EQUAL:
1150 o4(0xA3A00001); // movge r0,#1
1151 o4(0xB3A00000); // movlt r0,#0
1152 break;
1153 case OP_LESS:
1154 o4(0xA3A00000); // movge r0,#0
1155 o4(0xB3A00001); // movlt r0,#1
1156 break;
1157 default:
1158 error("Unknown comparison op %d", op);
1159 break;
1160 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001161 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
1162 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001163#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001164 o4(0xEEB46BC7); // fcmped d6, d7
1165 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001166 switch(op) {
1167 case OP_EQUALS:
1168 o4(0x03A00001); // moveq r0,#1
1169 o4(0x13A00000); // movne r0,#0
1170 break;
1171 case OP_NOT_EQUALS:
1172 o4(0x03A00000); // moveq r0,#0
1173 o4(0x13A00001); // movne r0,#1
1174 break;
1175 case OP_LESS_EQUAL:
1176 o4(0xD3A00001); // movle r0,#1
1177 o4(0xC3A00000); // movgt r0,#0
1178 break;
1179 case OP_GREATER:
1180 o4(0xD3A00000); // movle r0,#0
1181 o4(0xC3A00001); // movgt r0,#1
1182 break;
1183 case OP_GREATER_EQUAL:
1184 o4(0xA3A00001); // movge r0,#1
1185 o4(0xB3A00000); // movlt r0,#0
1186 break;
1187 case OP_LESS:
1188 o4(0xA3A00000); // movge r0,#0
1189 o4(0xB3A00001); // movlt r0,#1
1190 break;
1191 default:
1192 error("Unknown comparison op %d", op);
1193 break;
1194 }
1195#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001196 switch(op) {
1197 case OP_EQUALS:
1198 callRuntime((void*) runtime_cmp_eq_dd);
1199 break;
1200 case OP_NOT_EQUALS:
1201 callRuntime((void*) runtime_cmp_ne_dd);
1202 break;
1203 case OP_LESS_EQUAL:
1204 callRuntime((void*) runtime_cmp_le_dd);
1205 break;
1206 case OP_GREATER:
1207 callRuntime((void*) runtime_cmp_gt_dd);
1208 break;
1209 case OP_GREATER_EQUAL:
1210 callRuntime((void*) runtime_cmp_ge_dd);
1211 break;
1212 case OP_LESS:
1213 callRuntime((void*) runtime_cmp_lt_dd);
1214 break;
1215 default:
1216 error("Unknown comparison op %d", op);
1217 break;
1218 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001219#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001220 } else {
1221 setupFloatArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001222#ifdef ARM_USE_VFP
1223 o4(0xEEB47AE7); // fcmpes s14, s15
Jack Palevichc0f25332009-08-25 12:23:43 -07001224 o4(0xEEF1FA10); // fmstat
Jack Palevich30321cb2009-08-20 15:34:23 -07001225 switch(op) {
1226 case OP_EQUALS:
1227 o4(0x03A00001); // moveq r0,#1
1228 o4(0x13A00000); // movne r0,#0
1229 break;
1230 case OP_NOT_EQUALS:
1231 o4(0x03A00000); // moveq r0,#0
1232 o4(0x13A00001); // movne r0,#1
1233 break;
1234 case OP_LESS_EQUAL:
1235 o4(0xD3A00001); // movle r0,#1
1236 o4(0xC3A00000); // movgt r0,#0
1237 break;
1238 case OP_GREATER:
1239 o4(0xD3A00000); // movle r0,#0
1240 o4(0xC3A00001); // movgt r0,#1
1241 break;
1242 case OP_GREATER_EQUAL:
1243 o4(0xA3A00001); // movge r0,#1
1244 o4(0xB3A00000); // movlt r0,#0
1245 break;
1246 case OP_LESS:
1247 o4(0xA3A00000); // movge r0,#0
1248 o4(0xB3A00001); // movlt r0,#1
1249 break;
1250 default:
1251 error("Unknown comparison op %d", op);
1252 break;
1253 }
1254#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001255 switch(op) {
1256 case OP_EQUALS:
1257 callRuntime((void*) runtime_cmp_eq_ff);
1258 break;
1259 case OP_NOT_EQUALS:
1260 callRuntime((void*) runtime_cmp_ne_ff);
1261 break;
1262 case OP_LESS_EQUAL:
1263 callRuntime((void*) runtime_cmp_le_ff);
1264 break;
1265 case OP_GREATER:
1266 callRuntime((void*) runtime_cmp_gt_ff);
1267 break;
1268 case OP_GREATER_EQUAL:
1269 callRuntime((void*) runtime_cmp_ge_ff);
1270 break;
1271 case OP_LESS:
1272 callRuntime((void*) runtime_cmp_lt_ff);
1273 break;
1274 default:
1275 error("Unknown comparison op %d", op);
1276 break;
1277 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001278#endif
Jack Palevich8de461d2009-05-14 17:21:45 -07001279 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001280 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07001281 }
1282
Jack Palevich546b2242009-05-13 15:10:04 -07001283 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001284 Type* pR0Type = getR0Type();
1285 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -07001286 TypeTag tagR0 = pR0Type->tag;
1287 TypeTag tagTOS = pTOSType->tag;
1288 bool isFloatR0 = isFloatTag(tagR0);
1289 bool isFloatTOS = isFloatTag(tagTOS);
1290 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07001291 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -07001292 bool isPtrR0 = isPointerTag(tagR0);
1293 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001294 if (isPtrR0 || isPtrTOS) {
1295 if (isPtrR0 && isPtrTOS) {
1296 if (op != OP_MINUS) {
1297 error("Unsupported pointer-pointer operation %d.", op);
1298 }
1299 if (! typeEqual(pR0Type, pTOSType)) {
1300 error("Incompatible pointer types for subtraction.");
1301 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001302 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001303 setR0Type(mkpInt);
1304 int size = sizeOf(pR0Type->pHead);
1305 if (size != 1) {
1306 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001307 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001308 // TODO: Optimize for power-of-two.
1309 genOp(OP_DIV);
1310 }
1311 } else {
1312 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1313 error("Unsupported pointer-scalar operation %d", op);
1314 }
Jack Palevichb6154502009-08-04 14:56:09 -07001315 Type* pPtrType = getPointerArithmeticResultType(
1316 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001317 int size = sizeOf(pPtrType->pHead);
1318 if (size != 1) {
1319 // TODO: Optimize for power-of-two.
1320 liReg(size, 2);
1321 if (isPtrR0) {
1322 o4(0x0E0010192); // mul r1,r2,r1
1323 } else {
1324 o4(0x0E0000092); // mul r0,r2,r0
1325 }
1326 }
1327 switch(op) {
1328 case OP_PLUS:
1329 o4(0xE0810000); // add r0,r1,r0
1330 break;
1331 case OP_MINUS:
1332 o4(0xE0410000); // sub r0,r1,r0
1333 break;
1334 }
Jack Palevicha8f427f2009-07-13 18:40:08 -07001335 setR0Type(pPtrType);
1336 }
1337 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001338 switch(op) {
1339 case OP_MUL:
1340 o4(0x0E0000091); // mul r0,r1,r0
1341 break;
1342 case OP_DIV:
1343 callRuntime((void*) runtime_DIV);
1344 break;
1345 case OP_MOD:
1346 callRuntime((void*) runtime_MOD);
1347 break;
1348 case OP_PLUS:
1349 o4(0xE0810000); // add r0,r1,r0
1350 break;
1351 case OP_MINUS:
1352 o4(0xE0410000); // sub r0,r1,r0
1353 break;
1354 case OP_SHIFT_LEFT:
1355 o4(0xE1A00011); // lsl r0,r1,r0
1356 break;
1357 case OP_SHIFT_RIGHT:
1358 o4(0xE1A00051); // asr r0,r1,r0
1359 break;
1360 case OP_BIT_AND:
1361 o4(0xE0010000); // and r0,r1,r0
1362 break;
1363 case OP_BIT_XOR:
1364 o4(0xE0210000); // eor r0,r1,r0
1365 break;
1366 case OP_BIT_OR:
1367 o4(0xE1810000); // orr r0,r1,r0
1368 break;
1369 case OP_BIT_NOT:
1370 o4(0xE1E00000); // mvn r0, r0
1371 break;
1372 default:
1373 error("Unimplemented op %d\n", op);
1374 break;
1375 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001376 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001377 } else {
1378 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1379 if (pResultType->tag == TY_DOUBLE) {
1380 setupDoubleArgs();
Jack Palevich30321cb2009-08-20 15:34:23 -07001381
Jack Palevichb7718b92009-07-09 22:00:24 -07001382 switch(op) {
1383 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001384#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001385 o4(0xEE267B07); // fmuld d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001386#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001387 callRuntime((void*) runtime_op_mul_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001388#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001389 break;
1390 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001391#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001392 o4(0xEE867B07); // fdivd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001393#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001394 callRuntime((void*) runtime_op_div_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001395#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001396 break;
1397 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001398#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001399 o4(0xEE367B07); // faddd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001400#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001401 callRuntime((void*) runtime_op_add_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001402#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001403 break;
1404 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001405#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001406 o4(0xEE367B47); // fsubd d7, d6, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001407#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001408 callRuntime((void*) runtime_op_sub_dd);
Jack Palevich30321cb2009-08-20 15:34:23 -07001409#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001410 break;
1411 default:
1412 error("Unsupported binary floating operation %d\n", op);
1413 break;
1414 }
1415 } else {
1416 setupFloatArgs();
1417 switch(op) {
1418 case OP_MUL:
Jack Palevich30321cb2009-08-20 15:34:23 -07001419#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001420 o4(0xEE677A27); // fmuls s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001421#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001422 callRuntime((void*) runtime_op_mul_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001423#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001424 break;
1425 case OP_DIV:
Jack Palevich30321cb2009-08-20 15:34:23 -07001426#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001427 o4(0xEEC77A27); // fdivs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001428#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001429 callRuntime((void*) runtime_op_div_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001430#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001431 break;
1432 case OP_PLUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001433#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001434 o4(0xEE777A27); // fadds s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001435#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001436 callRuntime((void*) runtime_op_add_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001437#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001438 break;
1439 case OP_MINUS:
Jack Palevich30321cb2009-08-20 15:34:23 -07001440#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001441 o4(0xEE777A67); // fsubs s15, s14, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001442#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001443 callRuntime((void*) runtime_op_sub_ff);
Jack Palevich30321cb2009-08-20 15:34:23 -07001444#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001445 break;
1446 default:
1447 error("Unsupported binary floating operation %d\n", op);
1448 break;
1449 }
1450 }
1451 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001452 }
Jack Palevich22305132009-05-13 10:58:45 -07001453 }
1454
Jack Palevich58c30ee2009-07-17 16:35:23 -07001455 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001456 if (op != OP_LOGICAL_NOT) {
1457 error("Unknown unary cmp %d", op);
1458 } else {
1459 Type* pR0Type = getR0Type();
1460 TypeTag tag = collapseType(pR0Type->tag);
1461 switch(tag) {
1462 case TY_INT:
1463 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001464 o4(0xE1510000); // cmp r1, r0
1465 o4(0x03A00001); // moveq r0,#1
1466 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001467 break;
1468 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001469#ifdef ARM_USE_VFP
1470 o4(0xEEF57A40); // fcmpzs s15
1471 o4(0xEEF1FA10); // fmstat
1472 o4(0x03A00001); // moveq r0,#1
1473 o4(0x13A00000); // movne r0,#0
1474#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001475 callRuntime((void*) runtime_is_zero_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001476#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001477 break;
1478 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001479#ifdef ARM_USE_VFP
1480 o4(0xEEB57B40); // fcmpzd d7
1481 o4(0xEEF1FA10); // fmstat
1482 o4(0x03A00001); // moveq r0,#1
1483 o4(0x13A00000); // movne r0,#0
1484#else
Jack Palevichc0f25332009-08-25 12:23:43 -07001485 callRuntime((void*) runtime_is_zero_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001486#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001487 break;
1488 default:
1489 error("gUnaryCmp unsupported type");
1490 break;
1491 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001492 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001493 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001494 }
1495
1496 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001497 Type* pR0Type = getR0Type();
1498 TypeTag tag = collapseType(pR0Type->tag);
1499 switch(tag) {
1500 case TY_INT:
1501 switch(op) {
1502 case OP_MINUS:
1503 o4(0xE3A01000); // mov r1, #0
1504 o4(0xE0410000); // sub r0,r1,r0
1505 break;
1506 case OP_BIT_NOT:
1507 o4(0xE1E00000); // mvn r0, r0
1508 break;
1509 default:
1510 error("Unknown unary op %d\n", op);
1511 break;
1512 }
1513 break;
1514 case TY_FLOAT:
1515 case TY_DOUBLE:
1516 switch (op) {
1517 case OP_MINUS:
1518 if (tag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001519#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001520 o4(0xEEF17A67); // fnegs s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001521#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001522 callRuntime((void*) runtime_op_neg_f);
Jack Palevich30321cb2009-08-20 15:34:23 -07001523#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001524 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07001525#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001526 o4(0xEEB17B47); // fnegd d7, d7
Jack Palevich30321cb2009-08-20 15:34:23 -07001527#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001528 callRuntime((void*) runtime_op_neg_d);
Jack Palevich30321cb2009-08-20 15:34:23 -07001529#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001530 }
1531 break;
1532 case OP_BIT_NOT:
1533 error("Can't apply '~' operator to a float or double.");
1534 break;
1535 default:
1536 error("Unknown unary op %d\n", op);
1537 break;
1538 }
1539 break;
1540 default:
1541 error("genUnaryOp unsupported type");
1542 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001543 }
Jack Palevich22305132009-05-13 10:58:45 -07001544 }
1545
Jack Palevich1cdef202009-05-22 12:06:27 -07001546 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001547 Type* pR0Type = getR0Type();
1548 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001549
1550#ifdef ARM_USE_VFP
1551 switch (r0ct ) {
1552 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001553 o4(0xED6D7A01); // fstmfds sp!,{s15}
Jack Palevich30321cb2009-08-20 15:34:23 -07001554 mStackUse += 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001555 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001556 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001557 o4(0xED2D7B02); // fstmfdd sp!,{d7}
Jack Palevich30321cb2009-08-20 15:34:23 -07001558 mStackUse += 8;
Jack Palevichc0f25332009-08-25 12:23:43 -07001559 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001560 default:
1561 o4(0xE92D0001); // stmfd sp!,{r0}
1562 mStackUse += 4;
1563 }
1564#else
1565
Jack Palevichb7718b92009-07-09 22:00:24 -07001566 if (r0ct != TY_DOUBLE) {
1567 o4(0xE92D0001); // stmfd sp!,{r0}
1568 mStackUse += 4;
1569 } else {
1570 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1571 mStackUse += 8;
1572 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001573#endif
Jack Palevich8df46192009-07-07 14:48:51 -07001574 pushType();
-b master422972c2009-06-17 19:13:52 -07001575 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001576 }
1577
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001578 virtual void over() {
1579 // We know it's only used for int-ptr ops (++/--)
1580
1581 Type* pR0Type = getR0Type();
1582 TypeTag r0ct = collapseType(pR0Type->tag);
1583
1584 Type* pTOSType = getTOSType();
1585 TypeTag tosct = collapseType(pTOSType->tag);
1586
1587 assert (r0ct == TY_INT && tosct == TY_INT);
1588
1589 o4(0xE8BD0002); // ldmfd sp!,{r1}
1590 o4(0xE92D0001); // stmfd sp!,{r0}
1591 o4(0xE92D0002); // stmfd sp!,{r1}
1592 overType();
1593 mStackUse += 4;
1594 }
1595
Jack Palevich58c30ee2009-07-17 16:35:23 -07001596 virtual void popR0() {
1597 Type* pTOSType = getTOSType();
Jack Palevich30321cb2009-08-20 15:34:23 -07001598 TypeTag tosct = collapseType(pTOSType->tag);
1599#ifdef ARM_USE_VFP
1600 if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
Jack Palevichc0f25332009-08-25 12:23:43 -07001601 error("Unsupported popR0 float/double");
Jack Palevich30321cb2009-08-20 15:34:23 -07001602 }
1603#endif
1604 switch (tosct){
Jack Palevich58c30ee2009-07-17 16:35:23 -07001605 case TY_INT:
1606 case TY_FLOAT:
1607 o4(0xE8BD0001); // ldmfd sp!,{r0}
1608 mStackUse -= 4;
1609 break;
1610 case TY_DOUBLE:
1611 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1612 mStackUse -= 8;
1613 break;
1614 default:
1615 error("Can't pop this type.");
1616 break;
1617 }
1618 popType();
1619 LOG_STACK("popR0: %d\n", mStackUse);
1620 }
1621
1622 virtual void storeR0ToTOS() {
1623 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001624 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001625 Type* pDestType = pPointerType->pHead;
1626 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001627 o4(0xE8BD0004); // ldmfd sp!,{r2}
1628 popType();
-b master422972c2009-06-17 19:13:52 -07001629 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001630 switch (pDestType->tag) {
1631 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001632 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001633 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001634 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001635 case TY_FLOAT:
1636#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001637 o4(0xEDC27A00); // fsts s15, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001638#else
1639 o4(0xE5820000); // str r0, [r2]
1640#endif
1641 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001642 case TY_SHORT:
1643 o4(0xE1C200B0); // strh r0, [r2]
1644 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001645 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001646 o4(0xE5C20000); // strb r0, [r2]
1647 break;
1648 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001649#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001650 o4(0xED827B00); // fstd d7, [r2, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001651#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001652 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001653#endif
Jack Palevich9eed7a22009-07-06 17:24:34 -07001654 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001655 case TY_STRUCT:
1656 {
1657 int size = sizeOf(pDestType);
1658 if (size > 0) {
1659 liReg(size, 1);
1660 callRuntime((void*) runtime_structCopy);
1661 }
1662 }
1663 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001664 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001665 error("storeR0ToTOS: unimplemented type %d",
1666 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001667 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001668 }
Jack Palevich02effee2009-11-09 12:52:45 +08001669 setR0Type(pDestType);
Jack Palevich22305132009-05-13 10:58:45 -07001670 }
1671
Jack Palevich58c30ee2009-07-17 16:35:23 -07001672 virtual void loadR0FromR0() {
1673 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001674 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001675 Type* pNewType = pPointerType->pHead;
1676 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001677 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001678 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001679 case TY_INT:
1680 o4(0xE5900000); // ldr r0, [r0]
1681 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001682 case TY_FLOAT:
1683#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001684 o4(0xEDD07A00); // flds s15, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001685#else
1686 o4(0xE5900000); // ldr r0, [r0]
1687#endif
1688 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001689 case TY_SHORT:
1690 o4(0xE1D000F0); // ldrsh r0, [r0]
1691 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001692 case TY_CHAR:
1693 o4(0xE5D00000); // ldrb r0, [r0]
1694 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001695 case TY_DOUBLE:
Jack Palevich30321cb2009-08-20 15:34:23 -07001696#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001697 o4(0xED907B00); // fldd d7, [r0, #0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001698#else
Jack Palevicha7813bd2009-07-29 11:36:04 -07001699 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevich30321cb2009-08-20 15:34:23 -07001700#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001701 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001702 case TY_ARRAY:
1703 pNewType = pNewType->pTail;
1704 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07001705 case TY_STRUCT:
1706 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001707 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001708 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001709 break;
1710 }
Jack Palevich80e49722009-08-04 15:39:49 -07001711 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001712 }
1713
Jack Palevichb5e33312009-07-30 19:06:34 -07001714 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001715 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001716 // Local, fp relative
Jack Palevich9221bcc2009-08-26 16:15:07 -07001717
1718 size_t immediate = 0;
1719 bool inRange = false;
Jack Palevich4d93f302009-05-15 13:30:00 -07001720 if (ea < 0) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001721 inRange = encode12BitImmediate(-ea, &immediate);
1722 o4(0xE24B0000 | immediate); // sub r0, fp, #ea
Jack Palevich4d93f302009-05-15 13:30:00 -07001723 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07001724 inRange = encode12BitImmediate(ea, &immediate);
1725 o4(0xE28B0000 | immediate); // add r0, fp, #ea
1726 }
1727 if (! inRange) {
1728 error("Offset out of range: %08x", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -07001729 }
Jack Palevichbd894902009-05-14 19:35:31 -07001730 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001731 // Global, absolute.
1732 o4(0xE59F0000); // ldr r0, .L1
1733 o4(0xEA000000); // b .L99
1734 o4(ea); // .L1: .word 0
1735 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001736 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001737 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001738 }
1739
Jack Palevich9f51a262009-07-29 16:22:26 -07001740 virtual int leaForward(int ea, Type* pPointerType) {
1741 setR0Type(pPointerType);
1742 int result = ea;
1743 int pc = getPC();
1744 int offset = 0;
1745 if (ea) {
1746 offset = (pc - ea - 8) >> 2;
1747 if ((offset & 0xffff) != offset) {
1748 error("function forward reference out of bounds");
1749 }
1750 } else {
1751 offset = 0;
1752 }
1753 o4(0xE59F0000 | offset); // ldr r0, .L1
1754
1755 if (ea == 0) {
1756 o4(0xEA000000); // b .L99
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001757 result = getPC();
1758 o4(ea); // .L1: .word 0
Jack Palevich9f51a262009-07-29 16:22:26 -07001759 // .L99:
1760 }
1761 return result;
1762 }
1763
Jack Palevichb6154502009-08-04 14:56:09 -07001764 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001765 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001766 if (isPointerType(pType) && isPointerType(pR0Type)) {
1767 Type* pA = pR0Type;
1768 Type* pB = pType;
1769 // Array decays to pointer
1770 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1771 pA = pA->pTail;
1772 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001773 if (! (typeEqual(pA, pB)
1774 || pB->pHead->tag == TY_VOID
1775 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1776 )) {
1777 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07001778 }
Jack Palevichb6154502009-08-04 14:56:09 -07001779 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001780 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001781 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001782 TypeTag r0Tag = collapseType(pR0Type->tag);
1783 TypeTag destTag = collapseType(pType->tag);
1784 if (r0Tag == TY_INT) {
1785 if (destTag == TY_FLOAT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001786#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001787 o4(0xEE070A90); // fmsr s15, r0
1788 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001789
1790#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001791 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07001792#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001793 } else {
1794 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001795#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001796 o4(0xEE070A90); // fmsr s15, r0
1797 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001798
1799#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001800 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001801#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001802 }
1803 } else if (r0Tag == TY_FLOAT) {
1804 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001805#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001806 o4(0xEEFD7AE7); // ftosizs s15, s15
1807 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001808#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001809 callRuntime((void*) runtime_float_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001810#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001811 } else {
1812 assert(destTag == TY_DOUBLE);
Jack Palevich30321cb2009-08-20 15:34:23 -07001813#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07001814 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001815#else
Jack Palevichb7718b92009-07-09 22:00:24 -07001816 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07001817#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07001818 }
1819 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001820 if (r0Tag == TY_DOUBLE) {
1821 if (destTag == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07001822#ifdef ARM_USE_VFP
Jack Palevichc408bbf2009-09-08 12:07:32 -07001823 o4(0xEEFD7BC7); // ftosizd s15, d7
1824 o4(0xEE170A90); // fmrs r0, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07001825#else
Jack Palevichc408bbf2009-09-08 12:07:32 -07001826 callRuntime((void*) runtime_double_to_int);
Jack Palevich30321cb2009-08-20 15:34:23 -07001827#endif
Jack Palevichc408bbf2009-09-08 12:07:32 -07001828 } else {
1829 if(destTag == TY_FLOAT) {
1830#ifdef ARM_USE_VFP
1831 o4(0xEEF77BC7); // fcvtsd s15, d7
1832#else
1833 callRuntime((void*) runtime_double_to_float);
1834#endif
1835 } else {
1836 incompatibleTypes(pR0Type, pType);
1837 }
1838 }
Jack Palevichb7718b92009-07-09 22:00:24 -07001839 } else {
Jack Palevichc408bbf2009-09-08 12:07:32 -07001840 incompatibleTypes(pR0Type, pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001841 }
1842 }
Jack Palevich8df46192009-07-07 14:48:51 -07001843 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001844 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001845 }
1846
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001847 virtual int beginFunctionCallArguments() {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001848 int pc = getPC();
1849 o4(0xE24DDF00); // Placeholder sub sp, sp, #0
1850 return pc;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001851 }
1852
Jack Palevich8148c5b2009-07-16 18:24:47 -07001853 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001854 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001855 Type* pR0Type = getR0Type();
1856 TypeTag r0ct = collapseType(pR0Type->tag);
Jack Palevich30321cb2009-08-20 15:34:23 -07001857#ifdef ARM_USE_VFP
Jack Palevichb7718b92009-07-09 22:00:24 -07001858 switch(r0ct) {
1859 case TY_INT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001860 if (l < 0 || l > 4096-4) {
1861 error("l out of range for stack offset: 0x%08x", l);
1862 }
1863 o4(0xE58D0000 | l); // str r0, [sp, #l]
1864 return 4;
Jack Palevichc0f25332009-08-25 12:23:43 -07001865 case TY_FLOAT:
Jack Palevich30321cb2009-08-20 15:34:23 -07001866 if (l < 0 || l > 1020 || (l & 3)) {
1867 error("l out of range for stack offset: 0x%08x", l);
1868 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001869 o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l]
Jack Palevich30321cb2009-08-20 15:34:23 -07001870 return 4;
1871 case TY_DOUBLE: {
1872 // Align to 8 byte boundary
1873 int l2 = (l + 7) & ~7;
1874 if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1875 error("l out of range for stack offset: 0x%08x", l);
1876 }
Jack Palevichc0f25332009-08-25 12:23:43 -07001877 o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2]
Jack Palevich30321cb2009-08-20 15:34:23 -07001878 return (l2 - l) + 8;
1879 }
1880 default:
1881 assert(false);
1882 return 0;
1883 }
1884#else
1885 switch(r0ct) {
1886 case TY_INT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001887 case TY_FLOAT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001888 if (l < 0 || l > 4096-4) {
1889 error("l out of range for stack offset: 0x%08x", l);
1890 }
1891 o4(0xE58D0000 + l); // str r0, [sp, #l]
1892 return 4;
1893 case TY_DOUBLE: {
1894 // Align to 8 byte boundary
1895 int l2 = (l + 7) & ~7;
1896 if (l2 < 0 || l2 > 4096-8) {
1897 error("l out of range for stack offset: 0x%08x", l);
1898 }
1899 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1900 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1901 return (l2 - l) + 8;
1902 }
1903 default:
1904 assert(false);
1905 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001906 }
Jack Palevich30321cb2009-08-20 15:34:23 -07001907#endif
Jack Palevich7810bc92009-05-15 14:31:47 -07001908 }
1909
Jack Palevichb7718b92009-07-09 22:00:24 -07001910 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001911 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001912 // Have to calculate register arg count from actual stack size,
1913 // in order to properly handle ... functions.
1914 int regArgCount = l >> 2;
1915 if (regArgCount > 4) {
1916 regArgCount = 4;
1917 }
1918 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001919 argumentStackUse -= regArgCount * 4;
1920 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1921 }
1922 mStackUse += argumentStackUse;
1923
1924 // Align stack.
1925 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1926 * STACK_ALIGNMENT);
1927 mStackAlignmentAdjustment = 0;
1928 if (missalignment > 0) {
1929 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1930 }
1931 l += mStackAlignmentAdjustment;
1932
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001933 if (l < 0 || l > 0x3FC) {
1934 error("L out of range for stack adjustment: 0x%08x", l);
1935 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001936 flush();
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001937 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001938 mStackUse += mStackAlignmentAdjustment;
1939 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1940 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001941 }
1942
Jack Palevich8df46192009-07-07 14:48:51 -07001943 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001944 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001945 // Forward calls are always short (local)
Jack Palevichd30a2ce2009-09-09 19:08:54 -07001946 int pc = getPC();
1947 o4(0xEB000000 | encodeAddress(symbol));
1948 return pc;
Jack Palevich22305132009-05-13 10:58:45 -07001949 }
1950
Jack Palevich8df46192009-07-07 14:48:51 -07001951 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001952 assert(pFunc->tag == TY_FUNC);
1953 popType(); // Get rid of indirect fn pointer type
Jack Palevich7810bc92009-05-15 14:31:47 -07001954 int argCount = l >> 2;
1955 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001956 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001957 if (adjustedL < 0 || adjustedL > 4096-4) {
1958 error("l out of range for stack offset: 0x%08x", l);
1959 }
1960 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1961 o4(0xE12FFF3C); // blx r12
Jack Palevich30321cb2009-08-20 15:34:23 -07001962 Type* pReturnType = pFunc->pHead;
1963 setR0Type(pReturnType);
1964#ifdef ARM_USE_VFP
1965 switch(pReturnType->tag) {
1966 case TY_FLOAT:
Jack Palevichc0f25332009-08-25 12:23:43 -07001967 o4(0xEE070A90); // fmsr s15, r0
1968 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001969 case TY_DOUBLE:
Jack Palevichc0f25332009-08-25 12:23:43 -07001970 o4(0xEC410B17); // fmdrr d7, r0, r1
1971 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001972 default:
Jack Palevichc0f25332009-08-25 12:23:43 -07001973 break;
Jack Palevich30321cb2009-08-20 15:34:23 -07001974 }
1975#endif
Jack Palevich22305132009-05-13 10:58:45 -07001976 }
1977
Jack Palevichb7718b92009-07-09 22:00:24 -07001978 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001979 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001980 // Have to calculate register arg count from actual stack size,
1981 // in order to properly handle ... functions.
1982 int regArgCount = l >> 2;
1983 if (regArgCount > 4) {
1984 regArgCount = 4;
1985 }
1986 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001987 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1988 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001989 if (stackUse) {
1990 if (stackUse < 0 || stackUse > 255) {
1991 error("L out of range for stack adjustment: 0x%08x", l);
1992 }
1993 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001994 mStackUse -= stackUse * 4;
1995 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001996 }
Jack Palevich22305132009-05-13 10:58:45 -07001997 }
1998
Jack Palevicha6535612009-05-13 16:24:17 -07001999 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07002000 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07002001 }
2002
2003 /* output a symbol and patch all calls to it */
2004 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07002005 int n;
2006 int base = getBase();
2007 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07002008 while (t) {
2009 int data = * (int*) t;
2010 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
2011 if (decodedOffset == 0) {
2012 n = 0;
2013 } else {
2014 n = base + decodedOffset; /* next value */
2015 }
2016 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
2017 | encodeRelAddress(pc - t - 8);
2018 t = n;
2019 }
2020 }
2021
Jack Palevich9f51a262009-07-29 16:22:26 -07002022 /* output a symbol and patch all calls to it */
2023 virtual void resolveForward(int t) {
2024 if (t) {
2025 int pc = getPC();
2026 *(int *) t = pc;
2027 }
2028 }
2029
Jack Palevich1cdef202009-05-22 12:06:27 -07002030 virtual int finishCompile() {
2031#if defined(__arm__)
2032 const long base = long(getBase());
2033 const long curr = long(getPC());
2034 int err = cacheflush(base, curr, 0);
2035 return err;
2036#else
2037 return 0;
2038#endif
2039 }
2040
Jack Palevich9eed7a22009-07-06 17:24:34 -07002041 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002042 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002043 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002044 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07002045 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002046 case TY_CHAR:
2047 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002048 case TY_SHORT:
Jack Palevich9221bcc2009-08-26 16:15:07 -07002049 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002050 case TY_DOUBLE:
2051 return 8;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002052 case TY_ARRAY:
2053 return alignmentOf(pType->pHead);
2054 case TY_STRUCT:
2055 return pType->pHead->alignment & 0x7fffffff;
2056 case TY_FUNC:
2057 error("alignment of func not supported");
2058 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002059 default:
2060 return 4;
2061 }
2062 }
2063
2064 /**
2065 * Array element alignment (in bytes) for this type of data.
2066 */
2067 virtual size_t sizeOf(Type* pType){
2068 switch(pType->tag) {
2069 case TY_INT:
2070 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002071 case TY_SHORT:
2072 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002073 case TY_CHAR:
2074 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002075 case TY_FLOAT:
2076 return 4;
2077 case TY_DOUBLE:
2078 return 8;
2079 case TY_POINTER:
2080 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002081 case TY_ARRAY:
2082 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07002083 case TY_STRUCT:
2084 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07002085 default:
2086 error("Unsupported type %d", pType->tag);
2087 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002088 }
2089 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07002090
Jack Palevich22305132009-05-13 10:58:45 -07002091 private:
Jack Palevicha6535612009-05-13 16:24:17 -07002092
2093 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
2094
2095 /** Encode a relative address that might also be
2096 * a label.
2097 */
2098 int encodeAddress(int value) {
2099 int base = getBase();
2100 if (value >= base && value <= getPC() ) {
2101 // This is a label, encode it relative to the base.
2102 value = value - base;
2103 }
2104 return encodeRelAddress(value);
2105 }
2106
2107 int encodeRelAddress(int value) {
2108 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
2109 }
Jack Palevich22305132009-05-13 10:58:45 -07002110
Jack Palevichb7718b92009-07-09 22:00:24 -07002111 int calcRegArgCount(Type* pDecl) {
2112 int reg = 0;
2113 Type* pArgs = pDecl->pTail;
2114 while (pArgs && reg < 4) {
2115 Type* pArg = pArgs->pHead;
2116 if ( pArg->tag == TY_DOUBLE) {
2117 int evenReg = (reg + 1) & ~1;
2118 if (evenReg >= 4) {
2119 break;
2120 }
2121 reg = evenReg + 2;
2122 } else {
2123 reg++;
2124 }
2125 pArgs = pArgs->pTail;
2126 }
2127 return reg;
2128 }
2129
Jack Palevich58c30ee2009-07-17 16:35:23 -07002130 void setupIntPtrArgs() {
2131 o4(0xE8BD0002); // ldmfd sp!,{r1}
2132 mStackUse -= 4;
2133 popType();
2134 }
2135
Jack Palevich30321cb2009-08-20 15:34:23 -07002136 /* Pop TOS to R1 (use s14 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002137 * Make sure both R0 and TOS are floats. (Could be ints)
2138 * We know that at least one of R0 and TOS is already a float
2139 */
2140 void setupFloatArgs() {
2141 Type* pR0Type = getR0Type();
2142 Type* pTOSType = getTOSType();
2143 TypeTag tagR0 = collapseType(pR0Type->tag);
2144 TypeTag tagTOS = collapseType(pTOSType->tag);
2145 if (tagR0 != TY_FLOAT) {
2146 assert(tagR0 == TY_INT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002147#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002148 o4(0xEE070A90); // fmsr s15, r0
2149 o4(0xEEF87AE7); // fsitos s15, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002150#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002151 callRuntime((void*) runtime_int_to_float);
Jack Palevich30321cb2009-08-20 15:34:23 -07002152#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002153 }
2154 if (tagTOS != TY_FLOAT) {
2155 assert(tagTOS == TY_INT);
2156 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002157#ifdef ARM_USE_VFP
2158 o4(0xECBD7A01); // fldmfds sp!, {s14}
Jack Palevichc0f25332009-08-25 12:23:43 -07002159 o4(0xEEB87AC7); // fsitos s14, s14
Jack Palevich30321cb2009-08-20 15:34:23 -07002160#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002161 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
2162 o4(0xE59D0004); // ldr r0, [sp, #4]
2163 callRuntime((void*) runtime_int_to_float);
2164 o4(0xE1A01000); // mov r1, r0
2165 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
2166 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002167#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002168 } else {
2169 // Pop TOS
Jack Palevich30321cb2009-08-20 15:34:23 -07002170#ifdef ARM_USE_VFP
2171 o4(0xECBD7A01); // fldmfds sp!, {s14}
2172
2173#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002174 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich30321cb2009-08-20 15:34:23 -07002175#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002176 }
2177 mStackUse -= 4;
2178 popType();
2179 }
2180
Jack Palevich30321cb2009-08-20 15:34:23 -07002181 /* Pop TOS into R2..R3 (use D6 if VFP)
Jack Palevichb7718b92009-07-09 22:00:24 -07002182 * Make sure both R0 and TOS are doubles. Could be floats or ints.
2183 * We know that at least one of R0 and TOS are already a double.
2184 */
2185
2186 void setupDoubleArgs() {
2187 Type* pR0Type = getR0Type();
2188 Type* pTOSType = getTOSType();
2189 TypeTag tagR0 = collapseType(pR0Type->tag);
2190 TypeTag tagTOS = collapseType(pTOSType->tag);
2191 if (tagR0 != TY_DOUBLE) {
2192 if (tagR0 == TY_INT) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002193#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002194 o4(0xEE070A90); // fmsr s15, r0
2195 o4(0xEEB87BE7); // fsitod d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002196
2197#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002198 callRuntime((void*) runtime_int_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002199#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002200 } else {
2201 assert(tagR0 == TY_FLOAT);
Jack Palevich30321cb2009-08-20 15:34:23 -07002202#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002203 o4(0xEEB77AE7); // fcvtds d7, s15
Jack Palevich30321cb2009-08-20 15:34:23 -07002204#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002205 callRuntime((void*) runtime_float_to_double);
Jack Palevich30321cb2009-08-20 15:34:23 -07002206#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002207 }
2208 }
2209 if (tagTOS != TY_DOUBLE) {
Jack Palevich30321cb2009-08-20 15:34:23 -07002210#ifdef ARM_USE_VFP
2211 if (tagTOS == TY_INT) {
2212 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002213 o4(0xEEB86BE6); // fsitod d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002214 } else {
2215 assert(tagTOS == TY_FLOAT);
2216 o4(0xECFD6A01); // fldmfds sp!,{s13}
Jack Palevichc0f25332009-08-25 12:23:43 -07002217 o4(0xEEB76AE6); // fcvtds d6, s13
Jack Palevich30321cb2009-08-20 15:34:23 -07002218 }
2219#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002220 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
2221 o4(0xE59D0008); // ldr r0, [sp, #8]
2222 if (tagTOS == TY_INT) {
2223 callRuntime((void*) runtime_int_to_double);
2224 } else {
2225 assert(tagTOS == TY_FLOAT);
2226 callRuntime((void*) runtime_float_to_double);
2227 }
2228 o4(0xE1A02000); // mov r2, r0
2229 o4(0xE1A03001); // mov r3, r1
2230 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
2231 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
Jack Palevich30321cb2009-08-20 15:34:23 -07002232#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002233 mStackUse -= 4;
2234 } else {
Jack Palevich30321cb2009-08-20 15:34:23 -07002235#ifdef ARM_USE_VFP
Jack Palevichc0f25332009-08-25 12:23:43 -07002236 o4(0xECBD6B02); // fldmfdd sp!, {d6}
Jack Palevich30321cb2009-08-20 15:34:23 -07002237#else
Jack Palevichb7718b92009-07-09 22:00:24 -07002238 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
Jack Palevich30321cb2009-08-20 15:34:23 -07002239#endif
Jack Palevichb7718b92009-07-09 22:00:24 -07002240 mStackUse -= 8;
2241 }
2242 popType();
2243 }
2244
Jack Palevicha8f427f2009-07-13 18:40:08 -07002245 void liReg(int t, int reg) {
2246 assert(reg >= 0 && reg < 16);
2247 int rN = (reg & 0xf) << 12;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002248 size_t encodedImmediate;
2249 if (encode12BitImmediate(t, &encodedImmediate)) {
2250 o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
2251 } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07002252 // mvn means move constant ^ ~0
Jack Palevich9221bcc2009-08-26 16:15:07 -07002253 o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002254 } else {
Jack Palevich9221bcc2009-08-26 16:15:07 -07002255 o4(0xE51F0000 | rN); // ldr rN, .L3
2256 o4(0xEA000000); // b .L99
2257 o4(t); // .L3: .word 0
Jack Palevicha8f427f2009-07-13 18:40:08 -07002258 // .L99:
2259 }
2260 }
2261
Jack Palevichc408bbf2009-09-08 12:07:32 -07002262 void incompatibleTypes(Type* pR0Type, Type* pType) {
2263 error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag);
2264 }
2265
Jack Palevichb7718b92009-07-09 22:00:24 -07002266 void callRuntime(void* fn) {
2267 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07002268 o4(0xEA000000); // b .L99
2269 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07002270 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07002271 }
2272
Jack Palevichb7718b92009-07-09 22:00:24 -07002273 // Integer math:
2274
2275 static int runtime_DIV(int b, int a) {
2276 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07002277 }
2278
Jack Palevichb7718b92009-07-09 22:00:24 -07002279 static int runtime_MOD(int b, int a) {
2280 return a % b;
2281 }
2282
Jack Palevich9221bcc2009-08-26 16:15:07 -07002283 static void runtime_structCopy(void* src, size_t size, void* dest) {
2284 memcpy(dest, src, size);
2285 }
2286
Jack Palevich30321cb2009-08-20 15:34:23 -07002287#ifndef ARM_USE_VFP
2288
Jack Palevichb7718b92009-07-09 22:00:24 -07002289 // Comparison to zero
2290
2291 static int runtime_is_non_zero_f(float a) {
2292 return a != 0;
2293 }
2294
2295 static int runtime_is_non_zero_d(double a) {
2296 return a != 0;
2297 }
2298
2299 // Comparison to zero
2300
2301 static int runtime_is_zero_f(float a) {
2302 return a == 0;
2303 }
2304
2305 static int runtime_is_zero_d(double a) {
2306 return a == 0;
2307 }
2308
2309 // Type conversion
2310
2311 static int runtime_float_to_int(float a) {
2312 return (int) a;
2313 }
2314
2315 static double runtime_float_to_double(float a) {
2316 return (double) a;
2317 }
2318
2319 static int runtime_double_to_int(double a) {
2320 return (int) a;
2321 }
2322
2323 static float runtime_double_to_float(double a) {
2324 return (float) a;
2325 }
2326
2327 static float runtime_int_to_float(int a) {
2328 return (float) a;
2329 }
2330
2331 static double runtime_int_to_double(int a) {
2332 return (double) a;
2333 }
2334
2335 // Comparisons float
2336
2337 static int runtime_cmp_eq_ff(float b, float a) {
2338 return a == b;
2339 }
2340
2341 static int runtime_cmp_ne_ff(float b, float a) {
2342 return a != b;
2343 }
2344
2345 static int runtime_cmp_lt_ff(float b, float a) {
2346 return a < b;
2347 }
2348
2349 static int runtime_cmp_le_ff(float b, float a) {
2350 return a <= b;
2351 }
2352
2353 static int runtime_cmp_ge_ff(float b, float a) {
2354 return a >= b;
2355 }
2356
2357 static int runtime_cmp_gt_ff(float b, float a) {
2358 return a > b;
2359 }
2360
2361 // Comparisons double
2362
2363 static int runtime_cmp_eq_dd(double b, double a) {
2364 return a == b;
2365 }
2366
2367 static int runtime_cmp_ne_dd(double b, double a) {
2368 return a != b;
2369 }
2370
2371 static int runtime_cmp_lt_dd(double b, double a) {
2372 return a < b;
2373 }
2374
2375 static int runtime_cmp_le_dd(double b, double a) {
2376 return a <= b;
2377 }
2378
2379 static int runtime_cmp_ge_dd(double b, double a) {
2380 return a >= b;
2381 }
2382
2383 static int runtime_cmp_gt_dd(double b, double a) {
2384 return a > b;
2385 }
2386
2387 // Math float
2388
2389 static float runtime_op_add_ff(float b, float a) {
2390 return a + b;
2391 }
2392
2393 static float runtime_op_sub_ff(float b, float a) {
2394 return a - b;
2395 }
2396
2397 static float runtime_op_mul_ff(float b, float a) {
2398 return a * b;
2399 }
2400
2401 static float runtime_op_div_ff(float b, float a) {
2402 return a / b;
2403 }
2404
2405 static float runtime_op_neg_f(float a) {
2406 return -a;
2407 }
2408
2409 // Math double
2410
2411 static double runtime_op_add_dd(double b, double a) {
2412 return a + b;
2413 }
2414
2415 static double runtime_op_sub_dd(double b, double a) {
2416 return a - b;
2417 }
2418
2419 static double runtime_op_mul_dd(double b, double a) {
2420 return a * b;
2421 }
2422
2423 static double runtime_op_div_dd(double b, double a) {
2424 return a / b;
2425 }
2426
2427 static double runtime_op_neg_d(double a) {
2428 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07002429 }
-b master422972c2009-06-17 19:13:52 -07002430
Jack Palevich30321cb2009-08-20 15:34:23 -07002431#endif
2432
-b master422972c2009-06-17 19:13:52 -07002433 static const int STACK_ALIGNMENT = 8;
2434 int mStackUse;
2435 // This variable holds the amount we adjusted the stack in the most
2436 // recent endFunctionCallArguments call. It's examined by the
2437 // following adjustStackAfterCall call.
2438 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07002439 };
2440
Jack Palevich09555c72009-05-27 12:25:55 -07002441#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002442
2443#ifdef PROVIDE_X86_CODEGEN
2444
Jack Palevich21a15a22009-05-11 14:49:29 -07002445 class X86CodeGenerator : public CodeGenerator {
2446 public:
2447 X86CodeGenerator() {}
2448 virtual ~X86CodeGenerator() {}
2449
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002450 /* returns address to patch with local variable size
2451 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002452 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002453 o(0xe58955); /* push %ebp, mov %esp, %ebp */
2454 return oad(0xec81, 0); /* sub $xxx, %esp */
2455 }
2456
Jack Palevichb7718b92009-07-09 22:00:24 -07002457 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002458 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07002459 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002460 }
2461
Jack Palevich21a15a22009-05-11 14:49:29 -07002462 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002463 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002464 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002465 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002466 }
2467
Jack Palevich1a539db2009-07-08 13:04:41 -07002468 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07002469 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002470 switch (pType->tag) {
2471 case TY_FLOAT:
2472 oad(0x05D9, address); // flds
2473 break;
2474 case TY_DOUBLE:
2475 oad(0x05DD, address); // fldl
2476 break;
2477 default:
2478 assert(false);
2479 break;
2480 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002481 }
2482
Jack Palevich9221bcc2009-08-26 16:15:07 -07002483 virtual void addStructOffsetR0(int offset, Type* pType) {
2484 if (offset) {
2485 oad(0x05, offset); // addl offset, %eax
2486 }
2487 setR0Type(pType, ET_LVALUE);
2488 }
2489
Jack Palevich22305132009-05-13 10:58:45 -07002490 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002491 return psym(0xe9, t);
2492 }
2493
2494 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07002495 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002496 Type* pR0Type = getR0Type();
2497 TypeTag tagR0 = pR0Type->tag;
2498 bool isFloatR0 = isFloatTag(tagR0);
2499 if (isFloatR0) {
2500 o(0xeed9); // fldz
2501 o(0xe9da); // fucompp
2502 o(0xe0df); // fnstsw %ax
2503 o(0x9e); // sahf
2504 } else {
2505 o(0xc085); // test %eax, %eax
2506 }
2507 // Use two output statements to generate one instruction.
2508 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07002509 return psym(0x84 + l, t);
2510 }
2511
Jack Palevich58c30ee2009-07-17 16:35:23 -07002512 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002513 Type* pR0Type = getR0Type();
2514 Type* pTOSType = getTOSType();
2515 TypeTag tagR0 = pR0Type->tag;
2516 TypeTag tagTOS = pTOSType->tag;
2517 bool isFloatR0 = isFloatTag(tagR0);
2518 bool isFloatTOS = isFloatTag(tagTOS);
2519 if (!isFloatR0 && !isFloatTOS) {
2520 int t = decodeOp(op);
2521 o(0x59); /* pop %ecx */
2522 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002523 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002524 o(0x0f); /* setxx %al */
2525 o(t + 0x90);
2526 o(0xc0);
2527 popType();
2528 } else {
2529 setupFloatOperands();
2530 switch (op) {
2531 case OP_EQUALS:
2532 o(0xe9da); // fucompp
2533 o(0xe0df); // fnstsw %ax
2534 o(0x9e); // sahf
2535 o(0xc0940f); // sete %al
2536 o(0xc29b0f); // setnp %dl
2537 o(0xd021); // andl %edx, %eax
2538 break;
2539 case OP_NOT_EQUALS:
2540 o(0xe9da); // fucompp
2541 o(0xe0df); // fnstsw %ax
2542 o(0x9e); // sahf
2543 o(0xc0950f); // setne %al
2544 o(0xc29a0f); // setp %dl
2545 o(0xd009); // orl %edx, %eax
2546 break;
2547 case OP_GREATER_EQUAL:
2548 o(0xe9da); // fucompp
2549 o(0xe0df); // fnstsw %ax
2550 o(0x05c4f6); // testb $5, %ah
2551 o(0xc0940f); // sete %al
2552 break;
2553 case OP_LESS:
2554 o(0xc9d9); // fxch %st(1)
2555 o(0xe9da); // fucompp
2556 o(0xe0df); // fnstsw %ax
2557 o(0x9e); // sahf
2558 o(0xc0970f); // seta %al
2559 break;
2560 case OP_LESS_EQUAL:
2561 o(0xc9d9); // fxch %st(1)
2562 o(0xe9da); // fucompp
2563 o(0xe0df); // fnstsw %ax
2564 o(0x9e); // sahf
2565 o(0xc0930f); // setea %al
2566 break;
2567 case OP_GREATER:
2568 o(0xe9da); // fucompp
2569 o(0xe0df); // fnstsw %ax
2570 o(0x45c4f6); // testb $69, %ah
2571 o(0xc0940f); // sete %al
2572 break;
2573 default:
2574 error("Unknown comparison op");
2575 }
2576 o(0xc0b60f); // movzbl %al, %eax
2577 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002578 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07002579 }
2580
Jack Palevich546b2242009-05-13 15:10:04 -07002581 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002582 Type* pR0Type = getR0Type();
2583 Type* pTOSType = getTOSType();
2584 TypeTag tagR0 = pR0Type->tag;
2585 TypeTag tagTOS = pTOSType->tag;
2586 bool isFloatR0 = isFloatTag(tagR0);
2587 bool isFloatTOS = isFloatTag(tagTOS);
2588 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07002589 bool isPtrR0 = isPointerTag(tagR0);
2590 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002591 if (isPtrR0 || isPtrTOS) {
2592 if (isPtrR0 && isPtrTOS) {
2593 if (op != OP_MINUS) {
2594 error("Unsupported pointer-pointer operation %d.", op);
2595 }
2596 if (! typeEqual(pR0Type, pTOSType)) {
2597 error("Incompatible pointer types for subtraction.");
2598 }
2599 o(0x59); /* pop %ecx */
2600 o(decodeOp(op));
2601 popType();
2602 setR0Type(mkpInt);
2603 int size = sizeOf(pR0Type->pHead);
2604 if (size != 1) {
2605 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002606 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002607 // TODO: Optimize for power-of-two.
2608 genOp(OP_DIV);
2609 }
2610 } else {
2611 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2612 error("Unsupported pointer-scalar operation %d", op);
2613 }
Jack Palevichb6154502009-08-04 14:56:09 -07002614 Type* pPtrType = getPointerArithmeticResultType(
2615 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002616 o(0x59); /* pop %ecx */
2617 int size = sizeOf(pPtrType->pHead);
2618 if (size != 1) {
2619 // TODO: Optimize for power-of-two.
2620 if (isPtrR0) {
2621 oad(0xC969, size); // imull $size, %ecx
2622 } else {
2623 oad(0xC069, size); // mul $size, %eax
2624 }
2625 }
2626 o(decodeOp(op));
2627 popType();
2628 setR0Type(pPtrType);
2629 }
2630 } else {
2631 o(0x59); /* pop %ecx */
2632 o(decodeOp(op));
2633 if (op == OP_MOD)
2634 o(0x92); /* xchg %edx, %eax */
2635 popType();
2636 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002637 } else {
2638 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2639 setupFloatOperands();
2640 // Both float. x87 R0 == left hand, x87 R1 == right hand
2641 switch (op) {
2642 case OP_MUL:
2643 o(0xc9de); // fmulp
2644 break;
2645 case OP_DIV:
2646 o(0xf1de); // fdivp
2647 break;
2648 case OP_PLUS:
2649 o(0xc1de); // faddp
2650 break;
2651 case OP_MINUS:
2652 o(0xe1de); // fsubp
2653 break;
2654 default:
2655 error("Unsupported binary floating operation.");
2656 break;
2657 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002658 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002659 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002660 }
2661
Jack Palevich58c30ee2009-07-17 16:35:23 -07002662 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002663 if (op != OP_LOGICAL_NOT) {
2664 error("Unknown unary cmp %d", op);
2665 } else {
2666 Type* pR0Type = getR0Type();
2667 TypeTag tag = collapseType(pR0Type->tag);
2668 switch(tag) {
2669 case TY_INT: {
2670 oad(0xb9, 0); /* movl $0, %ecx */
2671 int t = decodeOp(op);
2672 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002673 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002674 o(0x0f); /* setxx %al */
2675 o(t + 0x90);
2676 o(0xc0);
2677 }
2678 break;
2679 case TY_FLOAT:
2680 case TY_DOUBLE:
2681 o(0xeed9); // fldz
2682 o(0xe9da); // fucompp
2683 o(0xe0df); // fnstsw %ax
2684 o(0x9e); // sahf
2685 o(0xc0950f); // setne %al
2686 o(0xc29a0f); // setp %dl
2687 o(0xd009); // orl %edx, %eax
2688 o(0xc0b60f); // movzbl %al, %eax
2689 o(0x01f083); // xorl $1, %eax
2690 break;
2691 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002692 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002693 break;
2694 }
2695 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002696 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002697 }
2698
2699 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002700 Type* pR0Type = getR0Type();
2701 TypeTag tag = collapseType(pR0Type->tag);
2702 switch(tag) {
2703 case TY_INT:
2704 oad(0xb9, 0); /* movl $0, %ecx */
2705 o(decodeOp(op));
2706 break;
2707 case TY_FLOAT:
2708 case TY_DOUBLE:
2709 switch (op) {
2710 case OP_MINUS:
2711 o(0xe0d9); // fchs
2712 break;
2713 case OP_BIT_NOT:
2714 error("Can't apply '~' operator to a float or double.");
2715 break;
2716 default:
2717 error("Unknown unary op %d\n", op);
2718 break;
2719 }
2720 break;
2721 default:
2722 error("genUnaryOp unsupported type");
2723 break;
2724 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002725 }
2726
Jack Palevich1cdef202009-05-22 12:06:27 -07002727 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002728 Type* pR0Type = getR0Type();
2729 TypeTag r0ct = collapseType(pR0Type->tag);
2730 switch(r0ct) {
2731 case TY_INT:
2732 o(0x50); /* push %eax */
2733 break;
2734 case TY_FLOAT:
2735 o(0x50); /* push %eax */
2736 o(0x241cd9); // fstps 0(%esp)
2737 break;
2738 case TY_DOUBLE:
2739 o(0x50); /* push %eax */
2740 o(0x50); /* push %eax */
2741 o(0x241cdd); // fstpl 0(%esp)
2742 break;
2743 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002744 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002745 break;
2746 }
Jack Palevich8df46192009-07-07 14:48:51 -07002747 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002748 }
2749
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002750 virtual void over() {
2751 // We know it's only used for int-ptr ops (++/--)
2752
2753 Type* pR0Type = getR0Type();
2754 TypeTag r0ct = collapseType(pR0Type->tag);
2755
2756 Type* pTOSType = getTOSType();
2757 TypeTag tosct = collapseType(pTOSType->tag);
2758
2759 assert (r0ct == TY_INT && tosct == TY_INT);
2760
2761 o(0x59); /* pop %ecx */
2762 o(0x50); /* push %eax */
2763 o(0x51); /* push %ecx */
2764
2765 overType();
2766 }
2767
Jack Palevich58c30ee2009-07-17 16:35:23 -07002768 virtual void popR0() {
2769 Type* pR0Type = getR0Type();
2770 TypeTag r0ct = collapseType(pR0Type->tag);
2771 switch(r0ct) {
2772 case TY_INT:
2773 o(0x58); /* popl %eax */
2774 break;
2775 case TY_FLOAT:
2776 o(0x2404d9); // flds (%esp)
2777 o(0x58); /* popl %eax */
2778 break;
2779 case TY_DOUBLE:
2780 o(0x2404dd); // fldl (%esp)
2781 o(0x58); /* popl %eax */
2782 o(0x58); /* popl %eax */
2783 break;
2784 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002785 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002786 break;
2787 }
2788 popType();
2789 }
2790
2791 virtual void storeR0ToTOS() {
2792 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002793 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002794 Type* pTargetType = pPointerType->pHead;
2795 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002796 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002797 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002798 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002799 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002800 case TY_INT:
2801 o(0x0189); /* movl %eax/%al, (%ecx) */
2802 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002803 case TY_SHORT:
2804 o(0x018966); /* movw %ax, (%ecx) */
2805 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002806 case TY_CHAR:
2807 o(0x0188); /* movl %eax/%al, (%ecx) */
2808 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002809 case TY_FLOAT:
2810 o(0x19d9); /* fstps (%ecx) */
2811 break;
2812 case TY_DOUBLE:
2813 o(0x19dd); /* fstpl (%ecx) */
2814 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002815 case TY_STRUCT:
2816 {
2817 // TODO: use alignment information to use movsw/movsl instead of movsb
2818 int size = sizeOf(pTargetType);
2819 if (size > 0) {
2820 o(0x9c); // pushf
2821 o(0x57); // pushl %edi
2822 o(0x56); // pushl %esi
2823 o(0xcf89); // movl %ecx, %edi
2824 o(0xc689); // movl %eax, %esi
2825 oad(0xb9, size); // mov #size, %ecx
2826 o(0xfc); // cld
2827 o(0xf3); // rep
2828 o(0xa4); // movsb
2829 o(0x5e); // popl %esi
2830 o(0x5f); // popl %edi
2831 o(0x9d); // popf
2832 }
2833 }
2834 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002835 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002836 error("storeR0ToTOS: unsupported type %d",
2837 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002838 break;
2839 }
Jack Palevich02effee2009-11-09 12:52:45 +08002840 setR0Type(pTargetType);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002841 }
2842
Jack Palevich58c30ee2009-07-17 16:35:23 -07002843 virtual void loadR0FromR0() {
2844 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002845 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002846 Type* pNewType = pPointerType->pHead;
2847 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002848 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002849 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002850 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002851 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002852 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002853 case TY_SHORT:
2854 o(0xbf0f); /* movswl (%eax), %eax */
2855 ob(0);
2856 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002857 case TY_CHAR:
2858 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002859 ob(0); /* add zero in code */
2860 break;
2861 case TY_FLOAT:
2862 o2(0x00d9); // flds (%eax)
2863 break;
2864 case TY_DOUBLE:
2865 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002866 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002867 case TY_ARRAY:
2868 pNewType = pNewType->pTail;
2869 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07002870 case TY_STRUCT:
2871 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002872 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002873 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002874 break;
2875 }
Jack Palevich80e49722009-08-04 15:39:49 -07002876 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002877 }
2878
Jack Palevichb5e33312009-07-30 19:06:34 -07002879 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002880 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002881 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002882 }
2883
Jack Palevich9f51a262009-07-29 16:22:26 -07002884 virtual int leaForward(int ea, Type* pPointerType) {
2885 oad(0xb8, ea); /* mov $xx, %eax */
2886 setR0Type(pPointerType);
2887 return getPC() - 4;
2888 }
2889
Jack Palevichb6154502009-08-04 14:56:09 -07002890 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002891 Type* pR0Type = getR0Type();
2892 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002893 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002894 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002895 return;
2896 }
Jack Palevichb6154502009-08-04 14:56:09 -07002897 if (isPointerType(pType) && isPointerType(pR0Type)) {
2898 Type* pA = pR0Type;
2899 Type* pB = pType;
2900 // Array decays to pointer
2901 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2902 pA = pA->pTail;
2903 }
Jack Palevichc0f25332009-08-25 12:23:43 -07002904 if (! (typeEqual(pA, pB)
2905 || pB->pHead->tag == TY_VOID
2906 || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2907 )) {
2908 error("Incompatible pointer or array types");
Jack Palevichb6154502009-08-04 14:56:09 -07002909 }
Jack Palevichb6154502009-08-04 14:56:09 -07002910 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002911 // do nothing special
2912 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2913 // do nothing special, both held in same register on x87.
2914 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002915 TypeTag r0Tag = collapseType(pR0Type->tag);
2916 TypeTag destTag = collapseType(pType->tag);
2917 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2918 // Convert R0 from int to float
2919 o(0x50); // push %eax
2920 o(0x2404DB); // fildl 0(%esp)
2921 o(0x58); // pop %eax
2922 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2923 // Convert R0 from float to int. Complicated because
2924 // need to save and restore the rounding mode.
2925 o(0x50); // push %eax
2926 o(0x50); // push %eax
2927 o(0x02247cD9); // fnstcw 2(%esp)
2928 o(0x2444b70f); // movzwl 2(%esp), %eax
2929 o(0x02);
2930 o(0x0cb4); // movb $12, %ah
2931 o(0x24048966); // movw %ax, 0(%esp)
2932 o(0x242cd9); // fldcw 0(%esp)
2933 o(0x04245cdb); // fistpl 4(%esp)
2934 o(0x02246cd9); // fldcw 2(%esp)
2935 o(0x58); // pop %eax
2936 o(0x58); // pop %eax
2937 } else {
2938 error("Incompatible types old: %d new: %d",
2939 pR0Type->tag, pType->tag);
2940 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002941 }
2942 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002943 }
2944
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002945 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002946 return oad(0xec81, 0); /* sub $xxx, %esp */
2947 }
2948
Jack Palevich8148c5b2009-07-16 18:24:47 -07002949 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2950 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002951 Type* pR0Type = getR0Type();
2952 TypeTag r0ct = collapseType(pR0Type->tag);
2953 switch(r0ct) {
2954 case TY_INT:
2955 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2956 return 4;
2957 case TY_FLOAT:
2958 oad(0x249CD9, l); /* fstps xxx(%esp) */
2959 return 4;
2960 case TY_DOUBLE:
2961 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2962 return 8;
2963 default:
2964 assert(false);
2965 return 0;
2966 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002967 }
2968
Jack Palevichb7718b92009-07-09 22:00:24 -07002969 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002970 * (int*) a = l;
2971 }
2972
Jack Palevich8df46192009-07-07 14:48:51 -07002973 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002974 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002975 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002976 return psym(0xe8, symbol); /* call xxx */
2977 }
2978
Jack Palevich8df46192009-07-07 14:48:51 -07002979 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002980 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002981 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002982 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002983 oad(0x2494ff, l); /* call *xxx(%esp) */
2984 }
2985
Jack Palevichb7718b92009-07-09 22:00:24 -07002986 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002987 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002988 if (isIndirect) {
2989 l += 4;
2990 }
-b master422972c2009-06-17 19:13:52 -07002991 if (l > 0) {
2992 oad(0xc481, l); /* add $xxx, %esp */
2993 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002994 }
2995
Jack Palevicha6535612009-05-13 16:24:17 -07002996 virtual int jumpOffset() {
2997 return 5;
2998 }
2999
Jack Paleviche7b59062009-05-19 17:12:17 -07003000 /* output a symbol and patch all calls to it */
3001 virtual void gsym(int t) {
3002 int n;
3003 int pc = getPC();
3004 while (t) {
3005 n = *(int *) t; /* next value */
3006 *(int *) t = pc - t - 4;
3007 t = n;
3008 }
3009 }
3010
Jack Palevich9f51a262009-07-29 16:22:26 -07003011 /* output a symbol and patch all calls to it, using absolute address */
3012 virtual void resolveForward(int t) {
3013 int n;
3014 int pc = getPC();
3015 while (t) {
3016 n = *(int *) t; /* next value */
3017 *(int *) t = pc;
3018 t = n;
3019 }
3020 }
3021
Jack Palevich1cdef202009-05-22 12:06:27 -07003022 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00003023 size_t pagesize = 4096;
3024 size_t base = (size_t) getBase() & ~ (pagesize - 1);
3025 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
3026 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
3027 if (err) {
3028 error("mprotect() failed: %d", errno);
3029 }
3030 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07003031 }
3032
Jack Palevich9eed7a22009-07-06 17:24:34 -07003033 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003034 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003035 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003036 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003037 switch (pType->tag) {
3038 case TY_CHAR:
3039 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003040 case TY_SHORT:
3041 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07003042 case TY_ARRAY:
3043 return alignmentOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003044 case TY_STRUCT:
3045 return pType->pHead->alignment & 0x7fffffff;
Jack Palevichb6154502009-08-04 14:56:09 -07003046 case TY_FUNC:
3047 error("alignment of func not supported");
3048 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07003049 default:
3050 return 4;
3051 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003052 }
3053
3054 /**
3055 * Array element alignment (in bytes) for this type of data.
3056 */
3057 virtual size_t sizeOf(Type* pType){
3058 switch(pType->tag) {
3059 case TY_INT:
3060 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003061 case TY_SHORT:
3062 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003063 case TY_CHAR:
3064 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003065 case TY_FLOAT:
3066 return 4;
3067 case TY_DOUBLE:
3068 return 8;
3069 case TY_POINTER:
3070 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07003071 case TY_ARRAY:
3072 return pType->length * sizeOf(pType->pHead);
Jack Palevich9221bcc2009-08-26 16:15:07 -07003073 case TY_STRUCT:
3074 return pType->pHead->length;
Jack Palevichb6154502009-08-04 14:56:09 -07003075 default:
3076 error("Unsupported type %d", pType->tag);
3077 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07003078 }
3079 }
3080
Jack Palevich21a15a22009-05-11 14:49:29 -07003081 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07003082
3083 /** Output 1 to 4 bytes.
3084 *
3085 */
3086 void o(int n) {
3087 /* cannot use unsigned, so we must do a hack */
3088 while (n && n != -1) {
3089 ob(n & 0xff);
3090 n = n >> 8;
3091 }
3092 }
3093
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003094 /* Output exactly 2 bytes
3095 */
3096 void o2(int n) {
3097 ob(n & 0xff);
3098 ob(0xff & (n >> 8));
3099 }
3100
Jack Paleviche7b59062009-05-19 17:12:17 -07003101 /* psym is used to put an instruction with a data field which is a
3102 reference to a symbol. It is in fact the same as oad ! */
3103 int psym(int n, int t) {
3104 return oad(n, t);
3105 }
3106
3107 /* instruction + address */
3108 int oad(int n, int t) {
3109 o(n);
3110 int result = getPC();
3111 o4(t);
3112 return result;
3113 }
3114
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003115 static const int operatorHelper[];
3116
3117 int decodeOp(int op) {
3118 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07003119 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07003120 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003121 }
3122 return operatorHelper[op];
3123 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003124
Jack Palevich546b2242009-05-13 15:10:04 -07003125 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003126 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00003127 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003128 }
Jack Palevicha39749f2009-07-08 20:40:31 -07003129
3130 void setupFloatOperands() {
3131 Type* pR0Type = getR0Type();
3132 Type* pTOSType = getTOSType();
3133 TypeTag tagR0 = pR0Type->tag;
3134 TypeTag tagTOS = pTOSType->tag;
3135 bool isFloatR0 = isFloatTag(tagR0);
3136 bool isFloatTOS = isFloatTag(tagTOS);
3137 if (! isFloatR0) {
3138 // Convert R0 from int to float
3139 o(0x50); // push %eax
3140 o(0x2404DB); // fildl 0(%esp)
3141 o(0x58); // pop %eax
3142 }
3143 if (! isFloatTOS){
3144 o(0x2404DB); // fildl 0(%esp);
3145 o(0x58); // pop %eax
3146 } else {
3147 if (tagTOS == TY_FLOAT) {
3148 o(0x2404d9); // flds (%esp)
3149 o(0x58); // pop %eax
3150 } else {
3151 o(0x2404dd); // fldl (%esp)
3152 o(0x58); // pop %eax
3153 o(0x58); // pop %eax
3154 }
3155 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003156 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07003157 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003158 };
3159
Jack Paleviche7b59062009-05-19 17:12:17 -07003160#endif // PROVIDE_X86_CODEGEN
3161
Jack Palevichb67b18f2009-06-11 21:12:23 -07003162#ifdef PROVIDE_TRACE_CODEGEN
3163 class TraceCodeGenerator : public CodeGenerator {
3164 private:
3165 CodeGenerator* mpBase;
3166
3167 public:
3168 TraceCodeGenerator(CodeGenerator* pBase) {
3169 mpBase = pBase;
3170 }
3171
3172 virtual ~TraceCodeGenerator() {
3173 delete mpBase;
3174 }
3175
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003176 virtual void init(ICodeBuf* pCodeBuf) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003177 mpBase->init(pCodeBuf);
3178 }
3179
3180 void setErrorSink(ErrorSink* pErrorSink) {
3181 mpBase->setErrorSink(pErrorSink);
3182 }
3183
3184 /* returns address to patch with local variable size
3185 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003186 virtual int functionEntry(Type* pDecl) {
3187 int result = mpBase->functionEntry(pDecl);
3188 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003189 return result;
3190 }
3191
Jack Palevichb7718b92009-07-09 22:00:24 -07003192 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
3193 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
3194 localVariableAddress, localVariableSize);
3195 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003196 }
3197
3198 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07003199 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003200 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07003201 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003202 }
3203
Jack Palevich1a539db2009-07-08 13:04:41 -07003204 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07003205 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07003206 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003207 }
3208
Jack Palevich9221bcc2009-08-26 16:15:07 -07003209 virtual void addStructOffsetR0(int offset, Type* pType) {
3210 fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
3211 mpBase->addStructOffsetR0(offset, pType);
3212 }
3213
Jack Palevichb67b18f2009-06-11 21:12:23 -07003214 virtual int gjmp(int t) {
3215 int result = mpBase->gjmp(t);
3216 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
3217 return result;
3218 }
3219
3220 /* l = 0: je, l == 1: jne */
3221 virtual int gtst(bool l, int t) {
3222 int result = mpBase->gtst(l, t);
3223 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3224 return result;
3225 }
3226
Jack Palevich58c30ee2009-07-17 16:35:23 -07003227 virtual void gcmp(int op) {
3228 fprintf(stderr, "gcmp(%d)\n", op);
3229 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003230 }
3231
3232 virtual void genOp(int op) {
3233 fprintf(stderr, "genOp(%d)\n", op);
3234 mpBase->genOp(op);
3235 }
3236
Jack Palevich9eed7a22009-07-06 17:24:34 -07003237
Jack Palevich58c30ee2009-07-17 16:35:23 -07003238 virtual void gUnaryCmp(int op) {
3239 fprintf(stderr, "gUnaryCmp(%d)\n", op);
3240 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003241 }
3242
3243 virtual void genUnaryOp(int op) {
3244 fprintf(stderr, "genUnaryOp(%d)\n", op);
3245 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003246 }
3247
3248 virtual void pushR0() {
3249 fprintf(stderr, "pushR0()\n");
3250 mpBase->pushR0();
3251 }
3252
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003253 virtual void over() {
3254 fprintf(stderr, "over()\n");
3255 mpBase->over();
3256 }
3257
Jack Palevich58c30ee2009-07-17 16:35:23 -07003258 virtual void popR0() {
3259 fprintf(stderr, "popR0()\n");
3260 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003261 }
3262
Jack Palevich58c30ee2009-07-17 16:35:23 -07003263 virtual void storeR0ToTOS() {
3264 fprintf(stderr, "storeR0ToTOS()\n");
3265 mpBase->storeR0ToTOS();
3266 }
3267
3268 virtual void loadR0FromR0() {
3269 fprintf(stderr, "loadR0FromR0()\n");
3270 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07003271 }
3272
Jack Palevichb5e33312009-07-30 19:06:34 -07003273 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3274 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3275 pPointerType->pHead->tag, et);
3276 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003277 }
3278
Jack Palevich9f51a262009-07-29 16:22:26 -07003279 virtual int leaForward(int ea, Type* pPointerType) {
3280 fprintf(stderr, "leaForward(%d)\n", ea);
3281 return mpBase->leaForward(ea, pPointerType);
3282 }
3283
Jack Palevich30321cb2009-08-20 15:34:23 -07003284 virtual void convertR0Imp(Type* pType, bool isCast){
3285 fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast);
3286 mpBase->convertR0Imp(pType, isCast);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003287 }
3288
3289 virtual int beginFunctionCallArguments() {
3290 int result = mpBase->beginFunctionCallArguments();
3291 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3292 return result;
3293 }
3294
Jack Palevich8148c5b2009-07-16 18:24:47 -07003295 virtual size_t storeR0ToArg(int l, Type* pArgType) {
3296 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3297 pArgType->tag);
3298 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003299 }
3300
Jack Palevichb7718b92009-07-09 22:00:24 -07003301 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07003302 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07003303 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003304 }
3305
Jack Palevich8df46192009-07-07 14:48:51 -07003306 virtual int callForward(int symbol, Type* pFunc) {
3307 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003308 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3309 return result;
3310 }
3311
Jack Palevich8df46192009-07-07 14:48:51 -07003312 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07003313 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3314 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07003315 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003316 }
3317
Jack Palevichb7718b92009-07-09 22:00:24 -07003318 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3319 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3320 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07003321 }
3322
3323 virtual int jumpOffset() {
3324 return mpBase->jumpOffset();
3325 }
3326
Jack Palevichb67b18f2009-06-11 21:12:23 -07003327 /* output a symbol and patch all calls to it */
3328 virtual void gsym(int t) {
3329 fprintf(stderr, "gsym(%d)\n", t);
3330 mpBase->gsym(t);
3331 }
3332
Jack Palevich9f51a262009-07-29 16:22:26 -07003333 virtual void resolveForward(int t) {
3334 mpBase->resolveForward(t);
3335 }
3336
Jack Palevichb67b18f2009-06-11 21:12:23 -07003337 virtual int finishCompile() {
3338 int result = mpBase->finishCompile();
3339 fprintf(stderr, "finishCompile() = %d\n", result);
3340 return result;
3341 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07003342
3343 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07003344 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07003345 */
Jack Palevichb7718b92009-07-09 22:00:24 -07003346 virtual size_t alignmentOf(Type* pType){
3347 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07003348 }
3349
3350 /**
3351 * Array element alignment (in bytes) for this type of data.
3352 */
3353 virtual size_t sizeOf(Type* pType){
3354 return mpBase->sizeOf(pType);
3355 }
Jack Palevich1a539db2009-07-08 13:04:41 -07003356
3357 virtual Type* getR0Type() {
3358 return mpBase->getR0Type();
3359 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07003360
3361 virtual ExpressionType getR0ExpressionType() {
3362 return mpBase->getR0ExpressionType();
3363 }
3364
3365 virtual void setR0ExpressionType(ExpressionType et) {
3366 mpBase->setR0ExpressionType(et);
3367 }
3368
3369 virtual size_t getExpressionStackDepth() {
3370 return mpBase->getExpressionStackDepth();
3371 }
Jack Palevichb5e33312009-07-30 19:06:34 -07003372
3373 virtual void forceR0RVal() {
3374 return mpBase->forceR0RVal();
3375 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07003376 };
3377
3378#endif // PROVIDE_TRACE_CODEGEN
3379
Jack Palevich569f1352009-06-29 14:29:08 -07003380 class Arena {
3381 public:
3382 // Used to record a given allocation amount.
3383 // Used:
3384 // Mark mark = arena.mark();
3385 // ... lots of arena.allocate()
3386 // arena.free(mark);
3387
3388 struct Mark {
3389 size_t chunk;
3390 size_t offset;
3391 };
3392
3393 Arena() {
3394 mCurrentChunk = 0;
3395 Chunk start(CHUNK_SIZE);
3396 mData.push_back(start);
3397 }
3398
3399 ~Arena() {
3400 for(size_t i = 0; i < mData.size(); i++) {
3401 mData[i].free();
3402 }
3403 }
3404
3405 // Alloc using the standard alignment size safe for any variable
3406 void* alloc(size_t size) {
3407 return alloc(size, 8);
3408 }
3409
3410 Mark mark(){
3411 Mark result;
3412 result.chunk = mCurrentChunk;
3413 result.offset = mData[mCurrentChunk].mOffset;
3414 return result;
3415 }
3416
3417 void freeToMark(const Mark& mark) {
3418 mCurrentChunk = mark.chunk;
3419 mData[mCurrentChunk].mOffset = mark.offset;
3420 }
3421
3422 private:
3423 // Allocate memory aligned to a given size
3424 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3425 // Memory is not zero filled.
3426
3427 void* alloc(size_t size, size_t alignment) {
3428 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3429 if (mCurrentChunk + 1 < mData.size()) {
3430 mCurrentChunk++;
3431 } else {
3432 size_t allocSize = CHUNK_SIZE;
3433 if (allocSize < size + alignment - 1) {
3434 allocSize = size + alignment - 1;
3435 }
3436 Chunk chunk(allocSize);
3437 mData.push_back(chunk);
3438 mCurrentChunk++;
3439 }
3440 }
3441 return mData[mCurrentChunk].allocate(size, alignment);
3442 }
3443
3444 static const size_t CHUNK_SIZE = 128*1024;
3445 // Note: this class does not deallocate its
3446 // memory when it's destroyed. It depends upon
3447 // its parent to deallocate the memory.
3448 struct Chunk {
3449 Chunk() {
3450 mpData = 0;
3451 mSize = 0;
3452 mOffset = 0;
3453 }
3454
3455 Chunk(size_t size) {
3456 mSize = size;
3457 mpData = (char*) malloc(size);
3458 mOffset = 0;
3459 }
3460
3461 ~Chunk() {
3462 // Doesn't deallocate memory.
3463 }
3464
3465 void* allocate(size_t size, size_t alignment) {
3466 size_t alignedOffset = aligned(mOffset, alignment);
3467 void* result = mpData + alignedOffset;
3468 mOffset = alignedOffset + size;
3469 return result;
3470 }
3471
3472 void free() {
3473 if (mpData) {
3474 ::free(mpData);
3475 mpData = 0;
3476 }
3477 }
3478
3479 size_t remainingCapacity(size_t alignment) {
3480 return aligned(mSize, alignment) - aligned(mOffset, alignment);
3481 }
3482
3483 // Assume alignment is a power of two
3484 inline size_t aligned(size_t v, size_t alignment) {
3485 size_t mask = alignment-1;
3486 return (v + mask) & ~mask;
3487 }
3488
3489 char* mpData;
3490 size_t mSize;
3491 size_t mOffset;
3492 };
3493
3494 size_t mCurrentChunk;
3495
3496 Vector<Chunk> mData;
3497 };
3498
Jack Palevich569f1352009-06-29 14:29:08 -07003499 struct VariableInfo;
3500
3501 struct Token {
3502 int hash;
3503 size_t length;
3504 char* pText;
3505 tokenid_t id;
3506
3507 // Current values for the token
3508 char* mpMacroDefinition;
3509 VariableInfo* mpVariableInfo;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003510 VariableInfo* mpStructInfo;
Jack Palevich569f1352009-06-29 14:29:08 -07003511 };
3512
3513 class TokenTable {
3514 public:
3515 // Don't use 0..0xff, allows characters and operators to be tokens too.
3516
3517 static const int TOKEN_BASE = 0x100;
3518 TokenTable() {
3519 mpMap = hashmapCreate(128, hashFn, equalsFn);
3520 }
3521
3522 ~TokenTable() {
3523 hashmapFree(mpMap);
3524 }
3525
3526 void setArena(Arena* pArena) {
3527 mpArena = pArena;
3528 }
3529
3530 // Returns a token for a given string of characters.
3531 tokenid_t intern(const char* pText, size_t length) {
3532 Token probe;
3533 int hash = hashmapHash((void*) pText, length);
3534 {
3535 Token probe;
3536 probe.hash = hash;
3537 probe.length = length;
3538 probe.pText = (char*) pText;
3539 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3540 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003541 return pValue->id;
3542 }
3543 }
3544
3545 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3546 memset(pToken, 0, sizeof(*pToken));
3547 pToken->hash = hash;
3548 pToken->length = length;
3549 pToken->pText = (char*) mpArena->alloc(length + 1);
3550 memcpy(pToken->pText, pText, length);
3551 pToken->pText[length] = 0;
3552 pToken->id = mTokens.size() + TOKEN_BASE;
3553 mTokens.push_back(pToken);
3554 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07003555 return pToken->id;
3556 }
3557
3558 // Return the Token for a given tokenid.
3559 Token& operator[](tokenid_t id) {
3560 return *mTokens[id - TOKEN_BASE];
3561 }
3562
3563 inline size_t size() {
3564 return mTokens.size();
3565 }
3566
3567 private:
3568
3569 static int hashFn(void* pKey) {
3570 Token* pToken = (Token*) pKey;
3571 return pToken->hash;
3572 }
3573
3574 static bool equalsFn(void* keyA, void* keyB) {
3575 Token* pTokenA = (Token*) keyA;
3576 Token* pTokenB = (Token*) keyB;
3577 // Don't need to compare hash values, they should always be equal
3578 return pTokenA->length == pTokenB->length
3579 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3580 }
3581
3582 Hashmap* mpMap;
3583 Vector<Token*> mTokens;
3584 Arena* mpArena;
3585 };
3586
Jack Palevich1cdef202009-05-22 12:06:27 -07003587 class InputStream {
3588 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07003589 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07003590 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003591 };
3592
3593 class TextInputStream : public InputStream {
3594 public:
3595 TextInputStream(const char* text, size_t textLength)
3596 : pText(text), mTextLength(textLength), mPosition(0) {
3597 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003598
Jack Palevichdc456462009-07-16 16:50:56 -07003599 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003600 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3601 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003602
Jack Palevichdc456462009-07-16 16:50:56 -07003603 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003604 const char* pText;
3605 size_t mTextLength;
3606 size_t mPosition;
3607 };
3608
Jack Palevicheedf9d22009-06-04 16:23:40 -07003609 class String {
3610 public:
3611 String() {
3612 mpBase = 0;
3613 mUsed = 0;
3614 mSize = 0;
3615 }
3616
Jack Palevich303d8ff2009-06-11 19:06:24 -07003617 String(const char* item, int len, bool adopt) {
3618 if (len < 0) {
3619 len = strlen(item);
3620 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003621 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003622 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003623 mUsed = len;
3624 mSize = len + 1;
3625 } else {
3626 mpBase = 0;
3627 mUsed = 0;
3628 mSize = 0;
3629 appendBytes(item, len);
3630 }
3631 }
3632
Jack Palevich303d8ff2009-06-11 19:06:24 -07003633 String(const String& other) {
3634 mpBase = 0;
3635 mUsed = 0;
3636 mSize = 0;
3637 appendBytes(other.getUnwrapped(), other.len());
3638 }
3639
Jack Palevicheedf9d22009-06-04 16:23:40 -07003640 ~String() {
3641 if (mpBase) {
3642 free(mpBase);
3643 }
3644 }
3645
Jack Palevicha6baa232009-06-12 11:25:59 -07003646 String& operator=(const String& other) {
3647 clear();
3648 appendBytes(other.getUnwrapped(), other.len());
3649 return *this;
3650 }
3651
Jack Palevich303d8ff2009-06-11 19:06:24 -07003652 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003653 return mpBase;
3654 }
3655
Jack Palevich303d8ff2009-06-11 19:06:24 -07003656 void clear() {
3657 mUsed = 0;
3658 if (mSize > 0) {
3659 mpBase[0] = 0;
3660 }
3661 }
3662
Jack Palevicheedf9d22009-06-04 16:23:40 -07003663 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003664 appendBytes(s, strlen(s));
3665 }
3666
3667 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003668 memcpy(ensure(n), s, n + 1);
3669 }
3670
3671 void append(char c) {
3672 * ensure(1) = c;
3673 }
3674
Jack Palevich86351982009-06-30 18:09:56 -07003675 void append(String& other) {
3676 appendBytes(other.getUnwrapped(), other.len());
3677 }
3678
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003679 char* orphan() {
3680 char* result = mpBase;
3681 mpBase = 0;
3682 mUsed = 0;
3683 mSize = 0;
3684 return result;
3685 }
3686
Jack Palevicheedf9d22009-06-04 16:23:40 -07003687 void printf(const char* fmt,...) {
3688 va_list ap;
3689 va_start(ap, fmt);
3690 vprintf(fmt, ap);
3691 va_end(ap);
3692 }
3693
3694 void vprintf(const char* fmt, va_list ap) {
3695 char* temp;
3696 int numChars = vasprintf(&temp, fmt, ap);
3697 memcpy(ensure(numChars), temp, numChars+1);
3698 free(temp);
3699 }
3700
Jack Palevich303d8ff2009-06-11 19:06:24 -07003701 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003702 return mUsed;
3703 }
3704
3705 private:
3706 char* ensure(int n) {
3707 size_t newUsed = mUsed + n;
3708 if (newUsed > mSize) {
3709 size_t newSize = mSize * 2 + 10;
3710 if (newSize < newUsed) {
3711 newSize = newUsed;
3712 }
3713 mpBase = (char*) realloc(mpBase, newSize + 1);
3714 mSize = newSize;
3715 }
3716 mpBase[newUsed] = '\0';
3717 char* result = mpBase + mUsed;
3718 mUsed = newUsed;
3719 return result;
3720 }
3721
3722 char* mpBase;
3723 size_t mUsed;
3724 size_t mSize;
3725 };
3726
Jack Palevich569f1352009-06-29 14:29:08 -07003727 void internKeywords() {
3728 // Note: order has to match TOK_ constants
3729 static const char* keywords[] = {
3730 "int",
3731 "char",
3732 "void",
3733 "if",
3734 "else",
3735 "while",
3736 "break",
3737 "return",
3738 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003739 "auto",
3740 "case",
3741 "const",
3742 "continue",
3743 "default",
3744 "do",
3745 "double",
3746 "enum",
3747 "extern",
3748 "float",
3749 "goto",
3750 "long",
3751 "register",
3752 "short",
3753 "signed",
3754 "sizeof",
3755 "static",
3756 "struct",
3757 "switch",
3758 "typedef",
3759 "union",
3760 "unsigned",
3761 "volatile",
3762 "_Bool",
3763 "_Complex",
3764 "_Imaginary",
3765 "inline",
3766 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003767
3768 // predefined tokens that can also be symbols start here:
3769 "pragma",
3770 "define",
3771 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003772 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003773
Jack Palevich569f1352009-06-29 14:29:08 -07003774 for(int i = 0; keywords[i]; i++) {
3775 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003776 }
Jack Palevich569f1352009-06-29 14:29:08 -07003777 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003778
Jack Palevich36d94142009-06-08 15:55:32 -07003779 struct InputState {
3780 InputStream* pStream;
3781 int oldCh;
3782 };
3783
Jack Palevich2db168f2009-06-11 14:29:47 -07003784 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003785 void* pAddress;
3786 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003787 tokenid_t tok;
3788 size_t level;
3789 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003790 Type* pType;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003791 bool isStructTag;
Jack Palevich2db168f2009-06-11 14:29:47 -07003792 };
3793
Jack Palevich303d8ff2009-06-11 19:06:24 -07003794 class SymbolStack {
3795 public:
3796 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003797 mpArena = 0;
3798 mpTokenTable = 0;
3799 }
3800
3801 void setArena(Arena* pArena) {
3802 mpArena = pArena;
3803 }
3804
3805 void setTokenTable(TokenTable* pTokenTable) {
3806 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003807 }
3808
3809 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003810 Mark mark;
3811 mark.mArenaMark = mpArena->mark();
3812 mark.mSymbolHead = mStack.size();
3813 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003814 }
3815
3816 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003817 // Undo any shadowing that was done:
3818 Mark mark = mLevelStack.back();
3819 mLevelStack.pop_back();
3820 while (mStack.size() > mark.mSymbolHead) {
3821 VariableInfo* pV = mStack.back();
3822 mStack.pop_back();
Jack Palevich9221bcc2009-08-26 16:15:07 -07003823 if (pV->isStructTag) {
3824 (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3825 } else {
3826 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3827 }
Jack Palevich303d8ff2009-06-11 19:06:24 -07003828 }
Jack Palevich569f1352009-06-29 14:29:08 -07003829 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003830 }
3831
Jack Palevich569f1352009-06-29 14:29:08 -07003832 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3833 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3834 return pV && pV->level == level();
3835 }
3836
Jack Palevich9221bcc2009-08-26 16:15:07 -07003837 bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3838 VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3839 return pV && pV->level == level();
3840 }
3841
Jack Palevich569f1352009-06-29 14:29:08 -07003842 VariableInfo* add(tokenid_t tok) {
3843 Token& token = (*mpTokenTable)[tok];
3844 VariableInfo* pOldV = token.mpVariableInfo;
3845 VariableInfo* pNewV =
3846 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3847 memset(pNewV, 0, sizeof(VariableInfo));
3848 pNewV->tok = tok;
3849 pNewV->level = level();
3850 pNewV->pOldDefinition = pOldV;
3851 token.mpVariableInfo = pNewV;
3852 mStack.push_back(pNewV);
3853 return pNewV;
3854 }
3855
Jack Palevich9221bcc2009-08-26 16:15:07 -07003856 VariableInfo* addStructTag(tokenid_t tok) {
3857 Token& token = (*mpTokenTable)[tok];
3858 VariableInfo* pOldS = token.mpStructInfo;
3859 VariableInfo* pNewS =
3860 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3861 memset(pNewS, 0, sizeof(VariableInfo));
3862 pNewS->tok = tok;
3863 pNewS->level = level();
3864 pNewS->isStructTag = true;
3865 pNewS->pOldDefinition = pOldS;
3866 token.mpStructInfo = pNewS;
3867 mStack.push_back(pNewS);
3868 return pNewS;
3869 }
3870
Jack Palevich86351982009-06-30 18:09:56 -07003871 VariableInfo* add(Type* pType) {
3872 VariableInfo* pVI = add(pType->id);
3873 pVI->pType = pType;
3874 return pVI;
3875 }
3876
Jack Palevich569f1352009-06-29 14:29:08 -07003877 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3878 for (size_t i = 0; i < mStack.size(); i++) {
3879 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003880 break;
3881 }
3882 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003883 }
3884
Jack Palevich303d8ff2009-06-11 19:06:24 -07003885 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003886 inline size_t level() {
3887 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003888 }
3889
Jack Palevich569f1352009-06-29 14:29:08 -07003890 struct Mark {
3891 Arena::Mark mArenaMark;
3892 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003893 };
3894
Jack Palevich569f1352009-06-29 14:29:08 -07003895 Arena* mpArena;
3896 TokenTable* mpTokenTable;
3897 Vector<VariableInfo*> mStack;
3898 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003899 };
Jack Palevich36d94142009-06-08 15:55:32 -07003900
3901 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003902 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003903 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003904 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003905 int tokl; // token operator level
3906 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003907 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003908 intptr_t loc; // local variable index
3909 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003910 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003911 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003912 char* dptr; // Macro state: Points to macro text during macro playback.
3913 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003914 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003915 ACCSymbolLookupFn mpSymbolLookupFn;
3916 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003917
3918 // Arena for the duration of the compile
3919 Arena mGlobalArena;
3920 // Arena for data that's only needed when compiling a single function
3921 Arena mLocalArena;
3922
Jack Palevich2ff5c222009-07-23 15:11:22 -07003923 Arena* mpCurrentArena;
3924
Jack Palevich569f1352009-06-29 14:29:08 -07003925 TokenTable mTokenTable;
3926 SymbolStack mGlobals;
3927 SymbolStack mLocals;
3928
Jack Palevich9221bcc2009-08-26 16:15:07 -07003929 SymbolStack* mpCurrentSymbolStack;
3930
Jack Palevich40600de2009-07-01 15:32:35 -07003931 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003932 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003933 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003934 Type* mkpChar; // char
3935 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003936 Type* mkpFloat;
3937 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003938 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003939 Type* mkpIntPtr;
3940 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003941 Type* mkpFloatPtr;
3942 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003943 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003944
Jack Palevich36d94142009-06-08 15:55:32 -07003945 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003946 int mLineNumber;
3947 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003948
Jack Palevichd30a2ce2009-09-09 19:08:54 -07003949 ICodeBuf* pCodeBuf;
Jack Palevich36d94142009-06-08 15:55:32 -07003950 CodeGenerator* pGen;
3951
Jack Palevicheedf9d22009-06-04 16:23:40 -07003952 String mErrorBuf;
3953
Jack Palevicheedf9d22009-06-04 16:23:40 -07003954 String mPragmas;
3955 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003956 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003957
Jack Palevich21a15a22009-05-11 14:49:29 -07003958 static const int ALLOC_SIZE = 99999;
3959
Jack Palevich303d8ff2009-06-11 19:06:24 -07003960 static const int TOK_DUMMY = 1;
3961 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003962 static const int TOK_NUM_FLOAT = 3;
3963 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003964 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich9221bcc2009-08-26 16:15:07 -07003965 static const int TOK_OP_ARROW = 6;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003966
3967 // 3..255 are character and/or operators
3968
Jack Palevich2db168f2009-06-11 14:29:47 -07003969 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003970 // Order has to match string list in "internKeywords".
3971 enum {
3972 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3973 TOK_INT = TOK_KEYWORD,
3974 TOK_CHAR,
3975 TOK_VOID,
3976 TOK_IF,
3977 TOK_ELSE,
3978 TOK_WHILE,
3979 TOK_BREAK,
3980 TOK_RETURN,
3981 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003982 TOK_AUTO,
3983 TOK_CASE,
3984 TOK_CONST,
3985 TOK_CONTINUE,
3986 TOK_DEFAULT,
3987 TOK_DO,
3988 TOK_DOUBLE,
3989 TOK_ENUM,
3990 TOK_EXTERN,
3991 TOK_FLOAT,
3992 TOK_GOTO,
3993 TOK_LONG,
3994 TOK_REGISTER,
3995 TOK_SHORT,
3996 TOK_SIGNED,
3997 TOK_SIZEOF,
3998 TOK_STATIC,
3999 TOK_STRUCT,
4000 TOK_SWITCH,
4001 TOK_TYPEDEF,
4002 TOK_UNION,
4003 TOK_UNSIGNED,
4004 TOK_VOLATILE,
4005 TOK__BOOL,
4006 TOK__COMPLEX,
4007 TOK__IMAGINARY,
4008 TOK_INLINE,
4009 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07004010
4011 // Symbols start after keywords
4012
4013 TOK_SYMBOL,
4014 TOK_PRAGMA = TOK_SYMBOL,
4015 TOK_DEFINE,
4016 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07004017 };
Jack Palevich21a15a22009-05-11 14:49:29 -07004018
4019 static const int LOCAL = 0x200;
4020
4021 static const int SYM_FORWARD = 0;
4022 static const int SYM_DEFINE = 1;
4023
4024 /* tokens in string heap */
4025 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07004026
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004027 static const int OP_INCREMENT = 0;
4028 static const int OP_DECREMENT = 1;
4029 static const int OP_MUL = 2;
4030 static const int OP_DIV = 3;
4031 static const int OP_MOD = 4;
4032 static const int OP_PLUS = 5;
4033 static const int OP_MINUS = 6;
4034 static const int OP_SHIFT_LEFT = 7;
4035 static const int OP_SHIFT_RIGHT = 8;
4036 static const int OP_LESS_EQUAL = 9;
4037 static const int OP_GREATER_EQUAL = 10;
4038 static const int OP_LESS = 11;
4039 static const int OP_GREATER = 12;
4040 static const int OP_EQUALS = 13;
4041 static const int OP_NOT_EQUALS = 14;
4042 static const int OP_LOGICAL_AND = 15;
4043 static const int OP_LOGICAL_OR = 16;
4044 static const int OP_BIT_AND = 17;
4045 static const int OP_BIT_XOR = 18;
4046 static const int OP_BIT_OR = 19;
4047 static const int OP_BIT_NOT = 20;
4048 static const int OP_LOGICAL_NOT = 21;
4049 static const int OP_COUNT = 22;
4050
4051 /* Operators are searched from front, the two-character operators appear
4052 * before the single-character operators with the same first character.
4053 * @ is used to pad out single-character operators.
4054 */
4055 static const char* operatorChars;
4056 static const char operatorLevel[];
4057
Jack Palevich569f1352009-06-29 14:29:08 -07004058 /* Called when we detect an internal problem. Does nothing in production.
4059 *
4060 */
4061 void internalError() {
4062 * (char*) 0 = 0;
4063 }
4064
Jack Palevich7f5b1a22009-08-17 16:54:56 -07004065 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07004066 if (!isTrue) {
Joe Onoratoecfd8e72009-08-28 09:26:31 -07004067 LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07004068 internalError();
4069 }
Jack Palevich86351982009-06-30 18:09:56 -07004070 }
4071
Jack Palevich40600de2009-07-01 15:32:35 -07004072 bool isSymbol(tokenid_t t) {
4073 return t >= TOK_SYMBOL &&
4074 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
4075 }
4076
4077 bool isSymbolOrKeyword(tokenid_t t) {
4078 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07004079 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07004080 }
4081
Jack Palevich86351982009-06-30 18:09:56 -07004082 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07004083 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004084 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
4085 if (pV && pV->tok != t) {
4086 internalError();
4087 }
4088 return pV;
4089 }
4090
4091 inline bool isDefined(tokenid_t t) {
4092 return t >= TOK_SYMBOL && VI(t) != 0;
4093 }
4094
Jack Palevich40600de2009-07-01 15:32:35 -07004095 const char* nameof(tokenid_t t) {
4096 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07004097 return mTokenTable[t].pText;
4098 }
4099
Jack Palevich21a15a22009-05-11 14:49:29 -07004100 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004101 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004102 }
4103
4104 void inp() {
4105 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07004106 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004107 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004108 dptr = 0;
4109 ch = dch;
4110 }
Jack Palevichdc456462009-07-16 16:50:56 -07004111 } else {
4112 if (mbBumpLine) {
4113 mLineNumber++;
4114 mbBumpLine = false;
4115 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07004116 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07004117 if (ch == '\n') {
4118 mbBumpLine = true;
4119 }
4120 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004121#if 0
4122 printf("ch='%c' 0x%x\n", ch, ch);
4123#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07004124 }
4125
4126 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07004127 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07004128 }
4129
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004130 int decodeHex(int c) {
4131 if (isdigit(c)) {
4132 c -= '0';
4133 } else if (c <= 'F') {
4134 c = c - 'A' + 10;
4135 } else {
4136 c =c - 'a' + 10;
4137 }
4138 return c;
4139 }
4140
Jack Palevichb4758ff2009-06-12 12:49:14 -07004141 /* read a character constant, advances ch to after end of constant */
4142 int getq() {
4143 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07004144 if (ch == '\\') {
4145 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004146 if (isoctal(ch)) {
4147 // 1 to 3 octal characters.
4148 val = 0;
4149 for(int i = 0; i < 3; i++) {
4150 if (isoctal(ch)) {
4151 val = (val << 3) + ch - '0';
4152 inp();
4153 }
4154 }
4155 return val;
4156 } else if (ch == 'x' || ch == 'X') {
4157 // N hex chars
4158 inp();
4159 if (! isxdigit(ch)) {
4160 error("'x' character escape requires at least one digit.");
4161 } else {
4162 val = 0;
4163 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004164 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004165 inp();
4166 }
4167 }
4168 } else {
4169 int val = ch;
4170 switch (ch) {
4171 case 'a':
4172 val = '\a';
4173 break;
4174 case 'b':
4175 val = '\b';
4176 break;
4177 case 'f':
4178 val = '\f';
4179 break;
4180 case 'n':
4181 val = '\n';
4182 break;
4183 case 'r':
4184 val = '\r';
4185 break;
4186 case 't':
4187 val = '\t';
4188 break;
4189 case 'v':
4190 val = '\v';
4191 break;
4192 case '\\':
4193 val = '\\';
4194 break;
4195 case '\'':
4196 val = '\'';
4197 break;
4198 case '"':
4199 val = '"';
4200 break;
4201 case '?':
4202 val = '?';
4203 break;
4204 default:
4205 error("Undefined character escape %c", ch);
4206 break;
4207 }
4208 inp();
4209 return val;
4210 }
4211 } else {
4212 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07004213 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07004214 return val;
4215 }
4216
4217 static bool isoctal(int ch) {
4218 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07004219 }
4220
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004221 bool acceptCh(int c) {
4222 bool result = c == ch;
4223 if (result) {
4224 pdef(ch);
4225 inp();
4226 }
4227 return result;
4228 }
4229
4230 bool acceptDigitsCh() {
4231 bool result = false;
4232 while (isdigit(ch)) {
4233 result = true;
4234 pdef(ch);
4235 inp();
4236 }
4237 return result;
4238 }
4239
4240 void parseFloat() {
4241 tok = TOK_NUM_DOUBLE;
4242 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004243 if(mTokenString.len() == 0) {
4244 mTokenString.append('0');
4245 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004246 acceptCh('.');
4247 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004248 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004249 acceptCh('-') || acceptCh('+');
4250 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004251 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004252 if (ch == 'f' || ch == 'F') {
4253 tok = TOK_NUM_FLOAT;
4254 inp();
4255 } else if (ch == 'l' || ch == 'L') {
4256 inp();
4257 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004258 }
4259 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004260 char* pEnd = pText + strlen(pText);
4261 char* pEndPtr = 0;
4262 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004263 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004264 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004265 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004266 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004267 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004268 if (errno || pEndPtr != pEnd) {
4269 error("Can't parse constant: %s", pText);
4270 }
4271 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004272 }
4273
Jack Palevich21a15a22009-05-11 14:49:29 -07004274 void next() {
4275 int l, a;
4276
Jack Palevich546b2242009-05-13 15:10:04 -07004277 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004278 if (ch == '#') {
4279 inp();
4280 next();
4281 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004282 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004283 } else if (tok == TOK_PRAGMA) {
4284 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07004285 } else if (tok == TOK_LINE) {
4286 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07004287 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004288 error("Unsupported preprocessor directive \"%s\"",
4289 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07004290 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004291 }
4292 inp();
4293 }
4294 tokl = 0;
4295 tok = ch;
4296 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004297 if (isdigit(ch) || ch == '.') {
4298 // Start of a numeric constant. Could be integer, float, or
4299 // double, won't know until we look further.
4300 mTokenString.clear();
4301 pdef(ch);
4302 inp();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004303 if (tok == '.' && !isdigit(ch)) {
4304 goto done;
4305 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004306 int base = 10;
4307 if (tok == '0') {
4308 if (ch == 'x' || ch == 'X') {
4309 base = 16;
4310 tok = TOK_NUM;
4311 tokc = 0;
4312 inp();
4313 while ( isxdigit(ch) ) {
4314 tokc = (tokc << 4) + decodeHex(ch);
4315 inp();
4316 }
4317 } else if (isoctal(ch)){
4318 base = 8;
4319 tok = TOK_NUM;
4320 tokc = 0;
4321 while ( isoctal(ch) ) {
4322 tokc = (tokc << 3) + (ch - '0');
4323 inp();
4324 }
4325 }
4326 } else if (isdigit(tok)){
4327 acceptDigitsCh();
4328 }
4329 if (base == 10) {
4330 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4331 parseFloat();
4332 } else {
4333 // It's an integer constant
4334 char* pText = mTokenString.getUnwrapped();
4335 char* pEnd = pText + strlen(pText);
4336 char* pEndPtr = 0;
4337 errno = 0;
4338 tokc = strtol(pText, &pEndPtr, base);
4339 if (errno || pEndPtr != pEnd) {
4340 error("Can't parse constant: %s %d %d", pText, base, errno);
4341 }
4342 tok = TOK_NUM;
4343 }
4344 }
4345 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07004346 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07004347 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004348 pdef(ch);
4349 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07004350 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07004351 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07004352 if (! mbSuppressMacroExpansion) {
4353 // Is this a macro?
4354 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4355 if (pMacroDefinition) {
4356 // Yes, it is a macro
4357 dptr = pMacroDefinition;
4358 dch = ch;
4359 inp();
4360 next();
4361 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004362 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004363 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07004364 inp();
4365 if (tok == '\'') {
4366 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07004367 tokc = getq();
4368 if (ch != '\'') {
4369 error("Expected a ' character, got %c", ch);
4370 } else {
4371 inp();
4372 }
Jack Palevich546b2242009-05-13 15:10:04 -07004373 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004374 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004375 while (ch && ch != EOF) {
4376 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07004377 inp();
4378 inp();
4379 if (ch == '/')
4380 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004381 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004382 if (ch == EOF) {
4383 error("End of file inside comment.");
4384 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004385 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004386 next();
Jack Palevichbd894902009-05-14 19:35:31 -07004387 } else if ((tok == '/') & (ch == '/')) {
4388 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004389 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07004390 inp();
4391 }
4392 inp();
4393 next();
Jack Palevich9221bcc2009-08-26 16:15:07 -07004394 } else if ((tok == '-') & (ch == '>')) {
4395 inp();
4396 tok = TOK_OP_ARROW;
Jack Palevich21a15a22009-05-11 14:49:29 -07004397 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004398 const char* t = operatorChars;
4399 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07004400 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004401 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004402 tokl = operatorLevel[opIndex];
4403 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07004404 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004405#if 0
4406 printf("%c%c -> tokl=%d tokc=0x%x\n",
4407 l, a, tokl, tokc);
4408#endif
4409 if (a == ch) {
4410 inp();
4411 tok = TOK_DUMMY; /* dummy token for double tokens */
4412 }
Jack Palevich0c017742009-07-31 12:00:39 -07004413 /* check for op=, valid for * / % + - << >> & ^ | */
4414 if (ch == '=' &&
4415 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07004416 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07004417 inp();
4418 tok = TOK_OP_ASSIGNMENT;
4419 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004420 break;
4421 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004422 opIndex++;
4423 }
4424 if (l == 0) {
4425 tokl = 0;
4426 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004427 }
4428 }
4429 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07004430
4431 done: ;
Jack Palevich21a15a22009-05-11 14:49:29 -07004432#if 0
4433 {
Jack Palevich569f1352009-06-29 14:29:08 -07004434 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004435 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07004436 fprintf(stderr, "%s\n", buf.getUnwrapped());
4437 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004438#endif
4439 }
4440
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004441 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07004442 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07004443 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07004444 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07004445 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004446 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004447 if (ch == '(') {
4448 delete pName;
4449 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07004450 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004451 }
4452 while (isspace(ch)) {
4453 inp();
4454 }
Jack Palevich569f1352009-06-29 14:29:08 -07004455 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07004456 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004457 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07004458 // Check for '//' comments.
4459 if (appendToValue && ch == '/') {
4460 inp();
4461 if (ch == '/') {
4462 appendToValue = false;
4463 } else {
4464 value.append('/');
4465 }
4466 }
4467 if (appendToValue && ch != EOF) {
4468 value.append(ch);
4469 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004470 inp();
4471 }
Jack Palevich569f1352009-06-29 14:29:08 -07004472 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4473 memcpy(pDefn, value.getUnwrapped(), value.len());
4474 pDefn[value.len()] = 0;
4475 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07004476 }
4477
Jack Palevicheedf9d22009-06-04 16:23:40 -07004478 void doPragma() {
4479 // # pragma name(val)
4480 int state = 0;
4481 while(ch != EOF && ch != '\n' && state < 10) {
4482 switch(state) {
4483 case 0:
4484 if (isspace(ch)) {
4485 inp();
4486 } else {
4487 state++;
4488 }
4489 break;
4490 case 1:
4491 if (isalnum(ch)) {
4492 mPragmas.append(ch);
4493 inp();
4494 } else if (ch == '(') {
4495 mPragmas.append(0);
4496 inp();
4497 state++;
4498 } else {
4499 state = 11;
4500 }
4501 break;
4502 case 2:
4503 if (isalnum(ch)) {
4504 mPragmas.append(ch);
4505 inp();
4506 } else if (ch == ')') {
4507 mPragmas.append(0);
4508 inp();
4509 state = 10;
4510 } else {
4511 state = 11;
4512 }
4513 break;
4514 }
4515 }
4516 if(state != 10) {
4517 error("Unexpected pragma syntax");
4518 }
4519 mPragmaStringCount += 2;
4520 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004521
Jack Palevichdc456462009-07-16 16:50:56 -07004522 void doLine() {
4523 // # line number { "filename "}
4524 next();
4525 if (tok != TOK_NUM) {
4526 error("Expected a line-number");
4527 } else {
4528 mLineNumber = tokc-1; // The end-of-line will increment it.
4529 }
4530 while(ch != EOF && ch != '\n') {
4531 inp();
4532 }
4533 }
4534
Jack Palevichac0e95e2009-05-29 13:53:44 -07004535 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07004536 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07004537 mErrorBuf.vprintf(fmt, ap);
4538 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07004539 }
4540
Jack Palevich8b0624c2009-05-20 12:12:06 -07004541 void skip(intptr_t c) {
Jack Palevichb13d4e82009-09-18 16:26:05 -07004542 if (!accept(c)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004543 error("'%c' expected", c);
4544 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004545 }
4546
Jack Palevich86351982009-06-30 18:09:56 -07004547 bool accept(intptr_t c) {
4548 if (tok == c) {
4549 next();
4550 return true;
4551 }
4552 return false;
4553 }
4554
Jack Palevich40600de2009-07-01 15:32:35 -07004555 bool acceptStringLiteral() {
4556 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07004557 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07004558 // This while loop merges multiple adjacent string constants.
4559 while (tok == '"') {
4560 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004561 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07004562 }
4563 if (ch != '"') {
4564 error("Unterminated string constant.");
4565 }
4566 inp();
4567 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07004568 }
Jack Palevich40600de2009-07-01 15:32:35 -07004569 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07004570 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004571 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07004572 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07004573
4574 return true;
4575 }
4576 return false;
4577 }
Jack Palevich8c246a92009-07-14 21:14:10 -07004578
Jack Palevichb1544ca2009-07-16 15:09:20 -07004579 void linkGlobal(tokenid_t t, bool isFunction) {
4580 VariableInfo* pVI = VI(t);
4581 void* n = NULL;
4582 if (mpSymbolLookupFn) {
4583 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4584 }
4585 if (pVI->pType == NULL) {
4586 if (isFunction) {
4587 pVI->pType = mkpIntFn;
4588 } else {
4589 pVI->pType = mkpInt;
4590 }
4591 }
4592 pVI->pAddress = n;
4593 }
4594
Jack Palevich29daf572009-07-30 19:38:55 -07004595 void unaryOrAssignment() {
4596 unary();
4597 if (accept('=')) {
4598 checkLVal();
4599 pGen->pushR0();
4600 expr();
4601 pGen->forceR0RVal();
4602 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07004603 } else if (tok == TOK_OP_ASSIGNMENT) {
4604 int t = tokc;
4605 next();
4606 checkLVal();
4607 pGen->pushR0();
4608 pGen->forceR0RVal();
4609 pGen->pushR0();
4610 expr();
4611 pGen->forceR0RVal();
4612 pGen->genOp(t);
4613 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07004614 }
4615 }
4616
Jack Palevich40600de2009-07-01 15:32:35 -07004617 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07004618 */
Jack Palevich29daf572009-07-30 19:38:55 -07004619 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004620 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07004621 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07004622 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004623 if (acceptStringLiteral()) {
4624 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07004625 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004626 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004627 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004628 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004629 t = tok;
4630 next();
4631 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004632 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004633 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004634 // Align to 4-byte boundary
4635 glo = (char*) (((intptr_t) glo + 3) & -4);
4636 * (float*) glo = (float) ad;
4637 pGen->loadFloat((int) glo, mkpFloat);
4638 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004639 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004640 // Align to 8-byte boundary
4641 glo = (char*) (((intptr_t) glo + 7) & -8);
4642 * (double*) glo = ad;
4643 pGen->loadFloat((int) glo, mkpDouble);
4644 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004645 } else if (c == 2) {
4646 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004647 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004648 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004649 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004650 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004651 else if (t == '+') {
4652 // ignore unary plus.
4653 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004654 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004655 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004656 } else if (c == 11) {
4657 // pre increment / pre decrement
4658 unary();
4659 doIncDec(a == OP_INCREMENT, 0);
4660 }
4661 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004662 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004663 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004664 if (pCast) {
4665 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004666 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004667 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004668 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004669 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004670 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004671 skip(')');
4672 }
4673 } else if (t == '*') {
4674 /* This is a pointer dereference.
4675 */
Jack Palevich29daf572009-07-30 19:38:55 -07004676 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004677 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004678 } else if (t == '&') {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004679 unary();
4680 doAddressOf();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004681 } else if (t == EOF ) {
4682 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004683 } else if (t == ';') {
4684 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004685 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004686 // Don't have to do anything special here, the error
4687 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004689 if (!isDefined(t)) {
4690 mGlobals.add(t);
4691 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004692 }
Jack Palevich8df46192009-07-07 14:48:51 -07004693 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004694 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004695 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004696 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004697 linkGlobal(t, tok == '(');
4698 n = (intptr_t) pVI->pAddress;
4699 if (!n && tok != '(') {
Jack Palevich1c60e462009-09-18 15:03:03 -07004700 error("Undeclared variable %s", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004701 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004702 }
Jack Palevich29daf572009-07-30 19:38:55 -07004703 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004704 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004705 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004706 linkGlobal(t, false);
4707 n = (intptr_t) pVI->pAddress;
4708 if (!n) {
Jack Palevich1c60e462009-09-18 15:03:03 -07004709 error("Undeclared variable %s", nameof(t));
Jack Palevichb1544ca2009-07-16 15:09:20 -07004710 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004711 }
Jack Palevich5b659092009-07-31 14:55:07 -07004712 }
4713 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004714 Type* pVal;
4715 ExpressionType et;
4716 if (pVI->pType->tag == TY_ARRAY) {
4717 pVal = pVI->pType;
4718 et = ET_RVALUE;
4719 } else {
4720 pVal = createPtrType(pVI->pType);
4721 et = ET_LVALUE;
4722 }
Jack Palevich5b659092009-07-31 14:55:07 -07004723 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004724 int tag = pVal->pHead->tag;
4725 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004726 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004727 }
Jack Palevich5b659092009-07-31 14:55:07 -07004728 pGen->leaR0(n, pVal, et);
4729 } else {
4730 pVI->pForward = (void*) pGen->leaForward(
4731 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004732 }
4733 }
4734 }
4735
Jack Palevich5b659092009-07-31 14:55:07 -07004736 /* Now handle postfix operators */
4737 for(;;) {
4738 if (tokl == 11) {
4739 // post inc / post dec
4740 doIncDec(tokc == OP_INCREMENT, true);
4741 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004742 } else if (accept('[')) {
4743 // Array reference
4744 pGen->forceR0RVal();
4745 pGen->pushR0();
4746 commaExpr();
4747 pGen->forceR0RVal();
4748 pGen->genOp(OP_PLUS);
4749 doPointer();
4750 skip(']');
Jack Palevich9221bcc2009-08-26 16:15:07 -07004751 } else if (accept('.')) {
4752 // struct element
4753 pGen->forceR0RVal();
4754 Type* pStruct = pGen->getR0Type();
4755 if (pStruct->tag == TY_STRUCT) {
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004756 doStructMember(pStruct, true);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004757 } else {
4758 error("expected a struct value to the left of '.'");
4759 }
4760 } else if (accept(TOK_OP_ARROW)) {
4761 pGen->forceR0RVal();
4762 Type* pPtr = pGen->getR0Type();
4763 if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4764 pGen->loadR0FromR0();
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004765 doStructMember(pPtr->pHead, false);
Jack Palevich9221bcc2009-08-26 16:15:07 -07004766 } else {
4767 error("Expected a pointer to a struct to the left of '->'");
4768 }
Jack Palevich5b659092009-07-31 14:55:07 -07004769 } else if (accept('(')) {
4770 /* function call */
4771 Type* pDecl = NULL;
4772 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004773 Type* pFn = pGen->getR0Type();
4774 assert(pFn->tag == TY_POINTER);
4775 assert(pFn->pHead->tag == TY_FUNC);
4776 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004777 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004778 Type* pArgList = pDecl->pTail;
4779 bool varArgs = pArgList == NULL;
4780 /* push args and invert order */
4781 a = pGen->beginFunctionCallArguments();
4782 int l = 0;
4783 int argCount = 0;
4784 while (tok != ')' && tok != EOF) {
4785 if (! varArgs && !pArgList) {
4786 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004787 }
Jack Palevich5b659092009-07-31 14:55:07 -07004788 expr();
4789 pGen->forceR0RVal();
4790 Type* pTargetType;
4791 if (pArgList) {
4792 pTargetType = pArgList->pHead;
4793 pArgList = pArgList->pTail;
4794 } else {
4795 // This is a ... function, just pass arguments in their
4796 // natural type.
4797 pTargetType = pGen->getR0Type();
4798 if (pTargetType->tag == TY_FLOAT) {
4799 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004800 } else if (pTargetType->tag == TY_ARRAY) {
4801 // Pass arrays by pointer.
4802 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004803 }
4804 }
4805 if (pTargetType->tag == TY_VOID) {
4806 error("Can't pass void value for argument %d",
4807 argCount + 1);
4808 } else {
4809 l += pGen->storeR0ToArg(l, pTargetType);
4810 }
4811 if (accept(',')) {
4812 // fine
4813 } else if ( tok != ')') {
4814 error("Expected ',' or ')'");
4815 }
4816 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004817 }
Jack Palevich5b659092009-07-31 14:55:07 -07004818 if (! varArgs && pArgList) {
4819 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004820 }
Jack Palevich5b659092009-07-31 14:55:07 -07004821 pGen->endFunctionCallArguments(pDecl, a, l);
4822 skip(')');
4823 pGen->callIndirect(l, pDecl);
4824 pGen->adjustStackAfterCall(pDecl, l, true);
4825 } else {
4826 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004827 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004828 }
4829 }
4830
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004831 void doStructMember(Type* pStruct, bool isDot) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07004832 Type* pStructElement = lookupStructMember(pStruct, tok);
4833 if (pStructElement) {
4834 next();
4835 pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4836 } else {
4837 String buf;
4838 decodeToken(buf, tok, true);
Jack Palevich8fe5dca2009-09-04 15:34:21 -07004839 error("Expected a struct member to the right of '%s', got %s",
4840 isDot ? "." : "->", buf.getUnwrapped());
Jack Palevich9221bcc2009-08-26 16:15:07 -07004841 }
4842 }
4843
Jack Palevichaaac9282009-07-31 14:34:34 -07004844 void doIncDec(int isInc, int isPost) {
4845 // R0 already has the lval
4846 checkLVal();
4847 int lit = isInc ? 1 : -1;
4848 pGen->pushR0();
4849 pGen->loadR0FromR0();
4850 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004851 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4852 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004853 error("++/-- illegal for this type. %d", tag);
4854 }
4855 if (isPost) {
4856 pGen->over();
4857 pGen->pushR0();
4858 pGen->li(lit);
4859 pGen->genOp(OP_PLUS);
4860 pGen->storeR0ToTOS();
4861 pGen->popR0();
4862 } else {
4863 pGen->pushR0();
4864 pGen->li(lit);
4865 pGen->genOp(OP_PLUS);
4866 pGen->over();
4867 pGen->storeR0ToTOS();
4868 pGen->popR0();
4869 }
4870 }
4871
Jack Palevich47cbea92009-07-31 15:25:53 -07004872 void doPointer() {
4873 pGen->forceR0RVal();
4874 Type* pR0Type = pGen->getR0Type();
4875 if (pR0Type->tag != TY_POINTER) {
4876 error("Expected a pointer type.");
4877 } else {
4878 if (pR0Type->pHead->tag != TY_FUNC) {
4879 pGen->setR0ExpressionType(ET_LVALUE);
4880 }
4881 }
4882 }
4883
Jack Palevich5fd66ae2009-09-04 15:24:23 -07004884 void doAddressOf() {
4885 Type* pR0 = pGen->getR0Type();
4886 bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4887 if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4888 error("Expected an lvalue");
4889 }
4890 Type* pR0Type = pGen->getR0Type();
4891 pGen->setR0ExpressionType(ET_RVALUE);
4892 }
4893
Jack Palevich40600de2009-07-01 15:32:35 -07004894 /* Recursive descent parser for binary operations.
4895 */
4896 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004897 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004898 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004899 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004900 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004901 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004902 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004903 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004904 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004905 t = tokc;
4906 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004907 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004908 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004909 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004910 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004911 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004912 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004913 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004914 // Check for syntax error.
4915 if (pGen->getR0Type() == NULL) {
4916 // We failed to parse a right-hand argument.
4917 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004918 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004919 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004920 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004921 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004922 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004923 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004924 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004925 }
4926 }
4927 }
4928 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004929 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004930 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004931 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004932 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004933 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004934 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004935 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004936 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004937 }
4938 }
4939 }
4940
Jack Palevich43aaee32009-07-31 14:01:37 -07004941 void commaExpr() {
4942 for(;;) {
4943 expr();
4944 if (!accept(',')) {
4945 break;
4946 }
4947 }
4948 }
4949
Jack Palevich21a15a22009-05-11 14:49:29 -07004950 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004951 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004952 }
4953
4954 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004955 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004956 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004957 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004958 }
4959
Jack Palevicha6baa232009-06-12 11:25:59 -07004960 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004961 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004962
Jack Palevich95727a02009-07-06 12:07:15 -07004963 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004964 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004965 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004966 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004967 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004968 next();
4969 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004970 a = test_expr();
4971 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004972 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004973 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004974 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004975 n = pGen->gjmp(0); /* jmp */
4976 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004977 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004978 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004979 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004980 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004981 }
Jack Palevich546b2242009-05-13 15:10:04 -07004982 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004983 t = tok;
4984 next();
4985 skip('(');
4986 if (t == TOK_WHILE) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004987 n = pCodeBuf->getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004988 a = test_expr();
4989 } else {
4990 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004991 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004992 skip(';');
Jack Palevichd30a2ce2009-09-09 19:08:54 -07004993 n = pCodeBuf->getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07004994 a = 0;
4995 if (tok != ';')
4996 a = test_expr();
4997 skip(';');
4998 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004999 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07005000 commaExpr();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005001 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005002 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07005003 n = t + 4;
5004 }
5005 }
5006 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07005007 block((intptr_t) &a, false);
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005008 pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005009 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07005010 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07005011 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005012 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005013 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005014 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07005015 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07005016 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005017 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07005018 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07005019 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07005020 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005021 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07005022 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07005023 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07005024 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07005025 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07005026 if (pReturnType->tag == TY_VOID) {
5027 error("Must not return a value from a void function");
5028 } else {
5029 pGen->convertR0(pReturnType);
5030 }
5031 } else {
5032 if (pReturnType->tag != TY_VOID) {
5033 error("Must specify a value here");
5034 }
Jack Palevich8df46192009-07-07 14:48:51 -07005035 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005036 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07005037 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005038 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07005039 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07005040 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07005041 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005042 }
5043 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005044
Jack Palevicha8f427f2009-07-13 18:40:08 -07005045 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07005046 if (a == b) {
5047 return true;
5048 }
5049 if (a == NULL || b == NULL) {
5050 return false;
5051 }
5052 TypeTag at = a->tag;
5053 if (at != b->tag) {
5054 return false;
5055 }
5056 if (at == TY_POINTER) {
5057 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07005058 } else if (at == TY_ARRAY) {
5059 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07005060 } else if (at == TY_FUNC || at == TY_PARAM) {
5061 return typeEqual(a->pHead, b->pHead)
5062 && typeEqual(a->pTail, b->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005063 } else if (at == TY_STRUCT) {
5064 return a->pHead == b->pHead;
Jack Palevich3f226492009-07-02 14:46:19 -07005065 }
5066 return true;
5067 }
5068
Jack Palevich2ff5c222009-07-23 15:11:22 -07005069 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07005070 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005071 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07005072 memset(pType, 0, sizeof(*pType));
5073 pType->tag = tag;
5074 pType->pHead = pHead;
5075 pType->pTail = pTail;
5076 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005077 }
5078
Jack Palevich2ff5c222009-07-23 15:11:22 -07005079 Type* createPtrType(Type* pType) {
5080 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005081 }
5082
5083 /**
5084 * Try to print a type in declaration order
5085 */
Jack Palevich86351982009-06-30 18:09:56 -07005086 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07005087 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07005088 if (pType == NULL) {
5089 buffer.appendCStr("null");
5090 return;
5091 }
Jack Palevich3f226492009-07-02 14:46:19 -07005092 decodeTypeImp(buffer, pType);
5093 }
5094
5095 void decodeTypeImp(String& buffer, Type* pType) {
5096 decodeTypeImpPrefix(buffer, pType);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005097 decodeId(buffer, pType->id);
5098 decodeTypeImpPostfix(buffer, pType);
5099 }
Jack Palevich3f226492009-07-02 14:46:19 -07005100
Jack Palevich9221bcc2009-08-26 16:15:07 -07005101 void decodeId(String& buffer, tokenid_t id) {
5102 if (id) {
5103 String temp;
5104 decodeToken(temp, id, false);
Jack Palevich86351982009-06-30 18:09:56 -07005105 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07005106 }
Jack Palevich3f226492009-07-02 14:46:19 -07005107 }
5108
5109 void decodeTypeImpPrefix(String& buffer, Type* pType) {
5110 TypeTag tag = pType->tag;
5111
Jack Palevich9221bcc2009-08-26 16:15:07 -07005112 if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
Jack Palevich3f226492009-07-02 14:46:19 -07005113 switch (tag) {
5114 case TY_INT:
5115 buffer.appendCStr("int");
5116 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005117 case TY_SHORT:
5118 buffer.appendCStr("short");
5119 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005120 case TY_CHAR:
5121 buffer.appendCStr("char");
5122 break;
5123 case TY_VOID:
5124 buffer.appendCStr("void");
5125 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005126 case TY_FLOAT:
5127 buffer.appendCStr("float");
5128 break;
5129 case TY_DOUBLE:
5130 buffer.appendCStr("double");
5131 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005132 case TY_STRUCT:
5133 {
5134 bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
5135 buffer.appendCStr(isStruct ? "struct" : "union");
5136 if (pType->pHead && pType->pHead->structTag) {
5137 buffer.append(' ');
5138 decodeId(buffer, pType->pHead->structTag);
5139 }
5140 }
5141 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005142 default:
5143 break;
5144 }
Jack Palevich86351982009-06-30 18:09:56 -07005145 buffer.append(' ');
5146 }
Jack Palevich3f226492009-07-02 14:46:19 -07005147
5148 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07005149 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07005150 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005151 case TY_SHORT:
5152 break;
Jack Palevich86351982009-06-30 18:09:56 -07005153 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07005154 break;
5155 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07005156 break;
Jack Palevich95727a02009-07-06 12:07:15 -07005157 case TY_FLOAT:
5158 break;
5159 case TY_DOUBLE:
5160 break;
Jack Palevich86351982009-06-30 18:09:56 -07005161 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07005162 decodeTypeImpPrefix(buffer, pType->pHead);
5163 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5164 buffer.append('(');
5165 }
5166 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07005167 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005168 case TY_ARRAY:
5169 decodeTypeImpPrefix(buffer, pType->pHead);
5170 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005171 case TY_STRUCT:
5172 break;
Jack Palevich86351982009-06-30 18:09:56 -07005173 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07005174 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005175 break;
5176 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07005177 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07005178 break;
5179 default:
5180 String temp;
5181 temp.printf("Unknown tag %d", pType->tag);
5182 buffer.append(temp);
5183 break;
5184 }
Jack Palevich3f226492009-07-02 14:46:19 -07005185 }
5186
5187 void decodeTypeImpPostfix(String& buffer, Type* pType) {
5188 TypeTag tag = pType->tag;
5189
5190 switch(tag) {
5191 case TY_POINTER:
5192 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
5193 buffer.append(')');
5194 }
5195 decodeTypeImpPostfix(buffer, pType->pHead);
5196 break;
Jack Palevichb6154502009-08-04 14:56:09 -07005197 case TY_ARRAY:
5198 {
5199 String temp;
5200 temp.printf("[%d]", pType->length);
5201 buffer.append(temp);
5202 }
5203 break;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005204 case TY_STRUCT:
5205 if (pType->pHead->length >= 0) {
5206 buffer.appendCStr(" {");
5207 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5208 decodeTypeImp(buffer, pArg->pHead);
5209 buffer.appendCStr(";");
5210 }
5211 buffer.append('}');
5212 }
5213 break;
Jack Palevich3f226492009-07-02 14:46:19 -07005214 case TY_FUNC:
5215 buffer.append('(');
5216 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5217 decodeTypeImp(buffer, pArg);
5218 if (pArg->pTail) {
5219 buffer.appendCStr(", ");
5220 }
5221 }
5222 buffer.append(')');
5223 break;
5224 default:
5225 break;
Jack Palevich86351982009-06-30 18:09:56 -07005226 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005227 }
5228
Jack Palevich86351982009-06-30 18:09:56 -07005229 void printType(Type* pType) {
5230 String buffer;
5231 decodeType(buffer, pType);
5232 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005233 }
5234
Jack Palevich2ff5c222009-07-23 15:11:22 -07005235 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07005236 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005237 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07005238 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005239 } else if (tok == TOK_SHORT) {
5240 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005241 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07005242 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005243 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07005244 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07005245 } else if (tok == TOK_FLOAT) {
5246 pType = mkpFloat;
5247 } else if (tok == TOK_DOUBLE) {
5248 pType = mkpDouble;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005249 } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5250 return acceptStruct();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005251 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005252 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005253 }
5254 next();
Jack Palevich86351982009-06-30 18:09:56 -07005255 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005256 }
5257
Jack Palevich9221bcc2009-08-26 16:15:07 -07005258 Type* acceptStruct() {
5259 assert(tok == TOK_STRUCT || tok == TOK_UNION);
5260 bool isStruct = tok == TOK_STRUCT;
5261 next();
5262 tokenid_t structTag = acceptSymbol();
5263 bool isDeclaration = accept('{');
5264 bool fail = false;
5265
5266 Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5267 if (structTag) {
5268 Token* pToken = &mTokenTable[structTag];
5269 VariableInfo* pStructInfo = pToken->mpStructInfo;
5270 bool needToDeclare = !pStructInfo;
5271 if (pStructInfo) {
5272 if (isDeclaration) {
5273 if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5274 if (pStructInfo->pType->pHead->length == -1) {
5275 // we're filling in a forward declaration.
5276 needToDeclare = false;
5277 } else {
5278 error("A struct with the same name is already defined at this level.");
5279 fail = true;
5280 }
5281 } else {
5282 needToDeclare = true;
5283 }
5284 }
5285 if (!fail) {
5286 assert(pStructInfo->isStructTag);
5287 pStructType->pHead = pStructInfo->pType;
5288 pStructType->pTail = pStructType->pHead->pTail;
5289 }
5290 }
5291
5292 if (needToDeclare) {
5293 // This is a new struct name
5294 pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5295 pStructType = createType(TY_STRUCT, NULL, NULL);
5296 pStructType->structTag = structTag;
5297 pStructType->pHead = pStructType;
5298 if (! isDeclaration) {
5299 // A forward declaration
5300 pStructType->length = -1;
5301 }
5302 pToken->mpStructInfo->pType = pStructType;
5303 }
5304 } else {
5305 // An anonymous struct
5306 pStructType->pHead = pStructType;
5307 }
5308
5309 if (isDeclaration) {
5310 size_t offset = 0;
5311 size_t structSize = 0;
5312 size_t structAlignment = 0;
5313 Type** pParamHolder = & pStructType->pHead->pTail;
5314 while (tok != '}' && tok != EOF) {
5315 Type* pPrimitiveType = expectPrimitiveType();
5316 if (pPrimitiveType) {
5317 while (tok != ';' && tok != EOF) {
5318 Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5319 if (!pItem) {
5320 break;
5321 }
5322 if (lookupStructMember(pStructType, pItem->id)) {
5323 String buf;
5324 decodeToken(buf, pItem->id, false);
5325 error("Duplicate struct member %s", buf.getUnwrapped());
5326 }
5327 Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5328 size_t alignment = pGen->alignmentOf(pItem);
5329 if (alignment > structAlignment) {
5330 structAlignment = alignment;
5331 }
5332 size_t alignmentMask = alignment - 1;
5333 offset = (offset + alignmentMask) & ~alignmentMask;
5334 pStructElement->length = offset;
5335 size_t size = pGen->sizeOf(pItem);
5336 if (isStruct) {
5337 offset += size;
5338 structSize = offset;
5339 } else {
5340 if (size >= structSize) {
5341 structSize = size;
5342 }
5343 }
5344 *pParamHolder = pStructElement;
5345 pParamHolder = &pStructElement->pTail;
5346 accept(',');
5347 }
5348 skip(';');
5349 } else {
5350 // Some sort of syntax error, skip token and keep trying
5351 next();
5352 }
5353 }
5354 if (!fail) {
5355 pStructType->pHead->length = structSize;
5356 pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5357 }
5358 skip('}');
5359 }
5360 if (fail) {
5361 pStructType = NULL;
5362 }
5363 return pStructType;
5364 }
5365
5366 Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5367 for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5368 if (pStructElement->pHead->id == memberId) {
5369 return pStructElement;
5370 }
5371 }
5372 return NULL;
5373 }
5374
Jack Palevich2ff5c222009-07-23 15:11:22 -07005375 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07005376 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07005377 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07005378 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005379 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005380 if (declName) {
5381 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07005382 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07005383 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich9221bcc2009-08-26 16:15:07 -07005384 *pType = *pOldType;
Jack Palevich86351982009-06-30 18:09:56 -07005385 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07005386 } else if (nameRequired) {
5387 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07005388 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005389#if 0
5390 fprintf(stderr, "Parsed a declaration: ");
5391 printType(pType);
5392#endif
Jack Palevich3377bfd2009-07-16 19:05:07 -07005393 if (reportFailure) {
5394 return NULL;
5395 }
Jack Palevich86351982009-06-30 18:09:56 -07005396 return pType;
5397 }
5398
Jack Palevich2ff5c222009-07-23 15:11:22 -07005399 Type* expectDeclaration(Type* pBaseType) {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005400 bool nameRequired = pBaseType->tag != TY_STRUCT;
5401 Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
Jack Palevich86351982009-06-30 18:09:56 -07005402 if (! pType) {
5403 error("Expected a declaration");
5404 }
5405 return pType;
5406 }
5407
Jack Palevich3f226492009-07-02 14:46:19 -07005408 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07005409 Type* acceptCastTypeDeclaration() {
5410 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07005411 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005412 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07005413 }
Jack Palevich86351982009-06-30 18:09:56 -07005414 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005415 }
5416
Jack Palevich2ff5c222009-07-23 15:11:22 -07005417 Type* expectCastTypeDeclaration() {
5418 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07005419 if (! pType) {
5420 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07005421 }
Jack Palevich3f226492009-07-02 14:46:19 -07005422 return pType;
5423 }
5424
5425 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005426 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005427 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005428 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07005429 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07005430 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005431 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005432 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005433 return pType;
5434 }
5435
5436 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005437 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07005438 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07005439 // direct-dcl :
5440 // name
5441 // (dcl)
5442 // direct-dcl()
5443 // direct-dcl[]
5444 Type* pNewHead = NULL;
5445 if (accept('(')) {
5446 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07005447 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07005448 skip(')');
5449 } else if ((declName = acceptSymbol()) != 0) {
5450 if (nameAllowed == false && declName) {
5451 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07005452 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005453 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07005454 } else if (nameRequired && ! declName) {
5455 String temp;
5456 decodeToken(temp, tok, true);
5457 error("Expected name. Got %s", temp.getUnwrapped());
5458 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07005459 }
Jack Palevichb6154502009-08-04 14:56:09 -07005460 for(;;) {
5461 if (accept('(')) {
5462 // Function declaration
5463 Type* pTail = acceptArgs(nameAllowed);
5464 pType = createType(TY_FUNC, pType, pTail);
5465 skip(')');
5466 } if (accept('[')) {
5467 if (tok != ']') {
5468 if (tok != TOK_NUM || tokc <= 0) {
5469 error("Expected positive integer constant");
5470 } else {
5471 Type* pDecayType = createPtrType(pType);
5472 pType = createType(TY_ARRAY, pType, pDecayType);
5473 pType->length = tokc;
5474 }
5475 next();
5476 }
5477 skip(']');
5478 } else {
5479 break;
5480 }
Jack Palevich86351982009-06-30 18:09:56 -07005481 }
Jack Palevich3f226492009-07-02 14:46:19 -07005482
5483 if (pNewHead) {
5484 Type* pA = pNewHead;
5485 while (pA->pHead) {
5486 pA = pA->pHead;
5487 }
5488 pA->pHead = pType;
5489 pType = pNewHead;
5490 }
Jack Palevich86351982009-06-30 18:09:56 -07005491 return pType;
5492 }
5493
Jack Palevich2ff5c222009-07-23 15:11:22 -07005494 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07005495 Type* pHead = NULL;
5496 Type* pTail = NULL;
5497 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005498 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005499 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005500 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07005501 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005502 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07005503 if (!pHead) {
5504 pHead = pParam;
5505 pTail = pParam;
5506 } else {
5507 pTail->pTail = pParam;
5508 pTail = pParam;
5509 }
5510 }
5511 }
5512 if (! accept(',')) {
5513 break;
5514 }
5515 }
5516 return pHead;
5517 }
5518
Jack Palevich2ff5c222009-07-23 15:11:22 -07005519 Type* expectPrimitiveType() {
5520 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005521 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07005522 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005523 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07005524 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07005525 }
Jack Palevich86351982009-06-30 18:09:56 -07005526 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005527 }
5528
Jack Palevichb5e33312009-07-30 19:06:34 -07005529 void checkLVal() {
5530 if (pGen->getR0ExpressionType() != ET_LVALUE) {
Jack Palevich5fd66ae2009-09-04 15:24:23 -07005531 error("Expected an lvalue");
Jack Palevichb5e33312009-07-30 19:06:34 -07005532 }
5533 }
5534
Jack Palevich86351982009-06-30 18:09:56 -07005535 void addGlobalSymbol(Type* pDecl) {
5536 tokenid_t t = pDecl->id;
5537 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005538 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005539 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005540 }
Jack Palevich86351982009-06-30 18:09:56 -07005541 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07005542 }
5543
Jack Palevich86351982009-06-30 18:09:56 -07005544 void reportDuplicate(tokenid_t t) {
5545 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07005546 }
5547
Jack Palevich86351982009-06-30 18:09:56 -07005548 void addLocalSymbol(Type* pDecl) {
5549 tokenid_t t = pDecl->id;
5550 if (mLocals.isDefinedAtCurrentLevel(t)) {
5551 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07005552 }
Jack Palevich86351982009-06-30 18:09:56 -07005553 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07005554 }
5555
Jack Palevich61de31f2009-09-08 11:06:40 -07005556 bool checkUndeclaredStruct(Type* pBaseType) {
5557 if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5558 String temp;
5559 decodeToken(temp, pBaseType->structTag, false);
5560 error("Undeclared struct %s", temp.getUnwrapped());
5561 return true;
5562 }
5563 return false;
5564 }
5565
Jack Palevich95727a02009-07-06 12:07:15 -07005566 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005567 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005568
Jack Palevich95727a02009-07-06 12:07:15 -07005569 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07005570 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005571 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005572 if (!pDecl) {
5573 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005574 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005575 if (!pDecl->id) {
5576 break;
5577 }
Jack Palevich61de31f2009-09-08 11:06:40 -07005578 if (checkUndeclaredStruct(pDecl)) {
5579 break;
5580 }
Jack Palevich86351982009-06-30 18:09:56 -07005581 addLocalSymbol(pDecl);
Jack Palevich1c60e462009-09-18 15:03:03 -07005582 if (pDecl->tag == TY_FUNC) {
5583 if (tok == '{') {
5584 error("Nested functions are not allowed. Did you forget a '}' ?");
5585 break;
5586 }
5587 // Else it's a forward declaration of a function.
5588 } else {
5589 int variableAddress = 0;
5590 size_t alignment = pGen->alignmentOf(pDecl);
5591 assert(alignment > 0);
5592 size_t alignmentMask = ~ (alignment - 1);
5593 size_t sizeOf = pGen->sizeOf(pDecl);
5594 assert(sizeOf > 0);
5595 loc = (loc + alignment - 1) & alignmentMask;
5596 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5597 loc = loc + alignedSize;
5598 variableAddress = -loc;
5599 VI(pDecl->id)->pAddress = (void*) variableAddress;
5600 if (accept('=')) {
5601 /* assignment */
5602 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5603 pGen->pushR0();
5604 expr();
5605 pGen->forceR0RVal();
5606 pGen->storeR0ToTOS();
5607 }
Jack Palevichd7461a72009-06-12 14:26:58 -07005608 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07005609 if (tok == ',')
5610 next();
5611 }
5612 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07005613 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07005614 }
5615 }
5616
Jack Palevichf1728be2009-06-12 13:53:51 -07005617 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07005618 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07005619 }
5620
Jack Palevich37c54bd2009-07-14 18:35:36 -07005621 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07005622 if (token == EOF ) {
5623 buffer.printf("EOF");
5624 } else if (token == TOK_NUM) {
5625 buffer.printf("numeric constant");
5626 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07005627 if (token < 32) {
5628 buffer.printf("'\\x%02x'", token);
5629 } else {
5630 buffer.printf("'%c'", token);
5631 }
Jack Palevich569f1352009-06-29 14:29:08 -07005632 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07005633 if (quote) {
5634 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5635 buffer.printf("keyword \"%s\"", nameof(token));
5636 } else {
5637 buffer.printf("symbol \"%s\"", nameof(token));
5638 }
5639 } else {
5640 buffer.printf("%s", nameof(token));
5641 }
Jack Palevich569f1352009-06-29 14:29:08 -07005642 }
5643 }
5644
Jack Palevich9221bcc2009-08-26 16:15:07 -07005645 void printToken(tokenid_t token) {
5646 String buffer;
5647 decodeToken(buffer, token, true);
5648 fprintf(stderr, "%s\n", buffer.getUnwrapped());
5649 }
5650
Jack Palevich40600de2009-07-01 15:32:35 -07005651 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07005652 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07005653 if (!result) {
5654 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07005655 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07005656 error("Expected symbol. Got %s", temp.getUnwrapped());
5657 }
5658 return result;
5659 }
5660
Jack Palevich86351982009-06-30 18:09:56 -07005661 tokenid_t acceptSymbol() {
5662 tokenid_t result = 0;
5663 if (tok >= TOK_SYMBOL) {
5664 result = tok;
5665 next();
Jack Palevich86351982009-06-30 18:09:56 -07005666 }
5667 return result;
5668 }
5669
Jack Palevichb7c81e92009-06-04 19:56:13 -07005670 void globalDeclarations() {
Jack Palevich9221bcc2009-08-26 16:15:07 -07005671 mpCurrentSymbolStack = &mGlobals;
Jack Palevichb7c81e92009-06-04 19:56:13 -07005672 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005673 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07005674 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07005675 break;
5676 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005677 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005678 if (!pDecl) {
5679 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07005680 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005681 if (!pDecl->id) {
5682 skip(';');
5683 continue;
5684 }
5685
Jack Palevich61de31f2009-09-08 11:06:40 -07005686 if (checkUndeclaredStruct(pDecl)) {
5687 skip(';');
5688 continue;
5689 }
5690
Jack Palevich86351982009-06-30 18:09:56 -07005691 if (! isDefined(pDecl->id)) {
5692 addGlobalSymbol(pDecl);
5693 }
5694 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07005695 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07005696 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07005697 }
Jack Palevich86351982009-06-30 18:09:56 -07005698 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005699 // it's a variable declaration
5700 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07005701 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07005702 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07005703 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07005704 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07005705 }
Jack Palevich86351982009-06-30 18:09:56 -07005706 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07005707 if (tok == TOK_NUM) {
5708 if (name) {
5709 * (int*) name->pAddress = tokc;
5710 }
5711 next();
5712 } else {
5713 error("Expected an integer constant");
5714 }
5715 }
Jack Palevich86351982009-06-30 18:09:56 -07005716 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07005717 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07005718 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07005719 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07005720 if (!pDecl) {
5721 break;
5722 }
5723 if (! isDefined(pDecl->id)) {
5724 addGlobalSymbol(pDecl);
5725 }
5726 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07005727 }
5728 skip(';');
5729 } else {
Jack Palevich86351982009-06-30 18:09:56 -07005730 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07005731 if (accept(';')) {
5732 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07005733 } else if (tok != '{') {
5734 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07005735 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005736 mpCurrentArena = &mLocalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005737 mpCurrentSymbolStack = &mLocals;
Jack Palevich95727a02009-07-06 12:07:15 -07005738 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07005739 /* patch forward references */
5740 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07005741 /* put function address */
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005742 name->pAddress = (void*) pCodeBuf->getPC();
Jack Palevich95727a02009-07-06 12:07:15 -07005743 }
5744 // Calculate stack offsets for parameters
5745 mLocals.pushLevel();
5746 intptr_t a = 8;
5747 int argCount = 0;
5748 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5749 Type* pArg = pP->pHead;
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005750 if (pArg->id) {
5751 addLocalSymbol(pArg);
5752 }
Jack Palevich95727a02009-07-06 12:07:15 -07005753 /* read param name and compute offset */
Jack Palevich9221bcc2009-08-26 16:15:07 -07005754 Type* pPassingType = passingType(pArg);
5755 size_t alignment = pGen->alignmentOf(pPassingType);
Jack Palevichb7718b92009-07-09 22:00:24 -07005756 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich0a01a5d2009-08-19 10:53:43 -07005757 if (pArg->id) {
5758 VI(pArg->id)->pAddress = (void*) a;
5759 }
Jack Palevich9221bcc2009-08-26 16:15:07 -07005760 a = a + pGen->sizeOf(pPassingType);
Jack Palevich95727a02009-07-06 12:07:15 -07005761 argCount++;
5762 }
5763 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07005764 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07005765 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07005766 block(0, true);
5767 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07005768 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07005769 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07005770 mpCurrentArena = &mGlobalArena;
Jack Palevich9221bcc2009-08-26 16:15:07 -07005771 mpCurrentSymbolStack = &mGlobals;
Jack Palevicha6baa232009-06-12 11:25:59 -07005772 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005773 }
5774 }
5775 }
5776
Jack Palevich9221bcc2009-08-26 16:15:07 -07005777 Type* passingType(Type* pType) {
5778 switch (pType->tag) {
5779 case TY_CHAR:
5780 case TY_SHORT:
5781 return mkpInt;
5782 default:
5783 return pType;
5784 }
5785 }
5786
Jack Palevich9cbd2262009-07-08 16:48:41 -07005787 char* allocGlobalSpace(size_t alignment, size_t bytes) {
5788 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5789 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07005790 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005791 error("Global space exhausted");
Jack Palevich9221bcc2009-08-26 16:15:07 -07005792 assert(false);
Jack Palevich0a280a02009-06-11 10:53:51 -07005793 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005794 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07005795 char* result = (char*) base;
5796 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005797 return result;
5798 }
5799
Jack Palevich21a15a22009-05-11 14:49:29 -07005800 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005801 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07005802 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07005803 pGlobalBase = 0;
5804 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005805 if (pGen) {
5806 delete pGen;
5807 pGen = 0;
5808 }
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005809 if (pCodeBuf) {
5810 delete pCodeBuf;
5811 pCodeBuf = 0;
5812 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005813 if (file) {
5814 delete file;
5815 file = 0;
5816 }
Jack Palevich21a15a22009-05-11 14:49:29 -07005817 }
5818
Jack Palevich8c246a92009-07-14 21:14:10 -07005819 // One-time initialization, when class is constructed.
5820 void init() {
5821 mpSymbolLookupFn = 0;
5822 mpSymbolLookupContext = 0;
5823 }
5824
Jack Palevich21a15a22009-05-11 14:49:29 -07005825 void clear() {
5826 tok = 0;
5827 tokc = 0;
5828 tokl = 0;
5829 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005830 rsym = 0;
5831 loc = 0;
5832 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005833 dptr = 0;
5834 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005835 file = 0;
5836 pGlobalBase = 0;
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005837 pCodeBuf = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07005838 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07005839 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07005840 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07005841 mLineNumber = 1;
5842 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07005843 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07005844 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005845
Jack Palevich22305132009-05-13 10:58:45 -07005846 void setArchitecture(const char* architecture) {
5847 delete pGen;
5848 pGen = 0;
5849
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005850 delete pCodeBuf;
5851 pCodeBuf = new CodeBuf();
5852
Jack Palevich22305132009-05-13 10:58:45 -07005853 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005854#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005855 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005856 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005857 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Palevich8b0624c2009-05-20 12:12:06 -07005858 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005859#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07005860#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07005861 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07005862 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07005863 }
Jack Paleviche7b59062009-05-19 17:12:17 -07005864#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07005865 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005866 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07005867 }
5868 }
5869
5870 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07005871#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07005872 pGen = new ARMCodeGenerator();
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005873 pCodeBuf = new ARMCodeBuf(pCodeBuf);
Jack Paleviche7b59062009-05-19 17:12:17 -07005874#elif defined(DEFAULT_X86_CODEGEN)
5875 pGen = new X86CodeGenerator();
5876#endif
5877 }
5878 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005879 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07005880 } else {
5881 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07005882 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005883 }
5884 }
5885
Jack Palevich77ae76e2009-05-10 19:59:24 -07005886public:
Jack Palevich22305132009-05-13 10:58:45 -07005887 struct args {
5888 args() {
5889 architecture = 0;
5890 }
5891 const char* architecture;
5892 };
5893
Jack Paleviche7b59062009-05-19 17:12:17 -07005894 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005895 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005896 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005897 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005898
Jack Paleviche7b59062009-05-19 17:12:17 -07005899 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005900 cleanup();
5901 }
5902
Jack Palevich8c246a92009-07-14 21:14:10 -07005903 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5904 mpSymbolLookupFn = pFn;
5905 mpSymbolLookupContext = pContext;
5906 }
5907
Jack Palevich1cdef202009-05-22 12:06:27 -07005908 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005909 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005910
Jack Palevich2ff5c222009-07-23 15:11:22 -07005911 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005912 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005913 cleanup();
5914 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005915 mTokenTable.setArena(&mGlobalArena);
5916 mGlobals.setArena(&mGlobalArena);
5917 mGlobals.setTokenTable(&mTokenTable);
5918 mLocals.setArena(&mLocalArena);
5919 mLocals.setTokenTable(&mTokenTable);
5920
5921 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005922 setArchitecture(NULL);
5923 if (!pGen) {
5924 return -1;
5925 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005926#ifdef PROVIDE_TRACE_CODEGEN
5927 pGen = new TraceCodeGenerator(pGen);
5928#endif
Jack Palevichd30a2ce2009-09-09 19:08:54 -07005929 pGen->setErrorSink(this);
5930
5931 if (pCodeBuf) {
5932 pCodeBuf->init(ALLOC_SIZE);
5933 }
5934 pGen->init(pCodeBuf);
Jack Palevich0a280a02009-06-11 10:53:51 -07005935 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005936 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5937 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005938 inp();
5939 next();
5940 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005941 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005942 result = pGen->finishCompile();
5943 if (result == 0) {
5944 if (mErrorBuf.len()) {
5945 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005946 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005947 }
Jack Palevichce105a92009-07-16 14:30:33 -07005948 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005949 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005950 }
5951
Jack Palevich86351982009-06-30 18:09:56 -07005952 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005953 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005954 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005955 mkpChar = createType(TY_CHAR, NULL, NULL);
5956 mkpVoid = createType(TY_VOID, NULL, NULL);
5957 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5958 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5959 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5960 mkpIntPtr = createPtrType(mkpInt);
5961 mkpCharPtr = createPtrType(mkpChar);
5962 mkpFloatPtr = createPtrType(mkpFloat);
5963 mkpDoublePtr = createPtrType(mkpDouble);
5964 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005965 }
5966
Jack Palevicha6baa232009-06-12 11:25:59 -07005967 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005968 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005969 }
5970
Jack Palevich569f1352009-06-29 14:29:08 -07005971 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005972 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005973 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005974 }
5975
Jack Palevich569f1352009-06-29 14:29:08 -07005976 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005977 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005978 error("Undefined forward reference: %s",
5979 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005980 }
5981 return true;
5982 }
5983
Jack Palevich1cdef202009-05-22 12:06:27 -07005984 /* Look through the symbol table to find a symbol.
5985 * If found, return its value.
5986 */
5987 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005988 if (mCompileResult == 0) {
5989 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5990 VariableInfo* pVariableInfo = VI(tok);
5991 if (pVariableInfo) {
5992 return pVariableInfo->pAddress;
5993 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005994 }
5995 return NULL;
5996 }
5997
Jack Palevicheedf9d22009-06-04 16:23:40 -07005998 void getPragmas(ACCsizei* actualStringCount,
5999 ACCsizei maxStringCount, ACCchar** strings) {
6000 int stringCount = mPragmaStringCount;
6001 if (actualStringCount) {
6002 *actualStringCount = stringCount;
6003 }
6004 if (stringCount > maxStringCount) {
6005 stringCount = maxStringCount;
6006 }
6007 if (strings) {
6008 char* pPragmas = mPragmas.getUnwrapped();
6009 while (stringCount-- > 0) {
6010 *strings++ = pPragmas;
6011 pPragmas += strlen(pPragmas) + 1;
6012 }
6013 }
6014 }
6015
Jack Palevichd5315572009-09-09 13:19:34 -07006016 void getProgramBinary(ACCvoid** base, ACCsizei* length) {
Jack Palevichd30a2ce2009-09-09 19:08:54 -07006017 *base = pCodeBuf->getBase();
6018 *length = (ACCsizei) pCodeBuf->getSize();
Jack Palevichd5315572009-09-09 13:19:34 -07006019 }
6020
Jack Palevichac0e95e2009-05-29 13:53:44 -07006021 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07006022 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07006023 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07006024};
6025
Jack Paleviche7b59062009-05-19 17:12:17 -07006026const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006027 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
6028
Jack Paleviche7b59062009-05-19 17:12:17 -07006029const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006030 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
6031 5, 5, /* ==, != */
6032 9, 10, /* &&, || */
6033 6, 7, 8, /* & ^ | */
6034 2, 2 /* ~ ! */
6035 };
6036
Jack Palevich8b0624c2009-05-20 12:12:06 -07006037#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07006038const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006039 0x1, // ++
6040 0xff, // --
6041 0xc1af0f, // *
6042 0xf9f79991, // /
6043 0xf9f79991, // % (With manual assist to swap results)
6044 0xc801, // +
6045 0xd8f7c829, // -
6046 0xe0d391, // <<
6047 0xf8d391, // >>
6048 0xe, // <=
6049 0xd, // >=
6050 0xc, // <
6051 0xf, // >
6052 0x4, // ==
6053 0x5, // !=
6054 0x0, // &&
6055 0x1, // ||
6056 0xc821, // &
6057 0xc831, // ^
6058 0xc809, // |
6059 0xd0f7, // ~
6060 0x4 // !
6061};
Jack Palevich8b0624c2009-05-20 12:12:06 -07006062#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07006063
Jack Palevich1cdef202009-05-22 12:06:27 -07006064struct ACCscript {
6065 ACCscript() {
6066 text = 0;
6067 textLength = 0;
6068 accError = ACC_NO_ERROR;
6069 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006070
Jack Palevich1cdef202009-05-22 12:06:27 -07006071 ~ACCscript() {
6072 delete text;
6073 }
Jack Palevich546b2242009-05-13 15:10:04 -07006074
Jack Palevich8c246a92009-07-14 21:14:10 -07006075 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
6076 compiler.registerSymbolCallback(pFn, pContext);
6077 }
6078
Jack Palevich1cdef202009-05-22 12:06:27 -07006079 void setError(ACCenum error) {
6080 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
6081 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006082 }
6083 }
6084
Jack Palevich1cdef202009-05-22 12:06:27 -07006085 ACCenum getError() {
6086 ACCenum result = accError;
6087 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07006088 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006089 }
6090
Jack Palevich1cdef202009-05-22 12:06:27 -07006091 Compiler compiler;
6092 char* text;
6093 int textLength;
6094 ACCenum accError;
6095};
6096
6097
6098extern "C"
6099ACCscript* accCreateScript() {
6100 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07006101}
Jack Palevich1cdef202009-05-22 12:06:27 -07006102
6103extern "C"
6104ACCenum accGetError( ACCscript* script ) {
6105 return script->getError();
6106}
6107
6108extern "C"
6109void accDeleteScript(ACCscript* script) {
6110 delete script;
6111}
6112
6113extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07006114void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
6115 ACCvoid* pContext) {
6116 script->registerSymbolCallback(pFn, pContext);
6117}
6118
6119extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07006120void accScriptSource(ACCscript* script,
6121 ACCsizei count,
6122 const ACCchar ** string,
6123 const ACCint * length) {
6124 int totalLength = 0;
6125 for(int i = 0; i < count; i++) {
6126 int len = -1;
6127 const ACCchar* s = string[i];
6128 if (length) {
6129 len = length[i];
6130 }
6131 if (len < 0) {
6132 len = strlen(s);
6133 }
6134 totalLength += len;
6135 }
6136 delete script->text;
6137 char* text = new char[totalLength + 1];
6138 script->text = text;
6139 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07006140 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07006141 for(int i = 0; i < count; i++) {
6142 int len = -1;
6143 const ACCchar* s = string[i];
6144 if (length) {
6145 len = length[i];
6146 }
6147 if (len < 0) {
6148 len = strlen(s);
6149 }
Jack Palevich09555c72009-05-27 12:25:55 -07006150 memcpy(dest, s, len);
6151 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07006152 }
6153 text[totalLength] = '\0';
Jack Palevich61de31f2009-09-08 11:06:40 -07006154
6155#ifdef DEBUG_SAVE_INPUT_TO_FILE
Jack Palevich9116bc42009-09-08 11:46:42 -07006156 LOGD("Saving input to file...");
Jack Palevich61de31f2009-09-08 11:06:40 -07006157 int counter;
6158 char path[PATH_MAX];
6159 for (counter = 0; counter < 4096; counter++) {
6160 sprintf(path, DEBUG_DUMP_PATTERN, counter);
6161 if(access(path, F_OK) != 0) {
6162 break;
6163 }
6164 }
6165 if (counter < 4096) {
Jack Palevich9116bc42009-09-08 11:46:42 -07006166 LOGD("Saving input to file %s", path);
Jack Palevich61de31f2009-09-08 11:06:40 -07006167 FILE* fd = fopen(path, "w");
6168 if (fd) {
6169 fwrite(text, totalLength, 1, fd);
6170 fclose(fd);
Jack Palevich9116bc42009-09-08 11:46:42 -07006171 LOGD("Saved input to file %s", path);
6172 } else {
6173 LOGD("Could not save. errno: %d", errno);
Jack Palevich61de31f2009-09-08 11:06:40 -07006174 }
6175 }
6176#endif
Jack Palevich1cdef202009-05-22 12:06:27 -07006177}
6178
6179extern "C"
6180void accCompileScript(ACCscript* script) {
6181 int result = script->compiler.compile(script->text, script->textLength);
6182 if (result) {
6183 script->setError(ACC_INVALID_OPERATION);
6184 }
6185}
6186
6187extern "C"
6188void accGetScriptiv(ACCscript* script,
6189 ACCenum pname,
6190 ACCint * params) {
6191 switch (pname) {
6192 case ACC_INFO_LOG_LENGTH:
6193 *params = 0;
6194 break;
6195 }
6196}
6197
6198extern "C"
6199void accGetScriptInfoLog(ACCscript* script,
6200 ACCsizei maxLength,
6201 ACCsizei * length,
6202 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006203 char* message = script->compiler.getErrorMessage();
6204 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07006205 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07006206 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07006207 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07006208 if (infoLog && maxLength > 0) {
6209 int trimmedLength = maxLength < messageLength ?
6210 maxLength : messageLength;
6211 memcpy(infoLog, message, trimmedLength);
6212 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07006213 }
6214}
6215
6216extern "C"
6217void accGetScriptLabel(ACCscript* script, const ACCchar * name,
6218 ACCvoid ** address) {
6219 void* value = script->compiler.lookup(name);
6220 if (value) {
6221 *address = value;
6222 } else {
6223 script->setError(ACC_INVALID_VALUE);
6224 }
6225}
6226
Jack Palevicheedf9d22009-06-04 16:23:40 -07006227extern "C"
6228void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
6229 ACCsizei maxStringCount, ACCchar** strings){
6230 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
6231}
6232
-b master422972c2009-06-17 19:13:52 -07006233extern "C"
Jack Palevichd5315572009-09-09 13:19:34 -07006234void accGetProgramBinary(ACCscript* script,
6235 ACCvoid** base, ACCsizei* length) {
6236 script->compiler.getProgramBinary(base, length);
-b master422972c2009-06-17 19:13:52 -07006237}
6238
Jack Palevicheedf9d22009-06-04 16:23:40 -07006239
Jack Palevich1cdef202009-05-22 12:06:27 -07006240} // namespace acc
6241