blob: b06ad53e9334add325f8419276d2897284faf2fe [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 Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000012#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070014#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070015#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070016#include <stdlib.h>
17#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070018#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich8dc662e2009-06-09 22:53:47 +000020#if defined(__i386__)
21#include <sys/mman.h>
22#endif
23
Jack Palevich546b2242009-05-13 15:10:04 -070024#if defined(__arm__)
25#include <unistd.h>
26#endif
27
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Paleviche7b59062009-05-19 17:12:17 -070039#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070040#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
Jack Palevicha6535612009-05-13 16:24:17 -070042
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
Jack Palevich9f51a262009-07-29 16:22:26 -070051#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070052// #define PROVIDE_TRACE_CODEGEN
53
Jack Palevichbbf8ab52009-05-11 11:54:30 -070054namespace acc {
55
Jack Palevich8df46192009-07-07 14:48:51 -070056// Subset of STL vector.
57template<class E> class Vector {
58 public:
59 Vector() {
60 mpBase = 0;
61 mUsed = 0;
62 mSize = 0;
63 }
64
65 ~Vector() {
66 if (mpBase) {
67 for(size_t i = 0; i < mUsed; i++) {
68 mpBase[mUsed].~E();
69 }
70 free(mpBase);
71 }
72 }
73
74 inline E& operator[](size_t i) {
75 return mpBase[i];
76 }
77
78 inline E& front() {
79 return mpBase[0];
80 }
81
82 inline E& back() {
83 return mpBase[mUsed - 1];
84 }
85
86 void pop_back() {
87 mUsed -= 1;
88 mpBase[mUsed].~E();
89 }
90
91 void push_back(const E& item) {
92 * ensure(1) = item;
93 }
94
95 size_t size() {
96 return mUsed;
97 }
98
99private:
100 E* ensure(int n) {
101 size_t newUsed = mUsed + n;
102 if (newUsed > mSize) {
103 size_t newSize = mSize * 2 + 10;
104 if (newSize < newUsed) {
105 newSize = newUsed;
106 }
107 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
108 mSize = newSize;
109 }
110 E* result = mpBase + mUsed;
111 mUsed = newUsed;
112 return result;
113 }
114
115 E* mpBase;
116 size_t mUsed;
117 size_t mSize;
118};
119
Jack Palevichac0e95e2009-05-29 13:53:44 -0700120class ErrorSink {
121public:
122 void error(const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 verror(fmt, ap);
126 va_end(ap);
127 }
128
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700129 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700136 TY_INT, // 0
137 TY_CHAR, // 1
138 TY_SHORT, // 2
139 TY_VOID, // 3
140 TY_FLOAT, // 4
141 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700142 TY_POINTER, // 6
143 TY_ARRAY, // 7
144 TY_STRUCT, // 8
145 TY_FUNC, // 9
146 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700147 };
148
149 struct Type {
150 TypeTag tag;
Jack Palevichb6154502009-08-04 14:56:09 -0700151 tokenid_t id; // For function arguments, local vars
152 int length; // length of array
Jack Palevich8df46192009-07-07 14:48:51 -0700153 Type* pHead;
154 Type* pTail;
155 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700156
Jack Palevichba929a42009-07-17 10:20:32 -0700157 enum ExpressionType {
158 ET_RVALUE,
159 ET_LVALUE
160 };
161
162 struct ExpressionValue {
163 ExpressionValue() {
164 et = ET_RVALUE;
165 pType = NULL;
166 }
167 ExpressionType et;
168 Type* pType;
169 };
170
Jack Palevich21a15a22009-05-11 14:49:29 -0700171 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700172 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700174 ErrorSink* mErrorSink;
175 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700176 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700177
Jack Palevich21a15a22009-05-11 14:49:29 -0700178 void release() {
179 if (pProgramBase != 0) {
180 free(pProgramBase);
181 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700182 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700183 }
184
Jack Palevich0a280a02009-06-11 10:53:51 -0700185 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700186 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700187 bool overflow = newSize > mSize;
188 if (overflow && !mOverflowed) {
189 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700190 if (mErrorSink) {
191 mErrorSink->error("Code too large: %d bytes", newSize);
192 }
193 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700194 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700195 }
196
Jack Palevich21a15a22009-05-11 14:49:29 -0700197 public:
198 CodeBuf() {
199 pProgramBase = 0;
200 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700201 mErrorSink = 0;
202 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700203 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700204 }
205
206 ~CodeBuf() {
207 release();
208 }
209
210 void init(int size) {
211 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700212 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700213 pProgramBase = (char*) calloc(1, size);
214 ind = pProgramBase;
215 }
216
Jack Palevichac0e95e2009-05-29 13:53:44 -0700217 void setErrorSink(ErrorSink* pErrorSink) {
218 mErrorSink = pErrorSink;
219 }
220
Jack Palevich546b2242009-05-13 15:10:04 -0700221 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700222 if(check(4)) {
223 return 0;
224 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700225 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700226 * (int*) ind = n;
227 ind += 4;
228 return result;
229 }
230
Jack Palevich21a15a22009-05-11 14:49:29 -0700231 /*
232 * Output a byte. Handles all values, 0..ff.
233 */
234 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700235 if(check(1)) {
236 return;
237 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700238 *ind++ = n;
239 }
240
Jack Palevich21a15a22009-05-11 14:49:29 -0700241 inline void* getBase() {
242 return (void*) pProgramBase;
243 }
244
Jack Palevich8b0624c2009-05-20 12:12:06 -0700245 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700246 return ind - pProgramBase;
247 }
248
Jack Palevich8b0624c2009-05-20 12:12:06 -0700249 intptr_t getPC() {
250 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 }
252 };
253
Jack Palevich1cdef202009-05-22 12:06:27 -0700254 /**
255 * A code generator creates an in-memory program, generating the code on
256 * the fly. There is one code generator implementation for each supported
257 * architecture.
258 *
259 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700260 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700261 * FP - a frame pointer for accessing function arguments and local
262 * variables.
263 * SP - a stack pointer for storing intermediate results while evaluating
264 * expressions. The stack pointer grows downwards.
265 *
266 * The function calling convention is that all arguments are placed on the
267 * stack such that the first argument has the lowest address.
268 * After the call, the result is in R0. The caller is responsible for
269 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700270 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700271 * FP and SP registers are saved.
272 */
273
Jack Palevich21a15a22009-05-11 14:49:29 -0700274 class CodeGenerator {
275 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700276 CodeGenerator() {
277 mErrorSink = 0;
278 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700279 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700280 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700281 virtual ~CodeGenerator() {}
282
Jack Palevich22305132009-05-13 10:58:45 -0700283 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700284 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700285 pCodeBuf->setErrorSink(mErrorSink);
286 }
287
Jack Palevichb67b18f2009-06-11 21:12:23 -0700288 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700289 mErrorSink = pErrorSink;
290 if (pCodeBuf) {
291 pCodeBuf->setErrorSink(mErrorSink);
292 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700293 }
294
Jack Palevich58c30ee2009-07-17 16:35:23 -0700295 /* Give the code generator some utility types so it can
296 * use its own types as needed for the results of some
297 * operations like gcmp.
298 */
299
Jack Palevicha8f427f2009-07-13 18:40:08 -0700300 void setTypes(Type* pInt) {
301 mkpInt = pInt;
302 }
303
Jack Palevich1cdef202009-05-22 12:06:27 -0700304 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700305 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 * Save the old value of the FP.
307 * Set the new value of the FP.
308 * Convert from the native platform calling convention to
309 * our stack-based calling convention. This may require
310 * pushing arguments from registers to the stack.
311 * Allocate "N" bytes of stack space. N isn't known yet, so
312 * just emit the instructions for adjusting the stack, and return
313 * the address to patch up. The patching will be done in
314 * functionExit().
315 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700316 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700317 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700318
Jack Palevich1cdef202009-05-22 12:06:27 -0700319 /* Emit a function epilog.
320 * Restore the old SP and FP register values.
321 * Return to the calling function.
322 * argCount - the number of arguments to the function.
323 * localVariableAddress - returned from functionEntry()
324 * localVariableSize - the size in bytes of the local variables.
325 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700326 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700327 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700328
Jack Palevich1cdef202009-05-22 12:06:27 -0700329 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700330 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700331
Jack Palevich1a539db2009-07-08 13:04:41 -0700332 /* Load floating point value from global address. */
333 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700334
Jack Palevich1cdef202009-05-22 12:06:27 -0700335 /* Jump to a target, and return the address of the word that
336 * holds the target data, in case it needs to be fixed up later.
337 */
Jack Palevich22305132009-05-13 10:58:45 -0700338 virtual int gjmp(int t) = 0;
339
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 /* Test R0 and jump to a target if the test succeeds.
341 * l = 0: je, l == 1: jne
342 * Return the address of the word that holds the targed data, in
343 * case it needs to be fixed up later.
344 */
Jack Palevich22305132009-05-13 10:58:45 -0700345 virtual int gtst(bool l, int t) = 0;
346
Jack Palevich9eed7a22009-07-06 17:24:34 -0700347 /* Compare TOS against R0, and store the boolean result in R0.
348 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700349 * op specifies the comparison.
350 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700351 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700352
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700355 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700356 */
Jack Palevich546b2242009-05-13 15:10:04 -0700357 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700358
Jack Palevich9eed7a22009-07-06 17:24:34 -0700359 /* Compare 0 against R0, and store the boolean result in R0.
360 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700362 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700363
364 /* Perform the arithmetic op specified by op. 0 is the
365 * left argument, R0 is the right argument.
366 */
367 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700369 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700370 */
371 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700372
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700373 /* Turn R0, TOS into R0 TOS R0 */
374
375 virtual void over() = 0;
376
377 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700378 */
379 virtual void popR0() = 0;
380
Jack Palevich9eed7a22009-07-06 17:24:34 -0700381 /* Store R0 to the address stored in TOS.
382 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700383 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700384 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700385
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700387 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700388 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700389
Jack Palevich1cdef202009-05-22 12:06:27 -0700390 /* Load the absolute address of a variable to R0.
391 * If ea <= LOCAL, then this is a local variable, or an
392 * argument, addressed relative to FP.
393 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700394 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700395 * et is ET_RVALUE for things like string constants, ET_LVALUE for
396 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700397 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700398 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700399
Jack Palevich9f51a262009-07-29 16:22:26 -0700400 /* Load the pc-relative address of a forward-referenced variable to R0.
401 * Return the address of the 4-byte constant so that it can be filled
402 * in later.
403 */
404 virtual int leaForward(int ea, Type* pPointerType) = 0;
405
Jack Palevich8df46192009-07-07 14:48:51 -0700406 /**
407 * Convert R0 to the given type.
408 */
Jack Palevichb6154502009-08-04 14:56:09 -0700409
410 void convertR0(Type* pType) {
411 convertR0Imp(pType, false);
412 }
413
414 void castR0(Type* pType) {
415 convertR0Imp(pType, true);
416 }
417
418 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700419
Jack Palevich1cdef202009-05-22 12:06:27 -0700420 /* Emit code to adjust the stack for a function call. Return the
421 * label for the address of the instruction that adjusts the
422 * stack size. This will be passed as argument "a" to
423 * endFunctionCallArguments.
424 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700425 virtual int beginFunctionCallArguments() = 0;
426
Jack Palevich1cdef202009-05-22 12:06:27 -0700427 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700428 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700429 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700430 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700431
Jack Palevich1cdef202009-05-22 12:06:27 -0700432 /* Patch the function call preamble.
433 * a is the address returned from beginFunctionCallArguments
434 * l is the number of bytes the arguments took on the stack.
435 * Typically you would also emit code to convert the argument
436 * list into whatever the native function calling convention is.
437 * On ARM for example you would pop the first 5 arguments into
438 * R0..R4
439 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700440 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700441
Jack Palevich1cdef202009-05-22 12:06:27 -0700442 /* Emit a call to an unknown function. The argument "symbol" needs to
443 * be stored in the location where the address should go. It forms
444 * a chain. The address will be patched later.
445 * Return the address of the word that has to be patched.
446 */
Jack Palevich8df46192009-07-07 14:48:51 -0700447 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700448
Jack Palevich1cdef202009-05-22 12:06:27 -0700449 /* Call a function pointer. L is the number of bytes the arguments
450 * take on the stack. The address of the function is stored at
451 * location SP + l.
452 */
Jack Palevich8df46192009-07-07 14:48:51 -0700453 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700454
Jack Palevich1cdef202009-05-22 12:06:27 -0700455 /* Adjust SP after returning from a function call. l is the
456 * number of bytes of arguments stored on the stack. isIndirect
457 * is true if this was an indirect call. (In which case the
458 * address of the function is stored at location SP + l.)
459 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700460 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700461
Jack Palevich1cdef202009-05-22 12:06:27 -0700462 /* Print a disassembly of the assembled code to out. Return
463 * non-zero if there is an error.
464 */
Jack Palevicha6535612009-05-13 16:24:17 -0700465 virtual int disassemble(FILE* out) = 0;
466
Jack Palevich1cdef202009-05-22 12:06:27 -0700467 /* Generate a symbol at the current PC. t is the head of a
468 * linked list of addresses to patch.
469 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700470 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700471
Jack Palevich9f51a262009-07-29 16:22:26 -0700472 /* Resolve a forward reference function at the current PC.
473 * t is the head of a
474 * linked list of addresses to patch.
475 * (Like gsym, but using absolute address, not PC relative address.)
476 */
477 virtual void resolveForward(int t) = 0;
478
Jack Palevich1cdef202009-05-22 12:06:27 -0700479 /*
480 * Do any cleanup work required at the end of a compile.
481 * For example, an instruction cache might need to be
482 * invalidated.
483 * Return non-zero if there is an error.
484 */
485 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700486
Jack Palevicha6535612009-05-13 16:24:17 -0700487 /**
488 * Adjust relative branches by this amount.
489 */
490 virtual int jumpOffset() = 0;
491
Jack Palevich9eed7a22009-07-06 17:24:34 -0700492 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700493 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700494 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700495 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700496
497 /**
498 * Array element alignment (in bytes) for this type of data.
499 */
500 virtual size_t sizeOf(Type* type) = 0;
501
Jack Palevich9cbd2262009-07-08 16:48:41 -0700502 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700503 * Stack alignment of this type of data
504 */
505 virtual size_t stackAlignmentOf(Type* pType) = 0;
506
507 /**
508 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700509 */
510 virtual size_t stackSizeOf(Type* pType) = 0;
511
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700512 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700513 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700514 }
515
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700516 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700517 return mExpressionStack.back().et;
518 }
519
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700520 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700521 mExpressionStack.back().et = et;
522 }
523
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700524 virtual size_t getExpressionStackDepth() {
525 return mExpressionStack.size();
526 }
527
Jack Palevichb5e33312009-07-30 19:06:34 -0700528 virtual void forceR0RVal() {
529 if (getR0ExpressionType() == ET_LVALUE) {
530 loadR0FromR0();
531 }
532 }
533
Jack Palevich21a15a22009-05-11 14:49:29 -0700534 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700535 /*
536 * Output a byte. Handles all values, 0..ff.
537 */
538 void ob(int n) {
539 pCodeBuf->ob(n);
540 }
541
Jack Palevich8b0624c2009-05-20 12:12:06 -0700542 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700543 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700544 }
545
Jack Palevich8b0624c2009-05-20 12:12:06 -0700546 intptr_t getBase() {
547 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700548 }
549
Jack Palevich8b0624c2009-05-20 12:12:06 -0700550 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700551 return pCodeBuf->getPC();
552 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700553
554 intptr_t getSize() {
555 return pCodeBuf->getSize();
556 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700557
558 void error(const char* fmt,...) {
559 va_list ap;
560 va_start(ap, fmt);
561 mErrorSink->verror(fmt, ap);
562 va_end(ap);
563 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700564
565 void assert(bool test) {
566 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700567 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700568 error("code generator assertion failed.");
569 }
570 }
Jack Palevich8df46192009-07-07 14:48:51 -0700571
572 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700573 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700574 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700575 mExpressionStack.back().et = ET_RVALUE;
576 }
577
578 void setR0Type(Type* pType, ExpressionType et) {
579 assert(pType != NULL);
580 mExpressionStack.back().pType = pType;
581 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700582 }
583
Jack Palevich8df46192009-07-07 14:48:51 -0700584 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700585 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700586 }
587
588 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700589 if (mExpressionStack.size()) {
590 mExpressionStack.push_back(mExpressionStack.back());
591 } else {
592 mExpressionStack.push_back(ExpressionValue());
593 }
594
Jack Palevich8df46192009-07-07 14:48:51 -0700595 }
596
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700597 void overType() {
598 size_t size = mExpressionStack.size();
599 if (size >= 2) {
600 mExpressionStack.push_back(mExpressionStack.back());
601 mExpressionStack[size-1] = mExpressionStack[size-2];
602 mExpressionStack[size-2] = mExpressionStack[size];
603 }
604 }
605
Jack Palevich8df46192009-07-07 14:48:51 -0700606 void popType() {
607 mExpressionStack.pop_back();
608 }
609
610 bool bitsSame(Type* pA, Type* pB) {
611 return collapseType(pA->tag) == collapseType(pB->tag);
612 }
613
614 TypeTag collapseType(TypeTag tag) {
615 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700616 TY_INT,
617 TY_INT,
618 TY_INT,
619 TY_VOID,
620 TY_FLOAT,
621 TY_DOUBLE,
622 TY_INT,
623 TY_INT,
624 TY_VOID,
625 TY_VOID,
626 TY_VOID
627 };
Jack Palevich8df46192009-07-07 14:48:51 -0700628 return collapsedTag[tag];
629 }
630
Jack Palevich1a539db2009-07-08 13:04:41 -0700631 TypeTag collapseTypeR0() {
632 return collapseType(getR0Type()->tag);
633 }
634
Jack Palevichb6154502009-08-04 14:56:09 -0700635 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700636 return isFloatTag(pType->tag);
637 }
638
Jack Palevichb6154502009-08-04 14:56:09 -0700639 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700640 return tag == TY_FLOAT || tag == TY_DOUBLE;
641 }
642
Jack Palevichb6154502009-08-04 14:56:09 -0700643 static bool isPointerType(Type* pType) {
644 return isPointerTag(pType->tag);
645 }
646
647 static bool isPointerTag(TypeTag tag) {
648 return tag == TY_POINTER || tag == TY_ARRAY;
649 }
650
651 Type* getPointerArithmeticResultType(Type* a, Type* b) {
652 TypeTag aTag = a->tag;
653 TypeTag bTag = b->tag;
654 if (aTag == TY_POINTER) {
655 return a;
656 }
657 if (bTag == TY_POINTER) {
658 return b;
659 }
660 if (aTag == TY_ARRAY) {
661 return a->pTail;
662 }
663 if (bTag == TY_ARRAY) {
664 return b->pTail;
665 }
666 return NULL;
667 }
668
Jack Palevicha8f427f2009-07-13 18:40:08 -0700669 Type* mkpInt;
670
Jack Palevich21a15a22009-05-11 14:49:29 -0700671 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700672 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700673 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700674 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700675 };
676
Jack Paleviche7b59062009-05-19 17:12:17 -0700677#ifdef PROVIDE_ARM_CODEGEN
678
Jack Palevich22305132009-05-13 10:58:45 -0700679 class ARMCodeGenerator : public CodeGenerator {
680 public:
681 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700682
Jack Palevich22305132009-05-13 10:58:45 -0700683 virtual ~ARMCodeGenerator() {}
684
685 /* returns address to patch with local variable size
686 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700687 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700688 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700689 // sp -> arg4 arg5 ...
690 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700691 int regArgCount = calcRegArgCount(pDecl);
692 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700693 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700694 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700695 }
696 // sp -> arg0 arg1 ...
697 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700698 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700699 // sp, fp -> oldfp, retadr, arg0 arg1 ....
700 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700701 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700702 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700703 // We don't know how many local variables we are going to use,
704 // but we will round the allocation up to a multiple of
705 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700706 }
707
Jack Palevichb7718b92009-07-09 22:00:24 -0700708 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700709 // Round local variable size up to a multiple of stack alignment
710 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
711 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700712 // Patch local variable allocation code:
713 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700714 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700715 }
Jack Palevich69796b62009-05-14 15:42:26 -0700716 *(char*) (localVariableAddress) = localVariableSize;
717
718 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
719 o4(0xE1A0E00B); // mov lr, fp
720 o4(0xE59BB000); // ldr fp, [fp]
721 o4(0xE28ED004); // add sp, lr, #4
722 // sp -> retadr, arg0, ...
723 o4(0xE8BD4000); // ldmfd sp!, {lr}
724 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700725
726 // We store the PC into the lr so we can adjust the sp before
727 // returning. We need to pull off the registers we pushed
728 // earlier. We don't need to actually store them anywhere,
729 // just adjust the stack.
730 int regArgCount = calcRegArgCount(pDecl);
731 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700732 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
733 }
734 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700735 }
736
737 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700738 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700739 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700740 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700741 }
742
Jack Palevich1a539db2009-07-08 13:04:41 -0700743 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700744 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700745 // Global, absolute address
746 o4(0xE59F0000); // ldr r0, .L1
747 o4(0xEA000000); // b .L99
748 o4(address); // .L1: .word ea
749 // .L99:
750
751 switch (pType->tag) {
752 case TY_FLOAT:
753 o4(0xE5900000); // ldr r0, [r0]
754 break;
755 case TY_DOUBLE:
756 o4(0xE1C000D0); // ldrd r0, [r0]
757 break;
758 default:
759 assert(false);
760 break;
761 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700762 }
763
Jack Palevich22305132009-05-13 10:58:45 -0700764 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700765 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700766 }
767
768 /* l = 0: je, l == 1: jne */
769 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700770 Type* pR0Type = getR0Type();
771 TypeTag tagR0 = pR0Type->tag;
772 switch(tagR0) {
773 case TY_FLOAT:
774 callRuntime((void*) runtime_is_non_zero_f);
775 break;
776 case TY_DOUBLE:
777 callRuntime((void*) runtime_is_non_zero_d);
778 break;
779 default:
780 break;
781 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700782 o4(0xE3500000); // cmp r0,#0
783 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
784 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700785 }
786
Jack Palevich58c30ee2009-07-17 16:35:23 -0700787 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700788 Type* pR0Type = getR0Type();
789 Type* pTOSType = getTOSType();
790 TypeTag tagR0 = collapseType(pR0Type->tag);
791 TypeTag tagTOS = collapseType(pTOSType->tag);
792 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700793 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700794 o4(0xE1510000); // cmp r1, r1
795 switch(op) {
796 case OP_EQUALS:
797 o4(0x03A00001); // moveq r0,#1
798 o4(0x13A00000); // movne r0,#0
799 break;
800 case OP_NOT_EQUALS:
801 o4(0x03A00000); // moveq r0,#0
802 o4(0x13A00001); // movne r0,#1
803 break;
804 case OP_LESS_EQUAL:
805 o4(0xD3A00001); // movle r0,#1
806 o4(0xC3A00000); // movgt r0,#0
807 break;
808 case OP_GREATER:
809 o4(0xD3A00000); // movle r0,#0
810 o4(0xC3A00001); // movgt r0,#1
811 break;
812 case OP_GREATER_EQUAL:
813 o4(0xA3A00001); // movge r0,#1
814 o4(0xB3A00000); // movlt r0,#0
815 break;
816 case OP_LESS:
817 o4(0xA3A00000); // movge r0,#0
818 o4(0xB3A00001); // movlt r0,#1
819 break;
820 default:
821 error("Unknown comparison op %d", op);
822 break;
823 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700824 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
825 setupDoubleArgs();
826 switch(op) {
827 case OP_EQUALS:
828 callRuntime((void*) runtime_cmp_eq_dd);
829 break;
830 case OP_NOT_EQUALS:
831 callRuntime((void*) runtime_cmp_ne_dd);
832 break;
833 case OP_LESS_EQUAL:
834 callRuntime((void*) runtime_cmp_le_dd);
835 break;
836 case OP_GREATER:
837 callRuntime((void*) runtime_cmp_gt_dd);
838 break;
839 case OP_GREATER_EQUAL:
840 callRuntime((void*) runtime_cmp_ge_dd);
841 break;
842 case OP_LESS:
843 callRuntime((void*) runtime_cmp_lt_dd);
844 break;
845 default:
846 error("Unknown comparison op %d", op);
847 break;
848 }
849 } else {
850 setupFloatArgs();
851 switch(op) {
852 case OP_EQUALS:
853 callRuntime((void*) runtime_cmp_eq_ff);
854 break;
855 case OP_NOT_EQUALS:
856 callRuntime((void*) runtime_cmp_ne_ff);
857 break;
858 case OP_LESS_EQUAL:
859 callRuntime((void*) runtime_cmp_le_ff);
860 break;
861 case OP_GREATER:
862 callRuntime((void*) runtime_cmp_gt_ff);
863 break;
864 case OP_GREATER_EQUAL:
865 callRuntime((void*) runtime_cmp_ge_ff);
866 break;
867 case OP_LESS:
868 callRuntime((void*) runtime_cmp_lt_ff);
869 break;
870 default:
871 error("Unknown comparison op %d", op);
872 break;
873 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700874 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700875 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700876 }
877
Jack Palevich546b2242009-05-13 15:10:04 -0700878 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700879 Type* pR0Type = getR0Type();
880 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700881 TypeTag tagR0 = pR0Type->tag;
882 TypeTag tagTOS = pTOSType->tag;
883 bool isFloatR0 = isFloatTag(tagR0);
884 bool isFloatTOS = isFloatTag(tagTOS);
885 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700886 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -0700887 bool isPtrR0 = isPointerTag(tagR0);
888 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700889 if (isPtrR0 || isPtrTOS) {
890 if (isPtrR0 && isPtrTOS) {
891 if (op != OP_MINUS) {
892 error("Unsupported pointer-pointer operation %d.", op);
893 }
894 if (! typeEqual(pR0Type, pTOSType)) {
895 error("Incompatible pointer types for subtraction.");
896 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700897 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700898 setR0Type(mkpInt);
899 int size = sizeOf(pR0Type->pHead);
900 if (size != 1) {
901 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700902 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700903 // TODO: Optimize for power-of-two.
904 genOp(OP_DIV);
905 }
906 } else {
907 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
908 error("Unsupported pointer-scalar operation %d", op);
909 }
Jack Palevichb6154502009-08-04 14:56:09 -0700910 Type* pPtrType = getPointerArithmeticResultType(
911 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700912 int size = sizeOf(pPtrType->pHead);
913 if (size != 1) {
914 // TODO: Optimize for power-of-two.
915 liReg(size, 2);
916 if (isPtrR0) {
917 o4(0x0E0010192); // mul r1,r2,r1
918 } else {
919 o4(0x0E0000092); // mul r0,r2,r0
920 }
921 }
922 switch(op) {
923 case OP_PLUS:
924 o4(0xE0810000); // add r0,r1,r0
925 break;
926 case OP_MINUS:
927 o4(0xE0410000); // sub r0,r1,r0
928 break;
929 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700930 setR0Type(pPtrType);
931 }
932 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700933 switch(op) {
934 case OP_MUL:
935 o4(0x0E0000091); // mul r0,r1,r0
936 break;
937 case OP_DIV:
938 callRuntime((void*) runtime_DIV);
939 break;
940 case OP_MOD:
941 callRuntime((void*) runtime_MOD);
942 break;
943 case OP_PLUS:
944 o4(0xE0810000); // add r0,r1,r0
945 break;
946 case OP_MINUS:
947 o4(0xE0410000); // sub r0,r1,r0
948 break;
949 case OP_SHIFT_LEFT:
950 o4(0xE1A00011); // lsl r0,r1,r0
951 break;
952 case OP_SHIFT_RIGHT:
953 o4(0xE1A00051); // asr r0,r1,r0
954 break;
955 case OP_BIT_AND:
956 o4(0xE0010000); // and r0,r1,r0
957 break;
958 case OP_BIT_XOR:
959 o4(0xE0210000); // eor r0,r1,r0
960 break;
961 case OP_BIT_OR:
962 o4(0xE1810000); // orr r0,r1,r0
963 break;
964 case OP_BIT_NOT:
965 o4(0xE1E00000); // mvn r0, r0
966 break;
967 default:
968 error("Unimplemented op %d\n", op);
969 break;
970 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700971 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700972 } else {
973 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
974 if (pResultType->tag == TY_DOUBLE) {
975 setupDoubleArgs();
976 switch(op) {
977 case OP_MUL:
978 callRuntime((void*) runtime_op_mul_dd);
979 break;
980 case OP_DIV:
981 callRuntime((void*) runtime_op_div_dd);
982 break;
983 case OP_PLUS:
984 callRuntime((void*) runtime_op_add_dd);
985 break;
986 case OP_MINUS:
987 callRuntime((void*) runtime_op_sub_dd);
988 break;
989 default:
990 error("Unsupported binary floating operation %d\n", op);
991 break;
992 }
993 } else {
994 setupFloatArgs();
995 switch(op) {
996 case OP_MUL:
997 callRuntime((void*) runtime_op_mul_ff);
998 break;
999 case OP_DIV:
1000 callRuntime((void*) runtime_op_div_ff);
1001 break;
1002 case OP_PLUS:
1003 callRuntime((void*) runtime_op_add_ff);
1004 break;
1005 case OP_MINUS:
1006 callRuntime((void*) runtime_op_sub_ff);
1007 break;
1008 default:
1009 error("Unsupported binary floating operation %d\n", op);
1010 break;
1011 }
1012 }
1013 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001014 }
Jack Palevich22305132009-05-13 10:58:45 -07001015 }
1016
Jack Palevich58c30ee2009-07-17 16:35:23 -07001017 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001018 if (op != OP_LOGICAL_NOT) {
1019 error("Unknown unary cmp %d", op);
1020 } else {
1021 Type* pR0Type = getR0Type();
1022 TypeTag tag = collapseType(pR0Type->tag);
1023 switch(tag) {
1024 case TY_INT:
1025 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001026 o4(0xE1510000); // cmp r1, r0
1027 o4(0x03A00001); // moveq r0,#1
1028 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001029 break;
1030 case TY_FLOAT:
1031 callRuntime((void*) runtime_is_zero_f);
1032 break;
1033 case TY_DOUBLE:
1034 callRuntime((void*) runtime_is_zero_d);
1035 break;
1036 default:
1037 error("gUnaryCmp unsupported type");
1038 break;
1039 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001040 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001041 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001042 }
1043
1044 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001045 Type* pR0Type = getR0Type();
1046 TypeTag tag = collapseType(pR0Type->tag);
1047 switch(tag) {
1048 case TY_INT:
1049 switch(op) {
1050 case OP_MINUS:
1051 o4(0xE3A01000); // mov r1, #0
1052 o4(0xE0410000); // sub r0,r1,r0
1053 break;
1054 case OP_BIT_NOT:
1055 o4(0xE1E00000); // mvn r0, r0
1056 break;
1057 default:
1058 error("Unknown unary op %d\n", op);
1059 break;
1060 }
1061 break;
1062 case TY_FLOAT:
1063 case TY_DOUBLE:
1064 switch (op) {
1065 case OP_MINUS:
1066 if (tag == TY_FLOAT) {
1067 callRuntime((void*) runtime_op_neg_f);
1068 } else {
1069 callRuntime((void*) runtime_op_neg_d);
1070 }
1071 break;
1072 case OP_BIT_NOT:
1073 error("Can't apply '~' operator to a float or double.");
1074 break;
1075 default:
1076 error("Unknown unary op %d\n", op);
1077 break;
1078 }
1079 break;
1080 default:
1081 error("genUnaryOp unsupported type");
1082 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001083 }
Jack Palevich22305132009-05-13 10:58:45 -07001084 }
1085
Jack Palevich1cdef202009-05-22 12:06:27 -07001086 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001087 Type* pR0Type = getR0Type();
1088 TypeTag r0ct = collapseType(pR0Type->tag);
1089 if (r0ct != TY_DOUBLE) {
1090 o4(0xE92D0001); // stmfd sp!,{r0}
1091 mStackUse += 4;
1092 } else {
1093 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1094 mStackUse += 8;
1095 }
Jack Palevich8df46192009-07-07 14:48:51 -07001096 pushType();
-b master422972c2009-06-17 19:13:52 -07001097 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001098 }
1099
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001100 virtual void over() {
1101 // We know it's only used for int-ptr ops (++/--)
1102
1103 Type* pR0Type = getR0Type();
1104 TypeTag r0ct = collapseType(pR0Type->tag);
1105
1106 Type* pTOSType = getTOSType();
1107 TypeTag tosct = collapseType(pTOSType->tag);
1108
1109 assert (r0ct == TY_INT && tosct == TY_INT);
1110
1111 o4(0xE8BD0002); // ldmfd sp!,{r1}
1112 o4(0xE92D0001); // stmfd sp!,{r0}
1113 o4(0xE92D0002); // stmfd sp!,{r1}
1114 overType();
1115 mStackUse += 4;
1116 }
1117
Jack Palevich58c30ee2009-07-17 16:35:23 -07001118 virtual void popR0() {
1119 Type* pTOSType = getTOSType();
1120 switch (collapseType(pTOSType->tag)){
1121 case TY_INT:
1122 case TY_FLOAT:
1123 o4(0xE8BD0001); // ldmfd sp!,{r0}
1124 mStackUse -= 4;
1125 break;
1126 case TY_DOUBLE:
1127 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1128 mStackUse -= 8;
1129 break;
1130 default:
1131 error("Can't pop this type.");
1132 break;
1133 }
1134 popType();
1135 LOG_STACK("popR0: %d\n", mStackUse);
1136 }
1137
1138 virtual void storeR0ToTOS() {
1139 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001140 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001141 Type* pDestType = pPointerType->pHead;
1142 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001143 o4(0xE8BD0004); // ldmfd sp!,{r2}
1144 popType();
-b master422972c2009-06-17 19:13:52 -07001145 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001146 switch (pDestType->tag) {
1147 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001148 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 case TY_FLOAT:
1150 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001151 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001152 case TY_SHORT:
1153 o4(0xE1C200B0); // strh r0, [r2]
1154 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001155 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001156 o4(0xE5C20000); // strb r0, [r2]
1157 break;
1158 case TY_DOUBLE:
1159 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001160 break;
1161 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001162 error("storeR0ToTOS: unimplemented type %d",
1163 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001164 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001165 }
Jack Palevich22305132009-05-13 10:58:45 -07001166 }
1167
Jack Palevich58c30ee2009-07-17 16:35:23 -07001168 virtual void loadR0FromR0() {
1169 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001170 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001171 Type* pNewType = pPointerType->pHead;
1172 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001173 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001174 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001175 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001176 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001177 o4(0xE5900000); // ldr r0, [r0]
1178 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001179 case TY_SHORT:
1180 o4(0xE1D000F0); // ldrsh r0, [r0]
1181 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001182 case TY_CHAR:
1183 o4(0xE5D00000); // ldrb r0, [r0]
1184 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001185 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001186 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001187 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001188 case TY_ARRAY:
1189 pNewType = pNewType->pTail;
1190 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001191 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001192 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001193 break;
1194 }
Jack Palevich80e49722009-08-04 15:39:49 -07001195 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001196 }
1197
Jack Palevichb5e33312009-07-30 19:06:34 -07001198 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001199 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001200 // Local, fp relative
1201 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1202 error("Offset out of range: %08x", ea);
1203 }
1204 if (ea < 0) {
1205 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1206 } else {
1207 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1208 }
Jack Palevichbd894902009-05-14 19:35:31 -07001209 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001210 // Global, absolute.
1211 o4(0xE59F0000); // ldr r0, .L1
1212 o4(0xEA000000); // b .L99
1213 o4(ea); // .L1: .word 0
1214 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001215 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001216 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001217 }
1218
Jack Palevich9f51a262009-07-29 16:22:26 -07001219 virtual int leaForward(int ea, Type* pPointerType) {
1220 setR0Type(pPointerType);
1221 int result = ea;
1222 int pc = getPC();
1223 int offset = 0;
1224 if (ea) {
1225 offset = (pc - ea - 8) >> 2;
1226 if ((offset & 0xffff) != offset) {
1227 error("function forward reference out of bounds");
1228 }
1229 } else {
1230 offset = 0;
1231 }
1232 o4(0xE59F0000 | offset); // ldr r0, .L1
1233
1234 if (ea == 0) {
1235 o4(0xEA000000); // b .L99
1236 result = o4(ea); // .L1: .word 0
1237 // .L99:
1238 }
1239 return result;
1240 }
1241
Jack Palevichb6154502009-08-04 14:56:09 -07001242 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001243 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001244 if (isPointerType(pType) && isPointerType(pR0Type)) {
1245 Type* pA = pR0Type;
1246 Type* pB = pType;
1247 // Array decays to pointer
1248 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1249 pA = pA->pTail;
1250 }
1251 if (typeEqual(pA, pB)) {
1252 return; // OK
1253 }
1254 if (pB->pHead->tag == TY_VOID) {
1255 return; // convert to void* is OK.
1256 }
1257 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
1258 && isCast) {
1259 return; // OK
1260 }
1261 error("Incompatible pointer or array types");
1262 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001263 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001264 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001265 TypeTag r0Tag = collapseType(pR0Type->tag);
1266 TypeTag destTag = collapseType(pType->tag);
1267 if (r0Tag == TY_INT) {
1268 if (destTag == TY_FLOAT) {
1269 callRuntime((void*) runtime_int_to_float);
1270 } else {
1271 assert(destTag == TY_DOUBLE);
1272 callRuntime((void*) runtime_int_to_double);
1273 }
1274 } else if (r0Tag == TY_FLOAT) {
1275 if (destTag == TY_INT) {
1276 callRuntime((void*) runtime_float_to_int);
1277 } else {
1278 assert(destTag == TY_DOUBLE);
1279 callRuntime((void*) runtime_float_to_double);
1280 }
1281 } else {
1282 assert (r0Tag == TY_DOUBLE);
1283 if (destTag == TY_INT) {
1284 callRuntime((void*) runtime_double_to_int);
1285 } else {
1286 assert(destTag == TY_FLOAT);
1287 callRuntime((void*) runtime_double_to_float);
1288 }
1289 }
Jack Palevich8df46192009-07-07 14:48:51 -07001290 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001291 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001292 }
1293
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001294 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001295 return o4(0xE24DDF00); // Placeholder
1296 }
1297
Jack Palevich8148c5b2009-07-16 18:24:47 -07001298 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001299 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001300 Type* pR0Type = getR0Type();
1301 TypeTag r0ct = collapseType(pR0Type->tag);
1302 switch(r0ct) {
1303 case TY_INT:
1304 case TY_FLOAT:
1305 if (l < 0 || l > 4096-4) {
1306 error("l out of range for stack offset: 0x%08x", l);
1307 }
1308 o4(0xE58D0000 + l); // str r0, [sp, #l]
1309 return 4;
1310 case TY_DOUBLE: {
1311 // Align to 8 byte boundary
1312 int l2 = (l + 7) & ~7;
1313 if (l2 < 0 || l2 > 4096-8) {
1314 error("l out of range for stack offset: 0x%08x", l);
1315 }
1316 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1317 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1318 return (l2 - l) + 8;
1319 }
1320 default:
1321 assert(false);
1322 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001323 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001324 }
1325
Jack Palevichb7718b92009-07-09 22:00:24 -07001326 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001327 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001328 // Have to calculate register arg count from actual stack size,
1329 // in order to properly handle ... functions.
1330 int regArgCount = l >> 2;
1331 if (regArgCount > 4) {
1332 regArgCount = 4;
1333 }
1334 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001335 argumentStackUse -= regArgCount * 4;
1336 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1337 }
1338 mStackUse += argumentStackUse;
1339
1340 // Align stack.
1341 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1342 * STACK_ALIGNMENT);
1343 mStackAlignmentAdjustment = 0;
1344 if (missalignment > 0) {
1345 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1346 }
1347 l += mStackAlignmentAdjustment;
1348
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001349 if (l < 0 || l > 0x3FC) {
1350 error("L out of range for stack adjustment: 0x%08x", l);
1351 }
1352 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001353 mStackUse += mStackAlignmentAdjustment;
1354 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1355 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001356 }
1357
Jack Palevich8df46192009-07-07 14:48:51 -07001358 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001359 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001360 // Forward calls are always short (local)
1361 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001362 }
1363
Jack Palevich8df46192009-07-07 14:48:51 -07001364 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001365 assert(pFunc->tag == TY_FUNC);
1366 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001367 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001368 int argCount = l >> 2;
1369 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001370 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001371 if (adjustedL < 0 || adjustedL > 4096-4) {
1372 error("l out of range for stack offset: 0x%08x", l);
1373 }
1374 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1375 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001376 }
1377
Jack Palevichb7718b92009-07-09 22:00:24 -07001378 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001379 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001380 // Have to calculate register arg count from actual stack size,
1381 // in order to properly handle ... functions.
1382 int regArgCount = l >> 2;
1383 if (regArgCount > 4) {
1384 regArgCount = 4;
1385 }
1386 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001387 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1388 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001389 if (stackUse) {
1390 if (stackUse < 0 || stackUse > 255) {
1391 error("L out of range for stack adjustment: 0x%08x", l);
1392 }
1393 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001394 mStackUse -= stackUse * 4;
1395 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001396 }
Jack Palevich22305132009-05-13 10:58:45 -07001397 }
1398
Jack Palevicha6535612009-05-13 16:24:17 -07001399 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001400 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001401 }
1402
1403 /* output a symbol and patch all calls to it */
1404 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001405 int n;
1406 int base = getBase();
1407 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001408 while (t) {
1409 int data = * (int*) t;
1410 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1411 if (decodedOffset == 0) {
1412 n = 0;
1413 } else {
1414 n = base + decodedOffset; /* next value */
1415 }
1416 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1417 | encodeRelAddress(pc - t - 8);
1418 t = n;
1419 }
1420 }
1421
Jack Palevich9f51a262009-07-29 16:22:26 -07001422 /* output a symbol and patch all calls to it */
1423 virtual void resolveForward(int t) {
1424 if (t) {
1425 int pc = getPC();
1426 *(int *) t = pc;
1427 }
1428 }
1429
Jack Palevich1cdef202009-05-22 12:06:27 -07001430 virtual int finishCompile() {
1431#if defined(__arm__)
1432 const long base = long(getBase());
1433 const long curr = long(getPC());
1434 int err = cacheflush(base, curr, 0);
1435 return err;
1436#else
1437 return 0;
1438#endif
1439 }
1440
Jack Palevicha6535612009-05-13 16:24:17 -07001441 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001442#ifdef ENABLE_ARM_DISASSEMBLY
1443 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001444 disasm_interface_t di;
1445 di.di_readword = disassemble_readword;
1446 di.di_printaddr = disassemble_printaddr;
1447 di.di_printf = disassemble_printf;
1448
1449 int base = getBase();
1450 int pc = getPC();
1451 for(int i = base; i < pc; i += 4) {
1452 fprintf(out, "%08x: %08x ", i, *(int*) i);
1453 ::disasm(&di, i, 0);
1454 }
Jack Palevich09555c72009-05-27 12:25:55 -07001455#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001456 return 0;
1457 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001458
Jack Palevich9eed7a22009-07-06 17:24:34 -07001459 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001460 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001461 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001462 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001463 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001464 case TY_CHAR:
1465 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001466 case TY_SHORT:
1467 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001468 case TY_DOUBLE:
1469 return 8;
1470 default:
1471 return 4;
1472 }
1473 }
1474
1475 /**
1476 * Array element alignment (in bytes) for this type of data.
1477 */
1478 virtual size_t sizeOf(Type* pType){
1479 switch(pType->tag) {
1480 case TY_INT:
1481 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001482 case TY_SHORT:
1483 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001484 case TY_CHAR:
1485 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001486 case TY_FLOAT:
1487 return 4;
1488 case TY_DOUBLE:
1489 return 8;
1490 case TY_POINTER:
1491 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001492 case TY_ARRAY:
1493 return pType->length * sizeOf(pType->pHead);
1494 default:
1495 error("Unsupported type %d", pType->tag);
1496 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001497 }
1498 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001499
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001500 virtual size_t stackAlignmentOf(Type* pType) {
1501 switch(pType->tag) {
1502 case TY_DOUBLE:
1503 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001504 case TY_ARRAY:
1505 return stackAlignmentOf(pType->pHead);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001506 default:
1507 return 4;
1508 }
1509 }
1510
Jack Palevich9cbd2262009-07-08 16:48:41 -07001511 virtual size_t stackSizeOf(Type* pType) {
1512 switch(pType->tag) {
1513 case TY_DOUBLE:
1514 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001515 case TY_ARRAY:
1516 return sizeOf(pType);
1517 case TY_FUNC:
1518 error("stackSizeOf func not supported");
1519 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001520 default:
1521 return 4;
1522 }
1523 }
1524
Jack Palevich22305132009-05-13 10:58:45 -07001525 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001526 static FILE* disasmOut;
1527
1528 static u_int
1529 disassemble_readword(u_int address)
1530 {
1531 return(*((u_int *)address));
1532 }
1533
1534 static void
1535 disassemble_printaddr(u_int address)
1536 {
1537 fprintf(disasmOut, "0x%08x", address);
1538 }
1539
1540 static void
1541 disassemble_printf(const char *fmt, ...) {
1542 va_list ap;
1543 va_start(ap, fmt);
1544 vfprintf(disasmOut, fmt, ap);
1545 va_end(ap);
1546 }
1547
1548 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1549
1550 /** Encode a relative address that might also be
1551 * a label.
1552 */
1553 int encodeAddress(int value) {
1554 int base = getBase();
1555 if (value >= base && value <= getPC() ) {
1556 // This is a label, encode it relative to the base.
1557 value = value - base;
1558 }
1559 return encodeRelAddress(value);
1560 }
1561
1562 int encodeRelAddress(int value) {
1563 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1564 }
Jack Palevich22305132009-05-13 10:58:45 -07001565
Jack Palevichb7718b92009-07-09 22:00:24 -07001566 int calcRegArgCount(Type* pDecl) {
1567 int reg = 0;
1568 Type* pArgs = pDecl->pTail;
1569 while (pArgs && reg < 4) {
1570 Type* pArg = pArgs->pHead;
1571 if ( pArg->tag == TY_DOUBLE) {
1572 int evenReg = (reg + 1) & ~1;
1573 if (evenReg >= 4) {
1574 break;
1575 }
1576 reg = evenReg + 2;
1577 } else {
1578 reg++;
1579 }
1580 pArgs = pArgs->pTail;
1581 }
1582 return reg;
1583 }
1584
Jack Palevich58c30ee2009-07-17 16:35:23 -07001585 void setupIntPtrArgs() {
1586 o4(0xE8BD0002); // ldmfd sp!,{r1}
1587 mStackUse -= 4;
1588 popType();
1589 }
1590
Jack Palevichb7718b92009-07-09 22:00:24 -07001591 /* Pop TOS to R1
1592 * Make sure both R0 and TOS are floats. (Could be ints)
1593 * We know that at least one of R0 and TOS is already a float
1594 */
1595 void setupFloatArgs() {
1596 Type* pR0Type = getR0Type();
1597 Type* pTOSType = getTOSType();
1598 TypeTag tagR0 = collapseType(pR0Type->tag);
1599 TypeTag tagTOS = collapseType(pTOSType->tag);
1600 if (tagR0 != TY_FLOAT) {
1601 assert(tagR0 == TY_INT);
1602 callRuntime((void*) runtime_int_to_float);
1603 }
1604 if (tagTOS != TY_FLOAT) {
1605 assert(tagTOS == TY_INT);
1606 assert(tagR0 == TY_FLOAT);
1607 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1608 o4(0xE59D0004); // ldr r0, [sp, #4]
1609 callRuntime((void*) runtime_int_to_float);
1610 o4(0xE1A01000); // mov r1, r0
1611 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1612 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1613 } else {
1614 // Pop TOS
1615 o4(0xE8BD0002); // ldmfd sp!,{r1}
1616 }
1617 mStackUse -= 4;
1618 popType();
1619 }
1620
1621 /* Pop TOS into R2..R3
1622 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1623 * We know that at least one of R0 and TOS are already a double.
1624 */
1625
1626 void setupDoubleArgs() {
1627 Type* pR0Type = getR0Type();
1628 Type* pTOSType = getTOSType();
1629 TypeTag tagR0 = collapseType(pR0Type->tag);
1630 TypeTag tagTOS = collapseType(pTOSType->tag);
1631 if (tagR0 != TY_DOUBLE) {
1632 if (tagR0 == TY_INT) {
1633 callRuntime((void*) runtime_int_to_double);
1634 } else {
1635 assert(tagR0 == TY_FLOAT);
1636 callRuntime((void*) runtime_float_to_double);
1637 }
1638 }
1639 if (tagTOS != TY_DOUBLE) {
1640 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1641 o4(0xE59D0008); // ldr r0, [sp, #8]
1642 if (tagTOS == TY_INT) {
1643 callRuntime((void*) runtime_int_to_double);
1644 } else {
1645 assert(tagTOS == TY_FLOAT);
1646 callRuntime((void*) runtime_float_to_double);
1647 }
1648 o4(0xE1A02000); // mov r2, r0
1649 o4(0xE1A03001); // mov r3, r1
1650 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1651 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1652 mStackUse -= 4;
1653 } else {
1654 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1655 mStackUse -= 8;
1656 }
1657 popType();
1658 }
1659
Jack Palevicha8f427f2009-07-13 18:40:08 -07001660 void liReg(int t, int reg) {
1661 assert(reg >= 0 && reg < 16);
1662 int rN = (reg & 0xf) << 12;
1663 if (t >= 0 && t < 255) {
1664 o4((0xE3A00000 + t) | rN); // mov rN, #0
1665 } else if (t >= -256 && t < 0) {
1666 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001667 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001668 } else {
1669 o4(0xE51F0000 | rN); // ldr rN, .L3
1670 o4(0xEA000000); // b .L99
1671 o4(t); // .L3: .word 0
1672 // .L99:
1673 }
1674 }
1675
Jack Palevichb7718b92009-07-09 22:00:24 -07001676 void callRuntime(void* fn) {
1677 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001678 o4(0xEA000000); // b .L99
1679 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001680 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001681 }
1682
Jack Palevichb7718b92009-07-09 22:00:24 -07001683 // Integer math:
1684
1685 static int runtime_DIV(int b, int a) {
1686 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001687 }
1688
Jack Palevichb7718b92009-07-09 22:00:24 -07001689 static int runtime_MOD(int b, int a) {
1690 return a % b;
1691 }
1692
1693 // Comparison to zero
1694
1695 static int runtime_is_non_zero_f(float a) {
1696 return a != 0;
1697 }
1698
1699 static int runtime_is_non_zero_d(double a) {
1700 return a != 0;
1701 }
1702
1703 // Comparison to zero
1704
1705 static int runtime_is_zero_f(float a) {
1706 return a == 0;
1707 }
1708
1709 static int runtime_is_zero_d(double a) {
1710 return a == 0;
1711 }
1712
1713 // Type conversion
1714
1715 static int runtime_float_to_int(float a) {
1716 return (int) a;
1717 }
1718
1719 static double runtime_float_to_double(float a) {
1720 return (double) a;
1721 }
1722
1723 static int runtime_double_to_int(double a) {
1724 return (int) a;
1725 }
1726
1727 static float runtime_double_to_float(double a) {
1728 return (float) a;
1729 }
1730
1731 static float runtime_int_to_float(int a) {
1732 return (float) a;
1733 }
1734
1735 static double runtime_int_to_double(int a) {
1736 return (double) a;
1737 }
1738
1739 // Comparisons float
1740
1741 static int runtime_cmp_eq_ff(float b, float a) {
1742 return a == b;
1743 }
1744
1745 static int runtime_cmp_ne_ff(float b, float a) {
1746 return a != b;
1747 }
1748
1749 static int runtime_cmp_lt_ff(float b, float a) {
1750 return a < b;
1751 }
1752
1753 static int runtime_cmp_le_ff(float b, float a) {
1754 return a <= b;
1755 }
1756
1757 static int runtime_cmp_ge_ff(float b, float a) {
1758 return a >= b;
1759 }
1760
1761 static int runtime_cmp_gt_ff(float b, float a) {
1762 return a > b;
1763 }
1764
1765 // Comparisons double
1766
1767 static int runtime_cmp_eq_dd(double b, double a) {
1768 return a == b;
1769 }
1770
1771 static int runtime_cmp_ne_dd(double b, double a) {
1772 return a != b;
1773 }
1774
1775 static int runtime_cmp_lt_dd(double b, double a) {
1776 return a < b;
1777 }
1778
1779 static int runtime_cmp_le_dd(double b, double a) {
1780 return a <= b;
1781 }
1782
1783 static int runtime_cmp_ge_dd(double b, double a) {
1784 return a >= b;
1785 }
1786
1787 static int runtime_cmp_gt_dd(double b, double a) {
1788 return a > b;
1789 }
1790
1791 // Math float
1792
1793 static float runtime_op_add_ff(float b, float a) {
1794 return a + b;
1795 }
1796
1797 static float runtime_op_sub_ff(float b, float a) {
1798 return a - b;
1799 }
1800
1801 static float runtime_op_mul_ff(float b, float a) {
1802 return a * b;
1803 }
1804
1805 static float runtime_op_div_ff(float b, float a) {
1806 return a / b;
1807 }
1808
1809 static float runtime_op_neg_f(float a) {
1810 return -a;
1811 }
1812
1813 // Math double
1814
1815 static double runtime_op_add_dd(double b, double a) {
1816 return a + b;
1817 }
1818
1819 static double runtime_op_sub_dd(double b, double a) {
1820 return a - b;
1821 }
1822
1823 static double runtime_op_mul_dd(double b, double a) {
1824 return a * b;
1825 }
1826
1827 static double runtime_op_div_dd(double b, double a) {
1828 return a / b;
1829 }
1830
1831 static double runtime_op_neg_d(double a) {
1832 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001833 }
-b master422972c2009-06-17 19:13:52 -07001834
1835 static const int STACK_ALIGNMENT = 8;
1836 int mStackUse;
1837 // This variable holds the amount we adjusted the stack in the most
1838 // recent endFunctionCallArguments call. It's examined by the
1839 // following adjustStackAfterCall call.
1840 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001841 };
1842
Jack Palevich09555c72009-05-27 12:25:55 -07001843#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001844
1845#ifdef PROVIDE_X86_CODEGEN
1846
Jack Palevich21a15a22009-05-11 14:49:29 -07001847 class X86CodeGenerator : public CodeGenerator {
1848 public:
1849 X86CodeGenerator() {}
1850 virtual ~X86CodeGenerator() {}
1851
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001852 /* returns address to patch with local variable size
1853 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001854 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001855 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1856 return oad(0xec81, 0); /* sub $xxx, %esp */
1857 }
1858
Jack Palevichb7718b92009-07-09 22:00:24 -07001859 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001860 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001861 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001862 }
1863
Jack Palevich21a15a22009-05-11 14:49:29 -07001864 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001865 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001866 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001867 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001868 }
1869
Jack Palevich1a539db2009-07-08 13:04:41 -07001870 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001871 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001872 switch (pType->tag) {
1873 case TY_FLOAT:
1874 oad(0x05D9, address); // flds
1875 break;
1876 case TY_DOUBLE:
1877 oad(0x05DD, address); // fldl
1878 break;
1879 default:
1880 assert(false);
1881 break;
1882 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001883 }
1884
Jack Palevich22305132009-05-13 10:58:45 -07001885 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001886 return psym(0xe9, t);
1887 }
1888
1889 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001890 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001891 Type* pR0Type = getR0Type();
1892 TypeTag tagR0 = pR0Type->tag;
1893 bool isFloatR0 = isFloatTag(tagR0);
1894 if (isFloatR0) {
1895 o(0xeed9); // fldz
1896 o(0xe9da); // fucompp
1897 o(0xe0df); // fnstsw %ax
1898 o(0x9e); // sahf
1899 } else {
1900 o(0xc085); // test %eax, %eax
1901 }
1902 // Use two output statements to generate one instruction.
1903 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001904 return psym(0x84 + l, t);
1905 }
1906
Jack Palevich58c30ee2009-07-17 16:35:23 -07001907 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001908 Type* pR0Type = getR0Type();
1909 Type* pTOSType = getTOSType();
1910 TypeTag tagR0 = pR0Type->tag;
1911 TypeTag tagTOS = pTOSType->tag;
1912 bool isFloatR0 = isFloatTag(tagR0);
1913 bool isFloatTOS = isFloatTag(tagTOS);
1914 if (!isFloatR0 && !isFloatTOS) {
1915 int t = decodeOp(op);
1916 o(0x59); /* pop %ecx */
1917 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001918 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001919 o(0x0f); /* setxx %al */
1920 o(t + 0x90);
1921 o(0xc0);
1922 popType();
1923 } else {
1924 setupFloatOperands();
1925 switch (op) {
1926 case OP_EQUALS:
1927 o(0xe9da); // fucompp
1928 o(0xe0df); // fnstsw %ax
1929 o(0x9e); // sahf
1930 o(0xc0940f); // sete %al
1931 o(0xc29b0f); // setnp %dl
1932 o(0xd021); // andl %edx, %eax
1933 break;
1934 case OP_NOT_EQUALS:
1935 o(0xe9da); // fucompp
1936 o(0xe0df); // fnstsw %ax
1937 o(0x9e); // sahf
1938 o(0xc0950f); // setne %al
1939 o(0xc29a0f); // setp %dl
1940 o(0xd009); // orl %edx, %eax
1941 break;
1942 case OP_GREATER_EQUAL:
1943 o(0xe9da); // fucompp
1944 o(0xe0df); // fnstsw %ax
1945 o(0x05c4f6); // testb $5, %ah
1946 o(0xc0940f); // sete %al
1947 break;
1948 case OP_LESS:
1949 o(0xc9d9); // fxch %st(1)
1950 o(0xe9da); // fucompp
1951 o(0xe0df); // fnstsw %ax
1952 o(0x9e); // sahf
1953 o(0xc0970f); // seta %al
1954 break;
1955 case OP_LESS_EQUAL:
1956 o(0xc9d9); // fxch %st(1)
1957 o(0xe9da); // fucompp
1958 o(0xe0df); // fnstsw %ax
1959 o(0x9e); // sahf
1960 o(0xc0930f); // setea %al
1961 break;
1962 case OP_GREATER:
1963 o(0xe9da); // fucompp
1964 o(0xe0df); // fnstsw %ax
1965 o(0x45c4f6); // testb $69, %ah
1966 o(0xc0940f); // sete %al
1967 break;
1968 default:
1969 error("Unknown comparison op");
1970 }
1971 o(0xc0b60f); // movzbl %al, %eax
1972 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001973 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001974 }
1975
Jack Palevich546b2242009-05-13 15:10:04 -07001976 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001977 Type* pR0Type = getR0Type();
1978 Type* pTOSType = getTOSType();
1979 TypeTag tagR0 = pR0Type->tag;
1980 TypeTag tagTOS = pTOSType->tag;
1981 bool isFloatR0 = isFloatTag(tagR0);
1982 bool isFloatTOS = isFloatTag(tagTOS);
1983 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07001984 bool isPtrR0 = isPointerTag(tagR0);
1985 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001986 if (isPtrR0 || isPtrTOS) {
1987 if (isPtrR0 && isPtrTOS) {
1988 if (op != OP_MINUS) {
1989 error("Unsupported pointer-pointer operation %d.", op);
1990 }
1991 if (! typeEqual(pR0Type, pTOSType)) {
1992 error("Incompatible pointer types for subtraction.");
1993 }
1994 o(0x59); /* pop %ecx */
1995 o(decodeOp(op));
1996 popType();
1997 setR0Type(mkpInt);
1998 int size = sizeOf(pR0Type->pHead);
1999 if (size != 1) {
2000 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002001 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002002 // TODO: Optimize for power-of-two.
2003 genOp(OP_DIV);
2004 }
2005 } else {
2006 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2007 error("Unsupported pointer-scalar operation %d", op);
2008 }
Jack Palevichb6154502009-08-04 14:56:09 -07002009 Type* pPtrType = getPointerArithmeticResultType(
2010 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002011 o(0x59); /* pop %ecx */
2012 int size = sizeOf(pPtrType->pHead);
2013 if (size != 1) {
2014 // TODO: Optimize for power-of-two.
2015 if (isPtrR0) {
2016 oad(0xC969, size); // imull $size, %ecx
2017 } else {
2018 oad(0xC069, size); // mul $size, %eax
2019 }
2020 }
2021 o(decodeOp(op));
2022 popType();
2023 setR0Type(pPtrType);
2024 }
2025 } else {
2026 o(0x59); /* pop %ecx */
2027 o(decodeOp(op));
2028 if (op == OP_MOD)
2029 o(0x92); /* xchg %edx, %eax */
2030 popType();
2031 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002032 } else {
2033 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2034 setupFloatOperands();
2035 // Both float. x87 R0 == left hand, x87 R1 == right hand
2036 switch (op) {
2037 case OP_MUL:
2038 o(0xc9de); // fmulp
2039 break;
2040 case OP_DIV:
2041 o(0xf1de); // fdivp
2042 break;
2043 case OP_PLUS:
2044 o(0xc1de); // faddp
2045 break;
2046 case OP_MINUS:
2047 o(0xe1de); // fsubp
2048 break;
2049 default:
2050 error("Unsupported binary floating operation.");
2051 break;
2052 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002053 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002054 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002055 }
2056
Jack Palevich58c30ee2009-07-17 16:35:23 -07002057 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002058 if (op != OP_LOGICAL_NOT) {
2059 error("Unknown unary cmp %d", op);
2060 } else {
2061 Type* pR0Type = getR0Type();
2062 TypeTag tag = collapseType(pR0Type->tag);
2063 switch(tag) {
2064 case TY_INT: {
2065 oad(0xb9, 0); /* movl $0, %ecx */
2066 int t = decodeOp(op);
2067 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002068 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002069 o(0x0f); /* setxx %al */
2070 o(t + 0x90);
2071 o(0xc0);
2072 }
2073 break;
2074 case TY_FLOAT:
2075 case TY_DOUBLE:
2076 o(0xeed9); // fldz
2077 o(0xe9da); // fucompp
2078 o(0xe0df); // fnstsw %ax
2079 o(0x9e); // sahf
2080 o(0xc0950f); // setne %al
2081 o(0xc29a0f); // setp %dl
2082 o(0xd009); // orl %edx, %eax
2083 o(0xc0b60f); // movzbl %al, %eax
2084 o(0x01f083); // xorl $1, %eax
2085 break;
2086 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002087 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002088 break;
2089 }
2090 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002091 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002092 }
2093
2094 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002095 Type* pR0Type = getR0Type();
2096 TypeTag tag = collapseType(pR0Type->tag);
2097 switch(tag) {
2098 case TY_INT:
2099 oad(0xb9, 0); /* movl $0, %ecx */
2100 o(decodeOp(op));
2101 break;
2102 case TY_FLOAT:
2103 case TY_DOUBLE:
2104 switch (op) {
2105 case OP_MINUS:
2106 o(0xe0d9); // fchs
2107 break;
2108 case OP_BIT_NOT:
2109 error("Can't apply '~' operator to a float or double.");
2110 break;
2111 default:
2112 error("Unknown unary op %d\n", op);
2113 break;
2114 }
2115 break;
2116 default:
2117 error("genUnaryOp unsupported type");
2118 break;
2119 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002120 }
2121
Jack Palevich1cdef202009-05-22 12:06:27 -07002122 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002123 Type* pR0Type = getR0Type();
2124 TypeTag r0ct = collapseType(pR0Type->tag);
2125 switch(r0ct) {
2126 case TY_INT:
2127 o(0x50); /* push %eax */
2128 break;
2129 case TY_FLOAT:
2130 o(0x50); /* push %eax */
2131 o(0x241cd9); // fstps 0(%esp)
2132 break;
2133 case TY_DOUBLE:
2134 o(0x50); /* push %eax */
2135 o(0x50); /* push %eax */
2136 o(0x241cdd); // fstpl 0(%esp)
2137 break;
2138 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002139 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002140 break;
2141 }
Jack Palevich8df46192009-07-07 14:48:51 -07002142 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002143 }
2144
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002145 virtual void over() {
2146 // We know it's only used for int-ptr ops (++/--)
2147
2148 Type* pR0Type = getR0Type();
2149 TypeTag r0ct = collapseType(pR0Type->tag);
2150
2151 Type* pTOSType = getTOSType();
2152 TypeTag tosct = collapseType(pTOSType->tag);
2153
2154 assert (r0ct == TY_INT && tosct == TY_INT);
2155
2156 o(0x59); /* pop %ecx */
2157 o(0x50); /* push %eax */
2158 o(0x51); /* push %ecx */
2159
2160 overType();
2161 }
2162
Jack Palevich58c30ee2009-07-17 16:35:23 -07002163 virtual void popR0() {
2164 Type* pR0Type = getR0Type();
2165 TypeTag r0ct = collapseType(pR0Type->tag);
2166 switch(r0ct) {
2167 case TY_INT:
2168 o(0x58); /* popl %eax */
2169 break;
2170 case TY_FLOAT:
2171 o(0x2404d9); // flds (%esp)
2172 o(0x58); /* popl %eax */
2173 break;
2174 case TY_DOUBLE:
2175 o(0x2404dd); // fldl (%esp)
2176 o(0x58); /* popl %eax */
2177 o(0x58); /* popl %eax */
2178 break;
2179 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002180 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002181 break;
2182 }
2183 popType();
2184 }
2185
2186 virtual void storeR0ToTOS() {
2187 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002188 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002189 Type* pTargetType = pPointerType->pHead;
2190 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002191 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002192 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002193 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002194 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002195 case TY_INT:
2196 o(0x0189); /* movl %eax/%al, (%ecx) */
2197 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002198 case TY_SHORT:
2199 o(0x018966); /* movw %ax, (%ecx) */
2200 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002201 case TY_CHAR:
2202 o(0x0188); /* movl %eax/%al, (%ecx) */
2203 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002204 case TY_FLOAT:
2205 o(0x19d9); /* fstps (%ecx) */
2206 break;
2207 case TY_DOUBLE:
2208 o(0x19dd); /* fstpl (%ecx) */
2209 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002210 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002211 error("storeR0ToTOS: unsupported type %d",
2212 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002213 break;
2214 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002215 }
2216
Jack Palevich58c30ee2009-07-17 16:35:23 -07002217 virtual void loadR0FromR0() {
2218 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002219 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002220 Type* pNewType = pPointerType->pHead;
2221 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002222 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002223 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002224 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002225 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002226 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002227 case TY_SHORT:
2228 o(0xbf0f); /* movswl (%eax), %eax */
2229 ob(0);
2230 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002231 case TY_CHAR:
2232 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002233 ob(0); /* add zero in code */
2234 break;
2235 case TY_FLOAT:
2236 o2(0x00d9); // flds (%eax)
2237 break;
2238 case TY_DOUBLE:
2239 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002240 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002241 case TY_ARRAY:
2242 pNewType = pNewType->pTail;
2243 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002244 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002245 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002246 break;
2247 }
Jack Palevich80e49722009-08-04 15:39:49 -07002248 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002249 }
2250
Jack Palevichb5e33312009-07-30 19:06:34 -07002251 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002252 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002253 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002254 }
2255
Jack Palevich9f51a262009-07-29 16:22:26 -07002256 virtual int leaForward(int ea, Type* pPointerType) {
2257 oad(0xb8, ea); /* mov $xx, %eax */
2258 setR0Type(pPointerType);
2259 return getPC() - 4;
2260 }
2261
Jack Palevichb6154502009-08-04 14:56:09 -07002262 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002263 Type* pR0Type = getR0Type();
2264 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002265 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002266 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002267 return;
2268 }
Jack Palevichb6154502009-08-04 14:56:09 -07002269 if (isPointerType(pType) && isPointerType(pR0Type)) {
2270 Type* pA = pR0Type;
2271 Type* pB = pType;
2272 // Array decays to pointer
2273 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2274 pA = pA->pTail;
2275 }
2276 if (typeEqual(pA, pB)) {
2277 return; // OK
2278 }
2279 if (pB->pHead->tag == TY_VOID) {
2280 return; // convert to void* is OK.
2281 }
2282 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
2283 && isCast) {
2284 return; // OK
2285 }
2286 error("Incompatible pointer or array types");
2287 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002288 // do nothing special
2289 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2290 // do nothing special, both held in same register on x87.
2291 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002292 TypeTag r0Tag = collapseType(pR0Type->tag);
2293 TypeTag destTag = collapseType(pType->tag);
2294 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2295 // Convert R0 from int to float
2296 o(0x50); // push %eax
2297 o(0x2404DB); // fildl 0(%esp)
2298 o(0x58); // pop %eax
2299 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2300 // Convert R0 from float to int. Complicated because
2301 // need to save and restore the rounding mode.
2302 o(0x50); // push %eax
2303 o(0x50); // push %eax
2304 o(0x02247cD9); // fnstcw 2(%esp)
2305 o(0x2444b70f); // movzwl 2(%esp), %eax
2306 o(0x02);
2307 o(0x0cb4); // movb $12, %ah
2308 o(0x24048966); // movw %ax, 0(%esp)
2309 o(0x242cd9); // fldcw 0(%esp)
2310 o(0x04245cdb); // fistpl 4(%esp)
2311 o(0x02246cd9); // fldcw 2(%esp)
2312 o(0x58); // pop %eax
2313 o(0x58); // pop %eax
2314 } else {
2315 error("Incompatible types old: %d new: %d",
2316 pR0Type->tag, pType->tag);
2317 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002318 }
2319 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002320 }
2321
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002322 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002323 return oad(0xec81, 0); /* sub $xxx, %esp */
2324 }
2325
Jack Palevich8148c5b2009-07-16 18:24:47 -07002326 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2327 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002328 Type* pR0Type = getR0Type();
2329 TypeTag r0ct = collapseType(pR0Type->tag);
2330 switch(r0ct) {
2331 case TY_INT:
2332 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2333 return 4;
2334 case TY_FLOAT:
2335 oad(0x249CD9, l); /* fstps xxx(%esp) */
2336 return 4;
2337 case TY_DOUBLE:
2338 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2339 return 8;
2340 default:
2341 assert(false);
2342 return 0;
2343 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002344 }
2345
Jack Palevichb7718b92009-07-09 22:00:24 -07002346 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002347 * (int*) a = l;
2348 }
2349
Jack Palevich8df46192009-07-07 14:48:51 -07002350 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002351 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002352 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002353 return psym(0xe8, symbol); /* call xxx */
2354 }
2355
Jack Palevich8df46192009-07-07 14:48:51 -07002356 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002357 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002358 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002359 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002360 oad(0x2494ff, l); /* call *xxx(%esp) */
2361 }
2362
Jack Palevichb7718b92009-07-09 22:00:24 -07002363 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002364 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002365 if (isIndirect) {
2366 l += 4;
2367 }
-b master422972c2009-06-17 19:13:52 -07002368 if (l > 0) {
2369 oad(0xc481, l); /* add $xxx, %esp */
2370 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002371 }
2372
Jack Palevicha6535612009-05-13 16:24:17 -07002373 virtual int jumpOffset() {
2374 return 5;
2375 }
2376
2377 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002378 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002379 }
2380
Jack Paleviche7b59062009-05-19 17:12:17 -07002381 /* output a symbol and patch all calls to it */
2382 virtual void gsym(int t) {
2383 int n;
2384 int pc = getPC();
2385 while (t) {
2386 n = *(int *) t; /* next value */
2387 *(int *) t = pc - t - 4;
2388 t = n;
2389 }
2390 }
2391
Jack Palevich9f51a262009-07-29 16:22:26 -07002392 /* output a symbol and patch all calls to it, using absolute address */
2393 virtual void resolveForward(int t) {
2394 int n;
2395 int pc = getPC();
2396 while (t) {
2397 n = *(int *) t; /* next value */
2398 *(int *) t = pc;
2399 t = n;
2400 }
2401 }
2402
Jack Palevich1cdef202009-05-22 12:06:27 -07002403 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002404 size_t pagesize = 4096;
2405 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2406 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2407 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2408 if (err) {
2409 error("mprotect() failed: %d", errno);
2410 }
2411 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002412 }
2413
Jack Palevich9eed7a22009-07-06 17:24:34 -07002414 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002415 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002416 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002417 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002418 switch (pType->tag) {
2419 case TY_CHAR:
2420 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002421 case TY_SHORT:
2422 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002423 case TY_ARRAY:
2424 return alignmentOf(pType->pHead);
2425 case TY_FUNC:
2426 error("alignment of func not supported");
2427 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002428 default:
2429 return 4;
2430 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002431 }
2432
2433 /**
2434 * Array element alignment (in bytes) for this type of data.
2435 */
2436 virtual size_t sizeOf(Type* pType){
2437 switch(pType->tag) {
2438 case TY_INT:
2439 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002440 case TY_SHORT:
2441 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002442 case TY_CHAR:
2443 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002444 case TY_FLOAT:
2445 return 4;
2446 case TY_DOUBLE:
2447 return 8;
2448 case TY_POINTER:
2449 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002450 case TY_ARRAY:
2451 return pType->length * sizeOf(pType->pHead);
2452 default:
2453 error("Unsupported type %d", pType->tag);
2454 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002455 }
2456 }
2457
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002458 virtual size_t stackAlignmentOf(Type* pType){
2459 return 4;
2460 }
2461
Jack Palevich9cbd2262009-07-08 16:48:41 -07002462 virtual size_t stackSizeOf(Type* pType) {
2463 switch(pType->tag) {
2464 case TY_DOUBLE:
2465 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07002466 case TY_ARRAY:
2467 return sizeOf(pType);
2468 case TY_FUNC:
2469 error("stackSizeOf func not supported");
2470 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002471 default:
2472 return 4;
2473 }
2474 }
2475
Jack Palevich21a15a22009-05-11 14:49:29 -07002476 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002477
2478 /** Output 1 to 4 bytes.
2479 *
2480 */
2481 void o(int n) {
2482 /* cannot use unsigned, so we must do a hack */
2483 while (n && n != -1) {
2484 ob(n & 0xff);
2485 n = n >> 8;
2486 }
2487 }
2488
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002489 /* Output exactly 2 bytes
2490 */
2491 void o2(int n) {
2492 ob(n & 0xff);
2493 ob(0xff & (n >> 8));
2494 }
2495
Jack Paleviche7b59062009-05-19 17:12:17 -07002496 /* psym is used to put an instruction with a data field which is a
2497 reference to a symbol. It is in fact the same as oad ! */
2498 int psym(int n, int t) {
2499 return oad(n, t);
2500 }
2501
2502 /* instruction + address */
2503 int oad(int n, int t) {
2504 o(n);
2505 int result = getPC();
2506 o4(t);
2507 return result;
2508 }
2509
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002510 static const int operatorHelper[];
2511
2512 int decodeOp(int op) {
2513 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002514 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002515 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002516 }
2517 return operatorHelper[op];
2518 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002519
Jack Palevich546b2242009-05-13 15:10:04 -07002520 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002521 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002522 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002523 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002524
2525 void setupFloatOperands() {
2526 Type* pR0Type = getR0Type();
2527 Type* pTOSType = getTOSType();
2528 TypeTag tagR0 = pR0Type->tag;
2529 TypeTag tagTOS = pTOSType->tag;
2530 bool isFloatR0 = isFloatTag(tagR0);
2531 bool isFloatTOS = isFloatTag(tagTOS);
2532 if (! isFloatR0) {
2533 // Convert R0 from int to float
2534 o(0x50); // push %eax
2535 o(0x2404DB); // fildl 0(%esp)
2536 o(0x58); // pop %eax
2537 }
2538 if (! isFloatTOS){
2539 o(0x2404DB); // fildl 0(%esp);
2540 o(0x58); // pop %eax
2541 } else {
2542 if (tagTOS == TY_FLOAT) {
2543 o(0x2404d9); // flds (%esp)
2544 o(0x58); // pop %eax
2545 } else {
2546 o(0x2404dd); // fldl (%esp)
2547 o(0x58); // pop %eax
2548 o(0x58); // pop %eax
2549 }
2550 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002551 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002552 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002553 };
2554
Jack Paleviche7b59062009-05-19 17:12:17 -07002555#endif // PROVIDE_X86_CODEGEN
2556
Jack Palevichb67b18f2009-06-11 21:12:23 -07002557#ifdef PROVIDE_TRACE_CODEGEN
2558 class TraceCodeGenerator : public CodeGenerator {
2559 private:
2560 CodeGenerator* mpBase;
2561
2562 public:
2563 TraceCodeGenerator(CodeGenerator* pBase) {
2564 mpBase = pBase;
2565 }
2566
2567 virtual ~TraceCodeGenerator() {
2568 delete mpBase;
2569 }
2570
2571 virtual void init(CodeBuf* pCodeBuf) {
2572 mpBase->init(pCodeBuf);
2573 }
2574
2575 void setErrorSink(ErrorSink* pErrorSink) {
2576 mpBase->setErrorSink(pErrorSink);
2577 }
2578
2579 /* returns address to patch with local variable size
2580 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002581 virtual int functionEntry(Type* pDecl) {
2582 int result = mpBase->functionEntry(pDecl);
2583 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002584 return result;
2585 }
2586
Jack Palevichb7718b92009-07-09 22:00:24 -07002587 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2588 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2589 localVariableAddress, localVariableSize);
2590 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002591 }
2592
2593 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002594 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002595 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002596 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002597 }
2598
Jack Palevich1a539db2009-07-08 13:04:41 -07002599 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002600 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002601 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002602 }
2603
Jack Palevichb67b18f2009-06-11 21:12:23 -07002604 virtual int gjmp(int t) {
2605 int result = mpBase->gjmp(t);
2606 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2607 return result;
2608 }
2609
2610 /* l = 0: je, l == 1: jne */
2611 virtual int gtst(bool l, int t) {
2612 int result = mpBase->gtst(l, t);
2613 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2614 return result;
2615 }
2616
Jack Palevich58c30ee2009-07-17 16:35:23 -07002617 virtual void gcmp(int op) {
2618 fprintf(stderr, "gcmp(%d)\n", op);
2619 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002620 }
2621
2622 virtual void genOp(int op) {
2623 fprintf(stderr, "genOp(%d)\n", op);
2624 mpBase->genOp(op);
2625 }
2626
Jack Palevich9eed7a22009-07-06 17:24:34 -07002627
Jack Palevich58c30ee2009-07-17 16:35:23 -07002628 virtual void gUnaryCmp(int op) {
2629 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2630 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002631 }
2632
2633 virtual void genUnaryOp(int op) {
2634 fprintf(stderr, "genUnaryOp(%d)\n", op);
2635 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002636 }
2637
2638 virtual void pushR0() {
2639 fprintf(stderr, "pushR0()\n");
2640 mpBase->pushR0();
2641 }
2642
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002643 virtual void over() {
2644 fprintf(stderr, "over()\n");
2645 mpBase->over();
2646 }
2647
Jack Palevich58c30ee2009-07-17 16:35:23 -07002648 virtual void popR0() {
2649 fprintf(stderr, "popR0()\n");
2650 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002651 }
2652
Jack Palevich58c30ee2009-07-17 16:35:23 -07002653 virtual void storeR0ToTOS() {
2654 fprintf(stderr, "storeR0ToTOS()\n");
2655 mpBase->storeR0ToTOS();
2656 }
2657
2658 virtual void loadR0FromR0() {
2659 fprintf(stderr, "loadR0FromR0()\n");
2660 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002661 }
2662
Jack Palevichb5e33312009-07-30 19:06:34 -07002663 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2664 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
2665 pPointerType->pHead->tag, et);
2666 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002667 }
2668
Jack Palevich9f51a262009-07-29 16:22:26 -07002669 virtual int leaForward(int ea, Type* pPointerType) {
2670 fprintf(stderr, "leaForward(%d)\n", ea);
2671 return mpBase->leaForward(ea, pPointerType);
2672 }
2673
Jack Palevich8df46192009-07-07 14:48:51 -07002674 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002675 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002676 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002677 }
2678
2679 virtual int beginFunctionCallArguments() {
2680 int result = mpBase->beginFunctionCallArguments();
2681 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2682 return result;
2683 }
2684
Jack Palevich8148c5b2009-07-16 18:24:47 -07002685 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2686 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2687 pArgType->tag);
2688 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002689 }
2690
Jack Palevichb7718b92009-07-09 22:00:24 -07002691 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002692 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002693 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002694 }
2695
Jack Palevich8df46192009-07-07 14:48:51 -07002696 virtual int callForward(int symbol, Type* pFunc) {
2697 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002698 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2699 return result;
2700 }
2701
Jack Palevich8df46192009-07-07 14:48:51 -07002702 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002703 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2704 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002705 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002706 }
2707
Jack Palevichb7718b92009-07-09 22:00:24 -07002708 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2709 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2710 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002711 }
2712
2713 virtual int jumpOffset() {
2714 return mpBase->jumpOffset();
2715 }
2716
2717 virtual int disassemble(FILE* out) {
2718 return mpBase->disassemble(out);
2719 }
2720
2721 /* output a symbol and patch all calls to it */
2722 virtual void gsym(int t) {
2723 fprintf(stderr, "gsym(%d)\n", t);
2724 mpBase->gsym(t);
2725 }
2726
Jack Palevich9f51a262009-07-29 16:22:26 -07002727 virtual void resolveForward(int t) {
2728 mpBase->resolveForward(t);
2729 }
2730
Jack Palevichb67b18f2009-06-11 21:12:23 -07002731 virtual int finishCompile() {
2732 int result = mpBase->finishCompile();
2733 fprintf(stderr, "finishCompile() = %d\n", result);
2734 return result;
2735 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002736
2737 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002738 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002739 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002740 virtual size_t alignmentOf(Type* pType){
2741 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002742 }
2743
2744 /**
2745 * Array element alignment (in bytes) for this type of data.
2746 */
2747 virtual size_t sizeOf(Type* pType){
2748 return mpBase->sizeOf(pType);
2749 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002750
Jack Palevich9cbd2262009-07-08 16:48:41 -07002751
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002752 virtual size_t stackAlignmentOf(Type* pType) {
2753 return mpBase->stackAlignmentOf(pType);
2754 }
2755
2756
Jack Palevich9cbd2262009-07-08 16:48:41 -07002757 virtual size_t stackSizeOf(Type* pType) {
2758 return mpBase->stackSizeOf(pType);
2759 }
2760
Jack Palevich1a539db2009-07-08 13:04:41 -07002761 virtual Type* getR0Type() {
2762 return mpBase->getR0Type();
2763 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002764
2765 virtual ExpressionType getR0ExpressionType() {
2766 return mpBase->getR0ExpressionType();
2767 }
2768
2769 virtual void setR0ExpressionType(ExpressionType et) {
2770 mpBase->setR0ExpressionType(et);
2771 }
2772
2773 virtual size_t getExpressionStackDepth() {
2774 return mpBase->getExpressionStackDepth();
2775 }
Jack Palevichb5e33312009-07-30 19:06:34 -07002776
2777 virtual void forceR0RVal() {
2778 return mpBase->forceR0RVal();
2779 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002780 };
2781
2782#endif // PROVIDE_TRACE_CODEGEN
2783
Jack Palevich569f1352009-06-29 14:29:08 -07002784 class Arena {
2785 public:
2786 // Used to record a given allocation amount.
2787 // Used:
2788 // Mark mark = arena.mark();
2789 // ... lots of arena.allocate()
2790 // arena.free(mark);
2791
2792 struct Mark {
2793 size_t chunk;
2794 size_t offset;
2795 };
2796
2797 Arena() {
2798 mCurrentChunk = 0;
2799 Chunk start(CHUNK_SIZE);
2800 mData.push_back(start);
2801 }
2802
2803 ~Arena() {
2804 for(size_t i = 0; i < mData.size(); i++) {
2805 mData[i].free();
2806 }
2807 }
2808
2809 // Alloc using the standard alignment size safe for any variable
2810 void* alloc(size_t size) {
2811 return alloc(size, 8);
2812 }
2813
2814 Mark mark(){
2815 Mark result;
2816 result.chunk = mCurrentChunk;
2817 result.offset = mData[mCurrentChunk].mOffset;
2818 return result;
2819 }
2820
2821 void freeToMark(const Mark& mark) {
2822 mCurrentChunk = mark.chunk;
2823 mData[mCurrentChunk].mOffset = mark.offset;
2824 }
2825
2826 private:
2827 // Allocate memory aligned to a given size
2828 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2829 // Memory is not zero filled.
2830
2831 void* alloc(size_t size, size_t alignment) {
2832 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2833 if (mCurrentChunk + 1 < mData.size()) {
2834 mCurrentChunk++;
2835 } else {
2836 size_t allocSize = CHUNK_SIZE;
2837 if (allocSize < size + alignment - 1) {
2838 allocSize = size + alignment - 1;
2839 }
2840 Chunk chunk(allocSize);
2841 mData.push_back(chunk);
2842 mCurrentChunk++;
2843 }
2844 }
2845 return mData[mCurrentChunk].allocate(size, alignment);
2846 }
2847
2848 static const size_t CHUNK_SIZE = 128*1024;
2849 // Note: this class does not deallocate its
2850 // memory when it's destroyed. It depends upon
2851 // its parent to deallocate the memory.
2852 struct Chunk {
2853 Chunk() {
2854 mpData = 0;
2855 mSize = 0;
2856 mOffset = 0;
2857 }
2858
2859 Chunk(size_t size) {
2860 mSize = size;
2861 mpData = (char*) malloc(size);
2862 mOffset = 0;
2863 }
2864
2865 ~Chunk() {
2866 // Doesn't deallocate memory.
2867 }
2868
2869 void* allocate(size_t size, size_t alignment) {
2870 size_t alignedOffset = aligned(mOffset, alignment);
2871 void* result = mpData + alignedOffset;
2872 mOffset = alignedOffset + size;
2873 return result;
2874 }
2875
2876 void free() {
2877 if (mpData) {
2878 ::free(mpData);
2879 mpData = 0;
2880 }
2881 }
2882
2883 size_t remainingCapacity(size_t alignment) {
2884 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2885 }
2886
2887 // Assume alignment is a power of two
2888 inline size_t aligned(size_t v, size_t alignment) {
2889 size_t mask = alignment-1;
2890 return (v + mask) & ~mask;
2891 }
2892
2893 char* mpData;
2894 size_t mSize;
2895 size_t mOffset;
2896 };
2897
2898 size_t mCurrentChunk;
2899
2900 Vector<Chunk> mData;
2901 };
2902
Jack Palevich569f1352009-06-29 14:29:08 -07002903 struct VariableInfo;
2904
2905 struct Token {
2906 int hash;
2907 size_t length;
2908 char* pText;
2909 tokenid_t id;
2910
2911 // Current values for the token
2912 char* mpMacroDefinition;
2913 VariableInfo* mpVariableInfo;
2914 };
2915
2916 class TokenTable {
2917 public:
2918 // Don't use 0..0xff, allows characters and operators to be tokens too.
2919
2920 static const int TOKEN_BASE = 0x100;
2921 TokenTable() {
2922 mpMap = hashmapCreate(128, hashFn, equalsFn);
2923 }
2924
2925 ~TokenTable() {
2926 hashmapFree(mpMap);
2927 }
2928
2929 void setArena(Arena* pArena) {
2930 mpArena = pArena;
2931 }
2932
2933 // Returns a token for a given string of characters.
2934 tokenid_t intern(const char* pText, size_t length) {
2935 Token probe;
2936 int hash = hashmapHash((void*) pText, length);
2937 {
2938 Token probe;
2939 probe.hash = hash;
2940 probe.length = length;
2941 probe.pText = (char*) pText;
2942 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2943 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002944 return pValue->id;
2945 }
2946 }
2947
2948 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2949 memset(pToken, 0, sizeof(*pToken));
2950 pToken->hash = hash;
2951 pToken->length = length;
2952 pToken->pText = (char*) mpArena->alloc(length + 1);
2953 memcpy(pToken->pText, pText, length);
2954 pToken->pText[length] = 0;
2955 pToken->id = mTokens.size() + TOKEN_BASE;
2956 mTokens.push_back(pToken);
2957 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002958 return pToken->id;
2959 }
2960
2961 // Return the Token for a given tokenid.
2962 Token& operator[](tokenid_t id) {
2963 return *mTokens[id - TOKEN_BASE];
2964 }
2965
2966 inline size_t size() {
2967 return mTokens.size();
2968 }
2969
2970 private:
2971
2972 static int hashFn(void* pKey) {
2973 Token* pToken = (Token*) pKey;
2974 return pToken->hash;
2975 }
2976
2977 static bool equalsFn(void* keyA, void* keyB) {
2978 Token* pTokenA = (Token*) keyA;
2979 Token* pTokenB = (Token*) keyB;
2980 // Don't need to compare hash values, they should always be equal
2981 return pTokenA->length == pTokenB->length
2982 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2983 }
2984
2985 Hashmap* mpMap;
2986 Vector<Token*> mTokens;
2987 Arena* mpArena;
2988 };
2989
Jack Palevich1cdef202009-05-22 12:06:27 -07002990 class InputStream {
2991 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002992 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002993 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002994 };
2995
2996 class TextInputStream : public InputStream {
2997 public:
2998 TextInputStream(const char* text, size_t textLength)
2999 : pText(text), mTextLength(textLength), mPosition(0) {
3000 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003001
Jack Palevichdc456462009-07-16 16:50:56 -07003002 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003003 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3004 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003005
Jack Palevichdc456462009-07-16 16:50:56 -07003006 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003007 const char* pText;
3008 size_t mTextLength;
3009 size_t mPosition;
3010 };
3011
Jack Palevicheedf9d22009-06-04 16:23:40 -07003012 class String {
3013 public:
3014 String() {
3015 mpBase = 0;
3016 mUsed = 0;
3017 mSize = 0;
3018 }
3019
Jack Palevich303d8ff2009-06-11 19:06:24 -07003020 String(const char* item, int len, bool adopt) {
3021 if (len < 0) {
3022 len = strlen(item);
3023 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003024 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003025 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003026 mUsed = len;
3027 mSize = len + 1;
3028 } else {
3029 mpBase = 0;
3030 mUsed = 0;
3031 mSize = 0;
3032 appendBytes(item, len);
3033 }
3034 }
3035
Jack Palevich303d8ff2009-06-11 19:06:24 -07003036 String(const String& other) {
3037 mpBase = 0;
3038 mUsed = 0;
3039 mSize = 0;
3040 appendBytes(other.getUnwrapped(), other.len());
3041 }
3042
Jack Palevicheedf9d22009-06-04 16:23:40 -07003043 ~String() {
3044 if (mpBase) {
3045 free(mpBase);
3046 }
3047 }
3048
Jack Palevicha6baa232009-06-12 11:25:59 -07003049 String& operator=(const String& other) {
3050 clear();
3051 appendBytes(other.getUnwrapped(), other.len());
3052 return *this;
3053 }
3054
Jack Palevich303d8ff2009-06-11 19:06:24 -07003055 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003056 return mpBase;
3057 }
3058
Jack Palevich303d8ff2009-06-11 19:06:24 -07003059 void clear() {
3060 mUsed = 0;
3061 if (mSize > 0) {
3062 mpBase[0] = 0;
3063 }
3064 }
3065
Jack Palevicheedf9d22009-06-04 16:23:40 -07003066 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003067 appendBytes(s, strlen(s));
3068 }
3069
3070 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003071 memcpy(ensure(n), s, n + 1);
3072 }
3073
3074 void append(char c) {
3075 * ensure(1) = c;
3076 }
3077
Jack Palevich86351982009-06-30 18:09:56 -07003078 void append(String& other) {
3079 appendBytes(other.getUnwrapped(), other.len());
3080 }
3081
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003082 char* orphan() {
3083 char* result = mpBase;
3084 mpBase = 0;
3085 mUsed = 0;
3086 mSize = 0;
3087 return result;
3088 }
3089
Jack Palevicheedf9d22009-06-04 16:23:40 -07003090 void printf(const char* fmt,...) {
3091 va_list ap;
3092 va_start(ap, fmt);
3093 vprintf(fmt, ap);
3094 va_end(ap);
3095 }
3096
3097 void vprintf(const char* fmt, va_list ap) {
3098 char* temp;
3099 int numChars = vasprintf(&temp, fmt, ap);
3100 memcpy(ensure(numChars), temp, numChars+1);
3101 free(temp);
3102 }
3103
Jack Palevich303d8ff2009-06-11 19:06:24 -07003104 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003105 return mUsed;
3106 }
3107
3108 private:
3109 char* ensure(int n) {
3110 size_t newUsed = mUsed + n;
3111 if (newUsed > mSize) {
3112 size_t newSize = mSize * 2 + 10;
3113 if (newSize < newUsed) {
3114 newSize = newUsed;
3115 }
3116 mpBase = (char*) realloc(mpBase, newSize + 1);
3117 mSize = newSize;
3118 }
3119 mpBase[newUsed] = '\0';
3120 char* result = mpBase + mUsed;
3121 mUsed = newUsed;
3122 return result;
3123 }
3124
3125 char* mpBase;
3126 size_t mUsed;
3127 size_t mSize;
3128 };
3129
Jack Palevich569f1352009-06-29 14:29:08 -07003130 void internKeywords() {
3131 // Note: order has to match TOK_ constants
3132 static const char* keywords[] = {
3133 "int",
3134 "char",
3135 "void",
3136 "if",
3137 "else",
3138 "while",
3139 "break",
3140 "return",
3141 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003142 "auto",
3143 "case",
3144 "const",
3145 "continue",
3146 "default",
3147 "do",
3148 "double",
3149 "enum",
3150 "extern",
3151 "float",
3152 "goto",
3153 "long",
3154 "register",
3155 "short",
3156 "signed",
3157 "sizeof",
3158 "static",
3159 "struct",
3160 "switch",
3161 "typedef",
3162 "union",
3163 "unsigned",
3164 "volatile",
3165 "_Bool",
3166 "_Complex",
3167 "_Imaginary",
3168 "inline",
3169 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003170
3171 // predefined tokens that can also be symbols start here:
3172 "pragma",
3173 "define",
3174 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003175 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003176
Jack Palevich569f1352009-06-29 14:29:08 -07003177 for(int i = 0; keywords[i]; i++) {
3178 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003179 }
Jack Palevich569f1352009-06-29 14:29:08 -07003180 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003181
Jack Palevich36d94142009-06-08 15:55:32 -07003182 struct InputState {
3183 InputStream* pStream;
3184 int oldCh;
3185 };
3186
Jack Palevich2db168f2009-06-11 14:29:47 -07003187 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003188 void* pAddress;
3189 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003190 tokenid_t tok;
3191 size_t level;
3192 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003193 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003194 };
3195
Jack Palevich303d8ff2009-06-11 19:06:24 -07003196 class SymbolStack {
3197 public:
3198 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003199 mpArena = 0;
3200 mpTokenTable = 0;
3201 }
3202
3203 void setArena(Arena* pArena) {
3204 mpArena = pArena;
3205 }
3206
3207 void setTokenTable(TokenTable* pTokenTable) {
3208 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003209 }
3210
3211 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003212 Mark mark;
3213 mark.mArenaMark = mpArena->mark();
3214 mark.mSymbolHead = mStack.size();
3215 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003216 }
3217
3218 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003219 // Undo any shadowing that was done:
3220 Mark mark = mLevelStack.back();
3221 mLevelStack.pop_back();
3222 while (mStack.size() > mark.mSymbolHead) {
3223 VariableInfo* pV = mStack.back();
3224 mStack.pop_back();
3225 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003226 }
Jack Palevich569f1352009-06-29 14:29:08 -07003227 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003228 }
3229
Jack Palevich569f1352009-06-29 14:29:08 -07003230 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3231 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3232 return pV && pV->level == level();
3233 }
3234
3235 VariableInfo* add(tokenid_t tok) {
3236 Token& token = (*mpTokenTable)[tok];
3237 VariableInfo* pOldV = token.mpVariableInfo;
3238 VariableInfo* pNewV =
3239 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3240 memset(pNewV, 0, sizeof(VariableInfo));
3241 pNewV->tok = tok;
3242 pNewV->level = level();
3243 pNewV->pOldDefinition = pOldV;
3244 token.mpVariableInfo = pNewV;
3245 mStack.push_back(pNewV);
3246 return pNewV;
3247 }
3248
Jack Palevich86351982009-06-30 18:09:56 -07003249 VariableInfo* add(Type* pType) {
3250 VariableInfo* pVI = add(pType->id);
3251 pVI->pType = pType;
3252 return pVI;
3253 }
3254
Jack Palevich569f1352009-06-29 14:29:08 -07003255 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3256 for (size_t i = 0; i < mStack.size(); i++) {
3257 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003258 break;
3259 }
3260 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003261 }
3262
Jack Palevich303d8ff2009-06-11 19:06:24 -07003263 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003264 inline size_t level() {
3265 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003266 }
3267
Jack Palevich569f1352009-06-29 14:29:08 -07003268 struct Mark {
3269 Arena::Mark mArenaMark;
3270 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003271 };
3272
Jack Palevich569f1352009-06-29 14:29:08 -07003273 Arena* mpArena;
3274 TokenTable* mpTokenTable;
3275 Vector<VariableInfo*> mStack;
3276 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003277 };
Jack Palevich36d94142009-06-08 15:55:32 -07003278
3279 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003280 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003281 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003282 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003283 int tokl; // token operator level
3284 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003285 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003286 intptr_t loc; // local variable index
3287 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003288 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003289 char* dptr; // Macro state: Points to macro text during macro playback.
3290 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003291 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003292 ACCSymbolLookupFn mpSymbolLookupFn;
3293 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003294
3295 // Arena for the duration of the compile
3296 Arena mGlobalArena;
3297 // Arena for data that's only needed when compiling a single function
3298 Arena mLocalArena;
3299
Jack Palevich2ff5c222009-07-23 15:11:22 -07003300 Arena* mpCurrentArena;
3301
Jack Palevich569f1352009-06-29 14:29:08 -07003302 TokenTable mTokenTable;
3303 SymbolStack mGlobals;
3304 SymbolStack mLocals;
3305
Jack Palevich40600de2009-07-01 15:32:35 -07003306 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003307 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003308 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003309 Type* mkpChar; // char
3310 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003311 Type* mkpFloat;
3312 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003313 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003314 Type* mkpIntPtr;
3315 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003316 Type* mkpFloatPtr;
3317 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003318 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003319
Jack Palevich36d94142009-06-08 15:55:32 -07003320 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003321 int mLineNumber;
3322 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003323
3324 CodeBuf codeBuf;
3325 CodeGenerator* pGen;
3326
Jack Palevicheedf9d22009-06-04 16:23:40 -07003327 String mErrorBuf;
3328
Jack Palevicheedf9d22009-06-04 16:23:40 -07003329 String mPragmas;
3330 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003331 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003332
Jack Palevich21a15a22009-05-11 14:49:29 -07003333 static const int ALLOC_SIZE = 99999;
3334
Jack Palevich303d8ff2009-06-11 19:06:24 -07003335 static const int TOK_DUMMY = 1;
3336 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003337 static const int TOK_NUM_FLOAT = 3;
3338 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003339 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003340
3341 // 3..255 are character and/or operators
3342
Jack Palevich2db168f2009-06-11 14:29:47 -07003343 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003344 // Order has to match string list in "internKeywords".
3345 enum {
3346 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3347 TOK_INT = TOK_KEYWORD,
3348 TOK_CHAR,
3349 TOK_VOID,
3350 TOK_IF,
3351 TOK_ELSE,
3352 TOK_WHILE,
3353 TOK_BREAK,
3354 TOK_RETURN,
3355 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003356 TOK_AUTO,
3357 TOK_CASE,
3358 TOK_CONST,
3359 TOK_CONTINUE,
3360 TOK_DEFAULT,
3361 TOK_DO,
3362 TOK_DOUBLE,
3363 TOK_ENUM,
3364 TOK_EXTERN,
3365 TOK_FLOAT,
3366 TOK_GOTO,
3367 TOK_LONG,
3368 TOK_REGISTER,
3369 TOK_SHORT,
3370 TOK_SIGNED,
3371 TOK_SIZEOF,
3372 TOK_STATIC,
3373 TOK_STRUCT,
3374 TOK_SWITCH,
3375 TOK_TYPEDEF,
3376 TOK_UNION,
3377 TOK_UNSIGNED,
3378 TOK_VOLATILE,
3379 TOK__BOOL,
3380 TOK__COMPLEX,
3381 TOK__IMAGINARY,
3382 TOK_INLINE,
3383 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003384
3385 // Symbols start after keywords
3386
3387 TOK_SYMBOL,
3388 TOK_PRAGMA = TOK_SYMBOL,
3389 TOK_DEFINE,
3390 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003391 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003392
3393 static const int LOCAL = 0x200;
3394
3395 static const int SYM_FORWARD = 0;
3396 static const int SYM_DEFINE = 1;
3397
3398 /* tokens in string heap */
3399 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003400
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003401 static const int OP_INCREMENT = 0;
3402 static const int OP_DECREMENT = 1;
3403 static const int OP_MUL = 2;
3404 static const int OP_DIV = 3;
3405 static const int OP_MOD = 4;
3406 static const int OP_PLUS = 5;
3407 static const int OP_MINUS = 6;
3408 static const int OP_SHIFT_LEFT = 7;
3409 static const int OP_SHIFT_RIGHT = 8;
3410 static const int OP_LESS_EQUAL = 9;
3411 static const int OP_GREATER_EQUAL = 10;
3412 static const int OP_LESS = 11;
3413 static const int OP_GREATER = 12;
3414 static const int OP_EQUALS = 13;
3415 static const int OP_NOT_EQUALS = 14;
3416 static const int OP_LOGICAL_AND = 15;
3417 static const int OP_LOGICAL_OR = 16;
3418 static const int OP_BIT_AND = 17;
3419 static const int OP_BIT_XOR = 18;
3420 static const int OP_BIT_OR = 19;
3421 static const int OP_BIT_NOT = 20;
3422 static const int OP_LOGICAL_NOT = 21;
3423 static const int OP_COUNT = 22;
3424
3425 /* Operators are searched from front, the two-character operators appear
3426 * before the single-character operators with the same first character.
3427 * @ is used to pad out single-character operators.
3428 */
3429 static const char* operatorChars;
3430 static const char operatorLevel[];
3431
Jack Palevich569f1352009-06-29 14:29:08 -07003432 /* Called when we detect an internal problem. Does nothing in production.
3433 *
3434 */
3435 void internalError() {
3436 * (char*) 0 = 0;
3437 }
3438
Jack Palevich86351982009-06-30 18:09:56 -07003439 void assert(bool isTrue) {
3440 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003441 internalError();
3442 }
Jack Palevich86351982009-06-30 18:09:56 -07003443 }
3444
Jack Palevich40600de2009-07-01 15:32:35 -07003445 bool isSymbol(tokenid_t t) {
3446 return t >= TOK_SYMBOL &&
3447 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3448 }
3449
3450 bool isSymbolOrKeyword(tokenid_t t) {
3451 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003452 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003453 }
3454
Jack Palevich86351982009-06-30 18:09:56 -07003455 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003456 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003457 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3458 if (pV && pV->tok != t) {
3459 internalError();
3460 }
3461 return pV;
3462 }
3463
3464 inline bool isDefined(tokenid_t t) {
3465 return t >= TOK_SYMBOL && VI(t) != 0;
3466 }
3467
Jack Palevich40600de2009-07-01 15:32:35 -07003468 const char* nameof(tokenid_t t) {
3469 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003470 return mTokenTable[t].pText;
3471 }
3472
Jack Palevich21a15a22009-05-11 14:49:29 -07003473 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003474 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003475 }
3476
3477 void inp() {
3478 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003479 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003480 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003481 dptr = 0;
3482 ch = dch;
3483 }
Jack Palevichdc456462009-07-16 16:50:56 -07003484 } else {
3485 if (mbBumpLine) {
3486 mLineNumber++;
3487 mbBumpLine = false;
3488 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003489 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003490 if (ch == '\n') {
3491 mbBumpLine = true;
3492 }
3493 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003494#if 0
3495 printf("ch='%c' 0x%x\n", ch, ch);
3496#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003497 }
3498
3499 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003500 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003501 }
3502
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003503 int decodeHex(int c) {
3504 if (isdigit(c)) {
3505 c -= '0';
3506 } else if (c <= 'F') {
3507 c = c - 'A' + 10;
3508 } else {
3509 c =c - 'a' + 10;
3510 }
3511 return c;
3512 }
3513
Jack Palevichb4758ff2009-06-12 12:49:14 -07003514 /* read a character constant, advances ch to after end of constant */
3515 int getq() {
3516 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003517 if (ch == '\\') {
3518 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003519 if (isoctal(ch)) {
3520 // 1 to 3 octal characters.
3521 val = 0;
3522 for(int i = 0; i < 3; i++) {
3523 if (isoctal(ch)) {
3524 val = (val << 3) + ch - '0';
3525 inp();
3526 }
3527 }
3528 return val;
3529 } else if (ch == 'x' || ch == 'X') {
3530 // N hex chars
3531 inp();
3532 if (! isxdigit(ch)) {
3533 error("'x' character escape requires at least one digit.");
3534 } else {
3535 val = 0;
3536 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003537 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003538 inp();
3539 }
3540 }
3541 } else {
3542 int val = ch;
3543 switch (ch) {
3544 case 'a':
3545 val = '\a';
3546 break;
3547 case 'b':
3548 val = '\b';
3549 break;
3550 case 'f':
3551 val = '\f';
3552 break;
3553 case 'n':
3554 val = '\n';
3555 break;
3556 case 'r':
3557 val = '\r';
3558 break;
3559 case 't':
3560 val = '\t';
3561 break;
3562 case 'v':
3563 val = '\v';
3564 break;
3565 case '\\':
3566 val = '\\';
3567 break;
3568 case '\'':
3569 val = '\'';
3570 break;
3571 case '"':
3572 val = '"';
3573 break;
3574 case '?':
3575 val = '?';
3576 break;
3577 default:
3578 error("Undefined character escape %c", ch);
3579 break;
3580 }
3581 inp();
3582 return val;
3583 }
3584 } else {
3585 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003586 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003587 return val;
3588 }
3589
3590 static bool isoctal(int ch) {
3591 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003592 }
3593
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003594 bool acceptCh(int c) {
3595 bool result = c == ch;
3596 if (result) {
3597 pdef(ch);
3598 inp();
3599 }
3600 return result;
3601 }
3602
3603 bool acceptDigitsCh() {
3604 bool result = false;
3605 while (isdigit(ch)) {
3606 result = true;
3607 pdef(ch);
3608 inp();
3609 }
3610 return result;
3611 }
3612
3613 void parseFloat() {
3614 tok = TOK_NUM_DOUBLE;
3615 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003616 if(mTokenString.len() == 0) {
3617 mTokenString.append('0');
3618 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003619 acceptCh('.');
3620 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003621 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003622 acceptCh('-') || acceptCh('+');
3623 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003624 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003625 if (ch == 'f' || ch == 'F') {
3626 tok = TOK_NUM_FLOAT;
3627 inp();
3628 } else if (ch == 'l' || ch == 'L') {
3629 inp();
3630 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003631 }
3632 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003633 char* pEnd = pText + strlen(pText);
3634 char* pEndPtr = 0;
3635 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003636 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003637 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003638 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003639 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003640 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003641 if (errno || pEndPtr != pEnd) {
3642 error("Can't parse constant: %s", pText);
3643 }
3644 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003645 }
3646
Jack Palevich21a15a22009-05-11 14:49:29 -07003647 void next() {
3648 int l, a;
3649
Jack Palevich546b2242009-05-13 15:10:04 -07003650 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003651 if (ch == '#') {
3652 inp();
3653 next();
3654 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003655 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003656 } else if (tok == TOK_PRAGMA) {
3657 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003658 } else if (tok == TOK_LINE) {
3659 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003660 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003661 error("Unsupported preprocessor directive \"%s\"",
3662 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003663 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003664 }
3665 inp();
3666 }
3667 tokl = 0;
3668 tok = ch;
3669 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003670 if (isdigit(ch) || ch == '.') {
3671 // Start of a numeric constant. Could be integer, float, or
3672 // double, won't know until we look further.
3673 mTokenString.clear();
3674 pdef(ch);
3675 inp();
3676 int base = 10;
3677 if (tok == '0') {
3678 if (ch == 'x' || ch == 'X') {
3679 base = 16;
3680 tok = TOK_NUM;
3681 tokc = 0;
3682 inp();
3683 while ( isxdigit(ch) ) {
3684 tokc = (tokc << 4) + decodeHex(ch);
3685 inp();
3686 }
3687 } else if (isoctal(ch)){
3688 base = 8;
3689 tok = TOK_NUM;
3690 tokc = 0;
3691 while ( isoctal(ch) ) {
3692 tokc = (tokc << 3) + (ch - '0');
3693 inp();
3694 }
3695 }
3696 } else if (isdigit(tok)){
3697 acceptDigitsCh();
3698 }
3699 if (base == 10) {
3700 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3701 parseFloat();
3702 } else {
3703 // It's an integer constant
3704 char* pText = mTokenString.getUnwrapped();
3705 char* pEnd = pText + strlen(pText);
3706 char* pEndPtr = 0;
3707 errno = 0;
3708 tokc = strtol(pText, &pEndPtr, base);
3709 if (errno || pEndPtr != pEnd) {
3710 error("Can't parse constant: %s %d %d", pText, base, errno);
3711 }
3712 tok = TOK_NUM;
3713 }
3714 }
3715 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003716 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003717 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003718 pdef(ch);
3719 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003720 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003721 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3722 // Is this a macro?
3723 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3724 if (pMacroDefinition) {
3725 // Yes, it is a macro
3726 dptr = pMacroDefinition;
3727 dch = ch;
3728 inp();
3729 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003730 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003731 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003732 inp();
3733 if (tok == '\'') {
3734 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003735 tokc = getq();
3736 if (ch != '\'') {
3737 error("Expected a ' character, got %c", ch);
3738 } else {
3739 inp();
3740 }
Jack Palevich546b2242009-05-13 15:10:04 -07003741 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003742 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003743 while (ch && ch != EOF) {
3744 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003745 inp();
3746 inp();
3747 if (ch == '/')
3748 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003749 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003750 if (ch == EOF) {
3751 error("End of file inside comment.");
3752 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003753 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003754 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003755 } else if ((tok == '/') & (ch == '/')) {
3756 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003757 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003758 inp();
3759 }
3760 inp();
3761 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003762 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003763 const char* t = operatorChars;
3764 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003765 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003766 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003767 tokl = operatorLevel[opIndex];
3768 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003769 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003770#if 0
3771 printf("%c%c -> tokl=%d tokc=0x%x\n",
3772 l, a, tokl, tokc);
3773#endif
3774 if (a == ch) {
3775 inp();
3776 tok = TOK_DUMMY; /* dummy token for double tokens */
3777 }
Jack Palevich0c017742009-07-31 12:00:39 -07003778 /* check for op=, valid for * / % + - << >> & ^ | */
3779 if (ch == '=' &&
3780 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07003781 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07003782 inp();
3783 tok = TOK_OP_ASSIGNMENT;
3784 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003785 break;
3786 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003787 opIndex++;
3788 }
3789 if (l == 0) {
3790 tokl = 0;
3791 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003792 }
3793 }
3794 }
3795#if 0
3796 {
Jack Palevich569f1352009-06-29 14:29:08 -07003797 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003798 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003799 fprintf(stderr, "%s\n", buf.getUnwrapped());
3800 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003801#endif
3802 }
3803
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003804 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003805 next();
3806 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003807 String* pName = new String();
3808 while (isspace(ch)) {
3809 inp();
3810 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003811 if (ch == '(') {
3812 delete pName;
3813 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003814 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003815 }
3816 while (isspace(ch)) {
3817 inp();
3818 }
Jack Palevich569f1352009-06-29 14:29:08 -07003819 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003820 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003821 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003822 inp();
3823 }
Jack Palevich569f1352009-06-29 14:29:08 -07003824 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3825 memcpy(pDefn, value.getUnwrapped(), value.len());
3826 pDefn[value.len()] = 0;
3827 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003828 }
3829
Jack Palevicheedf9d22009-06-04 16:23:40 -07003830 void doPragma() {
3831 // # pragma name(val)
3832 int state = 0;
3833 while(ch != EOF && ch != '\n' && state < 10) {
3834 switch(state) {
3835 case 0:
3836 if (isspace(ch)) {
3837 inp();
3838 } else {
3839 state++;
3840 }
3841 break;
3842 case 1:
3843 if (isalnum(ch)) {
3844 mPragmas.append(ch);
3845 inp();
3846 } else if (ch == '(') {
3847 mPragmas.append(0);
3848 inp();
3849 state++;
3850 } else {
3851 state = 11;
3852 }
3853 break;
3854 case 2:
3855 if (isalnum(ch)) {
3856 mPragmas.append(ch);
3857 inp();
3858 } else if (ch == ')') {
3859 mPragmas.append(0);
3860 inp();
3861 state = 10;
3862 } else {
3863 state = 11;
3864 }
3865 break;
3866 }
3867 }
3868 if(state != 10) {
3869 error("Unexpected pragma syntax");
3870 }
3871 mPragmaStringCount += 2;
3872 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003873
Jack Palevichdc456462009-07-16 16:50:56 -07003874 void doLine() {
3875 // # line number { "filename "}
3876 next();
3877 if (tok != TOK_NUM) {
3878 error("Expected a line-number");
3879 } else {
3880 mLineNumber = tokc-1; // The end-of-line will increment it.
3881 }
3882 while(ch != EOF && ch != '\n') {
3883 inp();
3884 }
3885 }
3886
Jack Palevichac0e95e2009-05-29 13:53:44 -07003887 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003888 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003889 mErrorBuf.vprintf(fmt, ap);
3890 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 }
3892
Jack Palevich8b0624c2009-05-20 12:12:06 -07003893 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003894 if (tok != c) {
3895 error("'%c' expected", c);
3896 }
3897 next();
3898 }
3899
Jack Palevich86351982009-06-30 18:09:56 -07003900 bool accept(intptr_t c) {
3901 if (tok == c) {
3902 next();
3903 return true;
3904 }
3905 return false;
3906 }
3907
Jack Palevich40600de2009-07-01 15:32:35 -07003908 bool acceptStringLiteral() {
3909 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003910 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003911 // This while loop merges multiple adjacent string constants.
3912 while (tok == '"') {
3913 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003914 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003915 }
3916 if (ch != '"') {
3917 error("Unterminated string constant.");
3918 }
3919 inp();
3920 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003921 }
Jack Palevich40600de2009-07-01 15:32:35 -07003922 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003923 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003924 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003925 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003926
3927 return true;
3928 }
3929 return false;
3930 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003931
Jack Palevichb1544ca2009-07-16 15:09:20 -07003932 void linkGlobal(tokenid_t t, bool isFunction) {
3933 VariableInfo* pVI = VI(t);
3934 void* n = NULL;
3935 if (mpSymbolLookupFn) {
3936 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3937 }
3938 if (pVI->pType == NULL) {
3939 if (isFunction) {
3940 pVI->pType = mkpIntFn;
3941 } else {
3942 pVI->pType = mkpInt;
3943 }
3944 }
3945 pVI->pAddress = n;
3946 }
3947
Jack Palevich29daf572009-07-30 19:38:55 -07003948 void unaryOrAssignment() {
3949 unary();
3950 if (accept('=')) {
3951 checkLVal();
3952 pGen->pushR0();
3953 expr();
3954 pGen->forceR0RVal();
3955 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003956 } else if (tok == TOK_OP_ASSIGNMENT) {
3957 int t = tokc;
3958 next();
3959 checkLVal();
3960 pGen->pushR0();
3961 pGen->forceR0RVal();
3962 pGen->pushR0();
3963 expr();
3964 pGen->forceR0RVal();
3965 pGen->genOp(t);
3966 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003967 }
3968 }
3969
Jack Palevich40600de2009-07-01 15:32:35 -07003970 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003971 */
Jack Palevich29daf572009-07-30 19:38:55 -07003972 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003973 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07003974 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07003975 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003976 if (acceptStringLiteral()) {
3977 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003978 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003979 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003980 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003981 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003982 t = tok;
3983 next();
3984 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003985 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003986 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003987 // Align to 4-byte boundary
3988 glo = (char*) (((intptr_t) glo + 3) & -4);
3989 * (float*) glo = (float) ad;
3990 pGen->loadFloat((int) glo, mkpFloat);
3991 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003992 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003993 // Align to 8-byte boundary
3994 glo = (char*) (((intptr_t) glo + 7) & -8);
3995 * (double*) glo = ad;
3996 pGen->loadFloat((int) glo, mkpDouble);
3997 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003998 } else if (c == 2) {
3999 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004000 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004001 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004002 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004003 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004004 else if (t == '+') {
4005 // ignore unary plus.
4006 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004007 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004008 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004009 } else if (c == 11) {
4010 // pre increment / pre decrement
4011 unary();
4012 doIncDec(a == OP_INCREMENT, 0);
4013 }
4014 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004015 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004016 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004017 if (pCast) {
4018 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004019 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004020 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004021 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004022 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004023 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004024 skip(')');
4025 }
4026 } else if (t == '*') {
4027 /* This is a pointer dereference.
4028 */
Jack Palevich29daf572009-07-30 19:38:55 -07004029 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004030 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004031 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004032 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004033 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4034 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004036 } else if (t == EOF ) {
4037 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004038 } else if (t == ';') {
4039 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004040 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004041 // Don't have to do anything special here, the error
4042 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004043 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004044 if (!isDefined(t)) {
4045 mGlobals.add(t);
4046 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004047 }
Jack Palevich8df46192009-07-07 14:48:51 -07004048 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004049 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004050 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004051 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004052 linkGlobal(t, tok == '(');
4053 n = (intptr_t) pVI->pAddress;
4054 if (!n && tok != '(') {
4055 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004056 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004057 }
Jack Palevich29daf572009-07-30 19:38:55 -07004058 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004059 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004060 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004061 linkGlobal(t, false);
4062 n = (intptr_t) pVI->pAddress;
4063 if (!n) {
4064 error("Undeclared variable %s\n", nameof(t));
4065 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004066 }
Jack Palevich5b659092009-07-31 14:55:07 -07004067 }
4068 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004069 Type* pVal;
4070 ExpressionType et;
4071 if (pVI->pType->tag == TY_ARRAY) {
4072 pVal = pVI->pType;
4073 et = ET_RVALUE;
4074 } else {
4075 pVal = createPtrType(pVI->pType);
4076 et = ET_LVALUE;
4077 }
Jack Palevich5b659092009-07-31 14:55:07 -07004078 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004079 int tag = pVal->pHead->tag;
4080 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004081 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004082 }
Jack Palevich5b659092009-07-31 14:55:07 -07004083 pGen->leaR0(n, pVal, et);
4084 } else {
4085 pVI->pForward = (void*) pGen->leaForward(
4086 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004087 }
4088 }
4089 }
4090
Jack Palevich5b659092009-07-31 14:55:07 -07004091 /* Now handle postfix operators */
4092 for(;;) {
4093 if (tokl == 11) {
4094 // post inc / post dec
4095 doIncDec(tokc == OP_INCREMENT, true);
4096 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004097 } else if (accept('[')) {
4098 // Array reference
4099 pGen->forceR0RVal();
4100 pGen->pushR0();
4101 commaExpr();
4102 pGen->forceR0RVal();
4103 pGen->genOp(OP_PLUS);
4104 doPointer();
4105 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004106 } else if (accept('(')) {
4107 /* function call */
4108 Type* pDecl = NULL;
4109 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004110 Type* pFn = pGen->getR0Type();
4111 assert(pFn->tag == TY_POINTER);
4112 assert(pFn->pHead->tag == TY_FUNC);
4113 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004114 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004115 Type* pArgList = pDecl->pTail;
4116 bool varArgs = pArgList == NULL;
4117 /* push args and invert order */
4118 a = pGen->beginFunctionCallArguments();
4119 int l = 0;
4120 int argCount = 0;
4121 while (tok != ')' && tok != EOF) {
4122 if (! varArgs && !pArgList) {
4123 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004124 }
Jack Palevich5b659092009-07-31 14:55:07 -07004125 expr();
4126 pGen->forceR0RVal();
4127 Type* pTargetType;
4128 if (pArgList) {
4129 pTargetType = pArgList->pHead;
4130 pArgList = pArgList->pTail;
4131 } else {
4132 // This is a ... function, just pass arguments in their
4133 // natural type.
4134 pTargetType = pGen->getR0Type();
4135 if (pTargetType->tag == TY_FLOAT) {
4136 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004137 } else if (pTargetType->tag == TY_ARRAY) {
4138 // Pass arrays by pointer.
4139 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004140 }
4141 }
4142 if (pTargetType->tag == TY_VOID) {
4143 error("Can't pass void value for argument %d",
4144 argCount + 1);
4145 } else {
4146 l += pGen->storeR0ToArg(l, pTargetType);
4147 }
4148 if (accept(',')) {
4149 // fine
4150 } else if ( tok != ')') {
4151 error("Expected ',' or ')'");
4152 }
4153 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004154 }
Jack Palevich5b659092009-07-31 14:55:07 -07004155 if (! varArgs && pArgList) {
4156 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004157 }
Jack Palevich5b659092009-07-31 14:55:07 -07004158 pGen->endFunctionCallArguments(pDecl, a, l);
4159 skip(')');
4160 pGen->callIndirect(l, pDecl);
4161 pGen->adjustStackAfterCall(pDecl, l, true);
4162 } else {
4163 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004164 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004165 }
4166 }
4167
Jack Palevichaaac9282009-07-31 14:34:34 -07004168 void doIncDec(int isInc, int isPost) {
4169 // R0 already has the lval
4170 checkLVal();
4171 int lit = isInc ? 1 : -1;
4172 pGen->pushR0();
4173 pGen->loadR0FromR0();
4174 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004175 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4176 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004177 error("++/-- illegal for this type. %d", tag);
4178 }
4179 if (isPost) {
4180 pGen->over();
4181 pGen->pushR0();
4182 pGen->li(lit);
4183 pGen->genOp(OP_PLUS);
4184 pGen->storeR0ToTOS();
4185 pGen->popR0();
4186 } else {
4187 pGen->pushR0();
4188 pGen->li(lit);
4189 pGen->genOp(OP_PLUS);
4190 pGen->over();
4191 pGen->storeR0ToTOS();
4192 pGen->popR0();
4193 }
4194 }
4195
Jack Palevich47cbea92009-07-31 15:25:53 -07004196 void doPointer() {
4197 pGen->forceR0RVal();
4198 Type* pR0Type = pGen->getR0Type();
4199 if (pR0Type->tag != TY_POINTER) {
4200 error("Expected a pointer type.");
4201 } else {
4202 if (pR0Type->pHead->tag != TY_FUNC) {
4203 pGen->setR0ExpressionType(ET_LVALUE);
4204 }
4205 }
4206 }
4207
Jack Palevich40600de2009-07-01 15:32:35 -07004208 /* Recursive descent parser for binary operations.
4209 */
4210 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004211 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004212 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004213 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004214 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004215 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004216 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004217 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004218 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004219 t = tokc;
4220 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004221 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004222 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004223 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004224 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004225 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004226 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004227 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004228 // Check for syntax error.
4229 if (pGen->getR0Type() == NULL) {
4230 // We failed to parse a right-hand argument.
4231 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004232 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004233 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004234 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004235 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004236 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004237 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004238 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004239 }
4240 }
4241 }
4242 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004243 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004244 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004245 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004246 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004247 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004248 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004249 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004250 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004251 }
4252 }
4253 }
4254
Jack Palevich43aaee32009-07-31 14:01:37 -07004255 void commaExpr() {
4256 for(;;) {
4257 expr();
4258 if (!accept(',')) {
4259 break;
4260 }
4261 }
4262 }
4263
Jack Palevich21a15a22009-05-11 14:49:29 -07004264 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004265 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004266 }
4267
4268 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004269 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004270 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004271 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004272 }
4273
Jack Palevicha6baa232009-06-12 11:25:59 -07004274 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004275 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004276
Jack Palevich95727a02009-07-06 12:07:15 -07004277 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004278 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004279 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004280 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004281 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004282 next();
4283 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004284 a = test_expr();
4285 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004286 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004287 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004288 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004289 n = pGen->gjmp(0); /* jmp */
4290 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004291 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004292 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004293 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004294 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004295 }
Jack Palevich546b2242009-05-13 15:10:04 -07004296 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004297 t = tok;
4298 next();
4299 skip('(');
4300 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004301 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004302 a = test_expr();
4303 } else {
4304 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004305 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004306 skip(';');
4307 n = codeBuf.getPC();
4308 a = 0;
4309 if (tok != ';')
4310 a = test_expr();
4311 skip(';');
4312 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004313 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004314 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004315 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004316 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004317 n = t + 4;
4318 }
4319 }
4320 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004321 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004322 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004323 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004324 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004325 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004326 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004327 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004328 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004329 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004330 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004331 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004332 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004333 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004334 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004335 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004336 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004337 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004338 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004339 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004340 if (pReturnType->tag == TY_VOID) {
4341 error("Must not return a value from a void function");
4342 } else {
4343 pGen->convertR0(pReturnType);
4344 }
4345 } else {
4346 if (pReturnType->tag != TY_VOID) {
4347 error("Must specify a value here");
4348 }
Jack Palevich8df46192009-07-07 14:48:51 -07004349 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004350 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004351 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004352 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004353 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004354 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004355 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004356 }
4357 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004358
Jack Palevicha8f427f2009-07-13 18:40:08 -07004359 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004360 if (a == b) {
4361 return true;
4362 }
4363 if (a == NULL || b == NULL) {
4364 return false;
4365 }
4366 TypeTag at = a->tag;
4367 if (at != b->tag) {
4368 return false;
4369 }
4370 if (at == TY_POINTER) {
4371 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004372 } else if (at == TY_ARRAY) {
4373 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004374 } else if (at == TY_FUNC || at == TY_PARAM) {
4375 return typeEqual(a->pHead, b->pHead)
4376 && typeEqual(a->pTail, b->pTail);
4377 }
4378 return true;
4379 }
4380
Jack Palevich2ff5c222009-07-23 15:11:22 -07004381 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004382 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004383 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004384 memset(pType, 0, sizeof(*pType));
4385 pType->tag = tag;
4386 pType->pHead = pHead;
4387 pType->pTail = pTail;
4388 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004389 }
4390
Jack Palevich2ff5c222009-07-23 15:11:22 -07004391 Type* createPtrType(Type* pType) {
4392 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004393 }
4394
4395 /**
4396 * Try to print a type in declaration order
4397 */
Jack Palevich86351982009-06-30 18:09:56 -07004398 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004399 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004400 if (pType == NULL) {
4401 buffer.appendCStr("null");
4402 return;
4403 }
Jack Palevich3f226492009-07-02 14:46:19 -07004404 decodeTypeImp(buffer, pType);
4405 }
4406
4407 void decodeTypeImp(String& buffer, Type* pType) {
4408 decodeTypeImpPrefix(buffer, pType);
4409
Jack Palevich86351982009-06-30 18:09:56 -07004410 String temp;
4411 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004412 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004413 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004414 }
4415
4416 decodeTypeImpPostfix(buffer, pType);
4417 }
4418
4419 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4420 TypeTag tag = pType->tag;
4421
Jack Palevich37c54bd2009-07-14 18:35:36 -07004422 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004423 switch (tag) {
4424 case TY_INT:
4425 buffer.appendCStr("int");
4426 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004427 case TY_SHORT:
4428 buffer.appendCStr("short");
4429 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004430 case TY_CHAR:
4431 buffer.appendCStr("char");
4432 break;
4433 case TY_VOID:
4434 buffer.appendCStr("void");
4435 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004436 case TY_FLOAT:
4437 buffer.appendCStr("float");
4438 break;
4439 case TY_DOUBLE:
4440 buffer.appendCStr("double");
4441 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004442 default:
4443 break;
4444 }
Jack Palevich86351982009-06-30 18:09:56 -07004445 buffer.append(' ');
4446 }
Jack Palevich3f226492009-07-02 14:46:19 -07004447
4448 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004449 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004450 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004451 case TY_SHORT:
4452 break;
Jack Palevich86351982009-06-30 18:09:56 -07004453 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004454 break;
4455 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004456 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004457 case TY_FLOAT:
4458 break;
4459 case TY_DOUBLE:
4460 break;
Jack Palevich86351982009-06-30 18:09:56 -07004461 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004462 decodeTypeImpPrefix(buffer, pType->pHead);
4463 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4464 buffer.append('(');
4465 }
4466 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004467 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004468 case TY_ARRAY:
4469 decodeTypeImpPrefix(buffer, pType->pHead);
4470 break;
Jack Palevich86351982009-06-30 18:09:56 -07004471 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004472 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004473 break;
4474 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004475 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004476 break;
4477 default:
4478 String temp;
4479 temp.printf("Unknown tag %d", pType->tag);
4480 buffer.append(temp);
4481 break;
4482 }
Jack Palevich3f226492009-07-02 14:46:19 -07004483 }
4484
4485 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4486 TypeTag tag = pType->tag;
4487
4488 switch(tag) {
4489 case TY_POINTER:
4490 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4491 buffer.append(')');
4492 }
4493 decodeTypeImpPostfix(buffer, pType->pHead);
4494 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004495 case TY_ARRAY:
4496 {
4497 String temp;
4498 temp.printf("[%d]", pType->length);
4499 buffer.append(temp);
4500 }
4501 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004502 case TY_FUNC:
4503 buffer.append('(');
4504 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4505 decodeTypeImp(buffer, pArg);
4506 if (pArg->pTail) {
4507 buffer.appendCStr(", ");
4508 }
4509 }
4510 buffer.append(')');
4511 break;
4512 default:
4513 break;
Jack Palevich86351982009-06-30 18:09:56 -07004514 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004515 }
4516
Jack Palevich86351982009-06-30 18:09:56 -07004517 void printType(Type* pType) {
4518 String buffer;
4519 decodeType(buffer, pType);
4520 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004521 }
4522
Jack Palevich2ff5c222009-07-23 15:11:22 -07004523 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004524 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004525 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004526 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004527 } else if (tok == TOK_SHORT) {
4528 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004529 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004530 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004531 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004532 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004533 } else if (tok == TOK_FLOAT) {
4534 pType = mkpFloat;
4535 } else if (tok == TOK_DOUBLE) {
4536 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004537 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004538 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004539 }
4540 next();
Jack Palevich86351982009-06-30 18:09:56 -07004541 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004542 }
4543
Jack Palevich2ff5c222009-07-23 15:11:22 -07004544 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004545 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004546 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004547 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004548 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004549 if (declName) {
4550 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004551 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004552 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004553
Jack Palevich86351982009-06-30 18:09:56 -07004554 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004555 pType->length = pOldType->length;
4556 } else if (nameRequired) {
4557 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004558 }
Jack Palevich3f226492009-07-02 14:46:19 -07004559 // fprintf(stderr, "Parsed a declaration: ");
4560 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004561 if (reportFailure) {
4562 return NULL;
4563 }
Jack Palevich86351982009-06-30 18:09:56 -07004564 return pType;
4565 }
4566
Jack Palevich2ff5c222009-07-23 15:11:22 -07004567 Type* expectDeclaration(Type* pBaseType) {
4568 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004569 if (! pType) {
4570 error("Expected a declaration");
4571 }
4572 return pType;
4573 }
4574
Jack Palevich3f226492009-07-02 14:46:19 -07004575 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004576 Type* acceptCastTypeDeclaration() {
4577 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004578 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004579 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004580 }
Jack Palevich86351982009-06-30 18:09:56 -07004581 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004582 }
4583
Jack Palevich2ff5c222009-07-23 15:11:22 -07004584 Type* expectCastTypeDeclaration() {
4585 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004586 if (! pType) {
4587 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004588 }
Jack Palevich3f226492009-07-02 14:46:19 -07004589 return pType;
4590 }
4591
4592 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004593 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004594 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004595 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004596 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004597 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004598 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004599 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004600 return pType;
4601 }
4602
4603 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004604 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004605 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004606 // direct-dcl :
4607 // name
4608 // (dcl)
4609 // direct-dcl()
4610 // direct-dcl[]
4611 Type* pNewHead = NULL;
4612 if (accept('(')) {
4613 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004614 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004615 skip(')');
4616 } else if ((declName = acceptSymbol()) != 0) {
4617 if (nameAllowed == false && declName) {
4618 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004619 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004620 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004621 } else if (nameRequired && ! declName) {
4622 String temp;
4623 decodeToken(temp, tok, true);
4624 error("Expected name. Got %s", temp.getUnwrapped());
4625 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004626 }
Jack Palevichb6154502009-08-04 14:56:09 -07004627 for(;;) {
4628 if (accept('(')) {
4629 // Function declaration
4630 Type* pTail = acceptArgs(nameAllowed);
4631 pType = createType(TY_FUNC, pType, pTail);
4632 skip(')');
4633 } if (accept('[')) {
4634 if (tok != ']') {
4635 if (tok != TOK_NUM || tokc <= 0) {
4636 error("Expected positive integer constant");
4637 } else {
4638 Type* pDecayType = createPtrType(pType);
4639 pType = createType(TY_ARRAY, pType, pDecayType);
4640 pType->length = tokc;
4641 }
4642 next();
4643 }
4644 skip(']');
4645 } else {
4646 break;
4647 }
Jack Palevich86351982009-06-30 18:09:56 -07004648 }
Jack Palevich3f226492009-07-02 14:46:19 -07004649
4650 if (pNewHead) {
4651 Type* pA = pNewHead;
4652 while (pA->pHead) {
4653 pA = pA->pHead;
4654 }
4655 pA->pHead = pType;
4656 pType = pNewHead;
4657 }
Jack Palevich86351982009-06-30 18:09:56 -07004658 return pType;
4659 }
4660
Jack Palevich2ff5c222009-07-23 15:11:22 -07004661 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004662 Type* pHead = NULL;
4663 Type* pTail = NULL;
4664 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004665 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004666 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004667 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004668 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004669 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004670 if (!pHead) {
4671 pHead = pParam;
4672 pTail = pParam;
4673 } else {
4674 pTail->pTail = pParam;
4675 pTail = pParam;
4676 }
4677 }
4678 }
4679 if (! accept(',')) {
4680 break;
4681 }
4682 }
4683 return pHead;
4684 }
4685
Jack Palevich2ff5c222009-07-23 15:11:22 -07004686 Type* expectPrimitiveType() {
4687 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004688 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004689 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004690 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004691 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004692 }
Jack Palevich86351982009-06-30 18:09:56 -07004693 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004694 }
4695
Jack Palevichb5e33312009-07-30 19:06:34 -07004696 void checkLVal() {
4697 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4698 error("Expected an lval");
4699 }
4700 }
4701
Jack Palevich86351982009-06-30 18:09:56 -07004702 void addGlobalSymbol(Type* pDecl) {
4703 tokenid_t t = pDecl->id;
4704 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004705 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004706 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004707 }
Jack Palevich86351982009-06-30 18:09:56 -07004708 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004709 }
4710
Jack Palevich86351982009-06-30 18:09:56 -07004711 void reportDuplicate(tokenid_t t) {
4712 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004713 }
4714
Jack Palevich86351982009-06-30 18:09:56 -07004715 void addLocalSymbol(Type* pDecl) {
4716 tokenid_t t = pDecl->id;
4717 if (mLocals.isDefinedAtCurrentLevel(t)) {
4718 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004719 }
Jack Palevich86351982009-06-30 18:09:56 -07004720 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004721 }
4722
Jack Palevich95727a02009-07-06 12:07:15 -07004723 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004724 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004725
Jack Palevich95727a02009-07-06 12:07:15 -07004726 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004727 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004728 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004729 if (!pDecl) {
4730 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004731 }
Jack Palevich86351982009-06-30 18:09:56 -07004732 int variableAddress = 0;
4733 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004734 size_t alignment = pGen->stackAlignmentOf(pDecl);
4735 size_t alignmentMask = ~ (alignment - 1);
4736 size_t sizeOf = pGen->sizeOf(pDecl);
4737 loc = (loc + alignment - 1) & alignmentMask;
4738 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4739 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004740 variableAddress = -loc;
4741 VI(pDecl->id)->pAddress = (void*) variableAddress;
4742 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004743 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004744 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004745 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004746 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004747 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004748 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004749 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004750 if (tok == ',')
4751 next();
4752 }
4753 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004754 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004755 }
4756 }
4757
Jack Palevichf1728be2009-06-12 13:53:51 -07004758 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004759 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004760 }
4761
Jack Palevich37c54bd2009-07-14 18:35:36 -07004762 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004763 if (token == EOF ) {
4764 buffer.printf("EOF");
4765 } else if (token == TOK_NUM) {
4766 buffer.printf("numeric constant");
4767 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004768 if (token < 32) {
4769 buffer.printf("'\\x%02x'", token);
4770 } else {
4771 buffer.printf("'%c'", token);
4772 }
Jack Palevich569f1352009-06-29 14:29:08 -07004773 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004774 if (quote) {
4775 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4776 buffer.printf("keyword \"%s\"", nameof(token));
4777 } else {
4778 buffer.printf("symbol \"%s\"", nameof(token));
4779 }
4780 } else {
4781 buffer.printf("%s", nameof(token));
4782 }
Jack Palevich569f1352009-06-29 14:29:08 -07004783 }
4784 }
4785
Jack Palevich40600de2009-07-01 15:32:35 -07004786 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004787 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004788 if (!result) {
4789 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004790 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004791 error("Expected symbol. Got %s", temp.getUnwrapped());
4792 }
4793 return result;
4794 }
4795
Jack Palevich86351982009-06-30 18:09:56 -07004796 tokenid_t acceptSymbol() {
4797 tokenid_t result = 0;
4798 if (tok >= TOK_SYMBOL) {
4799 result = tok;
4800 next();
Jack Palevich86351982009-06-30 18:09:56 -07004801 }
4802 return result;
4803 }
4804
Jack Palevichb7c81e92009-06-04 19:56:13 -07004805 void globalDeclarations() {
4806 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004807 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004808 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004809 break;
4810 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004811 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004812 if (!pDecl) {
4813 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004814 }
Jack Palevich86351982009-06-30 18:09:56 -07004815 if (! isDefined(pDecl->id)) {
4816 addGlobalSymbol(pDecl);
4817 }
4818 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004819 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004820 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004821 }
Jack Palevich86351982009-06-30 18:09:56 -07004822 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004823 // it's a variable declaration
4824 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004825 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004826 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004827 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004828 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004829 }
Jack Palevich86351982009-06-30 18:09:56 -07004830 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004831 if (tok == TOK_NUM) {
4832 if (name) {
4833 * (int*) name->pAddress = tokc;
4834 }
4835 next();
4836 } else {
4837 error("Expected an integer constant");
4838 }
4839 }
Jack Palevich86351982009-06-30 18:09:56 -07004840 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004841 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004842 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004843 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004844 if (!pDecl) {
4845 break;
4846 }
4847 if (! isDefined(pDecl->id)) {
4848 addGlobalSymbol(pDecl);
4849 }
4850 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004851 }
4852 skip(';');
4853 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004854 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004855 if (accept(';')) {
4856 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004857 } else if (tok != '{') {
4858 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004859 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004860 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004861 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004862 /* patch forward references */
4863 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004864 /* put function address */
4865 name->pAddress = (void*) codeBuf.getPC();
4866 }
4867 // Calculate stack offsets for parameters
4868 mLocals.pushLevel();
4869 intptr_t a = 8;
4870 int argCount = 0;
4871 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4872 Type* pArg = pP->pHead;
4873 addLocalSymbol(pArg);
4874 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004875 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004876 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004877 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004878 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004879 argCount++;
4880 }
4881 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004882 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004883 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004884 block(0, true);
4885 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004886 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004887 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004888 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004889 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004890 }
4891 }
4892 }
4893
Jack Palevich9cbd2262009-07-08 16:48:41 -07004894 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4895 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4896 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004897 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004898 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004899 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004900 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004901 char* result = (char*) base;
4902 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004903 return result;
4904 }
4905
Jack Palevich21a15a22009-05-11 14:49:29 -07004906 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004907 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004908 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004909 pGlobalBase = 0;
4910 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004911 if (pGen) {
4912 delete pGen;
4913 pGen = 0;
4914 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004915 if (file) {
4916 delete file;
4917 file = 0;
4918 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004919 }
4920
Jack Palevich8c246a92009-07-14 21:14:10 -07004921 // One-time initialization, when class is constructed.
4922 void init() {
4923 mpSymbolLookupFn = 0;
4924 mpSymbolLookupContext = 0;
4925 }
4926
Jack Palevich21a15a22009-05-11 14:49:29 -07004927 void clear() {
4928 tok = 0;
4929 tokc = 0;
4930 tokl = 0;
4931 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004932 rsym = 0;
4933 loc = 0;
4934 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004935 dptr = 0;
4936 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004937 file = 0;
4938 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004939 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004940 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004941 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004942 mLineNumber = 1;
4943 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004944 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004945
Jack Palevich22305132009-05-13 10:58:45 -07004946 void setArchitecture(const char* architecture) {
4947 delete pGen;
4948 pGen = 0;
4949
4950 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004951#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004952 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004953 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004954 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004955#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004956#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004957 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004958 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004959 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004960#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004961 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004962 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004963 }
4964 }
4965
4966 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004967#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004968 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004969#elif defined(DEFAULT_X86_CODEGEN)
4970 pGen = new X86CodeGenerator();
4971#endif
4972 }
4973 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004974 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004975 } else {
4976 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004977 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004978 }
4979 }
4980
Jack Palevich77ae76e2009-05-10 19:59:24 -07004981public:
Jack Palevich22305132009-05-13 10:58:45 -07004982 struct args {
4983 args() {
4984 architecture = 0;
4985 }
4986 const char* architecture;
4987 };
4988
Jack Paleviche7b59062009-05-19 17:12:17 -07004989 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004990 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004991 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004992 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004993
Jack Paleviche7b59062009-05-19 17:12:17 -07004994 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004995 cleanup();
4996 }
4997
Jack Palevich8c246a92009-07-14 21:14:10 -07004998 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4999 mpSymbolLookupFn = pFn;
5000 mpSymbolLookupContext = pContext;
5001 }
5002
Jack Palevich1cdef202009-05-22 12:06:27 -07005003 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005004 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005005
Jack Palevich2ff5c222009-07-23 15:11:22 -07005006 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005007 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005008 cleanup();
5009 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005010 mTokenTable.setArena(&mGlobalArena);
5011 mGlobals.setArena(&mGlobalArena);
5012 mGlobals.setTokenTable(&mTokenTable);
5013 mLocals.setArena(&mLocalArena);
5014 mLocals.setTokenTable(&mTokenTable);
5015
5016 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005017 codeBuf.init(ALLOC_SIZE);
5018 setArchitecture(NULL);
5019 if (!pGen) {
5020 return -1;
5021 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005022#ifdef PROVIDE_TRACE_CODEGEN
5023 pGen = new TraceCodeGenerator(pGen);
5024#endif
5025 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005026 pGen->init(&codeBuf);
5027 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005028 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5029 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005030 inp();
5031 next();
5032 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005033 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005034 result = pGen->finishCompile();
5035 if (result == 0) {
5036 if (mErrorBuf.len()) {
5037 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005038 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005039 }
Jack Palevichce105a92009-07-16 14:30:33 -07005040 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005041 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005042 }
5043
Jack Palevich86351982009-06-30 18:09:56 -07005044 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005045 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005046 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005047 mkpChar = createType(TY_CHAR, NULL, NULL);
5048 mkpVoid = createType(TY_VOID, NULL, NULL);
5049 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5050 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5051 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5052 mkpIntPtr = createPtrType(mkpInt);
5053 mkpCharPtr = createPtrType(mkpChar);
5054 mkpFloatPtr = createPtrType(mkpFloat);
5055 mkpDoublePtr = createPtrType(mkpDouble);
5056 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005057 }
5058
Jack Palevicha6baa232009-06-12 11:25:59 -07005059 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005060 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005061 }
5062
Jack Palevich569f1352009-06-29 14:29:08 -07005063 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005064 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005065 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005066 }
5067
Jack Palevich569f1352009-06-29 14:29:08 -07005068 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005069 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005070 error("Undefined forward reference: %s",
5071 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005072 }
5073 return true;
5074 }
5075
Jack Palevich21a15a22009-05-11 14:49:29 -07005076 int dump(FILE* out) {
5077 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5078 return 0;
5079 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005080
Jack Palevicha6535612009-05-13 16:24:17 -07005081 int disassemble(FILE* out) {
5082 return pGen->disassemble(out);
5083 }
5084
Jack Palevich1cdef202009-05-22 12:06:27 -07005085 /* Look through the symbol table to find a symbol.
5086 * If found, return its value.
5087 */
5088 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005089 if (mCompileResult == 0) {
5090 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5091 VariableInfo* pVariableInfo = VI(tok);
5092 if (pVariableInfo) {
5093 return pVariableInfo->pAddress;
5094 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005095 }
5096 return NULL;
5097 }
5098
Jack Palevicheedf9d22009-06-04 16:23:40 -07005099 void getPragmas(ACCsizei* actualStringCount,
5100 ACCsizei maxStringCount, ACCchar** strings) {
5101 int stringCount = mPragmaStringCount;
5102 if (actualStringCount) {
5103 *actualStringCount = stringCount;
5104 }
5105 if (stringCount > maxStringCount) {
5106 stringCount = maxStringCount;
5107 }
5108 if (strings) {
5109 char* pPragmas = mPragmas.getUnwrapped();
5110 while (stringCount-- > 0) {
5111 *strings++ = pPragmas;
5112 pPragmas += strlen(pPragmas) + 1;
5113 }
5114 }
5115 }
5116
Jack Palevichac0e95e2009-05-29 13:53:44 -07005117 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005118 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005119 }
5120
Jack Palevich77ae76e2009-05-10 19:59:24 -07005121};
5122
Jack Paleviche7b59062009-05-19 17:12:17 -07005123const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005124 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5125
Jack Paleviche7b59062009-05-19 17:12:17 -07005126const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005127 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5128 5, 5, /* ==, != */
5129 9, 10, /* &&, || */
5130 6, 7, 8, /* & ^ | */
5131 2, 2 /* ~ ! */
5132 };
5133
Jack Palevich8b0624c2009-05-20 12:12:06 -07005134#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005135FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005136#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005137
Jack Palevich8b0624c2009-05-20 12:12:06 -07005138#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005139const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005140 0x1, // ++
5141 0xff, // --
5142 0xc1af0f, // *
5143 0xf9f79991, // /
5144 0xf9f79991, // % (With manual assist to swap results)
5145 0xc801, // +
5146 0xd8f7c829, // -
5147 0xe0d391, // <<
5148 0xf8d391, // >>
5149 0xe, // <=
5150 0xd, // >=
5151 0xc, // <
5152 0xf, // >
5153 0x4, // ==
5154 0x5, // !=
5155 0x0, // &&
5156 0x1, // ||
5157 0xc821, // &
5158 0xc831, // ^
5159 0xc809, // |
5160 0xd0f7, // ~
5161 0x4 // !
5162};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005163#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005164
Jack Palevich1cdef202009-05-22 12:06:27 -07005165struct ACCscript {
5166 ACCscript() {
5167 text = 0;
5168 textLength = 0;
5169 accError = ACC_NO_ERROR;
5170 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005171
Jack Palevich1cdef202009-05-22 12:06:27 -07005172 ~ACCscript() {
5173 delete text;
5174 }
Jack Palevich546b2242009-05-13 15:10:04 -07005175
Jack Palevich8c246a92009-07-14 21:14:10 -07005176 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5177 compiler.registerSymbolCallback(pFn, pContext);
5178 }
5179
Jack Palevich1cdef202009-05-22 12:06:27 -07005180 void setError(ACCenum error) {
5181 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5182 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005183 }
5184 }
5185
Jack Palevich1cdef202009-05-22 12:06:27 -07005186 ACCenum getError() {
5187 ACCenum result = accError;
5188 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005189 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005190 }
5191
Jack Palevich1cdef202009-05-22 12:06:27 -07005192 Compiler compiler;
5193 char* text;
5194 int textLength;
5195 ACCenum accError;
5196};
5197
5198
5199extern "C"
5200ACCscript* accCreateScript() {
5201 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005202}
Jack Palevich1cdef202009-05-22 12:06:27 -07005203
5204extern "C"
5205ACCenum accGetError( ACCscript* script ) {
5206 return script->getError();
5207}
5208
5209extern "C"
5210void accDeleteScript(ACCscript* script) {
5211 delete script;
5212}
5213
5214extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005215void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5216 ACCvoid* pContext) {
5217 script->registerSymbolCallback(pFn, pContext);
5218}
5219
5220extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005221void accScriptSource(ACCscript* script,
5222 ACCsizei count,
5223 const ACCchar ** string,
5224 const ACCint * length) {
5225 int totalLength = 0;
5226 for(int i = 0; i < count; i++) {
5227 int len = -1;
5228 const ACCchar* s = string[i];
5229 if (length) {
5230 len = length[i];
5231 }
5232 if (len < 0) {
5233 len = strlen(s);
5234 }
5235 totalLength += len;
5236 }
5237 delete script->text;
5238 char* text = new char[totalLength + 1];
5239 script->text = text;
5240 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005241 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005242 for(int i = 0; i < count; i++) {
5243 int len = -1;
5244 const ACCchar* s = string[i];
5245 if (length) {
5246 len = length[i];
5247 }
5248 if (len < 0) {
5249 len = strlen(s);
5250 }
Jack Palevich09555c72009-05-27 12:25:55 -07005251 memcpy(dest, s, len);
5252 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005253 }
5254 text[totalLength] = '\0';
5255}
5256
5257extern "C"
5258void accCompileScript(ACCscript* script) {
5259 int result = script->compiler.compile(script->text, script->textLength);
5260 if (result) {
5261 script->setError(ACC_INVALID_OPERATION);
5262 }
5263}
5264
5265extern "C"
5266void accGetScriptiv(ACCscript* script,
5267 ACCenum pname,
5268 ACCint * params) {
5269 switch (pname) {
5270 case ACC_INFO_LOG_LENGTH:
5271 *params = 0;
5272 break;
5273 }
5274}
5275
5276extern "C"
5277void accGetScriptInfoLog(ACCscript* script,
5278 ACCsizei maxLength,
5279 ACCsizei * length,
5280 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005281 char* message = script->compiler.getErrorMessage();
5282 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005283 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005284 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005285 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005286 if (infoLog && maxLength > 0) {
5287 int trimmedLength = maxLength < messageLength ?
5288 maxLength : messageLength;
5289 memcpy(infoLog, message, trimmedLength);
5290 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005291 }
5292}
5293
5294extern "C"
5295void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5296 ACCvoid ** address) {
5297 void* value = script->compiler.lookup(name);
5298 if (value) {
5299 *address = value;
5300 } else {
5301 script->setError(ACC_INVALID_VALUE);
5302 }
5303}
5304
Jack Palevicheedf9d22009-06-04 16:23:40 -07005305extern "C"
5306void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5307 ACCsizei maxStringCount, ACCchar** strings){
5308 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5309}
5310
-b master422972c2009-06-17 19:13:52 -07005311extern "C"
5312void accDisassemble(ACCscript* script) {
5313 script->compiler.disassemble(stderr);
5314}
5315
Jack Palevicheedf9d22009-06-04 16:23:40 -07005316
Jack Palevich1cdef202009-05-22 12:06:27 -07005317} // namespace acc
5318