blob: 483a1ac6256bc9f2af8e618bc78a72c0f76518f1 [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich7f5b1a22009-08-17 16:54:56 -070011#define LOG_TAG "acc"
12#include <cutils/log.h>
13
Jack Palevich77ae76e2009-05-10 19:59:24 -070014#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000015#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070016#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070017#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070018#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070019#include <stdlib.h>
20#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070021#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070022
Jack Palevich8dc662e2009-06-09 22:53:47 +000023#if defined(__i386__)
24#include <sys/mman.h>
25#endif
26
Jack Palevich546b2242009-05-13 15:10:04 -070027#if defined(__arm__)
28#include <unistd.h>
29#endif
30
Jack Paleviche7b59062009-05-19 17:12:17 -070031#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070039#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070040#endif
41
Jack Paleviche7b59062009-05-19 17:12:17 -070042#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070043#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070044#endif
Jack Palevicha6535612009-05-13 16:24:17 -070045
Jack Palevich1cdef202009-05-22 12:06:27 -070046#include <acc/acc.h>
47
Jack Palevich09555c72009-05-27 12:25:55 -070048#define LOG_API(...) do {} while(0)
49// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070050
-b master422972c2009-06-17 19:13:52 -070051#define LOG_STACK(...) do {} while(0)
52// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
53
Jack Palevich9f51a262009-07-29 16:22:26 -070054#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070055// #define PROVIDE_TRACE_CODEGEN
56
Jack Palevich7f5b1a22009-08-17 16:54:56 -070057#define assert(b) assertImpl(b, __LINE__)
58
Jack Palevichbbf8ab52009-05-11 11:54:30 -070059namespace acc {
60
Jack Palevich8df46192009-07-07 14:48:51 -070061// Subset of STL vector.
62template<class E> class Vector {
63 public:
64 Vector() {
65 mpBase = 0;
66 mUsed = 0;
67 mSize = 0;
68 }
69
70 ~Vector() {
71 if (mpBase) {
72 for(size_t i = 0; i < mUsed; i++) {
73 mpBase[mUsed].~E();
74 }
75 free(mpBase);
76 }
77 }
78
79 inline E& operator[](size_t i) {
80 return mpBase[i];
81 }
82
83 inline E& front() {
84 return mpBase[0];
85 }
86
87 inline E& back() {
88 return mpBase[mUsed - 1];
89 }
90
91 void pop_back() {
92 mUsed -= 1;
93 mpBase[mUsed].~E();
94 }
95
96 void push_back(const E& item) {
97 * ensure(1) = item;
98 }
99
100 size_t size() {
101 return mUsed;
102 }
103
104private:
105 E* ensure(int n) {
106 size_t newUsed = mUsed + n;
107 if (newUsed > mSize) {
108 size_t newSize = mSize * 2 + 10;
109 if (newSize < newUsed) {
110 newSize = newUsed;
111 }
112 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
113 mSize = newSize;
114 }
115 E* result = mpBase + mUsed;
116 mUsed = newUsed;
117 return result;
118 }
119
120 E* mpBase;
121 size_t mUsed;
122 size_t mSize;
123};
124
Jack Palevichac0e95e2009-05-29 13:53:44 -0700125class ErrorSink {
126public:
127 void error(const char *fmt, ...) {
128 va_list ap;
129 va_start(ap, fmt);
130 verror(fmt, ap);
131 va_end(ap);
132 }
133
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700134 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700135 virtual void verror(const char* fmt, va_list ap) = 0;
136};
137
138class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700139 typedef int tokenid_t;
140 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700141 TY_INT, // 0
142 TY_CHAR, // 1
143 TY_SHORT, // 2
144 TY_VOID, // 3
145 TY_FLOAT, // 4
146 TY_DOUBLE, // 5
Jack Palevichb6154502009-08-04 14:56:09 -0700147 TY_POINTER, // 6
148 TY_ARRAY, // 7
149 TY_STRUCT, // 8
150 TY_FUNC, // 9
151 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700152 };
153
154 struct Type {
155 TypeTag tag;
Jack Palevichb6154502009-08-04 14:56:09 -0700156 tokenid_t id; // For function arguments, local vars
157 int length; // length of array
Jack Palevich8df46192009-07-07 14:48:51 -0700158 Type* pHead;
159 Type* pTail;
160 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700161
Jack Palevichba929a42009-07-17 10:20:32 -0700162 enum ExpressionType {
163 ET_RVALUE,
164 ET_LVALUE
165 };
166
167 struct ExpressionValue {
168 ExpressionValue() {
169 et = ET_RVALUE;
170 pType = NULL;
171 }
172 ExpressionType et;
173 Type* pType;
174 };
175
Jack Palevich21a15a22009-05-11 14:49:29 -0700176 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700177 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700178 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700179 ErrorSink* mErrorSink;
180 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700181 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700182
Jack Palevich21a15a22009-05-11 14:49:29 -0700183 void release() {
184 if (pProgramBase != 0) {
185 free(pProgramBase);
186 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700187 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700188 }
189
Jack Palevich0a280a02009-06-11 10:53:51 -0700190 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700191 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700192 bool overflow = newSize > mSize;
193 if (overflow && !mOverflowed) {
194 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700195 if (mErrorSink) {
196 mErrorSink->error("Code too large: %d bytes", newSize);
197 }
198 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700199 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700200 }
201
Jack Palevich21a15a22009-05-11 14:49:29 -0700202 public:
203 CodeBuf() {
204 pProgramBase = 0;
205 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700206 mErrorSink = 0;
207 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700208 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700209 }
210
211 ~CodeBuf() {
212 release();
213 }
214
215 void init(int size) {
216 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700217 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700218 pProgramBase = (char*) calloc(1, size);
219 ind = pProgramBase;
220 }
221
Jack Palevichac0e95e2009-05-29 13:53:44 -0700222 void setErrorSink(ErrorSink* pErrorSink) {
223 mErrorSink = pErrorSink;
224 }
225
Jack Palevich546b2242009-05-13 15:10:04 -0700226 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700227 if(check(4)) {
228 return 0;
229 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700230 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700231 * (int*) ind = n;
232 ind += 4;
233 return result;
234 }
235
Jack Palevich21a15a22009-05-11 14:49:29 -0700236 /*
237 * Output a byte. Handles all values, 0..ff.
238 */
239 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700240 if(check(1)) {
241 return;
242 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700243 *ind++ = n;
244 }
245
Jack Palevich21a15a22009-05-11 14:49:29 -0700246 inline void* getBase() {
247 return (void*) pProgramBase;
248 }
249
Jack Palevich8b0624c2009-05-20 12:12:06 -0700250 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700251 return ind - pProgramBase;
252 }
253
Jack Palevich8b0624c2009-05-20 12:12:06 -0700254 intptr_t getPC() {
255 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700256 }
257 };
258
Jack Palevich1cdef202009-05-22 12:06:27 -0700259 /**
260 * A code generator creates an in-memory program, generating the code on
261 * the fly. There is one code generator implementation for each supported
262 * architecture.
263 *
264 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700265 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700266 * FP - a frame pointer for accessing function arguments and local
267 * variables.
268 * SP - a stack pointer for storing intermediate results while evaluating
269 * expressions. The stack pointer grows downwards.
270 *
271 * The function calling convention is that all arguments are placed on the
272 * stack such that the first argument has the lowest address.
273 * After the call, the result is in R0. The caller is responsible for
274 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700275 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700276 * FP and SP registers are saved.
277 */
278
Jack Palevich21a15a22009-05-11 14:49:29 -0700279 class CodeGenerator {
280 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700281 CodeGenerator() {
282 mErrorSink = 0;
283 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700284 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700285 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700286 virtual ~CodeGenerator() {}
287
Jack Palevich22305132009-05-13 10:58:45 -0700288 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700289 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700290 pCodeBuf->setErrorSink(mErrorSink);
291 }
292
Jack Palevichb67b18f2009-06-11 21:12:23 -0700293 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700294 mErrorSink = pErrorSink;
295 if (pCodeBuf) {
296 pCodeBuf->setErrorSink(mErrorSink);
297 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700298 }
299
Jack Palevich58c30ee2009-07-17 16:35:23 -0700300 /* Give the code generator some utility types so it can
301 * use its own types as needed for the results of some
302 * operations like gcmp.
303 */
304
Jack Palevicha8f427f2009-07-13 18:40:08 -0700305 void setTypes(Type* pInt) {
306 mkpInt = pInt;
307 }
308
Jack Palevich1cdef202009-05-22 12:06:27 -0700309 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700310 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700311 * Save the old value of the FP.
312 * Set the new value of the FP.
313 * Convert from the native platform calling convention to
314 * our stack-based calling convention. This may require
315 * pushing arguments from registers to the stack.
316 * Allocate "N" bytes of stack space. N isn't known yet, so
317 * just emit the instructions for adjusting the stack, and return
318 * the address to patch up. The patching will be done in
319 * functionExit().
320 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700321 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700322 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700323
Jack Palevich1cdef202009-05-22 12:06:27 -0700324 /* Emit a function epilog.
325 * Restore the old SP and FP register values.
326 * Return to the calling function.
327 * argCount - the number of arguments to the function.
328 * localVariableAddress - returned from functionEntry()
329 * localVariableSize - the size in bytes of the local variables.
330 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700331 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700332 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700333
Jack Palevich1cdef202009-05-22 12:06:27 -0700334 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700335 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700336
Jack Palevich1a539db2009-07-08 13:04:41 -0700337 /* Load floating point value from global address. */
338 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700339
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 /* Jump to a target, and return the address of the word that
341 * holds the target data, in case it needs to be fixed up later.
342 */
Jack Palevich22305132009-05-13 10:58:45 -0700343 virtual int gjmp(int t) = 0;
344
Jack Palevich1cdef202009-05-22 12:06:27 -0700345 /* Test R0 and jump to a target if the test succeeds.
346 * l = 0: je, l == 1: jne
347 * Return the address of the word that holds the targed data, in
348 * case it needs to be fixed up later.
349 */
Jack Palevich22305132009-05-13 10:58:45 -0700350 virtual int gtst(bool l, int t) = 0;
351
Jack Palevich9eed7a22009-07-06 17:24:34 -0700352 /* Compare TOS against R0, and store the boolean result in R0.
353 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700354 * op specifies the comparison.
355 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700356 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700357
Jack Palevich9eed7a22009-07-06 17:24:34 -0700358 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700359 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700360 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700361 */
Jack Palevich546b2242009-05-13 15:10:04 -0700362 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700363
Jack Palevich9eed7a22009-07-06 17:24:34 -0700364 /* Compare 0 against R0, and store the boolean result in R0.
365 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700366 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700367 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700368
369 /* Perform the arithmetic op specified by op. 0 is the
370 * left argument, R0 is the right argument.
371 */
372 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700373
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700374 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700375 */
376 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700377
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700378 /* Turn R0, TOS into R0 TOS R0 */
379
380 virtual void over() = 0;
381
382 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700383 */
384 virtual void popR0() = 0;
385
Jack Palevich9eed7a22009-07-06 17:24:34 -0700386 /* Store R0 to the address stored in TOS.
387 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700388 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700389 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700390
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700392 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700393 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700394
Jack Palevich1cdef202009-05-22 12:06:27 -0700395 /* Load the absolute address of a variable to R0.
396 * If ea <= LOCAL, then this is a local variable, or an
397 * argument, addressed relative to FP.
398 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700399 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700400 * et is ET_RVALUE for things like string constants, ET_LVALUE for
401 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700402 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700403 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700404
Jack Palevich9f51a262009-07-29 16:22:26 -0700405 /* Load the pc-relative address of a forward-referenced variable to R0.
406 * Return the address of the 4-byte constant so that it can be filled
407 * in later.
408 */
409 virtual int leaForward(int ea, Type* pPointerType) = 0;
410
Jack Palevich8df46192009-07-07 14:48:51 -0700411 /**
412 * Convert R0 to the given type.
413 */
Jack Palevichb6154502009-08-04 14:56:09 -0700414
415 void convertR0(Type* pType) {
416 convertR0Imp(pType, false);
417 }
418
419 void castR0(Type* pType) {
420 convertR0Imp(pType, true);
421 }
422
423 virtual void convertR0Imp(Type* pType, bool isCast) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700424
Jack Palevich1cdef202009-05-22 12:06:27 -0700425 /* Emit code to adjust the stack for a function call. Return the
426 * label for the address of the instruction that adjusts the
427 * stack size. This will be passed as argument "a" to
428 * endFunctionCallArguments.
429 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700430 virtual int beginFunctionCallArguments() = 0;
431
Jack Palevich1cdef202009-05-22 12:06:27 -0700432 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700433 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700434 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700435 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700436
Jack Palevich1cdef202009-05-22 12:06:27 -0700437 /* Patch the function call preamble.
438 * a is the address returned from beginFunctionCallArguments
439 * l is the number of bytes the arguments took on the stack.
440 * Typically you would also emit code to convert the argument
441 * list into whatever the native function calling convention is.
442 * On ARM for example you would pop the first 5 arguments into
443 * R0..R4
444 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700445 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700446
Jack Palevich1cdef202009-05-22 12:06:27 -0700447 /* Emit a call to an unknown function. The argument "symbol" needs to
448 * be stored in the location where the address should go. It forms
449 * a chain. The address will be patched later.
450 * Return the address of the word that has to be patched.
451 */
Jack Palevich8df46192009-07-07 14:48:51 -0700452 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700453
Jack Palevich1cdef202009-05-22 12:06:27 -0700454 /* Call a function pointer. L is the number of bytes the arguments
455 * take on the stack. The address of the function is stored at
456 * location SP + l.
457 */
Jack Palevich8df46192009-07-07 14:48:51 -0700458 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700459
Jack Palevich1cdef202009-05-22 12:06:27 -0700460 /* Adjust SP after returning from a function call. l is the
461 * number of bytes of arguments stored on the stack. isIndirect
462 * is true if this was an indirect call. (In which case the
463 * address of the function is stored at location SP + l.)
464 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700465 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700466
Jack Palevich1cdef202009-05-22 12:06:27 -0700467 /* Print a disassembly of the assembled code to out. Return
468 * non-zero if there is an error.
469 */
Jack Palevicha6535612009-05-13 16:24:17 -0700470 virtual int disassemble(FILE* out) = 0;
471
Jack Palevich1cdef202009-05-22 12:06:27 -0700472 /* Generate a symbol at the current PC. t is the head of a
473 * linked list of addresses to patch.
474 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700475 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700476
Jack Palevich9f51a262009-07-29 16:22:26 -0700477 /* Resolve a forward reference function at the current PC.
478 * t is the head of a
479 * linked list of addresses to patch.
480 * (Like gsym, but using absolute address, not PC relative address.)
481 */
482 virtual void resolveForward(int t) = 0;
483
Jack Palevich1cdef202009-05-22 12:06:27 -0700484 /*
485 * Do any cleanup work required at the end of a compile.
486 * For example, an instruction cache might need to be
487 * invalidated.
488 * Return non-zero if there is an error.
489 */
490 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700491
Jack Palevicha6535612009-05-13 16:24:17 -0700492 /**
493 * Adjust relative branches by this amount.
494 */
495 virtual int jumpOffset() = 0;
496
Jack Palevich9eed7a22009-07-06 17:24:34 -0700497 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700498 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700499 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700500 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700501
502 /**
503 * Array element alignment (in bytes) for this type of data.
504 */
505 virtual size_t sizeOf(Type* type) = 0;
506
Jack Palevich9cbd2262009-07-08 16:48:41 -0700507 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700508 * Stack alignment of this type of data
509 */
510 virtual size_t stackAlignmentOf(Type* pType) = 0;
511
512 /**
513 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700514 */
515 virtual size_t stackSizeOf(Type* pType) = 0;
516
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700517 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700518 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700519 }
520
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700521 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700522 return mExpressionStack.back().et;
523 }
524
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700525 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700526 mExpressionStack.back().et = et;
527 }
528
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700529 virtual size_t getExpressionStackDepth() {
530 return mExpressionStack.size();
531 }
532
Jack Palevichb5e33312009-07-30 19:06:34 -0700533 virtual void forceR0RVal() {
534 if (getR0ExpressionType() == ET_LVALUE) {
535 loadR0FromR0();
536 }
537 }
538
Jack Palevich21a15a22009-05-11 14:49:29 -0700539 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700540 /*
541 * Output a byte. Handles all values, 0..ff.
542 */
543 void ob(int n) {
544 pCodeBuf->ob(n);
545 }
546
Jack Palevich8b0624c2009-05-20 12:12:06 -0700547 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700548 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700549 }
550
Jack Palevich8b0624c2009-05-20 12:12:06 -0700551 intptr_t getBase() {
552 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700553 }
554
Jack Palevich8b0624c2009-05-20 12:12:06 -0700555 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700556 return pCodeBuf->getPC();
557 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700558
559 intptr_t getSize() {
560 return pCodeBuf->getSize();
561 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700562
563 void error(const char* fmt,...) {
564 va_list ap;
565 va_start(ap, fmt);
566 mErrorSink->verror(fmt, ap);
567 va_end(ap);
568 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700569
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700570 void assertImpl(bool test, int line) {
Jack Palevich9eed7a22009-07-06 17:24:34 -0700571 if (!test) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -0700572 error("code generator assertion failed at line %s:%d.", __FILE__, line);
573 LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich1a539db2009-07-08 13:04:41 -0700574 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700575 }
576 }
Jack Palevich8df46192009-07-07 14:48:51 -0700577
578 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700579 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700580 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700581 mExpressionStack.back().et = ET_RVALUE;
582 }
583
584 void setR0Type(Type* pType, ExpressionType et) {
585 assert(pType != NULL);
586 mExpressionStack.back().pType = pType;
587 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700588 }
589
Jack Palevich8df46192009-07-07 14:48:51 -0700590 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700591 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700592 }
593
594 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700595 if (mExpressionStack.size()) {
596 mExpressionStack.push_back(mExpressionStack.back());
597 } else {
598 mExpressionStack.push_back(ExpressionValue());
599 }
600
Jack Palevich8df46192009-07-07 14:48:51 -0700601 }
602
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700603 void overType() {
604 size_t size = mExpressionStack.size();
605 if (size >= 2) {
606 mExpressionStack.push_back(mExpressionStack.back());
607 mExpressionStack[size-1] = mExpressionStack[size-2];
608 mExpressionStack[size-2] = mExpressionStack[size];
609 }
610 }
611
Jack Palevich8df46192009-07-07 14:48:51 -0700612 void popType() {
613 mExpressionStack.pop_back();
614 }
615
616 bool bitsSame(Type* pA, Type* pB) {
617 return collapseType(pA->tag) == collapseType(pB->tag);
618 }
619
620 TypeTag collapseType(TypeTag tag) {
621 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700622 TY_INT,
623 TY_INT,
624 TY_INT,
625 TY_VOID,
626 TY_FLOAT,
627 TY_DOUBLE,
628 TY_INT,
629 TY_INT,
630 TY_VOID,
631 TY_VOID,
632 TY_VOID
633 };
Jack Palevich8df46192009-07-07 14:48:51 -0700634 return collapsedTag[tag];
635 }
636
Jack Palevich1a539db2009-07-08 13:04:41 -0700637 TypeTag collapseTypeR0() {
638 return collapseType(getR0Type()->tag);
639 }
640
Jack Palevichb6154502009-08-04 14:56:09 -0700641 static bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700642 return isFloatTag(pType->tag);
643 }
644
Jack Palevichb6154502009-08-04 14:56:09 -0700645 static bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700646 return tag == TY_FLOAT || tag == TY_DOUBLE;
647 }
648
Jack Palevichb6154502009-08-04 14:56:09 -0700649 static bool isPointerType(Type* pType) {
650 return isPointerTag(pType->tag);
651 }
652
653 static bool isPointerTag(TypeTag tag) {
654 return tag == TY_POINTER || tag == TY_ARRAY;
655 }
656
657 Type* getPointerArithmeticResultType(Type* a, Type* b) {
658 TypeTag aTag = a->tag;
659 TypeTag bTag = b->tag;
660 if (aTag == TY_POINTER) {
661 return a;
662 }
663 if (bTag == TY_POINTER) {
664 return b;
665 }
666 if (aTag == TY_ARRAY) {
667 return a->pTail;
668 }
669 if (bTag == TY_ARRAY) {
670 return b->pTail;
671 }
672 return NULL;
673 }
674
Jack Palevicha8f427f2009-07-13 18:40:08 -0700675 Type* mkpInt;
676
Jack Palevich21a15a22009-05-11 14:49:29 -0700677 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700678 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700679 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700680 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700681 };
682
Jack Paleviche7b59062009-05-19 17:12:17 -0700683#ifdef PROVIDE_ARM_CODEGEN
684
Jack Palevich22305132009-05-13 10:58:45 -0700685 class ARMCodeGenerator : public CodeGenerator {
686 public:
687 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700688
Jack Palevich22305132009-05-13 10:58:45 -0700689 virtual ~ARMCodeGenerator() {}
690
691 /* returns address to patch with local variable size
692 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700693 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700694 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700695 // sp -> arg4 arg5 ...
696 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700697 int regArgCount = calcRegArgCount(pDecl);
698 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700699 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700700 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700701 }
702 // sp -> arg0 arg1 ...
703 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700704 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700705 // sp, fp -> oldfp, retadr, arg0 arg1 ....
706 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700707 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700708 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700709 // We don't know how many local variables we are going to use,
710 // but we will round the allocation up to a multiple of
711 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700712 }
713
Jack Palevichb7718b92009-07-09 22:00:24 -0700714 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700715 // Round local variable size up to a multiple of stack alignment
716 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
717 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700718 // Patch local variable allocation code:
719 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700720 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700721 }
Jack Palevich69796b62009-05-14 15:42:26 -0700722 *(char*) (localVariableAddress) = localVariableSize;
723
724 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
725 o4(0xE1A0E00B); // mov lr, fp
726 o4(0xE59BB000); // ldr fp, [fp]
727 o4(0xE28ED004); // add sp, lr, #4
728 // sp -> retadr, arg0, ...
729 o4(0xE8BD4000); // ldmfd sp!, {lr}
730 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700731
732 // We store the PC into the lr so we can adjust the sp before
733 // returning. We need to pull off the registers we pushed
734 // earlier. We don't need to actually store them anywhere,
735 // just adjust the stack.
736 int regArgCount = calcRegArgCount(pDecl);
737 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700738 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
739 }
740 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700741 }
742
743 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700744 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700745 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700746 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700747 }
748
Jack Palevich1a539db2009-07-08 13:04:41 -0700749 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700750 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700751 // Global, absolute address
752 o4(0xE59F0000); // ldr r0, .L1
753 o4(0xEA000000); // b .L99
754 o4(address); // .L1: .word ea
755 // .L99:
756
757 switch (pType->tag) {
758 case TY_FLOAT:
759 o4(0xE5900000); // ldr r0, [r0]
760 break;
761 case TY_DOUBLE:
762 o4(0xE1C000D0); // ldrd r0, [r0]
763 break;
764 default:
765 assert(false);
766 break;
767 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700768 }
769
Jack Palevich22305132009-05-13 10:58:45 -0700770 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700771 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700772 }
773
774 /* l = 0: je, l == 1: jne */
775 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700776 Type* pR0Type = getR0Type();
777 TypeTag tagR0 = pR0Type->tag;
778 switch(tagR0) {
779 case TY_FLOAT:
780 callRuntime((void*) runtime_is_non_zero_f);
781 break;
782 case TY_DOUBLE:
783 callRuntime((void*) runtime_is_non_zero_d);
784 break;
785 default:
786 break;
787 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700788 o4(0xE3500000); // cmp r0,#0
789 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
790 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700791 }
792
Jack Palevich58c30ee2009-07-17 16:35:23 -0700793 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700794 Type* pR0Type = getR0Type();
795 Type* pTOSType = getTOSType();
796 TypeTag tagR0 = collapseType(pR0Type->tag);
797 TypeTag tagTOS = collapseType(pTOSType->tag);
798 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700799 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700800 o4(0xE1510000); // cmp r1, r1
801 switch(op) {
802 case OP_EQUALS:
803 o4(0x03A00001); // moveq r0,#1
804 o4(0x13A00000); // movne r0,#0
805 break;
806 case OP_NOT_EQUALS:
807 o4(0x03A00000); // moveq r0,#0
808 o4(0x13A00001); // movne r0,#1
809 break;
810 case OP_LESS_EQUAL:
811 o4(0xD3A00001); // movle r0,#1
812 o4(0xC3A00000); // movgt r0,#0
813 break;
814 case OP_GREATER:
815 o4(0xD3A00000); // movle r0,#0
816 o4(0xC3A00001); // movgt r0,#1
817 break;
818 case OP_GREATER_EQUAL:
819 o4(0xA3A00001); // movge r0,#1
820 o4(0xB3A00000); // movlt r0,#0
821 break;
822 case OP_LESS:
823 o4(0xA3A00000); // movge r0,#0
824 o4(0xB3A00001); // movlt r0,#1
825 break;
826 default:
827 error("Unknown comparison op %d", op);
828 break;
829 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700830 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
831 setupDoubleArgs();
832 switch(op) {
833 case OP_EQUALS:
834 callRuntime((void*) runtime_cmp_eq_dd);
835 break;
836 case OP_NOT_EQUALS:
837 callRuntime((void*) runtime_cmp_ne_dd);
838 break;
839 case OP_LESS_EQUAL:
840 callRuntime((void*) runtime_cmp_le_dd);
841 break;
842 case OP_GREATER:
843 callRuntime((void*) runtime_cmp_gt_dd);
844 break;
845 case OP_GREATER_EQUAL:
846 callRuntime((void*) runtime_cmp_ge_dd);
847 break;
848 case OP_LESS:
849 callRuntime((void*) runtime_cmp_lt_dd);
850 break;
851 default:
852 error("Unknown comparison op %d", op);
853 break;
854 }
855 } else {
856 setupFloatArgs();
857 switch(op) {
858 case OP_EQUALS:
859 callRuntime((void*) runtime_cmp_eq_ff);
860 break;
861 case OP_NOT_EQUALS:
862 callRuntime((void*) runtime_cmp_ne_ff);
863 break;
864 case OP_LESS_EQUAL:
865 callRuntime((void*) runtime_cmp_le_ff);
866 break;
867 case OP_GREATER:
868 callRuntime((void*) runtime_cmp_gt_ff);
869 break;
870 case OP_GREATER_EQUAL:
871 callRuntime((void*) runtime_cmp_ge_ff);
872 break;
873 case OP_LESS:
874 callRuntime((void*) runtime_cmp_lt_ff);
875 break;
876 default:
877 error("Unknown comparison op %d", op);
878 break;
879 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700880 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700881 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700882 }
883
Jack Palevich546b2242009-05-13 15:10:04 -0700884 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700885 Type* pR0Type = getR0Type();
886 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700887 TypeTag tagR0 = pR0Type->tag;
888 TypeTag tagTOS = pTOSType->tag;
889 bool isFloatR0 = isFloatTag(tagR0);
890 bool isFloatTOS = isFloatTag(tagTOS);
891 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700892 setupIntPtrArgs();
Jack Palevichb6154502009-08-04 14:56:09 -0700893 bool isPtrR0 = isPointerTag(tagR0);
894 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700895 if (isPtrR0 || isPtrTOS) {
896 if (isPtrR0 && isPtrTOS) {
897 if (op != OP_MINUS) {
898 error("Unsupported pointer-pointer operation %d.", op);
899 }
900 if (! typeEqual(pR0Type, pTOSType)) {
901 error("Incompatible pointer types for subtraction.");
902 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700903 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700904 setR0Type(mkpInt);
905 int size = sizeOf(pR0Type->pHead);
906 if (size != 1) {
907 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700908 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700909 // TODO: Optimize for power-of-two.
910 genOp(OP_DIV);
911 }
912 } else {
913 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
914 error("Unsupported pointer-scalar operation %d", op);
915 }
Jack Palevichb6154502009-08-04 14:56:09 -0700916 Type* pPtrType = getPointerArithmeticResultType(
917 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700918 int size = sizeOf(pPtrType->pHead);
919 if (size != 1) {
920 // TODO: Optimize for power-of-two.
921 liReg(size, 2);
922 if (isPtrR0) {
923 o4(0x0E0010192); // mul r1,r2,r1
924 } else {
925 o4(0x0E0000092); // mul r0,r2,r0
926 }
927 }
928 switch(op) {
929 case OP_PLUS:
930 o4(0xE0810000); // add r0,r1,r0
931 break;
932 case OP_MINUS:
933 o4(0xE0410000); // sub r0,r1,r0
934 break;
935 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700936 setR0Type(pPtrType);
937 }
938 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700939 switch(op) {
940 case OP_MUL:
941 o4(0x0E0000091); // mul r0,r1,r0
942 break;
943 case OP_DIV:
944 callRuntime((void*) runtime_DIV);
945 break;
946 case OP_MOD:
947 callRuntime((void*) runtime_MOD);
948 break;
949 case OP_PLUS:
950 o4(0xE0810000); // add r0,r1,r0
951 break;
952 case OP_MINUS:
953 o4(0xE0410000); // sub r0,r1,r0
954 break;
955 case OP_SHIFT_LEFT:
956 o4(0xE1A00011); // lsl r0,r1,r0
957 break;
958 case OP_SHIFT_RIGHT:
959 o4(0xE1A00051); // asr r0,r1,r0
960 break;
961 case OP_BIT_AND:
962 o4(0xE0010000); // and r0,r1,r0
963 break;
964 case OP_BIT_XOR:
965 o4(0xE0210000); // eor r0,r1,r0
966 break;
967 case OP_BIT_OR:
968 o4(0xE1810000); // orr r0,r1,r0
969 break;
970 case OP_BIT_NOT:
971 o4(0xE1E00000); // mvn r0, r0
972 break;
973 default:
974 error("Unimplemented op %d\n", op);
975 break;
976 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700977 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700978 } else {
979 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
980 if (pResultType->tag == TY_DOUBLE) {
981 setupDoubleArgs();
982 switch(op) {
983 case OP_MUL:
984 callRuntime((void*) runtime_op_mul_dd);
985 break;
986 case OP_DIV:
987 callRuntime((void*) runtime_op_div_dd);
988 break;
989 case OP_PLUS:
990 callRuntime((void*) runtime_op_add_dd);
991 break;
992 case OP_MINUS:
993 callRuntime((void*) runtime_op_sub_dd);
994 break;
995 default:
996 error("Unsupported binary floating operation %d\n", op);
997 break;
998 }
999 } else {
1000 setupFloatArgs();
1001 switch(op) {
1002 case OP_MUL:
1003 callRuntime((void*) runtime_op_mul_ff);
1004 break;
1005 case OP_DIV:
1006 callRuntime((void*) runtime_op_div_ff);
1007 break;
1008 case OP_PLUS:
1009 callRuntime((void*) runtime_op_add_ff);
1010 break;
1011 case OP_MINUS:
1012 callRuntime((void*) runtime_op_sub_ff);
1013 break;
1014 default:
1015 error("Unsupported binary floating operation %d\n", op);
1016 break;
1017 }
1018 }
1019 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001020 }
Jack Palevich22305132009-05-13 10:58:45 -07001021 }
1022
Jack Palevich58c30ee2009-07-17 16:35:23 -07001023 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001024 if (op != OP_LOGICAL_NOT) {
1025 error("Unknown unary cmp %d", op);
1026 } else {
1027 Type* pR0Type = getR0Type();
1028 TypeTag tag = collapseType(pR0Type->tag);
1029 switch(tag) {
1030 case TY_INT:
1031 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001032 o4(0xE1510000); // cmp r1, r0
1033 o4(0x03A00001); // moveq r0,#1
1034 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -07001035 break;
1036 case TY_FLOAT:
1037 callRuntime((void*) runtime_is_zero_f);
1038 break;
1039 case TY_DOUBLE:
1040 callRuntime((void*) runtime_is_zero_d);
1041 break;
1042 default:
1043 error("gUnaryCmp unsupported type");
1044 break;
1045 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001046 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001047 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001048 }
1049
1050 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001051 Type* pR0Type = getR0Type();
1052 TypeTag tag = collapseType(pR0Type->tag);
1053 switch(tag) {
1054 case TY_INT:
1055 switch(op) {
1056 case OP_MINUS:
1057 o4(0xE3A01000); // mov r1, #0
1058 o4(0xE0410000); // sub r0,r1,r0
1059 break;
1060 case OP_BIT_NOT:
1061 o4(0xE1E00000); // mvn r0, r0
1062 break;
1063 default:
1064 error("Unknown unary op %d\n", op);
1065 break;
1066 }
1067 break;
1068 case TY_FLOAT:
1069 case TY_DOUBLE:
1070 switch (op) {
1071 case OP_MINUS:
1072 if (tag == TY_FLOAT) {
1073 callRuntime((void*) runtime_op_neg_f);
1074 } else {
1075 callRuntime((void*) runtime_op_neg_d);
1076 }
1077 break;
1078 case OP_BIT_NOT:
1079 error("Can't apply '~' operator to a float or double.");
1080 break;
1081 default:
1082 error("Unknown unary op %d\n", op);
1083 break;
1084 }
1085 break;
1086 default:
1087 error("genUnaryOp unsupported type");
1088 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001089 }
Jack Palevich22305132009-05-13 10:58:45 -07001090 }
1091
Jack Palevich1cdef202009-05-22 12:06:27 -07001092 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001093 Type* pR0Type = getR0Type();
1094 TypeTag r0ct = collapseType(pR0Type->tag);
1095 if (r0ct != TY_DOUBLE) {
1096 o4(0xE92D0001); // stmfd sp!,{r0}
1097 mStackUse += 4;
1098 } else {
1099 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1100 mStackUse += 8;
1101 }
Jack Palevich8df46192009-07-07 14:48:51 -07001102 pushType();
-b master422972c2009-06-17 19:13:52 -07001103 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001104 }
1105
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001106 virtual void over() {
1107 // We know it's only used for int-ptr ops (++/--)
1108
1109 Type* pR0Type = getR0Type();
1110 TypeTag r0ct = collapseType(pR0Type->tag);
1111
1112 Type* pTOSType = getTOSType();
1113 TypeTag tosct = collapseType(pTOSType->tag);
1114
1115 assert (r0ct == TY_INT && tosct == TY_INT);
1116
1117 o4(0xE8BD0002); // ldmfd sp!,{r1}
1118 o4(0xE92D0001); // stmfd sp!,{r0}
1119 o4(0xE92D0002); // stmfd sp!,{r1}
1120 overType();
1121 mStackUse += 4;
1122 }
1123
Jack Palevich58c30ee2009-07-17 16:35:23 -07001124 virtual void popR0() {
1125 Type* pTOSType = getTOSType();
1126 switch (collapseType(pTOSType->tag)){
1127 case TY_INT:
1128 case TY_FLOAT:
1129 o4(0xE8BD0001); // ldmfd sp!,{r0}
1130 mStackUse -= 4;
1131 break;
1132 case TY_DOUBLE:
1133 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1134 mStackUse -= 8;
1135 break;
1136 default:
1137 error("Can't pop this type.");
1138 break;
1139 }
1140 popType();
1141 LOG_STACK("popR0: %d\n", mStackUse);
1142 }
1143
1144 virtual void storeR0ToTOS() {
1145 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001146 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001147 Type* pDestType = pPointerType->pHead;
1148 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 o4(0xE8BD0004); // ldmfd sp!,{r2}
1150 popType();
-b master422972c2009-06-17 19:13:52 -07001151 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001152 switch (pDestType->tag) {
1153 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001154 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001155 case TY_FLOAT:
1156 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001157 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001158 case TY_SHORT:
1159 o4(0xE1C200B0); // strh r0, [r2]
1160 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001161 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001162 o4(0xE5C20000); // strb r0, [r2]
1163 break;
1164 case TY_DOUBLE:
1165 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001166 break;
1167 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001168 error("storeR0ToTOS: unimplemented type %d",
1169 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001170 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001171 }
Jack Palevich22305132009-05-13 10:58:45 -07001172 }
1173
Jack Palevich58c30ee2009-07-17 16:35:23 -07001174 virtual void loadR0FromR0() {
1175 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001176 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07001177 Type* pNewType = pPointerType->pHead;
1178 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07001179 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001180 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001181 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001182 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001183 o4(0xE5900000); // ldr r0, [r0]
1184 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001185 case TY_SHORT:
1186 o4(0xE1D000F0); // ldrsh r0, [r0]
1187 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001188 case TY_CHAR:
1189 o4(0xE5D00000); // ldrb r0, [r0]
1190 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001191 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001192 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001193 break;
Jack Palevich80e49722009-08-04 15:39:49 -07001194 case TY_ARRAY:
1195 pNewType = pNewType->pTail;
1196 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001197 default:
Jack Palevichb6154502009-08-04 14:56:09 -07001198 error("loadR0FromR0: unimplemented type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001199 break;
1200 }
Jack Palevich80e49722009-08-04 15:39:49 -07001201 setR0Type(pNewType);
Jack Palevich22305132009-05-13 10:58:45 -07001202 }
1203
Jack Palevichb5e33312009-07-30 19:06:34 -07001204 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001205 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001206 // Local, fp relative
1207 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1208 error("Offset out of range: %08x", ea);
1209 }
1210 if (ea < 0) {
1211 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1212 } else {
1213 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1214 }
Jack Palevichbd894902009-05-14 19:35:31 -07001215 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001216 // Global, absolute.
1217 o4(0xE59F0000); // ldr r0, .L1
1218 o4(0xEA000000); // b .L99
1219 o4(ea); // .L1: .word 0
1220 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001221 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001222 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001223 }
1224
Jack Palevich9f51a262009-07-29 16:22:26 -07001225 virtual int leaForward(int ea, Type* pPointerType) {
1226 setR0Type(pPointerType);
1227 int result = ea;
1228 int pc = getPC();
1229 int offset = 0;
1230 if (ea) {
1231 offset = (pc - ea - 8) >> 2;
1232 if ((offset & 0xffff) != offset) {
1233 error("function forward reference out of bounds");
1234 }
1235 } else {
1236 offset = 0;
1237 }
1238 o4(0xE59F0000 | offset); // ldr r0, .L1
1239
1240 if (ea == 0) {
1241 o4(0xEA000000); // b .L99
1242 result = o4(ea); // .L1: .word 0
1243 // .L99:
1244 }
1245 return result;
1246 }
1247
Jack Palevichb6154502009-08-04 14:56:09 -07001248 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07001249 Type* pR0Type = getR0Type();
Jack Palevichb6154502009-08-04 14:56:09 -07001250 if (isPointerType(pType) && isPointerType(pR0Type)) {
1251 Type* pA = pR0Type;
1252 Type* pB = pType;
1253 // Array decays to pointer
1254 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1255 pA = pA->pTail;
1256 }
1257 if (typeEqual(pA, pB)) {
1258 return; // OK
1259 }
1260 if (pB->pHead->tag == TY_VOID) {
1261 return; // convert to void* is OK.
1262 }
1263 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
1264 && isCast) {
1265 return; // OK
1266 }
1267 error("Incompatible pointer or array types");
1268 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001269 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001270 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001271 TypeTag r0Tag = collapseType(pR0Type->tag);
1272 TypeTag destTag = collapseType(pType->tag);
1273 if (r0Tag == TY_INT) {
1274 if (destTag == TY_FLOAT) {
1275 callRuntime((void*) runtime_int_to_float);
1276 } else {
1277 assert(destTag == TY_DOUBLE);
1278 callRuntime((void*) runtime_int_to_double);
1279 }
1280 } else if (r0Tag == TY_FLOAT) {
1281 if (destTag == TY_INT) {
1282 callRuntime((void*) runtime_float_to_int);
1283 } else {
1284 assert(destTag == TY_DOUBLE);
1285 callRuntime((void*) runtime_float_to_double);
1286 }
1287 } else {
1288 assert (r0Tag == TY_DOUBLE);
1289 if (destTag == TY_INT) {
1290 callRuntime((void*) runtime_double_to_int);
1291 } else {
1292 assert(destTag == TY_FLOAT);
1293 callRuntime((void*) runtime_double_to_float);
1294 }
1295 }
Jack Palevich8df46192009-07-07 14:48:51 -07001296 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001297 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001298 }
1299
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001300 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001301 return o4(0xE24DDF00); // Placeholder
1302 }
1303
Jack Palevich8148c5b2009-07-16 18:24:47 -07001304 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001305 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001306 Type* pR0Type = getR0Type();
1307 TypeTag r0ct = collapseType(pR0Type->tag);
1308 switch(r0ct) {
1309 case TY_INT:
1310 case TY_FLOAT:
1311 if (l < 0 || l > 4096-4) {
1312 error("l out of range for stack offset: 0x%08x", l);
1313 }
1314 o4(0xE58D0000 + l); // str r0, [sp, #l]
1315 return 4;
1316 case TY_DOUBLE: {
1317 // Align to 8 byte boundary
1318 int l2 = (l + 7) & ~7;
1319 if (l2 < 0 || l2 > 4096-8) {
1320 error("l out of range for stack offset: 0x%08x", l);
1321 }
1322 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1323 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1324 return (l2 - l) + 8;
1325 }
1326 default:
1327 assert(false);
1328 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001329 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001330 }
1331
Jack Palevichb7718b92009-07-09 22:00:24 -07001332 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001333 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001334 // Have to calculate register arg count from actual stack size,
1335 // in order to properly handle ... functions.
1336 int regArgCount = l >> 2;
1337 if (regArgCount > 4) {
1338 regArgCount = 4;
1339 }
1340 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001341 argumentStackUse -= regArgCount * 4;
1342 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1343 }
1344 mStackUse += argumentStackUse;
1345
1346 // Align stack.
1347 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1348 * STACK_ALIGNMENT);
1349 mStackAlignmentAdjustment = 0;
1350 if (missalignment > 0) {
1351 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1352 }
1353 l += mStackAlignmentAdjustment;
1354
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001355 if (l < 0 || l > 0x3FC) {
1356 error("L out of range for stack adjustment: 0x%08x", l);
1357 }
1358 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001359 mStackUse += mStackAlignmentAdjustment;
1360 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1361 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001362 }
1363
Jack Palevich8df46192009-07-07 14:48:51 -07001364 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001365 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001366 // Forward calls are always short (local)
1367 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001368 }
1369
Jack Palevich8df46192009-07-07 14:48:51 -07001370 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001371 assert(pFunc->tag == TY_FUNC);
1372 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001373 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001374 int argCount = l >> 2;
1375 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001376 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001377 if (adjustedL < 0 || adjustedL > 4096-4) {
1378 error("l out of range for stack offset: 0x%08x", l);
1379 }
1380 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1381 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001382 }
1383
Jack Palevichb7718b92009-07-09 22:00:24 -07001384 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001385 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001386 // Have to calculate register arg count from actual stack size,
1387 // in order to properly handle ... functions.
1388 int regArgCount = l >> 2;
1389 if (regArgCount > 4) {
1390 regArgCount = 4;
1391 }
1392 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001393 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1394 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001395 if (stackUse) {
1396 if (stackUse < 0 || stackUse > 255) {
1397 error("L out of range for stack adjustment: 0x%08x", l);
1398 }
1399 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001400 mStackUse -= stackUse * 4;
1401 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001402 }
Jack Palevich22305132009-05-13 10:58:45 -07001403 }
1404
Jack Palevicha6535612009-05-13 16:24:17 -07001405 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001406 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001407 }
1408
1409 /* output a symbol and patch all calls to it */
1410 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001411 int n;
1412 int base = getBase();
1413 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001414 while (t) {
1415 int data = * (int*) t;
1416 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1417 if (decodedOffset == 0) {
1418 n = 0;
1419 } else {
1420 n = base + decodedOffset; /* next value */
1421 }
1422 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1423 | encodeRelAddress(pc - t - 8);
1424 t = n;
1425 }
1426 }
1427
Jack Palevich9f51a262009-07-29 16:22:26 -07001428 /* output a symbol and patch all calls to it */
1429 virtual void resolveForward(int t) {
1430 if (t) {
1431 int pc = getPC();
1432 *(int *) t = pc;
1433 }
1434 }
1435
Jack Palevich1cdef202009-05-22 12:06:27 -07001436 virtual int finishCompile() {
1437#if defined(__arm__)
1438 const long base = long(getBase());
1439 const long curr = long(getPC());
1440 int err = cacheflush(base, curr, 0);
1441 return err;
1442#else
1443 return 0;
1444#endif
1445 }
1446
Jack Palevicha6535612009-05-13 16:24:17 -07001447 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001448#ifdef ENABLE_ARM_DISASSEMBLY
1449 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001450 disasm_interface_t di;
1451 di.di_readword = disassemble_readword;
1452 di.di_printaddr = disassemble_printaddr;
1453 di.di_printf = disassemble_printf;
1454
1455 int base = getBase();
1456 int pc = getPC();
1457 for(int i = base; i < pc; i += 4) {
1458 fprintf(out, "%08x: %08x ", i, *(int*) i);
1459 ::disasm(&di, i, 0);
1460 }
Jack Palevich09555c72009-05-27 12:25:55 -07001461#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001462 return 0;
1463 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001464
Jack Palevich9eed7a22009-07-06 17:24:34 -07001465 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001466 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001467 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001468 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001469 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001470 case TY_CHAR:
1471 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001472 case TY_SHORT:
1473 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001474 case TY_DOUBLE:
1475 return 8;
1476 default:
1477 return 4;
1478 }
1479 }
1480
1481 /**
1482 * Array element alignment (in bytes) for this type of data.
1483 */
1484 virtual size_t sizeOf(Type* pType){
1485 switch(pType->tag) {
1486 case TY_INT:
1487 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001488 case TY_SHORT:
1489 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001490 case TY_CHAR:
1491 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001492 case TY_FLOAT:
1493 return 4;
1494 case TY_DOUBLE:
1495 return 8;
1496 case TY_POINTER:
1497 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07001498 case TY_ARRAY:
1499 return pType->length * sizeOf(pType->pHead);
1500 default:
1501 error("Unsupported type %d", pType->tag);
1502 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001503 }
1504 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001505
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001506 virtual size_t stackAlignmentOf(Type* pType) {
1507 switch(pType->tag) {
1508 case TY_DOUBLE:
1509 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001510 case TY_ARRAY:
1511 return stackAlignmentOf(pType->pHead);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001512 default:
1513 return 4;
1514 }
1515 }
1516
Jack Palevich9cbd2262009-07-08 16:48:41 -07001517 virtual size_t stackSizeOf(Type* pType) {
1518 switch(pType->tag) {
1519 case TY_DOUBLE:
1520 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07001521 case TY_ARRAY:
1522 return sizeOf(pType);
1523 case TY_FUNC:
1524 error("stackSizeOf func not supported");
1525 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07001526 default:
1527 return 4;
1528 }
1529 }
1530
Jack Palevich22305132009-05-13 10:58:45 -07001531 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001532 static FILE* disasmOut;
1533
1534 static u_int
1535 disassemble_readword(u_int address)
1536 {
1537 return(*((u_int *)address));
1538 }
1539
1540 static void
1541 disassemble_printaddr(u_int address)
1542 {
1543 fprintf(disasmOut, "0x%08x", address);
1544 }
1545
1546 static void
1547 disassemble_printf(const char *fmt, ...) {
1548 va_list ap;
1549 va_start(ap, fmt);
1550 vfprintf(disasmOut, fmt, ap);
1551 va_end(ap);
1552 }
1553
1554 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1555
1556 /** Encode a relative address that might also be
1557 * a label.
1558 */
1559 int encodeAddress(int value) {
1560 int base = getBase();
1561 if (value >= base && value <= getPC() ) {
1562 // This is a label, encode it relative to the base.
1563 value = value - base;
1564 }
1565 return encodeRelAddress(value);
1566 }
1567
1568 int encodeRelAddress(int value) {
1569 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1570 }
Jack Palevich22305132009-05-13 10:58:45 -07001571
Jack Palevichb7718b92009-07-09 22:00:24 -07001572 int calcRegArgCount(Type* pDecl) {
1573 int reg = 0;
1574 Type* pArgs = pDecl->pTail;
1575 while (pArgs && reg < 4) {
1576 Type* pArg = pArgs->pHead;
1577 if ( pArg->tag == TY_DOUBLE) {
1578 int evenReg = (reg + 1) & ~1;
1579 if (evenReg >= 4) {
1580 break;
1581 }
1582 reg = evenReg + 2;
1583 } else {
1584 reg++;
1585 }
1586 pArgs = pArgs->pTail;
1587 }
1588 return reg;
1589 }
1590
Jack Palevich58c30ee2009-07-17 16:35:23 -07001591 void setupIntPtrArgs() {
1592 o4(0xE8BD0002); // ldmfd sp!,{r1}
1593 mStackUse -= 4;
1594 popType();
1595 }
1596
Jack Palevichb7718b92009-07-09 22:00:24 -07001597 /* Pop TOS to R1
1598 * Make sure both R0 and TOS are floats. (Could be ints)
1599 * We know that at least one of R0 and TOS is already a float
1600 */
1601 void setupFloatArgs() {
1602 Type* pR0Type = getR0Type();
1603 Type* pTOSType = getTOSType();
1604 TypeTag tagR0 = collapseType(pR0Type->tag);
1605 TypeTag tagTOS = collapseType(pTOSType->tag);
1606 if (tagR0 != TY_FLOAT) {
1607 assert(tagR0 == TY_INT);
1608 callRuntime((void*) runtime_int_to_float);
1609 }
1610 if (tagTOS != TY_FLOAT) {
1611 assert(tagTOS == TY_INT);
1612 assert(tagR0 == TY_FLOAT);
1613 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1614 o4(0xE59D0004); // ldr r0, [sp, #4]
1615 callRuntime((void*) runtime_int_to_float);
1616 o4(0xE1A01000); // mov r1, r0
1617 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1618 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1619 } else {
1620 // Pop TOS
1621 o4(0xE8BD0002); // ldmfd sp!,{r1}
1622 }
1623 mStackUse -= 4;
1624 popType();
1625 }
1626
1627 /* Pop TOS into R2..R3
1628 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1629 * We know that at least one of R0 and TOS are already a double.
1630 */
1631
1632 void setupDoubleArgs() {
1633 Type* pR0Type = getR0Type();
1634 Type* pTOSType = getTOSType();
1635 TypeTag tagR0 = collapseType(pR0Type->tag);
1636 TypeTag tagTOS = collapseType(pTOSType->tag);
1637 if (tagR0 != TY_DOUBLE) {
1638 if (tagR0 == TY_INT) {
1639 callRuntime((void*) runtime_int_to_double);
1640 } else {
1641 assert(tagR0 == TY_FLOAT);
1642 callRuntime((void*) runtime_float_to_double);
1643 }
1644 }
1645 if (tagTOS != TY_DOUBLE) {
1646 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1647 o4(0xE59D0008); // ldr r0, [sp, #8]
1648 if (tagTOS == TY_INT) {
1649 callRuntime((void*) runtime_int_to_double);
1650 } else {
1651 assert(tagTOS == TY_FLOAT);
1652 callRuntime((void*) runtime_float_to_double);
1653 }
1654 o4(0xE1A02000); // mov r2, r0
1655 o4(0xE1A03001); // mov r3, r1
1656 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1657 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1658 mStackUse -= 4;
1659 } else {
1660 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1661 mStackUse -= 8;
1662 }
1663 popType();
1664 }
1665
Jack Palevicha8f427f2009-07-13 18:40:08 -07001666 void liReg(int t, int reg) {
1667 assert(reg >= 0 && reg < 16);
1668 int rN = (reg & 0xf) << 12;
1669 if (t >= 0 && t < 255) {
1670 o4((0xE3A00000 + t) | rN); // mov rN, #0
1671 } else if (t >= -256 && t < 0) {
1672 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001673 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001674 } else {
1675 o4(0xE51F0000 | rN); // ldr rN, .L3
1676 o4(0xEA000000); // b .L99
1677 o4(t); // .L3: .word 0
1678 // .L99:
1679 }
1680 }
1681
Jack Palevichb7718b92009-07-09 22:00:24 -07001682 void callRuntime(void* fn) {
1683 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001684 o4(0xEA000000); // b .L99
1685 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001686 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001687 }
1688
Jack Palevichb7718b92009-07-09 22:00:24 -07001689 // Integer math:
1690
1691 static int runtime_DIV(int b, int a) {
1692 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001693 }
1694
Jack Palevichb7718b92009-07-09 22:00:24 -07001695 static int runtime_MOD(int b, int a) {
1696 return a % b;
1697 }
1698
1699 // Comparison to zero
1700
1701 static int runtime_is_non_zero_f(float a) {
1702 return a != 0;
1703 }
1704
1705 static int runtime_is_non_zero_d(double a) {
1706 return a != 0;
1707 }
1708
1709 // Comparison to zero
1710
1711 static int runtime_is_zero_f(float a) {
1712 return a == 0;
1713 }
1714
1715 static int runtime_is_zero_d(double a) {
1716 return a == 0;
1717 }
1718
1719 // Type conversion
1720
1721 static int runtime_float_to_int(float a) {
1722 return (int) a;
1723 }
1724
1725 static double runtime_float_to_double(float a) {
1726 return (double) a;
1727 }
1728
1729 static int runtime_double_to_int(double a) {
1730 return (int) a;
1731 }
1732
1733 static float runtime_double_to_float(double a) {
1734 return (float) a;
1735 }
1736
1737 static float runtime_int_to_float(int a) {
1738 return (float) a;
1739 }
1740
1741 static double runtime_int_to_double(int a) {
1742 return (double) a;
1743 }
1744
1745 // Comparisons float
1746
1747 static int runtime_cmp_eq_ff(float b, float a) {
1748 return a == b;
1749 }
1750
1751 static int runtime_cmp_ne_ff(float b, float a) {
1752 return a != b;
1753 }
1754
1755 static int runtime_cmp_lt_ff(float b, float a) {
1756 return a < b;
1757 }
1758
1759 static int runtime_cmp_le_ff(float b, float a) {
1760 return a <= b;
1761 }
1762
1763 static int runtime_cmp_ge_ff(float b, float a) {
1764 return a >= b;
1765 }
1766
1767 static int runtime_cmp_gt_ff(float b, float a) {
1768 return a > b;
1769 }
1770
1771 // Comparisons double
1772
1773 static int runtime_cmp_eq_dd(double b, double a) {
1774 return a == b;
1775 }
1776
1777 static int runtime_cmp_ne_dd(double b, double a) {
1778 return a != b;
1779 }
1780
1781 static int runtime_cmp_lt_dd(double b, double a) {
1782 return a < b;
1783 }
1784
1785 static int runtime_cmp_le_dd(double b, double a) {
1786 return a <= b;
1787 }
1788
1789 static int runtime_cmp_ge_dd(double b, double a) {
1790 return a >= b;
1791 }
1792
1793 static int runtime_cmp_gt_dd(double b, double a) {
1794 return a > b;
1795 }
1796
1797 // Math float
1798
1799 static float runtime_op_add_ff(float b, float a) {
1800 return a + b;
1801 }
1802
1803 static float runtime_op_sub_ff(float b, float a) {
1804 return a - b;
1805 }
1806
1807 static float runtime_op_mul_ff(float b, float a) {
1808 return a * b;
1809 }
1810
1811 static float runtime_op_div_ff(float b, float a) {
1812 return a / b;
1813 }
1814
1815 static float runtime_op_neg_f(float a) {
1816 return -a;
1817 }
1818
1819 // Math double
1820
1821 static double runtime_op_add_dd(double b, double a) {
1822 return a + b;
1823 }
1824
1825 static double runtime_op_sub_dd(double b, double a) {
1826 return a - b;
1827 }
1828
1829 static double runtime_op_mul_dd(double b, double a) {
1830 return a * b;
1831 }
1832
1833 static double runtime_op_div_dd(double b, double a) {
1834 return a / b;
1835 }
1836
1837 static double runtime_op_neg_d(double a) {
1838 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001839 }
-b master422972c2009-06-17 19:13:52 -07001840
1841 static const int STACK_ALIGNMENT = 8;
1842 int mStackUse;
1843 // This variable holds the amount we adjusted the stack in the most
1844 // recent endFunctionCallArguments call. It's examined by the
1845 // following adjustStackAfterCall call.
1846 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001847 };
1848
Jack Palevich09555c72009-05-27 12:25:55 -07001849#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001850
1851#ifdef PROVIDE_X86_CODEGEN
1852
Jack Palevich21a15a22009-05-11 14:49:29 -07001853 class X86CodeGenerator : public CodeGenerator {
1854 public:
1855 X86CodeGenerator() {}
1856 virtual ~X86CodeGenerator() {}
1857
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001858 /* returns address to patch with local variable size
1859 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001860 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001861 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1862 return oad(0xec81, 0); /* sub $xxx, %esp */
1863 }
1864
Jack Palevichb7718b92009-07-09 22:00:24 -07001865 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001866 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001867 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001868 }
1869
Jack Palevich21a15a22009-05-11 14:49:29 -07001870 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001871 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001872 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001873 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001874 }
1875
Jack Palevich1a539db2009-07-08 13:04:41 -07001876 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001877 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001878 switch (pType->tag) {
1879 case TY_FLOAT:
1880 oad(0x05D9, address); // flds
1881 break;
1882 case TY_DOUBLE:
1883 oad(0x05DD, address); // fldl
1884 break;
1885 default:
1886 assert(false);
1887 break;
1888 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001889 }
1890
Jack Palevich22305132009-05-13 10:58:45 -07001891 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001892 return psym(0xe9, t);
1893 }
1894
1895 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001896 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001897 Type* pR0Type = getR0Type();
1898 TypeTag tagR0 = pR0Type->tag;
1899 bool isFloatR0 = isFloatTag(tagR0);
1900 if (isFloatR0) {
1901 o(0xeed9); // fldz
1902 o(0xe9da); // fucompp
1903 o(0xe0df); // fnstsw %ax
1904 o(0x9e); // sahf
1905 } else {
1906 o(0xc085); // test %eax, %eax
1907 }
1908 // Use two output statements to generate one instruction.
1909 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001910 return psym(0x84 + l, t);
1911 }
1912
Jack Palevich58c30ee2009-07-17 16:35:23 -07001913 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001914 Type* pR0Type = getR0Type();
1915 Type* pTOSType = getTOSType();
1916 TypeTag tagR0 = pR0Type->tag;
1917 TypeTag tagTOS = pTOSType->tag;
1918 bool isFloatR0 = isFloatTag(tagR0);
1919 bool isFloatTOS = isFloatTag(tagTOS);
1920 if (!isFloatR0 && !isFloatTOS) {
1921 int t = decodeOp(op);
1922 o(0x59); /* pop %ecx */
1923 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001924 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001925 o(0x0f); /* setxx %al */
1926 o(t + 0x90);
1927 o(0xc0);
1928 popType();
1929 } else {
1930 setupFloatOperands();
1931 switch (op) {
1932 case OP_EQUALS:
1933 o(0xe9da); // fucompp
1934 o(0xe0df); // fnstsw %ax
1935 o(0x9e); // sahf
1936 o(0xc0940f); // sete %al
1937 o(0xc29b0f); // setnp %dl
1938 o(0xd021); // andl %edx, %eax
1939 break;
1940 case OP_NOT_EQUALS:
1941 o(0xe9da); // fucompp
1942 o(0xe0df); // fnstsw %ax
1943 o(0x9e); // sahf
1944 o(0xc0950f); // setne %al
1945 o(0xc29a0f); // setp %dl
1946 o(0xd009); // orl %edx, %eax
1947 break;
1948 case OP_GREATER_EQUAL:
1949 o(0xe9da); // fucompp
1950 o(0xe0df); // fnstsw %ax
1951 o(0x05c4f6); // testb $5, %ah
1952 o(0xc0940f); // sete %al
1953 break;
1954 case OP_LESS:
1955 o(0xc9d9); // fxch %st(1)
1956 o(0xe9da); // fucompp
1957 o(0xe0df); // fnstsw %ax
1958 o(0x9e); // sahf
1959 o(0xc0970f); // seta %al
1960 break;
1961 case OP_LESS_EQUAL:
1962 o(0xc9d9); // fxch %st(1)
1963 o(0xe9da); // fucompp
1964 o(0xe0df); // fnstsw %ax
1965 o(0x9e); // sahf
1966 o(0xc0930f); // setea %al
1967 break;
1968 case OP_GREATER:
1969 o(0xe9da); // fucompp
1970 o(0xe0df); // fnstsw %ax
1971 o(0x45c4f6); // testb $69, %ah
1972 o(0xc0940f); // sete %al
1973 break;
1974 default:
1975 error("Unknown comparison op");
1976 }
1977 o(0xc0b60f); // movzbl %al, %eax
1978 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001979 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001980 }
1981
Jack Palevich546b2242009-05-13 15:10:04 -07001982 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001983 Type* pR0Type = getR0Type();
1984 Type* pTOSType = getTOSType();
1985 TypeTag tagR0 = pR0Type->tag;
1986 TypeTag tagTOS = pTOSType->tag;
1987 bool isFloatR0 = isFloatTag(tagR0);
1988 bool isFloatTOS = isFloatTag(tagTOS);
1989 if (!isFloatR0 && !isFloatTOS) {
Jack Palevichb6154502009-08-04 14:56:09 -07001990 bool isPtrR0 = isPointerTag(tagR0);
1991 bool isPtrTOS = isPointerTag(tagTOS);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001992 if (isPtrR0 || isPtrTOS) {
1993 if (isPtrR0 && isPtrTOS) {
1994 if (op != OP_MINUS) {
1995 error("Unsupported pointer-pointer operation %d.", op);
1996 }
1997 if (! typeEqual(pR0Type, pTOSType)) {
1998 error("Incompatible pointer types for subtraction.");
1999 }
2000 o(0x59); /* pop %ecx */
2001 o(decodeOp(op));
2002 popType();
2003 setR0Type(mkpInt);
2004 int size = sizeOf(pR0Type->pHead);
2005 if (size != 1) {
2006 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07002007 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002008 // TODO: Optimize for power-of-two.
2009 genOp(OP_DIV);
2010 }
2011 } else {
2012 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2013 error("Unsupported pointer-scalar operation %d", op);
2014 }
Jack Palevichb6154502009-08-04 14:56:09 -07002015 Type* pPtrType = getPointerArithmeticResultType(
2016 pR0Type, pTOSType);
Jack Palevicha8f427f2009-07-13 18:40:08 -07002017 o(0x59); /* pop %ecx */
2018 int size = sizeOf(pPtrType->pHead);
2019 if (size != 1) {
2020 // TODO: Optimize for power-of-two.
2021 if (isPtrR0) {
2022 oad(0xC969, size); // imull $size, %ecx
2023 } else {
2024 oad(0xC069, size); // mul $size, %eax
2025 }
2026 }
2027 o(decodeOp(op));
2028 popType();
2029 setR0Type(pPtrType);
2030 }
2031 } else {
2032 o(0x59); /* pop %ecx */
2033 o(decodeOp(op));
2034 if (op == OP_MOD)
2035 o(0x92); /* xchg %edx, %eax */
2036 popType();
2037 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002038 } else {
2039 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2040 setupFloatOperands();
2041 // Both float. x87 R0 == left hand, x87 R1 == right hand
2042 switch (op) {
2043 case OP_MUL:
2044 o(0xc9de); // fmulp
2045 break;
2046 case OP_DIV:
2047 o(0xf1de); // fdivp
2048 break;
2049 case OP_PLUS:
2050 o(0xc1de); // faddp
2051 break;
2052 case OP_MINUS:
2053 o(0xe1de); // fsubp
2054 break;
2055 default:
2056 error("Unsupported binary floating operation.");
2057 break;
2058 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002059 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002060 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002061 }
2062
Jack Palevich58c30ee2009-07-17 16:35:23 -07002063 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002064 if (op != OP_LOGICAL_NOT) {
2065 error("Unknown unary cmp %d", op);
2066 } else {
2067 Type* pR0Type = getR0Type();
2068 TypeTag tag = collapseType(pR0Type->tag);
2069 switch(tag) {
2070 case TY_INT: {
2071 oad(0xb9, 0); /* movl $0, %ecx */
2072 int t = decodeOp(op);
2073 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002074 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07002075 o(0x0f); /* setxx %al */
2076 o(t + 0x90);
2077 o(0xc0);
2078 }
2079 break;
2080 case TY_FLOAT:
2081 case TY_DOUBLE:
2082 o(0xeed9); // fldz
2083 o(0xe9da); // fucompp
2084 o(0xe0df); // fnstsw %ax
2085 o(0x9e); // sahf
2086 o(0xc0950f); // setne %al
2087 o(0xc29a0f); // setp %dl
2088 o(0xd009); // orl %edx, %eax
2089 o(0xc0b60f); // movzbl %al, %eax
2090 o(0x01f083); // xorl $1, %eax
2091 break;
2092 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002093 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002094 break;
2095 }
2096 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002097 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002098 }
2099
2100 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002101 Type* pR0Type = getR0Type();
2102 TypeTag tag = collapseType(pR0Type->tag);
2103 switch(tag) {
2104 case TY_INT:
2105 oad(0xb9, 0); /* movl $0, %ecx */
2106 o(decodeOp(op));
2107 break;
2108 case TY_FLOAT:
2109 case TY_DOUBLE:
2110 switch (op) {
2111 case OP_MINUS:
2112 o(0xe0d9); // fchs
2113 break;
2114 case OP_BIT_NOT:
2115 error("Can't apply '~' operator to a float or double.");
2116 break;
2117 default:
2118 error("Unknown unary op %d\n", op);
2119 break;
2120 }
2121 break;
2122 default:
2123 error("genUnaryOp unsupported type");
2124 break;
2125 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002126 }
2127
Jack Palevich1cdef202009-05-22 12:06:27 -07002128 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002129 Type* pR0Type = getR0Type();
2130 TypeTag r0ct = collapseType(pR0Type->tag);
2131 switch(r0ct) {
2132 case TY_INT:
2133 o(0x50); /* push %eax */
2134 break;
2135 case TY_FLOAT:
2136 o(0x50); /* push %eax */
2137 o(0x241cd9); // fstps 0(%esp)
2138 break;
2139 case TY_DOUBLE:
2140 o(0x50); /* push %eax */
2141 o(0x50); /* push %eax */
2142 o(0x241cdd); // fstpl 0(%esp)
2143 break;
2144 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002145 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002146 break;
2147 }
Jack Palevich8df46192009-07-07 14:48:51 -07002148 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002149 }
2150
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002151 virtual void over() {
2152 // We know it's only used for int-ptr ops (++/--)
2153
2154 Type* pR0Type = getR0Type();
2155 TypeTag r0ct = collapseType(pR0Type->tag);
2156
2157 Type* pTOSType = getTOSType();
2158 TypeTag tosct = collapseType(pTOSType->tag);
2159
2160 assert (r0ct == TY_INT && tosct == TY_INT);
2161
2162 o(0x59); /* pop %ecx */
2163 o(0x50); /* push %eax */
2164 o(0x51); /* push %ecx */
2165
2166 overType();
2167 }
2168
Jack Palevich58c30ee2009-07-17 16:35:23 -07002169 virtual void popR0() {
2170 Type* pR0Type = getR0Type();
2171 TypeTag r0ct = collapseType(pR0Type->tag);
2172 switch(r0ct) {
2173 case TY_INT:
2174 o(0x58); /* popl %eax */
2175 break;
2176 case TY_FLOAT:
2177 o(0x2404d9); // flds (%esp)
2178 o(0x58); /* popl %eax */
2179 break;
2180 case TY_DOUBLE:
2181 o(0x2404dd); // fldl (%esp)
2182 o(0x58); /* popl %eax */
2183 o(0x58); /* popl %eax */
2184 break;
2185 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002186 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002187 break;
2188 }
2189 popType();
2190 }
2191
2192 virtual void storeR0ToTOS() {
2193 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002194 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002195 Type* pTargetType = pPointerType->pHead;
2196 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002197 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002198 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002199 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002200 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002201 case TY_INT:
2202 o(0x0189); /* movl %eax/%al, (%ecx) */
2203 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002204 case TY_SHORT:
2205 o(0x018966); /* movw %ax, (%ecx) */
2206 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002207 case TY_CHAR:
2208 o(0x0188); /* movl %eax/%al, (%ecx) */
2209 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002210 case TY_FLOAT:
2211 o(0x19d9); /* fstps (%ecx) */
2212 break;
2213 case TY_DOUBLE:
2214 o(0x19dd); /* fstpl (%ecx) */
2215 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002216 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002217 error("storeR0ToTOS: unsupported type %d",
2218 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002219 break;
2220 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002221 }
2222
Jack Palevich58c30ee2009-07-17 16:35:23 -07002223 virtual void loadR0FromR0() {
2224 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002225 assert(pPointerType->tag == TY_POINTER);
Jack Palevich80e49722009-08-04 15:39:49 -07002226 Type* pNewType = pPointerType->pHead;
2227 TypeTag tag = pNewType->tag;
Jack Palevichb6154502009-08-04 14:56:09 -07002228 switch (tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002229 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002230 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002231 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002232 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002233 case TY_SHORT:
2234 o(0xbf0f); /* movswl (%eax), %eax */
2235 ob(0);
2236 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002237 case TY_CHAR:
2238 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002239 ob(0); /* add zero in code */
2240 break;
2241 case TY_FLOAT:
2242 o2(0x00d9); // flds (%eax)
2243 break;
2244 case TY_DOUBLE:
2245 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002246 break;
Jack Palevich80e49722009-08-04 15:39:49 -07002247 case TY_ARRAY:
2248 pNewType = pNewType->pTail;
2249 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002250 default:
Jack Palevichb6154502009-08-04 14:56:09 -07002251 error("loadR0FromR0: unsupported type %d", tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002252 break;
2253 }
Jack Palevich80e49722009-08-04 15:39:49 -07002254 setR0Type(pNewType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002255 }
2256
Jack Palevichb5e33312009-07-30 19:06:34 -07002257 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002258 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002259 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002260 }
2261
Jack Palevich9f51a262009-07-29 16:22:26 -07002262 virtual int leaForward(int ea, Type* pPointerType) {
2263 oad(0xb8, ea); /* mov $xx, %eax */
2264 setR0Type(pPointerType);
2265 return getPC() - 4;
2266 }
2267
Jack Palevichb6154502009-08-04 14:56:09 -07002268 virtual void convertR0Imp(Type* pType, bool isCast){
Jack Palevich1a539db2009-07-08 13:04:41 -07002269 Type* pR0Type = getR0Type();
2270 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002271 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002272 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002273 return;
2274 }
Jack Palevichb6154502009-08-04 14:56:09 -07002275 if (isPointerType(pType) && isPointerType(pR0Type)) {
2276 Type* pA = pR0Type;
2277 Type* pB = pType;
2278 // Array decays to pointer
2279 if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2280 pA = pA->pTail;
2281 }
2282 if (typeEqual(pA, pB)) {
2283 return; // OK
2284 }
2285 if (pB->pHead->tag == TY_VOID) {
2286 return; // convert to void* is OK.
2287 }
2288 if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
2289 && isCast) {
2290 return; // OK
2291 }
2292 error("Incompatible pointer or array types");
2293 } else if (bitsSame(pType, pR0Type)) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002294 // do nothing special
2295 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2296 // do nothing special, both held in same register on x87.
2297 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002298 TypeTag r0Tag = collapseType(pR0Type->tag);
2299 TypeTag destTag = collapseType(pType->tag);
2300 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2301 // Convert R0 from int to float
2302 o(0x50); // push %eax
2303 o(0x2404DB); // fildl 0(%esp)
2304 o(0x58); // pop %eax
2305 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2306 // Convert R0 from float to int. Complicated because
2307 // need to save and restore the rounding mode.
2308 o(0x50); // push %eax
2309 o(0x50); // push %eax
2310 o(0x02247cD9); // fnstcw 2(%esp)
2311 o(0x2444b70f); // movzwl 2(%esp), %eax
2312 o(0x02);
2313 o(0x0cb4); // movb $12, %ah
2314 o(0x24048966); // movw %ax, 0(%esp)
2315 o(0x242cd9); // fldcw 0(%esp)
2316 o(0x04245cdb); // fistpl 4(%esp)
2317 o(0x02246cd9); // fldcw 2(%esp)
2318 o(0x58); // pop %eax
2319 o(0x58); // pop %eax
2320 } else {
2321 error("Incompatible types old: %d new: %d",
2322 pR0Type->tag, pType->tag);
2323 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002324 }
2325 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002326 }
2327
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002328 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002329 return oad(0xec81, 0); /* sub $xxx, %esp */
2330 }
2331
Jack Palevich8148c5b2009-07-16 18:24:47 -07002332 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2333 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002334 Type* pR0Type = getR0Type();
2335 TypeTag r0ct = collapseType(pR0Type->tag);
2336 switch(r0ct) {
2337 case TY_INT:
2338 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2339 return 4;
2340 case TY_FLOAT:
2341 oad(0x249CD9, l); /* fstps xxx(%esp) */
2342 return 4;
2343 case TY_DOUBLE:
2344 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2345 return 8;
2346 default:
2347 assert(false);
2348 return 0;
2349 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002350 }
2351
Jack Palevichb7718b92009-07-09 22:00:24 -07002352 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002353 * (int*) a = l;
2354 }
2355
Jack Palevich8df46192009-07-07 14:48:51 -07002356 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002357 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002358 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002359 return psym(0xe8, symbol); /* call xxx */
2360 }
2361
Jack Palevich8df46192009-07-07 14:48:51 -07002362 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002363 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002364 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002365 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002366 oad(0x2494ff, l); /* call *xxx(%esp) */
2367 }
2368
Jack Palevichb7718b92009-07-09 22:00:24 -07002369 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002370 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002371 if (isIndirect) {
2372 l += 4;
2373 }
-b master422972c2009-06-17 19:13:52 -07002374 if (l > 0) {
2375 oad(0xc481, l); /* add $xxx, %esp */
2376 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002377 }
2378
Jack Palevicha6535612009-05-13 16:24:17 -07002379 virtual int jumpOffset() {
2380 return 5;
2381 }
2382
2383 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002384 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002385 }
2386
Jack Paleviche7b59062009-05-19 17:12:17 -07002387 /* output a symbol and patch all calls to it */
2388 virtual void gsym(int t) {
2389 int n;
2390 int pc = getPC();
2391 while (t) {
2392 n = *(int *) t; /* next value */
2393 *(int *) t = pc - t - 4;
2394 t = n;
2395 }
2396 }
2397
Jack Palevich9f51a262009-07-29 16:22:26 -07002398 /* output a symbol and patch all calls to it, using absolute address */
2399 virtual void resolveForward(int t) {
2400 int n;
2401 int pc = getPC();
2402 while (t) {
2403 n = *(int *) t; /* next value */
2404 *(int *) t = pc;
2405 t = n;
2406 }
2407 }
2408
Jack Palevich1cdef202009-05-22 12:06:27 -07002409 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002410 size_t pagesize = 4096;
2411 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2412 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2413 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2414 if (err) {
2415 error("mprotect() failed: %d", errno);
2416 }
2417 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002418 }
2419
Jack Palevich9eed7a22009-07-06 17:24:34 -07002420 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002421 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002422 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002423 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002424 switch (pType->tag) {
2425 case TY_CHAR:
2426 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002427 case TY_SHORT:
2428 return 2;
Jack Palevichb6154502009-08-04 14:56:09 -07002429 case TY_ARRAY:
2430 return alignmentOf(pType->pHead);
2431 case TY_FUNC:
2432 error("alignment of func not supported");
2433 return 1;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002434 default:
2435 return 4;
2436 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002437 }
2438
2439 /**
2440 * Array element alignment (in bytes) for this type of data.
2441 */
2442 virtual size_t sizeOf(Type* pType){
2443 switch(pType->tag) {
2444 case TY_INT:
2445 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002446 case TY_SHORT:
2447 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002448 case TY_CHAR:
2449 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002450 case TY_FLOAT:
2451 return 4;
2452 case TY_DOUBLE:
2453 return 8;
2454 case TY_POINTER:
2455 return 4;
Jack Palevichb6154502009-08-04 14:56:09 -07002456 case TY_ARRAY:
2457 return pType->length * sizeOf(pType->pHead);
2458 default:
2459 error("Unsupported type %d", pType->tag);
2460 return 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002461 }
2462 }
2463
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002464 virtual size_t stackAlignmentOf(Type* pType){
2465 return 4;
2466 }
2467
Jack Palevich9cbd2262009-07-08 16:48:41 -07002468 virtual size_t stackSizeOf(Type* pType) {
2469 switch(pType->tag) {
2470 case TY_DOUBLE:
2471 return 8;
Jack Palevichb6154502009-08-04 14:56:09 -07002472 case TY_ARRAY:
2473 return sizeOf(pType);
2474 case TY_FUNC:
2475 error("stackSizeOf func not supported");
2476 return 4;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002477 default:
2478 return 4;
2479 }
2480 }
2481
Jack Palevich21a15a22009-05-11 14:49:29 -07002482 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002483
2484 /** Output 1 to 4 bytes.
2485 *
2486 */
2487 void o(int n) {
2488 /* cannot use unsigned, so we must do a hack */
2489 while (n && n != -1) {
2490 ob(n & 0xff);
2491 n = n >> 8;
2492 }
2493 }
2494
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002495 /* Output exactly 2 bytes
2496 */
2497 void o2(int n) {
2498 ob(n & 0xff);
2499 ob(0xff & (n >> 8));
2500 }
2501
Jack Paleviche7b59062009-05-19 17:12:17 -07002502 /* psym is used to put an instruction with a data field which is a
2503 reference to a symbol. It is in fact the same as oad ! */
2504 int psym(int n, int t) {
2505 return oad(n, t);
2506 }
2507
2508 /* instruction + address */
2509 int oad(int n, int t) {
2510 o(n);
2511 int result = getPC();
2512 o4(t);
2513 return result;
2514 }
2515
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002516 static const int operatorHelper[];
2517
2518 int decodeOp(int op) {
2519 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002520 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002521 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002522 }
2523 return operatorHelper[op];
2524 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002525
Jack Palevich546b2242009-05-13 15:10:04 -07002526 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002527 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002528 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002529 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002530
2531 void setupFloatOperands() {
2532 Type* pR0Type = getR0Type();
2533 Type* pTOSType = getTOSType();
2534 TypeTag tagR0 = pR0Type->tag;
2535 TypeTag tagTOS = pTOSType->tag;
2536 bool isFloatR0 = isFloatTag(tagR0);
2537 bool isFloatTOS = isFloatTag(tagTOS);
2538 if (! isFloatR0) {
2539 // Convert R0 from int to float
2540 o(0x50); // push %eax
2541 o(0x2404DB); // fildl 0(%esp)
2542 o(0x58); // pop %eax
2543 }
2544 if (! isFloatTOS){
2545 o(0x2404DB); // fildl 0(%esp);
2546 o(0x58); // pop %eax
2547 } else {
2548 if (tagTOS == TY_FLOAT) {
2549 o(0x2404d9); // flds (%esp)
2550 o(0x58); // pop %eax
2551 } else {
2552 o(0x2404dd); // fldl (%esp)
2553 o(0x58); // pop %eax
2554 o(0x58); // pop %eax
2555 }
2556 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002557 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002558 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002559 };
2560
Jack Paleviche7b59062009-05-19 17:12:17 -07002561#endif // PROVIDE_X86_CODEGEN
2562
Jack Palevichb67b18f2009-06-11 21:12:23 -07002563#ifdef PROVIDE_TRACE_CODEGEN
2564 class TraceCodeGenerator : public CodeGenerator {
2565 private:
2566 CodeGenerator* mpBase;
2567
2568 public:
2569 TraceCodeGenerator(CodeGenerator* pBase) {
2570 mpBase = pBase;
2571 }
2572
2573 virtual ~TraceCodeGenerator() {
2574 delete mpBase;
2575 }
2576
2577 virtual void init(CodeBuf* pCodeBuf) {
2578 mpBase->init(pCodeBuf);
2579 }
2580
2581 void setErrorSink(ErrorSink* pErrorSink) {
2582 mpBase->setErrorSink(pErrorSink);
2583 }
2584
2585 /* returns address to patch with local variable size
2586 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002587 virtual int functionEntry(Type* pDecl) {
2588 int result = mpBase->functionEntry(pDecl);
2589 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002590 return result;
2591 }
2592
Jack Palevichb7718b92009-07-09 22:00:24 -07002593 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2594 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2595 localVariableAddress, localVariableSize);
2596 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002597 }
2598
2599 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002600 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002601 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002602 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002603 }
2604
Jack Palevich1a539db2009-07-08 13:04:41 -07002605 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002606 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002607 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002608 }
2609
Jack Palevichb67b18f2009-06-11 21:12:23 -07002610 virtual int gjmp(int t) {
2611 int result = mpBase->gjmp(t);
2612 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2613 return result;
2614 }
2615
2616 /* l = 0: je, l == 1: jne */
2617 virtual int gtst(bool l, int t) {
2618 int result = mpBase->gtst(l, t);
2619 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2620 return result;
2621 }
2622
Jack Palevich58c30ee2009-07-17 16:35:23 -07002623 virtual void gcmp(int op) {
2624 fprintf(stderr, "gcmp(%d)\n", op);
2625 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002626 }
2627
2628 virtual void genOp(int op) {
2629 fprintf(stderr, "genOp(%d)\n", op);
2630 mpBase->genOp(op);
2631 }
2632
Jack Palevich9eed7a22009-07-06 17:24:34 -07002633
Jack Palevich58c30ee2009-07-17 16:35:23 -07002634 virtual void gUnaryCmp(int op) {
2635 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2636 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002637 }
2638
2639 virtual void genUnaryOp(int op) {
2640 fprintf(stderr, "genUnaryOp(%d)\n", op);
2641 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002642 }
2643
2644 virtual void pushR0() {
2645 fprintf(stderr, "pushR0()\n");
2646 mpBase->pushR0();
2647 }
2648
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002649 virtual void over() {
2650 fprintf(stderr, "over()\n");
2651 mpBase->over();
2652 }
2653
Jack Palevich58c30ee2009-07-17 16:35:23 -07002654 virtual void popR0() {
2655 fprintf(stderr, "popR0()\n");
2656 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002657 }
2658
Jack Palevich58c30ee2009-07-17 16:35:23 -07002659 virtual void storeR0ToTOS() {
2660 fprintf(stderr, "storeR0ToTOS()\n");
2661 mpBase->storeR0ToTOS();
2662 }
2663
2664 virtual void loadR0FromR0() {
2665 fprintf(stderr, "loadR0FromR0()\n");
2666 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002667 }
2668
Jack Palevichb5e33312009-07-30 19:06:34 -07002669 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2670 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
2671 pPointerType->pHead->tag, et);
2672 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002673 }
2674
Jack Palevich9f51a262009-07-29 16:22:26 -07002675 virtual int leaForward(int ea, Type* pPointerType) {
2676 fprintf(stderr, "leaForward(%d)\n", ea);
2677 return mpBase->leaForward(ea, pPointerType);
2678 }
2679
Jack Palevich8df46192009-07-07 14:48:51 -07002680 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002681 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002682 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002683 }
2684
2685 virtual int beginFunctionCallArguments() {
2686 int result = mpBase->beginFunctionCallArguments();
2687 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2688 return result;
2689 }
2690
Jack Palevich8148c5b2009-07-16 18:24:47 -07002691 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2692 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2693 pArgType->tag);
2694 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002695 }
2696
Jack Palevichb7718b92009-07-09 22:00:24 -07002697 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002698 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002699 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002700 }
2701
Jack Palevich8df46192009-07-07 14:48:51 -07002702 virtual int callForward(int symbol, Type* pFunc) {
2703 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002704 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2705 return result;
2706 }
2707
Jack Palevich8df46192009-07-07 14:48:51 -07002708 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002709 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2710 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002711 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002712 }
2713
Jack Palevichb7718b92009-07-09 22:00:24 -07002714 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2715 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2716 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002717 }
2718
2719 virtual int jumpOffset() {
2720 return mpBase->jumpOffset();
2721 }
2722
2723 virtual int disassemble(FILE* out) {
2724 return mpBase->disassemble(out);
2725 }
2726
2727 /* output a symbol and patch all calls to it */
2728 virtual void gsym(int t) {
2729 fprintf(stderr, "gsym(%d)\n", t);
2730 mpBase->gsym(t);
2731 }
2732
Jack Palevich9f51a262009-07-29 16:22:26 -07002733 virtual void resolveForward(int t) {
2734 mpBase->resolveForward(t);
2735 }
2736
Jack Palevichb67b18f2009-06-11 21:12:23 -07002737 virtual int finishCompile() {
2738 int result = mpBase->finishCompile();
2739 fprintf(stderr, "finishCompile() = %d\n", result);
2740 return result;
2741 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002742
2743 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002744 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002745 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002746 virtual size_t alignmentOf(Type* pType){
2747 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002748 }
2749
2750 /**
2751 * Array element alignment (in bytes) for this type of data.
2752 */
2753 virtual size_t sizeOf(Type* pType){
2754 return mpBase->sizeOf(pType);
2755 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002756
Jack Palevich9cbd2262009-07-08 16:48:41 -07002757
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002758 virtual size_t stackAlignmentOf(Type* pType) {
2759 return mpBase->stackAlignmentOf(pType);
2760 }
2761
2762
Jack Palevich9cbd2262009-07-08 16:48:41 -07002763 virtual size_t stackSizeOf(Type* pType) {
2764 return mpBase->stackSizeOf(pType);
2765 }
2766
Jack Palevich1a539db2009-07-08 13:04:41 -07002767 virtual Type* getR0Type() {
2768 return mpBase->getR0Type();
2769 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002770
2771 virtual ExpressionType getR0ExpressionType() {
2772 return mpBase->getR0ExpressionType();
2773 }
2774
2775 virtual void setR0ExpressionType(ExpressionType et) {
2776 mpBase->setR0ExpressionType(et);
2777 }
2778
2779 virtual size_t getExpressionStackDepth() {
2780 return mpBase->getExpressionStackDepth();
2781 }
Jack Palevichb5e33312009-07-30 19:06:34 -07002782
2783 virtual void forceR0RVal() {
2784 return mpBase->forceR0RVal();
2785 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002786 };
2787
2788#endif // PROVIDE_TRACE_CODEGEN
2789
Jack Palevich569f1352009-06-29 14:29:08 -07002790 class Arena {
2791 public:
2792 // Used to record a given allocation amount.
2793 // Used:
2794 // Mark mark = arena.mark();
2795 // ... lots of arena.allocate()
2796 // arena.free(mark);
2797
2798 struct Mark {
2799 size_t chunk;
2800 size_t offset;
2801 };
2802
2803 Arena() {
2804 mCurrentChunk = 0;
2805 Chunk start(CHUNK_SIZE);
2806 mData.push_back(start);
2807 }
2808
2809 ~Arena() {
2810 for(size_t i = 0; i < mData.size(); i++) {
2811 mData[i].free();
2812 }
2813 }
2814
2815 // Alloc using the standard alignment size safe for any variable
2816 void* alloc(size_t size) {
2817 return alloc(size, 8);
2818 }
2819
2820 Mark mark(){
2821 Mark result;
2822 result.chunk = mCurrentChunk;
2823 result.offset = mData[mCurrentChunk].mOffset;
2824 return result;
2825 }
2826
2827 void freeToMark(const Mark& mark) {
2828 mCurrentChunk = mark.chunk;
2829 mData[mCurrentChunk].mOffset = mark.offset;
2830 }
2831
2832 private:
2833 // Allocate memory aligned to a given size
2834 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2835 // Memory is not zero filled.
2836
2837 void* alloc(size_t size, size_t alignment) {
2838 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2839 if (mCurrentChunk + 1 < mData.size()) {
2840 mCurrentChunk++;
2841 } else {
2842 size_t allocSize = CHUNK_SIZE;
2843 if (allocSize < size + alignment - 1) {
2844 allocSize = size + alignment - 1;
2845 }
2846 Chunk chunk(allocSize);
2847 mData.push_back(chunk);
2848 mCurrentChunk++;
2849 }
2850 }
2851 return mData[mCurrentChunk].allocate(size, alignment);
2852 }
2853
2854 static const size_t CHUNK_SIZE = 128*1024;
2855 // Note: this class does not deallocate its
2856 // memory when it's destroyed. It depends upon
2857 // its parent to deallocate the memory.
2858 struct Chunk {
2859 Chunk() {
2860 mpData = 0;
2861 mSize = 0;
2862 mOffset = 0;
2863 }
2864
2865 Chunk(size_t size) {
2866 mSize = size;
2867 mpData = (char*) malloc(size);
2868 mOffset = 0;
2869 }
2870
2871 ~Chunk() {
2872 // Doesn't deallocate memory.
2873 }
2874
2875 void* allocate(size_t size, size_t alignment) {
2876 size_t alignedOffset = aligned(mOffset, alignment);
2877 void* result = mpData + alignedOffset;
2878 mOffset = alignedOffset + size;
2879 return result;
2880 }
2881
2882 void free() {
2883 if (mpData) {
2884 ::free(mpData);
2885 mpData = 0;
2886 }
2887 }
2888
2889 size_t remainingCapacity(size_t alignment) {
2890 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2891 }
2892
2893 // Assume alignment is a power of two
2894 inline size_t aligned(size_t v, size_t alignment) {
2895 size_t mask = alignment-1;
2896 return (v + mask) & ~mask;
2897 }
2898
2899 char* mpData;
2900 size_t mSize;
2901 size_t mOffset;
2902 };
2903
2904 size_t mCurrentChunk;
2905
2906 Vector<Chunk> mData;
2907 };
2908
Jack Palevich569f1352009-06-29 14:29:08 -07002909 struct VariableInfo;
2910
2911 struct Token {
2912 int hash;
2913 size_t length;
2914 char* pText;
2915 tokenid_t id;
2916
2917 // Current values for the token
2918 char* mpMacroDefinition;
2919 VariableInfo* mpVariableInfo;
2920 };
2921
2922 class TokenTable {
2923 public:
2924 // Don't use 0..0xff, allows characters and operators to be tokens too.
2925
2926 static const int TOKEN_BASE = 0x100;
2927 TokenTable() {
2928 mpMap = hashmapCreate(128, hashFn, equalsFn);
2929 }
2930
2931 ~TokenTable() {
2932 hashmapFree(mpMap);
2933 }
2934
2935 void setArena(Arena* pArena) {
2936 mpArena = pArena;
2937 }
2938
2939 // Returns a token for a given string of characters.
2940 tokenid_t intern(const char* pText, size_t length) {
2941 Token probe;
2942 int hash = hashmapHash((void*) pText, length);
2943 {
2944 Token probe;
2945 probe.hash = hash;
2946 probe.length = length;
2947 probe.pText = (char*) pText;
2948 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2949 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002950 return pValue->id;
2951 }
2952 }
2953
2954 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2955 memset(pToken, 0, sizeof(*pToken));
2956 pToken->hash = hash;
2957 pToken->length = length;
2958 pToken->pText = (char*) mpArena->alloc(length + 1);
2959 memcpy(pToken->pText, pText, length);
2960 pToken->pText[length] = 0;
2961 pToken->id = mTokens.size() + TOKEN_BASE;
2962 mTokens.push_back(pToken);
2963 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002964 return pToken->id;
2965 }
2966
2967 // Return the Token for a given tokenid.
2968 Token& operator[](tokenid_t id) {
2969 return *mTokens[id - TOKEN_BASE];
2970 }
2971
2972 inline size_t size() {
2973 return mTokens.size();
2974 }
2975
2976 private:
2977
2978 static int hashFn(void* pKey) {
2979 Token* pToken = (Token*) pKey;
2980 return pToken->hash;
2981 }
2982
2983 static bool equalsFn(void* keyA, void* keyB) {
2984 Token* pTokenA = (Token*) keyA;
2985 Token* pTokenB = (Token*) keyB;
2986 // Don't need to compare hash values, they should always be equal
2987 return pTokenA->length == pTokenB->length
2988 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2989 }
2990
2991 Hashmap* mpMap;
2992 Vector<Token*> mTokens;
2993 Arena* mpArena;
2994 };
2995
Jack Palevich1cdef202009-05-22 12:06:27 -07002996 class InputStream {
2997 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002998 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002999 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07003000 };
3001
3002 class TextInputStream : public InputStream {
3003 public:
3004 TextInputStream(const char* text, size_t textLength)
3005 : pText(text), mTextLength(textLength), mPosition(0) {
3006 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003007
Jack Palevichdc456462009-07-16 16:50:56 -07003008 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07003009 return mPosition < mTextLength ? pText[mPosition++] : EOF;
3010 }
Jack Palevich1cdef202009-05-22 12:06:27 -07003011
Jack Palevichdc456462009-07-16 16:50:56 -07003012 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07003013 const char* pText;
3014 size_t mTextLength;
3015 size_t mPosition;
3016 };
3017
Jack Palevicheedf9d22009-06-04 16:23:40 -07003018 class String {
3019 public:
3020 String() {
3021 mpBase = 0;
3022 mUsed = 0;
3023 mSize = 0;
3024 }
3025
Jack Palevich303d8ff2009-06-11 19:06:24 -07003026 String(const char* item, int len, bool adopt) {
3027 if (len < 0) {
3028 len = strlen(item);
3029 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003030 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003031 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003032 mUsed = len;
3033 mSize = len + 1;
3034 } else {
3035 mpBase = 0;
3036 mUsed = 0;
3037 mSize = 0;
3038 appendBytes(item, len);
3039 }
3040 }
3041
Jack Palevich303d8ff2009-06-11 19:06:24 -07003042 String(const String& other) {
3043 mpBase = 0;
3044 mUsed = 0;
3045 mSize = 0;
3046 appendBytes(other.getUnwrapped(), other.len());
3047 }
3048
Jack Palevicheedf9d22009-06-04 16:23:40 -07003049 ~String() {
3050 if (mpBase) {
3051 free(mpBase);
3052 }
3053 }
3054
Jack Palevicha6baa232009-06-12 11:25:59 -07003055 String& operator=(const String& other) {
3056 clear();
3057 appendBytes(other.getUnwrapped(), other.len());
3058 return *this;
3059 }
3060
Jack Palevich303d8ff2009-06-11 19:06:24 -07003061 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003062 return mpBase;
3063 }
3064
Jack Palevich303d8ff2009-06-11 19:06:24 -07003065 void clear() {
3066 mUsed = 0;
3067 if (mSize > 0) {
3068 mpBase[0] = 0;
3069 }
3070 }
3071
Jack Palevicheedf9d22009-06-04 16:23:40 -07003072 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003073 appendBytes(s, strlen(s));
3074 }
3075
3076 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003077 memcpy(ensure(n), s, n + 1);
3078 }
3079
3080 void append(char c) {
3081 * ensure(1) = c;
3082 }
3083
Jack Palevich86351982009-06-30 18:09:56 -07003084 void append(String& other) {
3085 appendBytes(other.getUnwrapped(), other.len());
3086 }
3087
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003088 char* orphan() {
3089 char* result = mpBase;
3090 mpBase = 0;
3091 mUsed = 0;
3092 mSize = 0;
3093 return result;
3094 }
3095
Jack Palevicheedf9d22009-06-04 16:23:40 -07003096 void printf(const char* fmt,...) {
3097 va_list ap;
3098 va_start(ap, fmt);
3099 vprintf(fmt, ap);
3100 va_end(ap);
3101 }
3102
3103 void vprintf(const char* fmt, va_list ap) {
3104 char* temp;
3105 int numChars = vasprintf(&temp, fmt, ap);
3106 memcpy(ensure(numChars), temp, numChars+1);
3107 free(temp);
3108 }
3109
Jack Palevich303d8ff2009-06-11 19:06:24 -07003110 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003111 return mUsed;
3112 }
3113
3114 private:
3115 char* ensure(int n) {
3116 size_t newUsed = mUsed + n;
3117 if (newUsed > mSize) {
3118 size_t newSize = mSize * 2 + 10;
3119 if (newSize < newUsed) {
3120 newSize = newUsed;
3121 }
3122 mpBase = (char*) realloc(mpBase, newSize + 1);
3123 mSize = newSize;
3124 }
3125 mpBase[newUsed] = '\0';
3126 char* result = mpBase + mUsed;
3127 mUsed = newUsed;
3128 return result;
3129 }
3130
3131 char* mpBase;
3132 size_t mUsed;
3133 size_t mSize;
3134 };
3135
Jack Palevich569f1352009-06-29 14:29:08 -07003136 void internKeywords() {
3137 // Note: order has to match TOK_ constants
3138 static const char* keywords[] = {
3139 "int",
3140 "char",
3141 "void",
3142 "if",
3143 "else",
3144 "while",
3145 "break",
3146 "return",
3147 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003148 "auto",
3149 "case",
3150 "const",
3151 "continue",
3152 "default",
3153 "do",
3154 "double",
3155 "enum",
3156 "extern",
3157 "float",
3158 "goto",
3159 "long",
3160 "register",
3161 "short",
3162 "signed",
3163 "sizeof",
3164 "static",
3165 "struct",
3166 "switch",
3167 "typedef",
3168 "union",
3169 "unsigned",
3170 "volatile",
3171 "_Bool",
3172 "_Complex",
3173 "_Imaginary",
3174 "inline",
3175 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003176
3177 // predefined tokens that can also be symbols start here:
3178 "pragma",
3179 "define",
3180 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003181 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003182
Jack Palevich569f1352009-06-29 14:29:08 -07003183 for(int i = 0; keywords[i]; i++) {
3184 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003185 }
Jack Palevich569f1352009-06-29 14:29:08 -07003186 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003187
Jack Palevich36d94142009-06-08 15:55:32 -07003188 struct InputState {
3189 InputStream* pStream;
3190 int oldCh;
3191 };
3192
Jack Palevich2db168f2009-06-11 14:29:47 -07003193 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003194 void* pAddress;
3195 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003196 tokenid_t tok;
3197 size_t level;
3198 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003199 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003200 };
3201
Jack Palevich303d8ff2009-06-11 19:06:24 -07003202 class SymbolStack {
3203 public:
3204 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003205 mpArena = 0;
3206 mpTokenTable = 0;
3207 }
3208
3209 void setArena(Arena* pArena) {
3210 mpArena = pArena;
3211 }
3212
3213 void setTokenTable(TokenTable* pTokenTable) {
3214 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003215 }
3216
3217 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003218 Mark mark;
3219 mark.mArenaMark = mpArena->mark();
3220 mark.mSymbolHead = mStack.size();
3221 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003222 }
3223
3224 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003225 // Undo any shadowing that was done:
3226 Mark mark = mLevelStack.back();
3227 mLevelStack.pop_back();
3228 while (mStack.size() > mark.mSymbolHead) {
3229 VariableInfo* pV = mStack.back();
3230 mStack.pop_back();
3231 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003232 }
Jack Palevich569f1352009-06-29 14:29:08 -07003233 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003234 }
3235
Jack Palevich569f1352009-06-29 14:29:08 -07003236 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3237 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3238 return pV && pV->level == level();
3239 }
3240
3241 VariableInfo* add(tokenid_t tok) {
3242 Token& token = (*mpTokenTable)[tok];
3243 VariableInfo* pOldV = token.mpVariableInfo;
3244 VariableInfo* pNewV =
3245 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3246 memset(pNewV, 0, sizeof(VariableInfo));
3247 pNewV->tok = tok;
3248 pNewV->level = level();
3249 pNewV->pOldDefinition = pOldV;
3250 token.mpVariableInfo = pNewV;
3251 mStack.push_back(pNewV);
3252 return pNewV;
3253 }
3254
Jack Palevich86351982009-06-30 18:09:56 -07003255 VariableInfo* add(Type* pType) {
3256 VariableInfo* pVI = add(pType->id);
3257 pVI->pType = pType;
3258 return pVI;
3259 }
3260
Jack Palevich569f1352009-06-29 14:29:08 -07003261 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3262 for (size_t i = 0; i < mStack.size(); i++) {
3263 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003264 break;
3265 }
3266 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003267 }
3268
Jack Palevich303d8ff2009-06-11 19:06:24 -07003269 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003270 inline size_t level() {
3271 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003272 }
3273
Jack Palevich569f1352009-06-29 14:29:08 -07003274 struct Mark {
3275 Arena::Mark mArenaMark;
3276 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003277 };
3278
Jack Palevich569f1352009-06-29 14:29:08 -07003279 Arena* mpArena;
3280 TokenTable* mpTokenTable;
3281 Vector<VariableInfo*> mStack;
3282 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003283 };
Jack Palevich36d94142009-06-08 15:55:32 -07003284
3285 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003286 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003287 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003288 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003289 int tokl; // token operator level
3290 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003291 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003292 intptr_t loc; // local variable index
3293 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003294 String mTokenString;
Jack Palevich815d8b82009-08-18 18:25:56 -07003295 bool mbSuppressMacroExpansion;
Jack Palevich36d94142009-06-08 15:55:32 -07003296 char* dptr; // Macro state: Points to macro text during macro playback.
3297 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003298 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003299 ACCSymbolLookupFn mpSymbolLookupFn;
3300 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003301
3302 // Arena for the duration of the compile
3303 Arena mGlobalArena;
3304 // Arena for data that's only needed when compiling a single function
3305 Arena mLocalArena;
3306
Jack Palevich2ff5c222009-07-23 15:11:22 -07003307 Arena* mpCurrentArena;
3308
Jack Palevich569f1352009-06-29 14:29:08 -07003309 TokenTable mTokenTable;
3310 SymbolStack mGlobals;
3311 SymbolStack mLocals;
3312
Jack Palevich40600de2009-07-01 15:32:35 -07003313 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003314 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003315 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003316 Type* mkpChar; // char
3317 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003318 Type* mkpFloat;
3319 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003320 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003321 Type* mkpIntPtr;
3322 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003323 Type* mkpFloatPtr;
3324 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003325 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003326
Jack Palevich36d94142009-06-08 15:55:32 -07003327 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003328 int mLineNumber;
3329 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003330
3331 CodeBuf codeBuf;
3332 CodeGenerator* pGen;
3333
Jack Palevicheedf9d22009-06-04 16:23:40 -07003334 String mErrorBuf;
3335
Jack Palevicheedf9d22009-06-04 16:23:40 -07003336 String mPragmas;
3337 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003338 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003339
Jack Palevich21a15a22009-05-11 14:49:29 -07003340 static const int ALLOC_SIZE = 99999;
3341
Jack Palevich303d8ff2009-06-11 19:06:24 -07003342 static const int TOK_DUMMY = 1;
3343 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003344 static const int TOK_NUM_FLOAT = 3;
3345 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003346 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003347
3348 // 3..255 are character and/or operators
3349
Jack Palevich2db168f2009-06-11 14:29:47 -07003350 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003351 // Order has to match string list in "internKeywords".
3352 enum {
3353 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3354 TOK_INT = TOK_KEYWORD,
3355 TOK_CHAR,
3356 TOK_VOID,
3357 TOK_IF,
3358 TOK_ELSE,
3359 TOK_WHILE,
3360 TOK_BREAK,
3361 TOK_RETURN,
3362 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003363 TOK_AUTO,
3364 TOK_CASE,
3365 TOK_CONST,
3366 TOK_CONTINUE,
3367 TOK_DEFAULT,
3368 TOK_DO,
3369 TOK_DOUBLE,
3370 TOK_ENUM,
3371 TOK_EXTERN,
3372 TOK_FLOAT,
3373 TOK_GOTO,
3374 TOK_LONG,
3375 TOK_REGISTER,
3376 TOK_SHORT,
3377 TOK_SIGNED,
3378 TOK_SIZEOF,
3379 TOK_STATIC,
3380 TOK_STRUCT,
3381 TOK_SWITCH,
3382 TOK_TYPEDEF,
3383 TOK_UNION,
3384 TOK_UNSIGNED,
3385 TOK_VOLATILE,
3386 TOK__BOOL,
3387 TOK__COMPLEX,
3388 TOK__IMAGINARY,
3389 TOK_INLINE,
3390 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003391
3392 // Symbols start after keywords
3393
3394 TOK_SYMBOL,
3395 TOK_PRAGMA = TOK_SYMBOL,
3396 TOK_DEFINE,
3397 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003398 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003399
3400 static const int LOCAL = 0x200;
3401
3402 static const int SYM_FORWARD = 0;
3403 static const int SYM_DEFINE = 1;
3404
3405 /* tokens in string heap */
3406 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003407
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003408 static const int OP_INCREMENT = 0;
3409 static const int OP_DECREMENT = 1;
3410 static const int OP_MUL = 2;
3411 static const int OP_DIV = 3;
3412 static const int OP_MOD = 4;
3413 static const int OP_PLUS = 5;
3414 static const int OP_MINUS = 6;
3415 static const int OP_SHIFT_LEFT = 7;
3416 static const int OP_SHIFT_RIGHT = 8;
3417 static const int OP_LESS_EQUAL = 9;
3418 static const int OP_GREATER_EQUAL = 10;
3419 static const int OP_LESS = 11;
3420 static const int OP_GREATER = 12;
3421 static const int OP_EQUALS = 13;
3422 static const int OP_NOT_EQUALS = 14;
3423 static const int OP_LOGICAL_AND = 15;
3424 static const int OP_LOGICAL_OR = 16;
3425 static const int OP_BIT_AND = 17;
3426 static const int OP_BIT_XOR = 18;
3427 static const int OP_BIT_OR = 19;
3428 static const int OP_BIT_NOT = 20;
3429 static const int OP_LOGICAL_NOT = 21;
3430 static const int OP_COUNT = 22;
3431
3432 /* Operators are searched from front, the two-character operators appear
3433 * before the single-character operators with the same first character.
3434 * @ is used to pad out single-character operators.
3435 */
3436 static const char* operatorChars;
3437 static const char operatorLevel[];
3438
Jack Palevich569f1352009-06-29 14:29:08 -07003439 /* Called when we detect an internal problem. Does nothing in production.
3440 *
3441 */
3442 void internalError() {
3443 * (char*) 0 = 0;
3444 }
3445
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003446 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003447 if (!isTrue) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003448 LOGD("assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003449 internalError();
3450 }
Jack Palevich86351982009-06-30 18:09:56 -07003451 }
3452
Jack Palevich40600de2009-07-01 15:32:35 -07003453 bool isSymbol(tokenid_t t) {
3454 return t >= TOK_SYMBOL &&
3455 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3456 }
3457
3458 bool isSymbolOrKeyword(tokenid_t t) {
3459 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003460 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003461 }
3462
Jack Palevich86351982009-06-30 18:09:56 -07003463 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003464 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003465 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3466 if (pV && pV->tok != t) {
3467 internalError();
3468 }
3469 return pV;
3470 }
3471
3472 inline bool isDefined(tokenid_t t) {
3473 return t >= TOK_SYMBOL && VI(t) != 0;
3474 }
3475
Jack Palevich40600de2009-07-01 15:32:35 -07003476 const char* nameof(tokenid_t t) {
3477 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003478 return mTokenTable[t].pText;
3479 }
3480
Jack Palevich21a15a22009-05-11 14:49:29 -07003481 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003482 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003483 }
3484
3485 void inp() {
3486 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003487 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003488 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003489 dptr = 0;
3490 ch = dch;
3491 }
Jack Palevichdc456462009-07-16 16:50:56 -07003492 } else {
3493 if (mbBumpLine) {
3494 mLineNumber++;
3495 mbBumpLine = false;
3496 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003497 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003498 if (ch == '\n') {
3499 mbBumpLine = true;
3500 }
3501 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003502#if 0
3503 printf("ch='%c' 0x%x\n", ch, ch);
3504#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003505 }
3506
3507 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003508 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003509 }
3510
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003511 int decodeHex(int c) {
3512 if (isdigit(c)) {
3513 c -= '0';
3514 } else if (c <= 'F') {
3515 c = c - 'A' + 10;
3516 } else {
3517 c =c - 'a' + 10;
3518 }
3519 return c;
3520 }
3521
Jack Palevichb4758ff2009-06-12 12:49:14 -07003522 /* read a character constant, advances ch to after end of constant */
3523 int getq() {
3524 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003525 if (ch == '\\') {
3526 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003527 if (isoctal(ch)) {
3528 // 1 to 3 octal characters.
3529 val = 0;
3530 for(int i = 0; i < 3; i++) {
3531 if (isoctal(ch)) {
3532 val = (val << 3) + ch - '0';
3533 inp();
3534 }
3535 }
3536 return val;
3537 } else if (ch == 'x' || ch == 'X') {
3538 // N hex chars
3539 inp();
3540 if (! isxdigit(ch)) {
3541 error("'x' character escape requires at least one digit.");
3542 } else {
3543 val = 0;
3544 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003545 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003546 inp();
3547 }
3548 }
3549 } else {
3550 int val = ch;
3551 switch (ch) {
3552 case 'a':
3553 val = '\a';
3554 break;
3555 case 'b':
3556 val = '\b';
3557 break;
3558 case 'f':
3559 val = '\f';
3560 break;
3561 case 'n':
3562 val = '\n';
3563 break;
3564 case 'r':
3565 val = '\r';
3566 break;
3567 case 't':
3568 val = '\t';
3569 break;
3570 case 'v':
3571 val = '\v';
3572 break;
3573 case '\\':
3574 val = '\\';
3575 break;
3576 case '\'':
3577 val = '\'';
3578 break;
3579 case '"':
3580 val = '"';
3581 break;
3582 case '?':
3583 val = '?';
3584 break;
3585 default:
3586 error("Undefined character escape %c", ch);
3587 break;
3588 }
3589 inp();
3590 return val;
3591 }
3592 } else {
3593 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003594 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003595 return val;
3596 }
3597
3598 static bool isoctal(int ch) {
3599 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003600 }
3601
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003602 bool acceptCh(int c) {
3603 bool result = c == ch;
3604 if (result) {
3605 pdef(ch);
3606 inp();
3607 }
3608 return result;
3609 }
3610
3611 bool acceptDigitsCh() {
3612 bool result = false;
3613 while (isdigit(ch)) {
3614 result = true;
3615 pdef(ch);
3616 inp();
3617 }
3618 return result;
3619 }
3620
3621 void parseFloat() {
3622 tok = TOK_NUM_DOUBLE;
3623 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003624 if(mTokenString.len() == 0) {
3625 mTokenString.append('0');
3626 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003627 acceptCh('.');
3628 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003629 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003630 acceptCh('-') || acceptCh('+');
3631 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003632 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003633 if (ch == 'f' || ch == 'F') {
3634 tok = TOK_NUM_FLOAT;
3635 inp();
3636 } else if (ch == 'l' || ch == 'L') {
3637 inp();
3638 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003639 }
3640 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003641 char* pEnd = pText + strlen(pText);
3642 char* pEndPtr = 0;
3643 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003644 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003645 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003646 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003647 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003648 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003649 if (errno || pEndPtr != pEnd) {
3650 error("Can't parse constant: %s", pText);
3651 }
3652 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003653 }
3654
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 void next() {
3656 int l, a;
3657
Jack Palevich546b2242009-05-13 15:10:04 -07003658 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003659 if (ch == '#') {
3660 inp();
3661 next();
3662 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003663 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003664 } else if (tok == TOK_PRAGMA) {
3665 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003666 } else if (tok == TOK_LINE) {
3667 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003668 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003669 error("Unsupported preprocessor directive \"%s\"",
3670 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003671 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003672 }
3673 inp();
3674 }
3675 tokl = 0;
3676 tok = ch;
3677 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003678 if (isdigit(ch) || ch == '.') {
3679 // Start of a numeric constant. Could be integer, float, or
3680 // double, won't know until we look further.
3681 mTokenString.clear();
3682 pdef(ch);
3683 inp();
3684 int base = 10;
3685 if (tok == '0') {
3686 if (ch == 'x' || ch == 'X') {
3687 base = 16;
3688 tok = TOK_NUM;
3689 tokc = 0;
3690 inp();
3691 while ( isxdigit(ch) ) {
3692 tokc = (tokc << 4) + decodeHex(ch);
3693 inp();
3694 }
3695 } else if (isoctal(ch)){
3696 base = 8;
3697 tok = TOK_NUM;
3698 tokc = 0;
3699 while ( isoctal(ch) ) {
3700 tokc = (tokc << 3) + (ch - '0');
3701 inp();
3702 }
3703 }
3704 } else if (isdigit(tok)){
3705 acceptDigitsCh();
3706 }
3707 if (base == 10) {
3708 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3709 parseFloat();
3710 } else {
3711 // It's an integer constant
3712 char* pText = mTokenString.getUnwrapped();
3713 char* pEnd = pText + strlen(pText);
3714 char* pEndPtr = 0;
3715 errno = 0;
3716 tokc = strtol(pText, &pEndPtr, base);
3717 if (errno || pEndPtr != pEnd) {
3718 error("Can't parse constant: %s %d %d", pText, base, errno);
3719 }
3720 tok = TOK_NUM;
3721 }
3722 }
3723 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003724 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003725 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003726 pdef(ch);
3727 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003728 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003729 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
Jack Palevich815d8b82009-08-18 18:25:56 -07003730 if (! mbSuppressMacroExpansion) {
3731 // Is this a macro?
3732 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3733 if (pMacroDefinition) {
3734 // Yes, it is a macro
3735 dptr = pMacroDefinition;
3736 dch = ch;
3737 inp();
3738 next();
3739 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003740 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003741 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003742 inp();
3743 if (tok == '\'') {
3744 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003745 tokc = getq();
3746 if (ch != '\'') {
3747 error("Expected a ' character, got %c", ch);
3748 } else {
3749 inp();
3750 }
Jack Palevich546b2242009-05-13 15:10:04 -07003751 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003752 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003753 while (ch && ch != EOF) {
3754 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003755 inp();
3756 inp();
3757 if (ch == '/')
3758 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003759 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003760 if (ch == EOF) {
3761 error("End of file inside comment.");
3762 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003763 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003764 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003765 } else if ((tok == '/') & (ch == '/')) {
3766 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003767 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003768 inp();
3769 }
3770 inp();
3771 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003772 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003773 const char* t = operatorChars;
3774 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003775 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003776 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003777 tokl = operatorLevel[opIndex];
3778 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003779 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003780#if 0
3781 printf("%c%c -> tokl=%d tokc=0x%x\n",
3782 l, a, tokl, tokc);
3783#endif
3784 if (a == ch) {
3785 inp();
3786 tok = TOK_DUMMY; /* dummy token for double tokens */
3787 }
Jack Palevich0c017742009-07-31 12:00:39 -07003788 /* check for op=, valid for * / % + - << >> & ^ | */
3789 if (ch == '=' &&
3790 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07003791 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07003792 inp();
3793 tok = TOK_OP_ASSIGNMENT;
3794 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003795 break;
3796 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003797 opIndex++;
3798 }
3799 if (l == 0) {
3800 tokl = 0;
3801 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003802 }
3803 }
3804 }
3805#if 0
3806 {
Jack Palevich569f1352009-06-29 14:29:08 -07003807 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003808 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003809 fprintf(stderr, "%s\n", buf.getUnwrapped());
3810 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003811#endif
3812 }
3813
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003814 void doDefine() {
Jack Palevich815d8b82009-08-18 18:25:56 -07003815 mbSuppressMacroExpansion = true;
Jack Palevich569f1352009-06-29 14:29:08 -07003816 next();
Jack Palevich815d8b82009-08-18 18:25:56 -07003817 mbSuppressMacroExpansion = false;
Jack Palevich569f1352009-06-29 14:29:08 -07003818 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003819 String* pName = new String();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003820 if (ch == '(') {
3821 delete pName;
3822 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003823 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003824 }
3825 while (isspace(ch)) {
3826 inp();
3827 }
Jack Palevich569f1352009-06-29 14:29:08 -07003828 String value;
Jack Palevich0b1827a2009-08-18 17:44:12 -07003829 bool appendToValue = true;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003830 while (ch != '\n' && ch != EOF) {
Jack Palevich0b1827a2009-08-18 17:44:12 -07003831 // Check for '//' comments.
3832 if (appendToValue && ch == '/') {
3833 inp();
3834 if (ch == '/') {
3835 appendToValue = false;
3836 } else {
3837 value.append('/');
3838 }
3839 }
3840 if (appendToValue && ch != EOF) {
3841 value.append(ch);
3842 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003843 inp();
3844 }
Jack Palevich569f1352009-06-29 14:29:08 -07003845 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3846 memcpy(pDefn, value.getUnwrapped(), value.len());
3847 pDefn[value.len()] = 0;
3848 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003849 }
3850
Jack Palevicheedf9d22009-06-04 16:23:40 -07003851 void doPragma() {
3852 // # pragma name(val)
3853 int state = 0;
3854 while(ch != EOF && ch != '\n' && state < 10) {
3855 switch(state) {
3856 case 0:
3857 if (isspace(ch)) {
3858 inp();
3859 } else {
3860 state++;
3861 }
3862 break;
3863 case 1:
3864 if (isalnum(ch)) {
3865 mPragmas.append(ch);
3866 inp();
3867 } else if (ch == '(') {
3868 mPragmas.append(0);
3869 inp();
3870 state++;
3871 } else {
3872 state = 11;
3873 }
3874 break;
3875 case 2:
3876 if (isalnum(ch)) {
3877 mPragmas.append(ch);
3878 inp();
3879 } else if (ch == ')') {
3880 mPragmas.append(0);
3881 inp();
3882 state = 10;
3883 } else {
3884 state = 11;
3885 }
3886 break;
3887 }
3888 }
3889 if(state != 10) {
3890 error("Unexpected pragma syntax");
3891 }
3892 mPragmaStringCount += 2;
3893 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003894
Jack Palevichdc456462009-07-16 16:50:56 -07003895 void doLine() {
3896 // # line number { "filename "}
3897 next();
3898 if (tok != TOK_NUM) {
3899 error("Expected a line-number");
3900 } else {
3901 mLineNumber = tokc-1; // The end-of-line will increment it.
3902 }
3903 while(ch != EOF && ch != '\n') {
3904 inp();
3905 }
3906 }
3907
Jack Palevichac0e95e2009-05-29 13:53:44 -07003908 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003909 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003910 mErrorBuf.vprintf(fmt, ap);
3911 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003912 }
3913
Jack Palevich8b0624c2009-05-20 12:12:06 -07003914 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003915 if (tok != c) {
3916 error("'%c' expected", c);
3917 }
3918 next();
3919 }
3920
Jack Palevich86351982009-06-30 18:09:56 -07003921 bool accept(intptr_t c) {
3922 if (tok == c) {
3923 next();
3924 return true;
3925 }
3926 return false;
3927 }
3928
Jack Palevich40600de2009-07-01 15:32:35 -07003929 bool acceptStringLiteral() {
3930 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003931 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003932 // This while loop merges multiple adjacent string constants.
3933 while (tok == '"') {
3934 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003935 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003936 }
3937 if (ch != '"') {
3938 error("Unterminated string constant.");
3939 }
3940 inp();
3941 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003942 }
Jack Palevich40600de2009-07-01 15:32:35 -07003943 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003944 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003945 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003946 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003947
3948 return true;
3949 }
3950 return false;
3951 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003952
Jack Palevichb1544ca2009-07-16 15:09:20 -07003953 void linkGlobal(tokenid_t t, bool isFunction) {
3954 VariableInfo* pVI = VI(t);
3955 void* n = NULL;
3956 if (mpSymbolLookupFn) {
3957 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3958 }
3959 if (pVI->pType == NULL) {
3960 if (isFunction) {
3961 pVI->pType = mkpIntFn;
3962 } else {
3963 pVI->pType = mkpInt;
3964 }
3965 }
3966 pVI->pAddress = n;
3967 }
3968
Jack Palevich29daf572009-07-30 19:38:55 -07003969 void unaryOrAssignment() {
3970 unary();
3971 if (accept('=')) {
3972 checkLVal();
3973 pGen->pushR0();
3974 expr();
3975 pGen->forceR0RVal();
3976 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003977 } else if (tok == TOK_OP_ASSIGNMENT) {
3978 int t = tokc;
3979 next();
3980 checkLVal();
3981 pGen->pushR0();
3982 pGen->forceR0RVal();
3983 pGen->pushR0();
3984 expr();
3985 pGen->forceR0RVal();
3986 pGen->genOp(t);
3987 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003988 }
3989 }
3990
Jack Palevich40600de2009-07-01 15:32:35 -07003991 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003992 */
Jack Palevich29daf572009-07-30 19:38:55 -07003993 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003994 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07003995 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07003996 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003997 if (acceptStringLiteral()) {
3998 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003999 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07004000 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07004001 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004002 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07004003 t = tok;
4004 next();
4005 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004006 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004007 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004008 // Align to 4-byte boundary
4009 glo = (char*) (((intptr_t) glo + 3) & -4);
4010 * (float*) glo = (float) ad;
4011 pGen->loadFloat((int) glo, mkpFloat);
4012 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07004013 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004014 // Align to 8-byte boundary
4015 glo = (char*) (((intptr_t) glo + 7) & -8);
4016 * (double*) glo = ad;
4017 pGen->loadFloat((int) glo, mkpDouble);
4018 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004019 } else if (c == 2) {
4020 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004021 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004022 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004023 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004024 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004025 else if (t == '+') {
4026 // ignore unary plus.
4027 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004028 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004029 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004030 } else if (c == 11) {
4031 // pre increment / pre decrement
4032 unary();
4033 doIncDec(a == OP_INCREMENT, 0);
4034 }
4035 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004036 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004037 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004038 if (pCast) {
4039 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004040 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004041 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004042 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004043 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004044 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004045 skip(')');
4046 }
4047 } else if (t == '*') {
4048 /* This is a pointer dereference.
4049 */
Jack Palevich29daf572009-07-30 19:38:55 -07004050 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004051 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004052 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004053 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004054 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4055 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004057 } else if (t == EOF ) {
4058 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004059 } else if (t == ';') {
4060 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004061 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004062 // Don't have to do anything special here, the error
4063 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004064 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004065 if (!isDefined(t)) {
4066 mGlobals.add(t);
4067 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004068 }
Jack Palevich8df46192009-07-07 14:48:51 -07004069 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004070 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004071 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004072 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004073 linkGlobal(t, tok == '(');
4074 n = (intptr_t) pVI->pAddress;
4075 if (!n && tok != '(') {
4076 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004077 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004078 }
Jack Palevich29daf572009-07-30 19:38:55 -07004079 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004080 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004081 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004082 linkGlobal(t, false);
4083 n = (intptr_t) pVI->pAddress;
4084 if (!n) {
4085 error("Undeclared variable %s\n", nameof(t));
4086 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004087 }
Jack Palevich5b659092009-07-31 14:55:07 -07004088 }
4089 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004090 Type* pVal;
4091 ExpressionType et;
4092 if (pVI->pType->tag == TY_ARRAY) {
4093 pVal = pVI->pType;
4094 et = ET_RVALUE;
4095 } else {
4096 pVal = createPtrType(pVI->pType);
4097 et = ET_LVALUE;
4098 }
Jack Palevich5b659092009-07-31 14:55:07 -07004099 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004100 int tag = pVal->pHead->tag;
4101 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004102 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004103 }
Jack Palevich5b659092009-07-31 14:55:07 -07004104 pGen->leaR0(n, pVal, et);
4105 } else {
4106 pVI->pForward = (void*) pGen->leaForward(
4107 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004108 }
4109 }
4110 }
4111
Jack Palevich5b659092009-07-31 14:55:07 -07004112 /* Now handle postfix operators */
4113 for(;;) {
4114 if (tokl == 11) {
4115 // post inc / post dec
4116 doIncDec(tokc == OP_INCREMENT, true);
4117 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004118 } else if (accept('[')) {
4119 // Array reference
4120 pGen->forceR0RVal();
4121 pGen->pushR0();
4122 commaExpr();
4123 pGen->forceR0RVal();
4124 pGen->genOp(OP_PLUS);
4125 doPointer();
4126 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004127 } else if (accept('(')) {
4128 /* function call */
4129 Type* pDecl = NULL;
4130 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004131 Type* pFn = pGen->getR0Type();
4132 assert(pFn->tag == TY_POINTER);
4133 assert(pFn->pHead->tag == TY_FUNC);
4134 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004135 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004136 Type* pArgList = pDecl->pTail;
4137 bool varArgs = pArgList == NULL;
4138 /* push args and invert order */
4139 a = pGen->beginFunctionCallArguments();
4140 int l = 0;
4141 int argCount = 0;
4142 while (tok != ')' && tok != EOF) {
4143 if (! varArgs && !pArgList) {
4144 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004145 }
Jack Palevich5b659092009-07-31 14:55:07 -07004146 expr();
4147 pGen->forceR0RVal();
4148 Type* pTargetType;
4149 if (pArgList) {
4150 pTargetType = pArgList->pHead;
4151 pArgList = pArgList->pTail;
4152 } else {
4153 // This is a ... function, just pass arguments in their
4154 // natural type.
4155 pTargetType = pGen->getR0Type();
4156 if (pTargetType->tag == TY_FLOAT) {
4157 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004158 } else if (pTargetType->tag == TY_ARRAY) {
4159 // Pass arrays by pointer.
4160 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004161 }
4162 }
4163 if (pTargetType->tag == TY_VOID) {
4164 error("Can't pass void value for argument %d",
4165 argCount + 1);
4166 } else {
4167 l += pGen->storeR0ToArg(l, pTargetType);
4168 }
4169 if (accept(',')) {
4170 // fine
4171 } else if ( tok != ')') {
4172 error("Expected ',' or ')'");
4173 }
4174 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004175 }
Jack Palevich5b659092009-07-31 14:55:07 -07004176 if (! varArgs && pArgList) {
4177 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004178 }
Jack Palevich5b659092009-07-31 14:55:07 -07004179 pGen->endFunctionCallArguments(pDecl, a, l);
4180 skip(')');
4181 pGen->callIndirect(l, pDecl);
4182 pGen->adjustStackAfterCall(pDecl, l, true);
4183 } else {
4184 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004185 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004186 }
4187 }
4188
Jack Palevichaaac9282009-07-31 14:34:34 -07004189 void doIncDec(int isInc, int isPost) {
4190 // R0 already has the lval
4191 checkLVal();
4192 int lit = isInc ? 1 : -1;
4193 pGen->pushR0();
4194 pGen->loadR0FromR0();
4195 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004196 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4197 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004198 error("++/-- illegal for this type. %d", tag);
4199 }
4200 if (isPost) {
4201 pGen->over();
4202 pGen->pushR0();
4203 pGen->li(lit);
4204 pGen->genOp(OP_PLUS);
4205 pGen->storeR0ToTOS();
4206 pGen->popR0();
4207 } else {
4208 pGen->pushR0();
4209 pGen->li(lit);
4210 pGen->genOp(OP_PLUS);
4211 pGen->over();
4212 pGen->storeR0ToTOS();
4213 pGen->popR0();
4214 }
4215 }
4216
Jack Palevich47cbea92009-07-31 15:25:53 -07004217 void doPointer() {
4218 pGen->forceR0RVal();
4219 Type* pR0Type = pGen->getR0Type();
4220 if (pR0Type->tag != TY_POINTER) {
4221 error("Expected a pointer type.");
4222 } else {
4223 if (pR0Type->pHead->tag != TY_FUNC) {
4224 pGen->setR0ExpressionType(ET_LVALUE);
4225 }
4226 }
4227 }
4228
Jack Palevich40600de2009-07-01 15:32:35 -07004229 /* Recursive descent parser for binary operations.
4230 */
4231 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004232 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004233 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004234 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004235 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004236 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004237 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004238 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004239 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004240 t = tokc;
4241 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004242 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004243 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004244 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004245 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004246 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004247 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004248 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004249 // Check for syntax error.
4250 if (pGen->getR0Type() == NULL) {
4251 // We failed to parse a right-hand argument.
4252 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004253 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004254 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004255 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004256 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004257 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004258 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004259 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004260 }
4261 }
4262 }
4263 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004264 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004265 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004266 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004267 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004268 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004269 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004270 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004271 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004272 }
4273 }
4274 }
4275
Jack Palevich43aaee32009-07-31 14:01:37 -07004276 void commaExpr() {
4277 for(;;) {
4278 expr();
4279 if (!accept(',')) {
4280 break;
4281 }
4282 }
4283 }
4284
Jack Palevich21a15a22009-05-11 14:49:29 -07004285 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004286 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004287 }
4288
4289 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004290 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004291 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004292 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004293 }
4294
Jack Palevicha6baa232009-06-12 11:25:59 -07004295 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004296 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004297
Jack Palevich95727a02009-07-06 12:07:15 -07004298 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004299 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004300 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004301 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004302 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004303 next();
4304 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004305 a = test_expr();
4306 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004307 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004308 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004309 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004310 n = pGen->gjmp(0); /* jmp */
4311 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004312 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004313 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004314 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004315 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004316 }
Jack Palevich546b2242009-05-13 15:10:04 -07004317 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004318 t = tok;
4319 next();
4320 skip('(');
4321 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004322 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004323 a = test_expr();
4324 } else {
4325 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004326 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004327 skip(';');
4328 n = codeBuf.getPC();
4329 a = 0;
4330 if (tok != ';')
4331 a = test_expr();
4332 skip(';');
4333 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004334 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004335 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004336 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004337 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004338 n = t + 4;
4339 }
4340 }
4341 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004342 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004343 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004344 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004345 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004346 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004347 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004348 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004349 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004350 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004351 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004352 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004353 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004354 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004355 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004356 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004357 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004358 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004359 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004360 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004361 if (pReturnType->tag == TY_VOID) {
4362 error("Must not return a value from a void function");
4363 } else {
4364 pGen->convertR0(pReturnType);
4365 }
4366 } else {
4367 if (pReturnType->tag != TY_VOID) {
4368 error("Must specify a value here");
4369 }
Jack Palevich8df46192009-07-07 14:48:51 -07004370 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004371 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004372 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004373 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004374 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004375 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004376 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004377 }
4378 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004379
Jack Palevicha8f427f2009-07-13 18:40:08 -07004380 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004381 if (a == b) {
4382 return true;
4383 }
4384 if (a == NULL || b == NULL) {
4385 return false;
4386 }
4387 TypeTag at = a->tag;
4388 if (at != b->tag) {
4389 return false;
4390 }
4391 if (at == TY_POINTER) {
4392 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004393 } else if (at == TY_ARRAY) {
4394 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004395 } else if (at == TY_FUNC || at == TY_PARAM) {
4396 return typeEqual(a->pHead, b->pHead)
4397 && typeEqual(a->pTail, b->pTail);
4398 }
4399 return true;
4400 }
4401
Jack Palevich2ff5c222009-07-23 15:11:22 -07004402 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004403 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004404 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004405 memset(pType, 0, sizeof(*pType));
4406 pType->tag = tag;
4407 pType->pHead = pHead;
4408 pType->pTail = pTail;
4409 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004410 }
4411
Jack Palevich2ff5c222009-07-23 15:11:22 -07004412 Type* createPtrType(Type* pType) {
4413 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004414 }
4415
4416 /**
4417 * Try to print a type in declaration order
4418 */
Jack Palevich86351982009-06-30 18:09:56 -07004419 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004420 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004421 if (pType == NULL) {
4422 buffer.appendCStr("null");
4423 return;
4424 }
Jack Palevich3f226492009-07-02 14:46:19 -07004425 decodeTypeImp(buffer, pType);
4426 }
4427
4428 void decodeTypeImp(String& buffer, Type* pType) {
4429 decodeTypeImpPrefix(buffer, pType);
4430
Jack Palevich86351982009-06-30 18:09:56 -07004431 String temp;
4432 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004433 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004434 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004435 }
4436
4437 decodeTypeImpPostfix(buffer, pType);
4438 }
4439
4440 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4441 TypeTag tag = pType->tag;
4442
Jack Palevich37c54bd2009-07-14 18:35:36 -07004443 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004444 switch (tag) {
4445 case TY_INT:
4446 buffer.appendCStr("int");
4447 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004448 case TY_SHORT:
4449 buffer.appendCStr("short");
4450 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004451 case TY_CHAR:
4452 buffer.appendCStr("char");
4453 break;
4454 case TY_VOID:
4455 buffer.appendCStr("void");
4456 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004457 case TY_FLOAT:
4458 buffer.appendCStr("float");
4459 break;
4460 case TY_DOUBLE:
4461 buffer.appendCStr("double");
4462 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004463 default:
4464 break;
4465 }
Jack Palevich86351982009-06-30 18:09:56 -07004466 buffer.append(' ');
4467 }
Jack Palevich3f226492009-07-02 14:46:19 -07004468
4469 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004470 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004471 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004472 case TY_SHORT:
4473 break;
Jack Palevich86351982009-06-30 18:09:56 -07004474 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004475 break;
4476 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004477 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004478 case TY_FLOAT:
4479 break;
4480 case TY_DOUBLE:
4481 break;
Jack Palevich86351982009-06-30 18:09:56 -07004482 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004483 decodeTypeImpPrefix(buffer, pType->pHead);
4484 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4485 buffer.append('(');
4486 }
4487 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004488 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004489 case TY_ARRAY:
4490 decodeTypeImpPrefix(buffer, pType->pHead);
4491 break;
Jack Palevich86351982009-06-30 18:09:56 -07004492 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004493 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004494 break;
4495 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004496 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004497 break;
4498 default:
4499 String temp;
4500 temp.printf("Unknown tag %d", pType->tag);
4501 buffer.append(temp);
4502 break;
4503 }
Jack Palevich3f226492009-07-02 14:46:19 -07004504 }
4505
4506 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4507 TypeTag tag = pType->tag;
4508
4509 switch(tag) {
4510 case TY_POINTER:
4511 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4512 buffer.append(')');
4513 }
4514 decodeTypeImpPostfix(buffer, pType->pHead);
4515 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004516 case TY_ARRAY:
4517 {
4518 String temp;
4519 temp.printf("[%d]", pType->length);
4520 buffer.append(temp);
4521 }
4522 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004523 case TY_FUNC:
4524 buffer.append('(');
4525 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4526 decodeTypeImp(buffer, pArg);
4527 if (pArg->pTail) {
4528 buffer.appendCStr(", ");
4529 }
4530 }
4531 buffer.append(')');
4532 break;
4533 default:
4534 break;
Jack Palevich86351982009-06-30 18:09:56 -07004535 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004536 }
4537
Jack Palevich86351982009-06-30 18:09:56 -07004538 void printType(Type* pType) {
4539 String buffer;
4540 decodeType(buffer, pType);
4541 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004542 }
4543
Jack Palevich2ff5c222009-07-23 15:11:22 -07004544 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004545 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004546 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004547 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004548 } else if (tok == TOK_SHORT) {
4549 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004550 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004551 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004552 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004553 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004554 } else if (tok == TOK_FLOAT) {
4555 pType = mkpFloat;
4556 } else if (tok == TOK_DOUBLE) {
4557 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004558 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004559 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004560 }
4561 next();
Jack Palevich86351982009-06-30 18:09:56 -07004562 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004563 }
4564
Jack Palevich2ff5c222009-07-23 15:11:22 -07004565 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004566 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004567 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004568 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004569 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004570 if (declName) {
4571 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004572 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004573 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004574
Jack Palevich86351982009-06-30 18:09:56 -07004575 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004576 pType->length = pOldType->length;
4577 } else if (nameRequired) {
4578 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004579 }
Jack Palevich3f226492009-07-02 14:46:19 -07004580 // fprintf(stderr, "Parsed a declaration: ");
4581 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004582 if (reportFailure) {
4583 return NULL;
4584 }
Jack Palevich86351982009-06-30 18:09:56 -07004585 return pType;
4586 }
4587
Jack Palevich2ff5c222009-07-23 15:11:22 -07004588 Type* expectDeclaration(Type* pBaseType) {
4589 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004590 if (! pType) {
4591 error("Expected a declaration");
4592 }
4593 return pType;
4594 }
4595
Jack Palevich3f226492009-07-02 14:46:19 -07004596 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004597 Type* acceptCastTypeDeclaration() {
4598 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004599 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004600 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004601 }
Jack Palevich86351982009-06-30 18:09:56 -07004602 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004603 }
4604
Jack Palevich2ff5c222009-07-23 15:11:22 -07004605 Type* expectCastTypeDeclaration() {
4606 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004607 if (! pType) {
4608 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004609 }
Jack Palevich3f226492009-07-02 14:46:19 -07004610 return pType;
4611 }
4612
4613 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004614 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004615 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004616 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004617 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004618 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004619 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004620 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004621 return pType;
4622 }
4623
4624 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004625 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004626 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004627 // direct-dcl :
4628 // name
4629 // (dcl)
4630 // direct-dcl()
4631 // direct-dcl[]
4632 Type* pNewHead = NULL;
4633 if (accept('(')) {
4634 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004635 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004636 skip(')');
4637 } else if ((declName = acceptSymbol()) != 0) {
4638 if (nameAllowed == false && declName) {
4639 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004640 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004641 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004642 } else if (nameRequired && ! declName) {
4643 String temp;
4644 decodeToken(temp, tok, true);
4645 error("Expected name. Got %s", temp.getUnwrapped());
4646 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004647 }
Jack Palevichb6154502009-08-04 14:56:09 -07004648 for(;;) {
4649 if (accept('(')) {
4650 // Function declaration
4651 Type* pTail = acceptArgs(nameAllowed);
4652 pType = createType(TY_FUNC, pType, pTail);
4653 skip(')');
4654 } if (accept('[')) {
4655 if (tok != ']') {
4656 if (tok != TOK_NUM || tokc <= 0) {
4657 error("Expected positive integer constant");
4658 } else {
4659 Type* pDecayType = createPtrType(pType);
4660 pType = createType(TY_ARRAY, pType, pDecayType);
4661 pType->length = tokc;
4662 }
4663 next();
4664 }
4665 skip(']');
4666 } else {
4667 break;
4668 }
Jack Palevich86351982009-06-30 18:09:56 -07004669 }
Jack Palevich3f226492009-07-02 14:46:19 -07004670
4671 if (pNewHead) {
4672 Type* pA = pNewHead;
4673 while (pA->pHead) {
4674 pA = pA->pHead;
4675 }
4676 pA->pHead = pType;
4677 pType = pNewHead;
4678 }
Jack Palevich86351982009-06-30 18:09:56 -07004679 return pType;
4680 }
4681
Jack Palevich2ff5c222009-07-23 15:11:22 -07004682 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004683 Type* pHead = NULL;
4684 Type* pTail = NULL;
4685 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004686 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004687 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004688 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004689 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004690 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004691 if (!pHead) {
4692 pHead = pParam;
4693 pTail = pParam;
4694 } else {
4695 pTail->pTail = pParam;
4696 pTail = pParam;
4697 }
4698 }
4699 }
4700 if (! accept(',')) {
4701 break;
4702 }
4703 }
4704 return pHead;
4705 }
4706
Jack Palevich2ff5c222009-07-23 15:11:22 -07004707 Type* expectPrimitiveType() {
4708 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004709 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004710 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004711 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004712 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004713 }
Jack Palevich86351982009-06-30 18:09:56 -07004714 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004715 }
4716
Jack Palevichb5e33312009-07-30 19:06:34 -07004717 void checkLVal() {
4718 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4719 error("Expected an lval");
4720 }
4721 }
4722
Jack Palevich86351982009-06-30 18:09:56 -07004723 void addGlobalSymbol(Type* pDecl) {
4724 tokenid_t t = pDecl->id;
4725 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004726 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004727 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004728 }
Jack Palevich86351982009-06-30 18:09:56 -07004729 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004730 }
4731
Jack Palevich86351982009-06-30 18:09:56 -07004732 void reportDuplicate(tokenid_t t) {
4733 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004734 }
4735
Jack Palevich86351982009-06-30 18:09:56 -07004736 void addLocalSymbol(Type* pDecl) {
4737 tokenid_t t = pDecl->id;
4738 if (mLocals.isDefinedAtCurrentLevel(t)) {
4739 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004740 }
Jack Palevich86351982009-06-30 18:09:56 -07004741 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004742 }
4743
Jack Palevich95727a02009-07-06 12:07:15 -07004744 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004745 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004746
Jack Palevich95727a02009-07-06 12:07:15 -07004747 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004748 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004749 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004750 if (!pDecl) {
4751 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004752 }
Jack Palevich86351982009-06-30 18:09:56 -07004753 int variableAddress = 0;
4754 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004755 size_t alignment = pGen->stackAlignmentOf(pDecl);
4756 size_t alignmentMask = ~ (alignment - 1);
4757 size_t sizeOf = pGen->sizeOf(pDecl);
4758 loc = (loc + alignment - 1) & alignmentMask;
4759 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4760 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004761 variableAddress = -loc;
4762 VI(pDecl->id)->pAddress = (void*) variableAddress;
4763 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004764 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004765 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004766 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004767 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004768 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004769 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004770 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004771 if (tok == ',')
4772 next();
4773 }
4774 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004775 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004776 }
4777 }
4778
Jack Palevichf1728be2009-06-12 13:53:51 -07004779 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004780 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004781 }
4782
Jack Palevich37c54bd2009-07-14 18:35:36 -07004783 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004784 if (token == EOF ) {
4785 buffer.printf("EOF");
4786 } else if (token == TOK_NUM) {
4787 buffer.printf("numeric constant");
4788 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004789 if (token < 32) {
4790 buffer.printf("'\\x%02x'", token);
4791 } else {
4792 buffer.printf("'%c'", token);
4793 }
Jack Palevich569f1352009-06-29 14:29:08 -07004794 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004795 if (quote) {
4796 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4797 buffer.printf("keyword \"%s\"", nameof(token));
4798 } else {
4799 buffer.printf("symbol \"%s\"", nameof(token));
4800 }
4801 } else {
4802 buffer.printf("%s", nameof(token));
4803 }
Jack Palevich569f1352009-06-29 14:29:08 -07004804 }
4805 }
4806
Jack Palevich40600de2009-07-01 15:32:35 -07004807 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004808 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004809 if (!result) {
4810 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004811 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004812 error("Expected symbol. Got %s", temp.getUnwrapped());
4813 }
4814 return result;
4815 }
4816
Jack Palevich86351982009-06-30 18:09:56 -07004817 tokenid_t acceptSymbol() {
4818 tokenid_t result = 0;
4819 if (tok >= TOK_SYMBOL) {
4820 result = tok;
4821 next();
Jack Palevich86351982009-06-30 18:09:56 -07004822 }
4823 return result;
4824 }
4825
Jack Palevichb7c81e92009-06-04 19:56:13 -07004826 void globalDeclarations() {
4827 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004828 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004829 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004830 break;
4831 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004832 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004833 if (!pDecl) {
4834 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004835 }
Jack Palevich86351982009-06-30 18:09:56 -07004836 if (! isDefined(pDecl->id)) {
4837 addGlobalSymbol(pDecl);
4838 }
4839 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004840 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004841 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004842 }
Jack Palevich86351982009-06-30 18:09:56 -07004843 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004844 // it's a variable declaration
4845 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004846 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004847 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004848 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004849 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004850 }
Jack Palevich86351982009-06-30 18:09:56 -07004851 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004852 if (tok == TOK_NUM) {
4853 if (name) {
4854 * (int*) name->pAddress = tokc;
4855 }
4856 next();
4857 } else {
4858 error("Expected an integer constant");
4859 }
4860 }
Jack Palevich86351982009-06-30 18:09:56 -07004861 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004862 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004863 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004864 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004865 if (!pDecl) {
4866 break;
4867 }
4868 if (! isDefined(pDecl->id)) {
4869 addGlobalSymbol(pDecl);
4870 }
4871 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004872 }
4873 skip(';');
4874 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004875 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004876 if (accept(';')) {
4877 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004878 } else if (tok != '{') {
4879 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004880 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004881 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004882 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004883 /* patch forward references */
4884 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004885 /* put function address */
4886 name->pAddress = (void*) codeBuf.getPC();
4887 }
4888 // Calculate stack offsets for parameters
4889 mLocals.pushLevel();
4890 intptr_t a = 8;
4891 int argCount = 0;
4892 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4893 Type* pArg = pP->pHead;
4894 addLocalSymbol(pArg);
4895 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004896 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004897 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004898 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004899 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004900 argCount++;
4901 }
4902 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004903 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004904 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004905 block(0, true);
4906 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004907 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004908 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004909 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004910 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004911 }
4912 }
4913 }
4914
Jack Palevich9cbd2262009-07-08 16:48:41 -07004915 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4916 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4917 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004918 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004919 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004920 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004921 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004922 char* result = (char*) base;
4923 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004924 return result;
4925 }
4926
Jack Palevich21a15a22009-05-11 14:49:29 -07004927 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004928 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004929 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004930 pGlobalBase = 0;
4931 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004932 if (pGen) {
4933 delete pGen;
4934 pGen = 0;
4935 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004936 if (file) {
4937 delete file;
4938 file = 0;
4939 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004940 }
4941
Jack Palevich8c246a92009-07-14 21:14:10 -07004942 // One-time initialization, when class is constructed.
4943 void init() {
4944 mpSymbolLookupFn = 0;
4945 mpSymbolLookupContext = 0;
4946 }
4947
Jack Palevich21a15a22009-05-11 14:49:29 -07004948 void clear() {
4949 tok = 0;
4950 tokc = 0;
4951 tokl = 0;
4952 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004953 rsym = 0;
4954 loc = 0;
4955 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004956 dptr = 0;
4957 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004958 file = 0;
4959 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004960 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004961 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004962 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004963 mLineNumber = 1;
4964 mbBumpLine = false;
Jack Palevich815d8b82009-08-18 18:25:56 -07004965 mbSuppressMacroExpansion = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004966 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004967
Jack Palevich22305132009-05-13 10:58:45 -07004968 void setArchitecture(const char* architecture) {
4969 delete pGen;
4970 pGen = 0;
4971
4972 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004973#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004974 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004975 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004976 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004977#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004978#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004979 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004980 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004981 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004982#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004983 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004984 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004985 }
4986 }
4987
4988 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004989#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004990 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004991#elif defined(DEFAULT_X86_CODEGEN)
4992 pGen = new X86CodeGenerator();
4993#endif
4994 }
4995 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004996 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004997 } else {
4998 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004999 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07005000 }
5001 }
5002
Jack Palevich77ae76e2009-05-10 19:59:24 -07005003public:
Jack Palevich22305132009-05-13 10:58:45 -07005004 struct args {
5005 args() {
5006 architecture = 0;
5007 }
5008 const char* architecture;
5009 };
5010
Jack Paleviche7b59062009-05-19 17:12:17 -07005011 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07005012 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07005013 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07005014 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005015
Jack Paleviche7b59062009-05-19 17:12:17 -07005016 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005017 cleanup();
5018 }
5019
Jack Palevich8c246a92009-07-14 21:14:10 -07005020 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5021 mpSymbolLookupFn = pFn;
5022 mpSymbolLookupContext = pContext;
5023 }
5024
Jack Palevich1cdef202009-05-22 12:06:27 -07005025 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005026 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005027
Jack Palevich2ff5c222009-07-23 15:11:22 -07005028 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005029 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005030 cleanup();
5031 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005032 mTokenTable.setArena(&mGlobalArena);
5033 mGlobals.setArena(&mGlobalArena);
5034 mGlobals.setTokenTable(&mTokenTable);
5035 mLocals.setArena(&mLocalArena);
5036 mLocals.setTokenTable(&mTokenTable);
5037
5038 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005039 codeBuf.init(ALLOC_SIZE);
5040 setArchitecture(NULL);
5041 if (!pGen) {
5042 return -1;
5043 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005044#ifdef PROVIDE_TRACE_CODEGEN
5045 pGen = new TraceCodeGenerator(pGen);
5046#endif
5047 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005048 pGen->init(&codeBuf);
5049 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005050 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5051 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005052 inp();
5053 next();
5054 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005055 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005056 result = pGen->finishCompile();
5057 if (result == 0) {
5058 if (mErrorBuf.len()) {
5059 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005060 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005061 }
Jack Palevichce105a92009-07-16 14:30:33 -07005062 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005063 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005064 }
5065
Jack Palevich86351982009-06-30 18:09:56 -07005066 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005067 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005068 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005069 mkpChar = createType(TY_CHAR, NULL, NULL);
5070 mkpVoid = createType(TY_VOID, NULL, NULL);
5071 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5072 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5073 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5074 mkpIntPtr = createPtrType(mkpInt);
5075 mkpCharPtr = createPtrType(mkpChar);
5076 mkpFloatPtr = createPtrType(mkpFloat);
5077 mkpDoublePtr = createPtrType(mkpDouble);
5078 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005079 }
5080
Jack Palevicha6baa232009-06-12 11:25:59 -07005081 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005082 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005083 }
5084
Jack Palevich569f1352009-06-29 14:29:08 -07005085 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005086 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005087 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005088 }
5089
Jack Palevich569f1352009-06-29 14:29:08 -07005090 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005091 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005092 error("Undefined forward reference: %s",
5093 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005094 }
5095 return true;
5096 }
5097
Jack Palevich21a15a22009-05-11 14:49:29 -07005098 int dump(FILE* out) {
5099 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5100 return 0;
5101 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005102
Jack Palevicha6535612009-05-13 16:24:17 -07005103 int disassemble(FILE* out) {
5104 return pGen->disassemble(out);
5105 }
5106
Jack Palevich1cdef202009-05-22 12:06:27 -07005107 /* Look through the symbol table to find a symbol.
5108 * If found, return its value.
5109 */
5110 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005111 if (mCompileResult == 0) {
5112 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5113 VariableInfo* pVariableInfo = VI(tok);
5114 if (pVariableInfo) {
5115 return pVariableInfo->pAddress;
5116 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005117 }
5118 return NULL;
5119 }
5120
Jack Palevicheedf9d22009-06-04 16:23:40 -07005121 void getPragmas(ACCsizei* actualStringCount,
5122 ACCsizei maxStringCount, ACCchar** strings) {
5123 int stringCount = mPragmaStringCount;
5124 if (actualStringCount) {
5125 *actualStringCount = stringCount;
5126 }
5127 if (stringCount > maxStringCount) {
5128 stringCount = maxStringCount;
5129 }
5130 if (strings) {
5131 char* pPragmas = mPragmas.getUnwrapped();
5132 while (stringCount-- > 0) {
5133 *strings++ = pPragmas;
5134 pPragmas += strlen(pPragmas) + 1;
5135 }
5136 }
5137 }
5138
Jack Palevichac0e95e2009-05-29 13:53:44 -07005139 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005140 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005141 }
5142
Jack Palevich77ae76e2009-05-10 19:59:24 -07005143};
5144
Jack Paleviche7b59062009-05-19 17:12:17 -07005145const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005146 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5147
Jack Paleviche7b59062009-05-19 17:12:17 -07005148const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005149 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5150 5, 5, /* ==, != */
5151 9, 10, /* &&, || */
5152 6, 7, 8, /* & ^ | */
5153 2, 2 /* ~ ! */
5154 };
5155
Jack Palevich8b0624c2009-05-20 12:12:06 -07005156#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005157FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005158#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005159
Jack Palevich8b0624c2009-05-20 12:12:06 -07005160#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005161const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005162 0x1, // ++
5163 0xff, // --
5164 0xc1af0f, // *
5165 0xf9f79991, // /
5166 0xf9f79991, // % (With manual assist to swap results)
5167 0xc801, // +
5168 0xd8f7c829, // -
5169 0xe0d391, // <<
5170 0xf8d391, // >>
5171 0xe, // <=
5172 0xd, // >=
5173 0xc, // <
5174 0xf, // >
5175 0x4, // ==
5176 0x5, // !=
5177 0x0, // &&
5178 0x1, // ||
5179 0xc821, // &
5180 0xc831, // ^
5181 0xc809, // |
5182 0xd0f7, // ~
5183 0x4 // !
5184};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005185#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005186
Jack Palevich1cdef202009-05-22 12:06:27 -07005187struct ACCscript {
5188 ACCscript() {
5189 text = 0;
5190 textLength = 0;
5191 accError = ACC_NO_ERROR;
5192 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005193
Jack Palevich1cdef202009-05-22 12:06:27 -07005194 ~ACCscript() {
5195 delete text;
5196 }
Jack Palevich546b2242009-05-13 15:10:04 -07005197
Jack Palevich8c246a92009-07-14 21:14:10 -07005198 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5199 compiler.registerSymbolCallback(pFn, pContext);
5200 }
5201
Jack Palevich1cdef202009-05-22 12:06:27 -07005202 void setError(ACCenum error) {
5203 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5204 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005205 }
5206 }
5207
Jack Palevich1cdef202009-05-22 12:06:27 -07005208 ACCenum getError() {
5209 ACCenum result = accError;
5210 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005211 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005212 }
5213
Jack Palevich1cdef202009-05-22 12:06:27 -07005214 Compiler compiler;
5215 char* text;
5216 int textLength;
5217 ACCenum accError;
5218};
5219
5220
5221extern "C"
5222ACCscript* accCreateScript() {
5223 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005224}
Jack Palevich1cdef202009-05-22 12:06:27 -07005225
5226extern "C"
5227ACCenum accGetError( ACCscript* script ) {
5228 return script->getError();
5229}
5230
5231extern "C"
5232void accDeleteScript(ACCscript* script) {
5233 delete script;
5234}
5235
5236extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005237void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5238 ACCvoid* pContext) {
5239 script->registerSymbolCallback(pFn, pContext);
5240}
5241
5242extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005243void accScriptSource(ACCscript* script,
5244 ACCsizei count,
5245 const ACCchar ** string,
5246 const ACCint * length) {
5247 int totalLength = 0;
5248 for(int i = 0; i < count; i++) {
5249 int len = -1;
5250 const ACCchar* s = string[i];
5251 if (length) {
5252 len = length[i];
5253 }
5254 if (len < 0) {
5255 len = strlen(s);
5256 }
5257 totalLength += len;
5258 }
5259 delete script->text;
5260 char* text = new char[totalLength + 1];
5261 script->text = text;
5262 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005263 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005264 for(int i = 0; i < count; i++) {
5265 int len = -1;
5266 const ACCchar* s = string[i];
5267 if (length) {
5268 len = length[i];
5269 }
5270 if (len < 0) {
5271 len = strlen(s);
5272 }
Jack Palevich09555c72009-05-27 12:25:55 -07005273 memcpy(dest, s, len);
5274 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005275 }
5276 text[totalLength] = '\0';
5277}
5278
5279extern "C"
5280void accCompileScript(ACCscript* script) {
5281 int result = script->compiler.compile(script->text, script->textLength);
5282 if (result) {
5283 script->setError(ACC_INVALID_OPERATION);
5284 }
5285}
5286
5287extern "C"
5288void accGetScriptiv(ACCscript* script,
5289 ACCenum pname,
5290 ACCint * params) {
5291 switch (pname) {
5292 case ACC_INFO_LOG_LENGTH:
5293 *params = 0;
5294 break;
5295 }
5296}
5297
5298extern "C"
5299void accGetScriptInfoLog(ACCscript* script,
5300 ACCsizei maxLength,
5301 ACCsizei * length,
5302 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005303 char* message = script->compiler.getErrorMessage();
5304 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005305 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005306 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005307 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005308 if (infoLog && maxLength > 0) {
5309 int trimmedLength = maxLength < messageLength ?
5310 maxLength : messageLength;
5311 memcpy(infoLog, message, trimmedLength);
5312 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005313 }
5314}
5315
5316extern "C"
5317void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5318 ACCvoid ** address) {
5319 void* value = script->compiler.lookup(name);
5320 if (value) {
5321 *address = value;
5322 } else {
5323 script->setError(ACC_INVALID_VALUE);
5324 }
5325}
5326
Jack Palevicheedf9d22009-06-04 16:23:40 -07005327extern "C"
5328void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5329 ACCsizei maxStringCount, ACCchar** strings){
5330 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5331}
5332
-b master422972c2009-06-17 19:13:52 -07005333extern "C"
5334void accDisassemble(ACCscript* script) {
5335 script->compiler.disassemble(stderr);
5336}
5337
Jack Palevicheedf9d22009-06-04 16:23:40 -07005338
Jack Palevich1cdef202009-05-22 12:06:27 -07005339} // namespace acc
5340