blob: 684d807c463925de275e614d9ae840e1be97ce3a [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 Palevich36d94142009-06-08 15:55:32 -07003295 char* dptr; // Macro state: Points to macro text during macro playback.
3296 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003297 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003298 ACCSymbolLookupFn mpSymbolLookupFn;
3299 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003300
3301 // Arena for the duration of the compile
3302 Arena mGlobalArena;
3303 // Arena for data that's only needed when compiling a single function
3304 Arena mLocalArena;
3305
Jack Palevich2ff5c222009-07-23 15:11:22 -07003306 Arena* mpCurrentArena;
3307
Jack Palevich569f1352009-06-29 14:29:08 -07003308 TokenTable mTokenTable;
3309 SymbolStack mGlobals;
3310 SymbolStack mLocals;
3311
Jack Palevich40600de2009-07-01 15:32:35 -07003312 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003313 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003314 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003315 Type* mkpChar; // char
3316 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003317 Type* mkpFloat;
3318 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003319 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003320 Type* mkpIntPtr;
3321 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003322 Type* mkpFloatPtr;
3323 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003324 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003325
Jack Palevich36d94142009-06-08 15:55:32 -07003326 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003327 int mLineNumber;
3328 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003329
3330 CodeBuf codeBuf;
3331 CodeGenerator* pGen;
3332
Jack Palevicheedf9d22009-06-04 16:23:40 -07003333 String mErrorBuf;
3334
Jack Palevicheedf9d22009-06-04 16:23:40 -07003335 String mPragmas;
3336 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003337 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003338
Jack Palevich21a15a22009-05-11 14:49:29 -07003339 static const int ALLOC_SIZE = 99999;
3340
Jack Palevich303d8ff2009-06-11 19:06:24 -07003341 static const int TOK_DUMMY = 1;
3342 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003343 static const int TOK_NUM_FLOAT = 3;
3344 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003345 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003346
3347 // 3..255 are character and/or operators
3348
Jack Palevich2db168f2009-06-11 14:29:47 -07003349 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003350 // Order has to match string list in "internKeywords".
3351 enum {
3352 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3353 TOK_INT = TOK_KEYWORD,
3354 TOK_CHAR,
3355 TOK_VOID,
3356 TOK_IF,
3357 TOK_ELSE,
3358 TOK_WHILE,
3359 TOK_BREAK,
3360 TOK_RETURN,
3361 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003362 TOK_AUTO,
3363 TOK_CASE,
3364 TOK_CONST,
3365 TOK_CONTINUE,
3366 TOK_DEFAULT,
3367 TOK_DO,
3368 TOK_DOUBLE,
3369 TOK_ENUM,
3370 TOK_EXTERN,
3371 TOK_FLOAT,
3372 TOK_GOTO,
3373 TOK_LONG,
3374 TOK_REGISTER,
3375 TOK_SHORT,
3376 TOK_SIGNED,
3377 TOK_SIZEOF,
3378 TOK_STATIC,
3379 TOK_STRUCT,
3380 TOK_SWITCH,
3381 TOK_TYPEDEF,
3382 TOK_UNION,
3383 TOK_UNSIGNED,
3384 TOK_VOLATILE,
3385 TOK__BOOL,
3386 TOK__COMPLEX,
3387 TOK__IMAGINARY,
3388 TOK_INLINE,
3389 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003390
3391 // Symbols start after keywords
3392
3393 TOK_SYMBOL,
3394 TOK_PRAGMA = TOK_SYMBOL,
3395 TOK_DEFINE,
3396 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003397 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003398
3399 static const int LOCAL = 0x200;
3400
3401 static const int SYM_FORWARD = 0;
3402 static const int SYM_DEFINE = 1;
3403
3404 /* tokens in string heap */
3405 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003406
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003407 static const int OP_INCREMENT = 0;
3408 static const int OP_DECREMENT = 1;
3409 static const int OP_MUL = 2;
3410 static const int OP_DIV = 3;
3411 static const int OP_MOD = 4;
3412 static const int OP_PLUS = 5;
3413 static const int OP_MINUS = 6;
3414 static const int OP_SHIFT_LEFT = 7;
3415 static const int OP_SHIFT_RIGHT = 8;
3416 static const int OP_LESS_EQUAL = 9;
3417 static const int OP_GREATER_EQUAL = 10;
3418 static const int OP_LESS = 11;
3419 static const int OP_GREATER = 12;
3420 static const int OP_EQUALS = 13;
3421 static const int OP_NOT_EQUALS = 14;
3422 static const int OP_LOGICAL_AND = 15;
3423 static const int OP_LOGICAL_OR = 16;
3424 static const int OP_BIT_AND = 17;
3425 static const int OP_BIT_XOR = 18;
3426 static const int OP_BIT_OR = 19;
3427 static const int OP_BIT_NOT = 20;
3428 static const int OP_LOGICAL_NOT = 21;
3429 static const int OP_COUNT = 22;
3430
3431 /* Operators are searched from front, the two-character operators appear
3432 * before the single-character operators with the same first character.
3433 * @ is used to pad out single-character operators.
3434 */
3435 static const char* operatorChars;
3436 static const char operatorLevel[];
3437
Jack Palevich569f1352009-06-29 14:29:08 -07003438 /* Called when we detect an internal problem. Does nothing in production.
3439 *
3440 */
3441 void internalError() {
3442 * (char*) 0 = 0;
3443 }
3444
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003445 void assertImpl(bool isTrue, int line) {
Jack Palevich86351982009-06-30 18:09:56 -07003446 if (!isTrue) {
Jack Palevich7f5b1a22009-08-17 16:54:56 -07003447 LOGD("assertion failed at line %s:%d.", __FILE__, line);
Jack Palevich569f1352009-06-29 14:29:08 -07003448 internalError();
3449 }
Jack Palevich86351982009-06-30 18:09:56 -07003450 }
3451
Jack Palevich40600de2009-07-01 15:32:35 -07003452 bool isSymbol(tokenid_t t) {
3453 return t >= TOK_SYMBOL &&
3454 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3455 }
3456
3457 bool isSymbolOrKeyword(tokenid_t t) {
3458 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003459 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003460 }
3461
Jack Palevich86351982009-06-30 18:09:56 -07003462 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003463 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003464 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3465 if (pV && pV->tok != t) {
3466 internalError();
3467 }
3468 return pV;
3469 }
3470
3471 inline bool isDefined(tokenid_t t) {
3472 return t >= TOK_SYMBOL && VI(t) != 0;
3473 }
3474
Jack Palevich40600de2009-07-01 15:32:35 -07003475 const char* nameof(tokenid_t t) {
3476 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003477 return mTokenTable[t].pText;
3478 }
3479
Jack Palevich21a15a22009-05-11 14:49:29 -07003480 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003481 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003482 }
3483
3484 void inp() {
3485 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003486 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003487 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003488 dptr = 0;
3489 ch = dch;
3490 }
Jack Palevichdc456462009-07-16 16:50:56 -07003491 } else {
3492 if (mbBumpLine) {
3493 mLineNumber++;
3494 mbBumpLine = false;
3495 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003496 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003497 if (ch == '\n') {
3498 mbBumpLine = true;
3499 }
3500 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003501#if 0
3502 printf("ch='%c' 0x%x\n", ch, ch);
3503#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003504 }
3505
3506 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003507 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003508 }
3509
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003510 int decodeHex(int c) {
3511 if (isdigit(c)) {
3512 c -= '0';
3513 } else if (c <= 'F') {
3514 c = c - 'A' + 10;
3515 } else {
3516 c =c - 'a' + 10;
3517 }
3518 return c;
3519 }
3520
Jack Palevichb4758ff2009-06-12 12:49:14 -07003521 /* read a character constant, advances ch to after end of constant */
3522 int getq() {
3523 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003524 if (ch == '\\') {
3525 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003526 if (isoctal(ch)) {
3527 // 1 to 3 octal characters.
3528 val = 0;
3529 for(int i = 0; i < 3; i++) {
3530 if (isoctal(ch)) {
3531 val = (val << 3) + ch - '0';
3532 inp();
3533 }
3534 }
3535 return val;
3536 } else if (ch == 'x' || ch == 'X') {
3537 // N hex chars
3538 inp();
3539 if (! isxdigit(ch)) {
3540 error("'x' character escape requires at least one digit.");
3541 } else {
3542 val = 0;
3543 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003544 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003545 inp();
3546 }
3547 }
3548 } else {
3549 int val = ch;
3550 switch (ch) {
3551 case 'a':
3552 val = '\a';
3553 break;
3554 case 'b':
3555 val = '\b';
3556 break;
3557 case 'f':
3558 val = '\f';
3559 break;
3560 case 'n':
3561 val = '\n';
3562 break;
3563 case 'r':
3564 val = '\r';
3565 break;
3566 case 't':
3567 val = '\t';
3568 break;
3569 case 'v':
3570 val = '\v';
3571 break;
3572 case '\\':
3573 val = '\\';
3574 break;
3575 case '\'':
3576 val = '\'';
3577 break;
3578 case '"':
3579 val = '"';
3580 break;
3581 case '?':
3582 val = '?';
3583 break;
3584 default:
3585 error("Undefined character escape %c", ch);
3586 break;
3587 }
3588 inp();
3589 return val;
3590 }
3591 } else {
3592 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003593 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003594 return val;
3595 }
3596
3597 static bool isoctal(int ch) {
3598 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003599 }
3600
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003601 bool acceptCh(int c) {
3602 bool result = c == ch;
3603 if (result) {
3604 pdef(ch);
3605 inp();
3606 }
3607 return result;
3608 }
3609
3610 bool acceptDigitsCh() {
3611 bool result = false;
3612 while (isdigit(ch)) {
3613 result = true;
3614 pdef(ch);
3615 inp();
3616 }
3617 return result;
3618 }
3619
3620 void parseFloat() {
3621 tok = TOK_NUM_DOUBLE;
3622 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003623 if(mTokenString.len() == 0) {
3624 mTokenString.append('0');
3625 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003626 acceptCh('.');
3627 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003628 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003629 acceptCh('-') || acceptCh('+');
3630 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003631 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003632 if (ch == 'f' || ch == 'F') {
3633 tok = TOK_NUM_FLOAT;
3634 inp();
3635 } else if (ch == 'l' || ch == 'L') {
3636 inp();
3637 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003638 }
3639 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003640 char* pEnd = pText + strlen(pText);
3641 char* pEndPtr = 0;
3642 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003643 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003644 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003645 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003646 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003647 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003648 if (errno || pEndPtr != pEnd) {
3649 error("Can't parse constant: %s", pText);
3650 }
3651 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003652 }
3653
Jack Palevich21a15a22009-05-11 14:49:29 -07003654 void next() {
3655 int l, a;
3656
Jack Palevich546b2242009-05-13 15:10:04 -07003657 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003658 if (ch == '#') {
3659 inp();
3660 next();
3661 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003662 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003663 } else if (tok == TOK_PRAGMA) {
3664 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003665 } else if (tok == TOK_LINE) {
3666 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003667 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003668 error("Unsupported preprocessor directive \"%s\"",
3669 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003670 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003671 }
3672 inp();
3673 }
3674 tokl = 0;
3675 tok = ch;
3676 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003677 if (isdigit(ch) || ch == '.') {
3678 // Start of a numeric constant. Could be integer, float, or
3679 // double, won't know until we look further.
3680 mTokenString.clear();
3681 pdef(ch);
3682 inp();
3683 int base = 10;
3684 if (tok == '0') {
3685 if (ch == 'x' || ch == 'X') {
3686 base = 16;
3687 tok = TOK_NUM;
3688 tokc = 0;
3689 inp();
3690 while ( isxdigit(ch) ) {
3691 tokc = (tokc << 4) + decodeHex(ch);
3692 inp();
3693 }
3694 } else if (isoctal(ch)){
3695 base = 8;
3696 tok = TOK_NUM;
3697 tokc = 0;
3698 while ( isoctal(ch) ) {
3699 tokc = (tokc << 3) + (ch - '0');
3700 inp();
3701 }
3702 }
3703 } else if (isdigit(tok)){
3704 acceptDigitsCh();
3705 }
3706 if (base == 10) {
3707 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3708 parseFloat();
3709 } else {
3710 // It's an integer constant
3711 char* pText = mTokenString.getUnwrapped();
3712 char* pEnd = pText + strlen(pText);
3713 char* pEndPtr = 0;
3714 errno = 0;
3715 tokc = strtol(pText, &pEndPtr, base);
3716 if (errno || pEndPtr != pEnd) {
3717 error("Can't parse constant: %s %d %d", pText, base, errno);
3718 }
3719 tok = TOK_NUM;
3720 }
3721 }
3722 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003723 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003724 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003725 pdef(ch);
3726 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003727 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003728 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3729 // Is this a macro?
3730 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3731 if (pMacroDefinition) {
3732 // Yes, it is a macro
3733 dptr = pMacroDefinition;
3734 dch = ch;
3735 inp();
3736 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003737 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003738 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003739 inp();
3740 if (tok == '\'') {
3741 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003742 tokc = getq();
3743 if (ch != '\'') {
3744 error("Expected a ' character, got %c", ch);
3745 } else {
3746 inp();
3747 }
Jack Palevich546b2242009-05-13 15:10:04 -07003748 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003749 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003750 while (ch && ch != EOF) {
3751 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003752 inp();
3753 inp();
3754 if (ch == '/')
3755 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003756 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003757 if (ch == EOF) {
3758 error("End of file inside comment.");
3759 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003760 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003761 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003762 } else if ((tok == '/') & (ch == '/')) {
3763 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003764 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003765 inp();
3766 }
3767 inp();
3768 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003769 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003770 const char* t = operatorChars;
3771 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003772 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003773 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003774 tokl = operatorLevel[opIndex];
3775 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003776 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003777#if 0
3778 printf("%c%c -> tokl=%d tokc=0x%x\n",
3779 l, a, tokl, tokc);
3780#endif
3781 if (a == ch) {
3782 inp();
3783 tok = TOK_DUMMY; /* dummy token for double tokens */
3784 }
Jack Palevich0c017742009-07-31 12:00:39 -07003785 /* check for op=, valid for * / % + - << >> & ^ | */
3786 if (ch == '=' &&
3787 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07003788 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07003789 inp();
3790 tok = TOK_OP_ASSIGNMENT;
3791 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003792 break;
3793 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003794 opIndex++;
3795 }
3796 if (l == 0) {
3797 tokl = 0;
3798 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003799 }
3800 }
3801 }
3802#if 0
3803 {
Jack Palevich569f1352009-06-29 14:29:08 -07003804 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003805 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003806 fprintf(stderr, "%s\n", buf.getUnwrapped());
3807 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003808#endif
3809 }
3810
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003811 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003812 next();
3813 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003814 String* pName = new String();
3815 while (isspace(ch)) {
3816 inp();
3817 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003818 if (ch == '(') {
3819 delete pName;
3820 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003821 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003822 }
3823 while (isspace(ch)) {
3824 inp();
3825 }
Jack Palevich569f1352009-06-29 14:29:08 -07003826 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003827 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003828 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003829 inp();
3830 }
Jack Palevich569f1352009-06-29 14:29:08 -07003831 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3832 memcpy(pDefn, value.getUnwrapped(), value.len());
3833 pDefn[value.len()] = 0;
3834 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003835 }
3836
Jack Palevicheedf9d22009-06-04 16:23:40 -07003837 void doPragma() {
3838 // # pragma name(val)
3839 int state = 0;
3840 while(ch != EOF && ch != '\n' && state < 10) {
3841 switch(state) {
3842 case 0:
3843 if (isspace(ch)) {
3844 inp();
3845 } else {
3846 state++;
3847 }
3848 break;
3849 case 1:
3850 if (isalnum(ch)) {
3851 mPragmas.append(ch);
3852 inp();
3853 } else if (ch == '(') {
3854 mPragmas.append(0);
3855 inp();
3856 state++;
3857 } else {
3858 state = 11;
3859 }
3860 break;
3861 case 2:
3862 if (isalnum(ch)) {
3863 mPragmas.append(ch);
3864 inp();
3865 } else if (ch == ')') {
3866 mPragmas.append(0);
3867 inp();
3868 state = 10;
3869 } else {
3870 state = 11;
3871 }
3872 break;
3873 }
3874 }
3875 if(state != 10) {
3876 error("Unexpected pragma syntax");
3877 }
3878 mPragmaStringCount += 2;
3879 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003880
Jack Palevichdc456462009-07-16 16:50:56 -07003881 void doLine() {
3882 // # line number { "filename "}
3883 next();
3884 if (tok != TOK_NUM) {
3885 error("Expected a line-number");
3886 } else {
3887 mLineNumber = tokc-1; // The end-of-line will increment it.
3888 }
3889 while(ch != EOF && ch != '\n') {
3890 inp();
3891 }
3892 }
3893
Jack Palevichac0e95e2009-05-29 13:53:44 -07003894 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003895 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003896 mErrorBuf.vprintf(fmt, ap);
3897 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003898 }
3899
Jack Palevich8b0624c2009-05-20 12:12:06 -07003900 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003901 if (tok != c) {
3902 error("'%c' expected", c);
3903 }
3904 next();
3905 }
3906
Jack Palevich86351982009-06-30 18:09:56 -07003907 bool accept(intptr_t c) {
3908 if (tok == c) {
3909 next();
3910 return true;
3911 }
3912 return false;
3913 }
3914
Jack Palevich40600de2009-07-01 15:32:35 -07003915 bool acceptStringLiteral() {
3916 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003917 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003918 // This while loop merges multiple adjacent string constants.
3919 while (tok == '"') {
3920 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003921 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003922 }
3923 if (ch != '"') {
3924 error("Unterminated string constant.");
3925 }
3926 inp();
3927 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003928 }
Jack Palevich40600de2009-07-01 15:32:35 -07003929 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003930 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003931 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003932 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003933
3934 return true;
3935 }
3936 return false;
3937 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003938
Jack Palevichb1544ca2009-07-16 15:09:20 -07003939 void linkGlobal(tokenid_t t, bool isFunction) {
3940 VariableInfo* pVI = VI(t);
3941 void* n = NULL;
3942 if (mpSymbolLookupFn) {
3943 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3944 }
3945 if (pVI->pType == NULL) {
3946 if (isFunction) {
3947 pVI->pType = mkpIntFn;
3948 } else {
3949 pVI->pType = mkpInt;
3950 }
3951 }
3952 pVI->pAddress = n;
3953 }
3954
Jack Palevich29daf572009-07-30 19:38:55 -07003955 void unaryOrAssignment() {
3956 unary();
3957 if (accept('=')) {
3958 checkLVal();
3959 pGen->pushR0();
3960 expr();
3961 pGen->forceR0RVal();
3962 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003963 } else if (tok == TOK_OP_ASSIGNMENT) {
3964 int t = tokc;
3965 next();
3966 checkLVal();
3967 pGen->pushR0();
3968 pGen->forceR0RVal();
3969 pGen->pushR0();
3970 expr();
3971 pGen->forceR0RVal();
3972 pGen->genOp(t);
3973 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003974 }
3975 }
3976
Jack Palevich40600de2009-07-01 15:32:35 -07003977 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003978 */
Jack Palevich29daf572009-07-30 19:38:55 -07003979 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003980 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07003981 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07003982 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003983 if (acceptStringLiteral()) {
3984 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003985 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003986 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003987 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003988 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003989 t = tok;
3990 next();
3991 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003992 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003993 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003994 // Align to 4-byte boundary
3995 glo = (char*) (((intptr_t) glo + 3) & -4);
3996 * (float*) glo = (float) ad;
3997 pGen->loadFloat((int) glo, mkpFloat);
3998 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003999 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07004000 // Align to 8-byte boundary
4001 glo = (char*) (((intptr_t) glo + 7) & -8);
4002 * (double*) glo = ad;
4003 pGen->loadFloat((int) glo, mkpDouble);
4004 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004005 } else if (c == 2) {
4006 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004007 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004008 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004009 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004010 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004011 else if (t == '+') {
4012 // ignore unary plus.
4013 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004014 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004015 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004016 } else if (c == 11) {
4017 // pre increment / pre decrement
4018 unary();
4019 doIncDec(a == OP_INCREMENT, 0);
4020 }
4021 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004022 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004023 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004024 if (pCast) {
4025 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004026 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004027 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004028 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004029 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004030 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004031 skip(')');
4032 }
4033 } else if (t == '*') {
4034 /* This is a pointer dereference.
4035 */
Jack Palevich29daf572009-07-30 19:38:55 -07004036 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004037 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004038 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004039 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004040 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4041 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004042 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004043 } else if (t == EOF ) {
4044 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004045 } else if (t == ';') {
4046 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004047 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004048 // Don't have to do anything special here, the error
4049 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004050 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004051 if (!isDefined(t)) {
4052 mGlobals.add(t);
4053 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004054 }
Jack Palevich8df46192009-07-07 14:48:51 -07004055 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004056 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004057 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004058 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004059 linkGlobal(t, tok == '(');
4060 n = (intptr_t) pVI->pAddress;
4061 if (!n && tok != '(') {
4062 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004063 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004064 }
Jack Palevich29daf572009-07-30 19:38:55 -07004065 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004066 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004067 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004068 linkGlobal(t, false);
4069 n = (intptr_t) pVI->pAddress;
4070 if (!n) {
4071 error("Undeclared variable %s\n", nameof(t));
4072 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004073 }
Jack Palevich5b659092009-07-31 14:55:07 -07004074 }
4075 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004076 Type* pVal;
4077 ExpressionType et;
4078 if (pVI->pType->tag == TY_ARRAY) {
4079 pVal = pVI->pType;
4080 et = ET_RVALUE;
4081 } else {
4082 pVal = createPtrType(pVI->pType);
4083 et = ET_LVALUE;
4084 }
Jack Palevich5b659092009-07-31 14:55:07 -07004085 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004086 int tag = pVal->pHead->tag;
4087 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004088 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004089 }
Jack Palevich5b659092009-07-31 14:55:07 -07004090 pGen->leaR0(n, pVal, et);
4091 } else {
4092 pVI->pForward = (void*) pGen->leaForward(
4093 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004094 }
4095 }
4096 }
4097
Jack Palevich5b659092009-07-31 14:55:07 -07004098 /* Now handle postfix operators */
4099 for(;;) {
4100 if (tokl == 11) {
4101 // post inc / post dec
4102 doIncDec(tokc == OP_INCREMENT, true);
4103 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004104 } else if (accept('[')) {
4105 // Array reference
4106 pGen->forceR0RVal();
4107 pGen->pushR0();
4108 commaExpr();
4109 pGen->forceR0RVal();
4110 pGen->genOp(OP_PLUS);
4111 doPointer();
4112 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004113 } else if (accept('(')) {
4114 /* function call */
4115 Type* pDecl = NULL;
4116 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004117 Type* pFn = pGen->getR0Type();
4118 assert(pFn->tag == TY_POINTER);
4119 assert(pFn->pHead->tag == TY_FUNC);
4120 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004121 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004122 Type* pArgList = pDecl->pTail;
4123 bool varArgs = pArgList == NULL;
4124 /* push args and invert order */
4125 a = pGen->beginFunctionCallArguments();
4126 int l = 0;
4127 int argCount = 0;
4128 while (tok != ')' && tok != EOF) {
4129 if (! varArgs && !pArgList) {
4130 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004131 }
Jack Palevich5b659092009-07-31 14:55:07 -07004132 expr();
4133 pGen->forceR0RVal();
4134 Type* pTargetType;
4135 if (pArgList) {
4136 pTargetType = pArgList->pHead;
4137 pArgList = pArgList->pTail;
4138 } else {
4139 // This is a ... function, just pass arguments in their
4140 // natural type.
4141 pTargetType = pGen->getR0Type();
4142 if (pTargetType->tag == TY_FLOAT) {
4143 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004144 } else if (pTargetType->tag == TY_ARRAY) {
4145 // Pass arrays by pointer.
4146 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004147 }
4148 }
4149 if (pTargetType->tag == TY_VOID) {
4150 error("Can't pass void value for argument %d",
4151 argCount + 1);
4152 } else {
4153 l += pGen->storeR0ToArg(l, pTargetType);
4154 }
4155 if (accept(',')) {
4156 // fine
4157 } else if ( tok != ')') {
4158 error("Expected ',' or ')'");
4159 }
4160 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004161 }
Jack Palevich5b659092009-07-31 14:55:07 -07004162 if (! varArgs && pArgList) {
4163 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004164 }
Jack Palevich5b659092009-07-31 14:55:07 -07004165 pGen->endFunctionCallArguments(pDecl, a, l);
4166 skip(')');
4167 pGen->callIndirect(l, pDecl);
4168 pGen->adjustStackAfterCall(pDecl, l, true);
4169 } else {
4170 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004171 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004172 }
4173 }
4174
Jack Palevichaaac9282009-07-31 14:34:34 -07004175 void doIncDec(int isInc, int isPost) {
4176 // R0 already has the lval
4177 checkLVal();
4178 int lit = isInc ? 1 : -1;
4179 pGen->pushR0();
4180 pGen->loadR0FromR0();
4181 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004182 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4183 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004184 error("++/-- illegal for this type. %d", tag);
4185 }
4186 if (isPost) {
4187 pGen->over();
4188 pGen->pushR0();
4189 pGen->li(lit);
4190 pGen->genOp(OP_PLUS);
4191 pGen->storeR0ToTOS();
4192 pGen->popR0();
4193 } else {
4194 pGen->pushR0();
4195 pGen->li(lit);
4196 pGen->genOp(OP_PLUS);
4197 pGen->over();
4198 pGen->storeR0ToTOS();
4199 pGen->popR0();
4200 }
4201 }
4202
Jack Palevich47cbea92009-07-31 15:25:53 -07004203 void doPointer() {
4204 pGen->forceR0RVal();
4205 Type* pR0Type = pGen->getR0Type();
4206 if (pR0Type->tag != TY_POINTER) {
4207 error("Expected a pointer type.");
4208 } else {
4209 if (pR0Type->pHead->tag != TY_FUNC) {
4210 pGen->setR0ExpressionType(ET_LVALUE);
4211 }
4212 }
4213 }
4214
Jack Palevich40600de2009-07-01 15:32:35 -07004215 /* Recursive descent parser for binary operations.
4216 */
4217 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004218 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004219 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004220 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004221 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004222 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004223 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004224 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004225 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004226 t = tokc;
4227 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004228 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004229 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004230 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004231 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004232 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004233 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004234 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004235 // Check for syntax error.
4236 if (pGen->getR0Type() == NULL) {
4237 // We failed to parse a right-hand argument.
4238 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004239 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004240 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004241 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004242 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004243 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004244 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004245 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004246 }
4247 }
4248 }
4249 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004250 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004251 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004252 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004253 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004254 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004255 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004256 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004257 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004258 }
4259 }
4260 }
4261
Jack Palevich43aaee32009-07-31 14:01:37 -07004262 void commaExpr() {
4263 for(;;) {
4264 expr();
4265 if (!accept(',')) {
4266 break;
4267 }
4268 }
4269 }
4270
Jack Palevich21a15a22009-05-11 14:49:29 -07004271 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004272 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004273 }
4274
4275 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004276 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004277 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004278 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004279 }
4280
Jack Palevicha6baa232009-06-12 11:25:59 -07004281 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004282 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004283
Jack Palevich95727a02009-07-06 12:07:15 -07004284 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004285 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004286 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004287 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004288 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004289 next();
4290 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004291 a = test_expr();
4292 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004293 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004294 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004295 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004296 n = pGen->gjmp(0); /* jmp */
4297 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004298 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004299 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004300 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004301 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004302 }
Jack Palevich546b2242009-05-13 15:10:04 -07004303 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004304 t = tok;
4305 next();
4306 skip('(');
4307 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004308 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004309 a = test_expr();
4310 } else {
4311 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004312 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004313 skip(';');
4314 n = codeBuf.getPC();
4315 a = 0;
4316 if (tok != ';')
4317 a = test_expr();
4318 skip(';');
4319 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004320 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004321 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004322 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004323 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004324 n = t + 4;
4325 }
4326 }
4327 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004328 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004329 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004330 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004331 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004332 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004333 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004334 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004335 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004336 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004337 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004338 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004339 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004340 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004341 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004342 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004343 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004344 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004345 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004346 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004347 if (pReturnType->tag == TY_VOID) {
4348 error("Must not return a value from a void function");
4349 } else {
4350 pGen->convertR0(pReturnType);
4351 }
4352 } else {
4353 if (pReturnType->tag != TY_VOID) {
4354 error("Must specify a value here");
4355 }
Jack Palevich8df46192009-07-07 14:48:51 -07004356 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004357 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004358 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004359 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004360 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004361 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004362 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004363 }
4364 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004365
Jack Palevicha8f427f2009-07-13 18:40:08 -07004366 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004367 if (a == b) {
4368 return true;
4369 }
4370 if (a == NULL || b == NULL) {
4371 return false;
4372 }
4373 TypeTag at = a->tag;
4374 if (at != b->tag) {
4375 return false;
4376 }
4377 if (at == TY_POINTER) {
4378 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004379 } else if (at == TY_ARRAY) {
4380 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004381 } else if (at == TY_FUNC || at == TY_PARAM) {
4382 return typeEqual(a->pHead, b->pHead)
4383 && typeEqual(a->pTail, b->pTail);
4384 }
4385 return true;
4386 }
4387
Jack Palevich2ff5c222009-07-23 15:11:22 -07004388 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004389 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004390 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004391 memset(pType, 0, sizeof(*pType));
4392 pType->tag = tag;
4393 pType->pHead = pHead;
4394 pType->pTail = pTail;
4395 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004396 }
4397
Jack Palevich2ff5c222009-07-23 15:11:22 -07004398 Type* createPtrType(Type* pType) {
4399 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004400 }
4401
4402 /**
4403 * Try to print a type in declaration order
4404 */
Jack Palevich86351982009-06-30 18:09:56 -07004405 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004406 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004407 if (pType == NULL) {
4408 buffer.appendCStr("null");
4409 return;
4410 }
Jack Palevich3f226492009-07-02 14:46:19 -07004411 decodeTypeImp(buffer, pType);
4412 }
4413
4414 void decodeTypeImp(String& buffer, Type* pType) {
4415 decodeTypeImpPrefix(buffer, pType);
4416
Jack Palevich86351982009-06-30 18:09:56 -07004417 String temp;
4418 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004419 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004420 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004421 }
4422
4423 decodeTypeImpPostfix(buffer, pType);
4424 }
4425
4426 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4427 TypeTag tag = pType->tag;
4428
Jack Palevich37c54bd2009-07-14 18:35:36 -07004429 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004430 switch (tag) {
4431 case TY_INT:
4432 buffer.appendCStr("int");
4433 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004434 case TY_SHORT:
4435 buffer.appendCStr("short");
4436 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004437 case TY_CHAR:
4438 buffer.appendCStr("char");
4439 break;
4440 case TY_VOID:
4441 buffer.appendCStr("void");
4442 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004443 case TY_FLOAT:
4444 buffer.appendCStr("float");
4445 break;
4446 case TY_DOUBLE:
4447 buffer.appendCStr("double");
4448 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004449 default:
4450 break;
4451 }
Jack Palevich86351982009-06-30 18:09:56 -07004452 buffer.append(' ');
4453 }
Jack Palevich3f226492009-07-02 14:46:19 -07004454
4455 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004456 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004457 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004458 case TY_SHORT:
4459 break;
Jack Palevich86351982009-06-30 18:09:56 -07004460 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004461 break;
4462 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004463 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004464 case TY_FLOAT:
4465 break;
4466 case TY_DOUBLE:
4467 break;
Jack Palevich86351982009-06-30 18:09:56 -07004468 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004469 decodeTypeImpPrefix(buffer, pType->pHead);
4470 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4471 buffer.append('(');
4472 }
4473 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004474 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004475 case TY_ARRAY:
4476 decodeTypeImpPrefix(buffer, pType->pHead);
4477 break;
Jack Palevich86351982009-06-30 18:09:56 -07004478 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004479 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004480 break;
4481 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004482 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004483 break;
4484 default:
4485 String temp;
4486 temp.printf("Unknown tag %d", pType->tag);
4487 buffer.append(temp);
4488 break;
4489 }
Jack Palevich3f226492009-07-02 14:46:19 -07004490 }
4491
4492 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4493 TypeTag tag = pType->tag;
4494
4495 switch(tag) {
4496 case TY_POINTER:
4497 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4498 buffer.append(')');
4499 }
4500 decodeTypeImpPostfix(buffer, pType->pHead);
4501 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004502 case TY_ARRAY:
4503 {
4504 String temp;
4505 temp.printf("[%d]", pType->length);
4506 buffer.append(temp);
4507 }
4508 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004509 case TY_FUNC:
4510 buffer.append('(');
4511 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4512 decodeTypeImp(buffer, pArg);
4513 if (pArg->pTail) {
4514 buffer.appendCStr(", ");
4515 }
4516 }
4517 buffer.append(')');
4518 break;
4519 default:
4520 break;
Jack Palevich86351982009-06-30 18:09:56 -07004521 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004522 }
4523
Jack Palevich86351982009-06-30 18:09:56 -07004524 void printType(Type* pType) {
4525 String buffer;
4526 decodeType(buffer, pType);
4527 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004528 }
4529
Jack Palevich2ff5c222009-07-23 15:11:22 -07004530 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004531 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004532 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004533 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004534 } else if (tok == TOK_SHORT) {
4535 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004536 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004537 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004538 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004539 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004540 } else if (tok == TOK_FLOAT) {
4541 pType = mkpFloat;
4542 } else if (tok == TOK_DOUBLE) {
4543 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004544 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004545 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004546 }
4547 next();
Jack Palevich86351982009-06-30 18:09:56 -07004548 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004549 }
4550
Jack Palevich2ff5c222009-07-23 15:11:22 -07004551 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004552 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004553 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004554 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004555 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004556 if (declName) {
4557 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004558 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004559 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004560
Jack Palevich86351982009-06-30 18:09:56 -07004561 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004562 pType->length = pOldType->length;
4563 } else if (nameRequired) {
4564 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004565 }
Jack Palevich3f226492009-07-02 14:46:19 -07004566 // fprintf(stderr, "Parsed a declaration: ");
4567 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004568 if (reportFailure) {
4569 return NULL;
4570 }
Jack Palevich86351982009-06-30 18:09:56 -07004571 return pType;
4572 }
4573
Jack Palevich2ff5c222009-07-23 15:11:22 -07004574 Type* expectDeclaration(Type* pBaseType) {
4575 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004576 if (! pType) {
4577 error("Expected a declaration");
4578 }
4579 return pType;
4580 }
4581
Jack Palevich3f226492009-07-02 14:46:19 -07004582 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004583 Type* acceptCastTypeDeclaration() {
4584 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004585 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004586 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004587 }
Jack Palevich86351982009-06-30 18:09:56 -07004588 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004589 }
4590
Jack Palevich2ff5c222009-07-23 15:11:22 -07004591 Type* expectCastTypeDeclaration() {
4592 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004593 if (! pType) {
4594 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004595 }
Jack Palevich3f226492009-07-02 14:46:19 -07004596 return pType;
4597 }
4598
4599 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004600 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004601 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004602 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004603 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004604 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004605 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004606 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004607 return pType;
4608 }
4609
4610 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004611 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004612 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004613 // direct-dcl :
4614 // name
4615 // (dcl)
4616 // direct-dcl()
4617 // direct-dcl[]
4618 Type* pNewHead = NULL;
4619 if (accept('(')) {
4620 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004621 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004622 skip(')');
4623 } else if ((declName = acceptSymbol()) != 0) {
4624 if (nameAllowed == false && declName) {
4625 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004626 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004627 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004628 } else if (nameRequired && ! declName) {
4629 String temp;
4630 decodeToken(temp, tok, true);
4631 error("Expected name. Got %s", temp.getUnwrapped());
4632 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004633 }
Jack Palevichb6154502009-08-04 14:56:09 -07004634 for(;;) {
4635 if (accept('(')) {
4636 // Function declaration
4637 Type* pTail = acceptArgs(nameAllowed);
4638 pType = createType(TY_FUNC, pType, pTail);
4639 skip(')');
4640 } if (accept('[')) {
4641 if (tok != ']') {
4642 if (tok != TOK_NUM || tokc <= 0) {
4643 error("Expected positive integer constant");
4644 } else {
4645 Type* pDecayType = createPtrType(pType);
4646 pType = createType(TY_ARRAY, pType, pDecayType);
4647 pType->length = tokc;
4648 }
4649 next();
4650 }
4651 skip(']');
4652 } else {
4653 break;
4654 }
Jack Palevich86351982009-06-30 18:09:56 -07004655 }
Jack Palevich3f226492009-07-02 14:46:19 -07004656
4657 if (pNewHead) {
4658 Type* pA = pNewHead;
4659 while (pA->pHead) {
4660 pA = pA->pHead;
4661 }
4662 pA->pHead = pType;
4663 pType = pNewHead;
4664 }
Jack Palevich86351982009-06-30 18:09:56 -07004665 return pType;
4666 }
4667
Jack Palevich2ff5c222009-07-23 15:11:22 -07004668 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004669 Type* pHead = NULL;
4670 Type* pTail = NULL;
4671 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004672 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004673 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004674 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004675 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004676 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004677 if (!pHead) {
4678 pHead = pParam;
4679 pTail = pParam;
4680 } else {
4681 pTail->pTail = pParam;
4682 pTail = pParam;
4683 }
4684 }
4685 }
4686 if (! accept(',')) {
4687 break;
4688 }
4689 }
4690 return pHead;
4691 }
4692
Jack Palevich2ff5c222009-07-23 15:11:22 -07004693 Type* expectPrimitiveType() {
4694 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004695 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004696 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004697 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004698 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004699 }
Jack Palevich86351982009-06-30 18:09:56 -07004700 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004701 }
4702
Jack Palevichb5e33312009-07-30 19:06:34 -07004703 void checkLVal() {
4704 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4705 error("Expected an lval");
4706 }
4707 }
4708
Jack Palevich86351982009-06-30 18:09:56 -07004709 void addGlobalSymbol(Type* pDecl) {
4710 tokenid_t t = pDecl->id;
4711 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004712 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004713 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004714 }
Jack Palevich86351982009-06-30 18:09:56 -07004715 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004716 }
4717
Jack Palevich86351982009-06-30 18:09:56 -07004718 void reportDuplicate(tokenid_t t) {
4719 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004720 }
4721
Jack Palevich86351982009-06-30 18:09:56 -07004722 void addLocalSymbol(Type* pDecl) {
4723 tokenid_t t = pDecl->id;
4724 if (mLocals.isDefinedAtCurrentLevel(t)) {
4725 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004726 }
Jack Palevich86351982009-06-30 18:09:56 -07004727 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004728 }
4729
Jack Palevich95727a02009-07-06 12:07:15 -07004730 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004731 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004732
Jack Palevich95727a02009-07-06 12:07:15 -07004733 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004734 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004735 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004736 if (!pDecl) {
4737 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004738 }
Jack Palevich86351982009-06-30 18:09:56 -07004739 int variableAddress = 0;
4740 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004741 size_t alignment = pGen->stackAlignmentOf(pDecl);
4742 size_t alignmentMask = ~ (alignment - 1);
4743 size_t sizeOf = pGen->sizeOf(pDecl);
4744 loc = (loc + alignment - 1) & alignmentMask;
4745 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4746 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004747 variableAddress = -loc;
4748 VI(pDecl->id)->pAddress = (void*) variableAddress;
4749 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004750 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004751 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004752 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004753 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004754 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004755 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004756 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004757 if (tok == ',')
4758 next();
4759 }
4760 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004761 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004762 }
4763 }
4764
Jack Palevichf1728be2009-06-12 13:53:51 -07004765 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004766 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004767 }
4768
Jack Palevich37c54bd2009-07-14 18:35:36 -07004769 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004770 if (token == EOF ) {
4771 buffer.printf("EOF");
4772 } else if (token == TOK_NUM) {
4773 buffer.printf("numeric constant");
4774 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004775 if (token < 32) {
4776 buffer.printf("'\\x%02x'", token);
4777 } else {
4778 buffer.printf("'%c'", token);
4779 }
Jack Palevich569f1352009-06-29 14:29:08 -07004780 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004781 if (quote) {
4782 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4783 buffer.printf("keyword \"%s\"", nameof(token));
4784 } else {
4785 buffer.printf("symbol \"%s\"", nameof(token));
4786 }
4787 } else {
4788 buffer.printf("%s", nameof(token));
4789 }
Jack Palevich569f1352009-06-29 14:29:08 -07004790 }
4791 }
4792
Jack Palevich40600de2009-07-01 15:32:35 -07004793 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004794 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004795 if (!result) {
4796 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004797 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004798 error("Expected symbol. Got %s", temp.getUnwrapped());
4799 }
4800 return result;
4801 }
4802
Jack Palevich86351982009-06-30 18:09:56 -07004803 tokenid_t acceptSymbol() {
4804 tokenid_t result = 0;
4805 if (tok >= TOK_SYMBOL) {
4806 result = tok;
4807 next();
Jack Palevich86351982009-06-30 18:09:56 -07004808 }
4809 return result;
4810 }
4811
Jack Palevichb7c81e92009-06-04 19:56:13 -07004812 void globalDeclarations() {
4813 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004814 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004815 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004816 break;
4817 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004818 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004819 if (!pDecl) {
4820 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004821 }
Jack Palevich86351982009-06-30 18:09:56 -07004822 if (! isDefined(pDecl->id)) {
4823 addGlobalSymbol(pDecl);
4824 }
4825 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004826 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004827 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004828 }
Jack Palevich86351982009-06-30 18:09:56 -07004829 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004830 // it's a variable declaration
4831 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004832 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004833 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004834 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004835 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004836 }
Jack Palevich86351982009-06-30 18:09:56 -07004837 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004838 if (tok == TOK_NUM) {
4839 if (name) {
4840 * (int*) name->pAddress = tokc;
4841 }
4842 next();
4843 } else {
4844 error("Expected an integer constant");
4845 }
4846 }
Jack Palevich86351982009-06-30 18:09:56 -07004847 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004848 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004849 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004850 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004851 if (!pDecl) {
4852 break;
4853 }
4854 if (! isDefined(pDecl->id)) {
4855 addGlobalSymbol(pDecl);
4856 }
4857 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004858 }
4859 skip(';');
4860 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004861 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004862 if (accept(';')) {
4863 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004864 } else if (tok != '{') {
4865 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004866 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004867 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004868 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004869 /* patch forward references */
4870 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004871 /* put function address */
4872 name->pAddress = (void*) codeBuf.getPC();
4873 }
4874 // Calculate stack offsets for parameters
4875 mLocals.pushLevel();
4876 intptr_t a = 8;
4877 int argCount = 0;
4878 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4879 Type* pArg = pP->pHead;
4880 addLocalSymbol(pArg);
4881 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004882 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004883 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004884 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004885 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004886 argCount++;
4887 }
4888 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004889 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004890 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004891 block(0, true);
4892 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004893 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004894 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004895 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004896 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004897 }
4898 }
4899 }
4900
Jack Palevich9cbd2262009-07-08 16:48:41 -07004901 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4902 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4903 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004904 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004905 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004906 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004907 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004908 char* result = (char*) base;
4909 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004910 return result;
4911 }
4912
Jack Palevich21a15a22009-05-11 14:49:29 -07004913 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004914 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004915 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004916 pGlobalBase = 0;
4917 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004918 if (pGen) {
4919 delete pGen;
4920 pGen = 0;
4921 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004922 if (file) {
4923 delete file;
4924 file = 0;
4925 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004926 }
4927
Jack Palevich8c246a92009-07-14 21:14:10 -07004928 // One-time initialization, when class is constructed.
4929 void init() {
4930 mpSymbolLookupFn = 0;
4931 mpSymbolLookupContext = 0;
4932 }
4933
Jack Palevich21a15a22009-05-11 14:49:29 -07004934 void clear() {
4935 tok = 0;
4936 tokc = 0;
4937 tokl = 0;
4938 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004939 rsym = 0;
4940 loc = 0;
4941 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004942 dptr = 0;
4943 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004944 file = 0;
4945 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004946 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004947 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004948 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004949 mLineNumber = 1;
4950 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004951 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004952
Jack Palevich22305132009-05-13 10:58:45 -07004953 void setArchitecture(const char* architecture) {
4954 delete pGen;
4955 pGen = 0;
4956
4957 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004958#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004959 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004960 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004961 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004962#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004963#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004964 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004965 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004966 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004967#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004968 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004969 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004970 }
4971 }
4972
4973 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004974#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004975 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004976#elif defined(DEFAULT_X86_CODEGEN)
4977 pGen = new X86CodeGenerator();
4978#endif
4979 }
4980 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004981 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004982 } else {
4983 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004984 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004985 }
4986 }
4987
Jack Palevich77ae76e2009-05-10 19:59:24 -07004988public:
Jack Palevich22305132009-05-13 10:58:45 -07004989 struct args {
4990 args() {
4991 architecture = 0;
4992 }
4993 const char* architecture;
4994 };
4995
Jack Paleviche7b59062009-05-19 17:12:17 -07004996 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004997 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004998 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004999 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005000
Jack Paleviche7b59062009-05-19 17:12:17 -07005001 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07005002 cleanup();
5003 }
5004
Jack Palevich8c246a92009-07-14 21:14:10 -07005005 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5006 mpSymbolLookupFn = pFn;
5007 mpSymbolLookupContext = pContext;
5008 }
5009
Jack Palevich1cdef202009-05-22 12:06:27 -07005010 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005011 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005012
Jack Palevich2ff5c222009-07-23 15:11:22 -07005013 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005014 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005015 cleanup();
5016 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005017 mTokenTable.setArena(&mGlobalArena);
5018 mGlobals.setArena(&mGlobalArena);
5019 mGlobals.setTokenTable(&mTokenTable);
5020 mLocals.setArena(&mLocalArena);
5021 mLocals.setTokenTable(&mTokenTable);
5022
5023 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005024 codeBuf.init(ALLOC_SIZE);
5025 setArchitecture(NULL);
5026 if (!pGen) {
5027 return -1;
5028 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005029#ifdef PROVIDE_TRACE_CODEGEN
5030 pGen = new TraceCodeGenerator(pGen);
5031#endif
5032 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005033 pGen->init(&codeBuf);
5034 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005035 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5036 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005037 inp();
5038 next();
5039 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005040 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005041 result = pGen->finishCompile();
5042 if (result == 0) {
5043 if (mErrorBuf.len()) {
5044 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005045 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005046 }
Jack Palevichce105a92009-07-16 14:30:33 -07005047 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005048 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005049 }
5050
Jack Palevich86351982009-06-30 18:09:56 -07005051 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005052 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005053 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005054 mkpChar = createType(TY_CHAR, NULL, NULL);
5055 mkpVoid = createType(TY_VOID, NULL, NULL);
5056 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5057 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5058 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5059 mkpIntPtr = createPtrType(mkpInt);
5060 mkpCharPtr = createPtrType(mkpChar);
5061 mkpFloatPtr = createPtrType(mkpFloat);
5062 mkpDoublePtr = createPtrType(mkpDouble);
5063 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005064 }
5065
Jack Palevicha6baa232009-06-12 11:25:59 -07005066 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005067 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005068 }
5069
Jack Palevich569f1352009-06-29 14:29:08 -07005070 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005071 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005072 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005073 }
5074
Jack Palevich569f1352009-06-29 14:29:08 -07005075 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005076 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005077 error("Undefined forward reference: %s",
5078 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005079 }
5080 return true;
5081 }
5082
Jack Palevich21a15a22009-05-11 14:49:29 -07005083 int dump(FILE* out) {
5084 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5085 return 0;
5086 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005087
Jack Palevicha6535612009-05-13 16:24:17 -07005088 int disassemble(FILE* out) {
5089 return pGen->disassemble(out);
5090 }
5091
Jack Palevich1cdef202009-05-22 12:06:27 -07005092 /* Look through the symbol table to find a symbol.
5093 * If found, return its value.
5094 */
5095 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005096 if (mCompileResult == 0) {
5097 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5098 VariableInfo* pVariableInfo = VI(tok);
5099 if (pVariableInfo) {
5100 return pVariableInfo->pAddress;
5101 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005102 }
5103 return NULL;
5104 }
5105
Jack Palevicheedf9d22009-06-04 16:23:40 -07005106 void getPragmas(ACCsizei* actualStringCount,
5107 ACCsizei maxStringCount, ACCchar** strings) {
5108 int stringCount = mPragmaStringCount;
5109 if (actualStringCount) {
5110 *actualStringCount = stringCount;
5111 }
5112 if (stringCount > maxStringCount) {
5113 stringCount = maxStringCount;
5114 }
5115 if (strings) {
5116 char* pPragmas = mPragmas.getUnwrapped();
5117 while (stringCount-- > 0) {
5118 *strings++ = pPragmas;
5119 pPragmas += strlen(pPragmas) + 1;
5120 }
5121 }
5122 }
5123
Jack Palevichac0e95e2009-05-29 13:53:44 -07005124 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005125 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005126 }
5127
Jack Palevich77ae76e2009-05-10 19:59:24 -07005128};
5129
Jack Paleviche7b59062009-05-19 17:12:17 -07005130const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005131 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5132
Jack Paleviche7b59062009-05-19 17:12:17 -07005133const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005134 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5135 5, 5, /* ==, != */
5136 9, 10, /* &&, || */
5137 6, 7, 8, /* & ^ | */
5138 2, 2 /* ~ ! */
5139 };
5140
Jack Palevich8b0624c2009-05-20 12:12:06 -07005141#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005142FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005143#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005144
Jack Palevich8b0624c2009-05-20 12:12:06 -07005145#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005146const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005147 0x1, // ++
5148 0xff, // --
5149 0xc1af0f, // *
5150 0xf9f79991, // /
5151 0xf9f79991, // % (With manual assist to swap results)
5152 0xc801, // +
5153 0xd8f7c829, // -
5154 0xe0d391, // <<
5155 0xf8d391, // >>
5156 0xe, // <=
5157 0xd, // >=
5158 0xc, // <
5159 0xf, // >
5160 0x4, // ==
5161 0x5, // !=
5162 0x0, // &&
5163 0x1, // ||
5164 0xc821, // &
5165 0xc831, // ^
5166 0xc809, // |
5167 0xd0f7, // ~
5168 0x4 // !
5169};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005170#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005171
Jack Palevich1cdef202009-05-22 12:06:27 -07005172struct ACCscript {
5173 ACCscript() {
5174 text = 0;
5175 textLength = 0;
5176 accError = ACC_NO_ERROR;
5177 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005178
Jack Palevich1cdef202009-05-22 12:06:27 -07005179 ~ACCscript() {
5180 delete text;
5181 }
Jack Palevich546b2242009-05-13 15:10:04 -07005182
Jack Palevich8c246a92009-07-14 21:14:10 -07005183 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5184 compiler.registerSymbolCallback(pFn, pContext);
5185 }
5186
Jack Palevich1cdef202009-05-22 12:06:27 -07005187 void setError(ACCenum error) {
5188 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5189 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005190 }
5191 }
5192
Jack Palevich1cdef202009-05-22 12:06:27 -07005193 ACCenum getError() {
5194 ACCenum result = accError;
5195 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005196 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005197 }
5198
Jack Palevich1cdef202009-05-22 12:06:27 -07005199 Compiler compiler;
5200 char* text;
5201 int textLength;
5202 ACCenum accError;
5203};
5204
5205
5206extern "C"
5207ACCscript* accCreateScript() {
5208 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005209}
Jack Palevich1cdef202009-05-22 12:06:27 -07005210
5211extern "C"
5212ACCenum accGetError( ACCscript* script ) {
5213 return script->getError();
5214}
5215
5216extern "C"
5217void accDeleteScript(ACCscript* script) {
5218 delete script;
5219}
5220
5221extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005222void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5223 ACCvoid* pContext) {
5224 script->registerSymbolCallback(pFn, pContext);
5225}
5226
5227extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005228void accScriptSource(ACCscript* script,
5229 ACCsizei count,
5230 const ACCchar ** string,
5231 const ACCint * length) {
5232 int totalLength = 0;
5233 for(int i = 0; i < count; i++) {
5234 int len = -1;
5235 const ACCchar* s = string[i];
5236 if (length) {
5237 len = length[i];
5238 }
5239 if (len < 0) {
5240 len = strlen(s);
5241 }
5242 totalLength += len;
5243 }
5244 delete script->text;
5245 char* text = new char[totalLength + 1];
5246 script->text = text;
5247 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005248 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005249 for(int i = 0; i < count; i++) {
5250 int len = -1;
5251 const ACCchar* s = string[i];
5252 if (length) {
5253 len = length[i];
5254 }
5255 if (len < 0) {
5256 len = strlen(s);
5257 }
Jack Palevich09555c72009-05-27 12:25:55 -07005258 memcpy(dest, s, len);
5259 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005260 }
5261 text[totalLength] = '\0';
5262}
5263
5264extern "C"
5265void accCompileScript(ACCscript* script) {
5266 int result = script->compiler.compile(script->text, script->textLength);
5267 if (result) {
5268 script->setError(ACC_INVALID_OPERATION);
5269 }
5270}
5271
5272extern "C"
5273void accGetScriptiv(ACCscript* script,
5274 ACCenum pname,
5275 ACCint * params) {
5276 switch (pname) {
5277 case ACC_INFO_LOG_LENGTH:
5278 *params = 0;
5279 break;
5280 }
5281}
5282
5283extern "C"
5284void accGetScriptInfoLog(ACCscript* script,
5285 ACCsizei maxLength,
5286 ACCsizei * length,
5287 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005288 char* message = script->compiler.getErrorMessage();
5289 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005290 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005291 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005292 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005293 if (infoLog && maxLength > 0) {
5294 int trimmedLength = maxLength < messageLength ?
5295 maxLength : messageLength;
5296 memcpy(infoLog, message, trimmedLength);
5297 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005298 }
5299}
5300
5301extern "C"
5302void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5303 ACCvoid ** address) {
5304 void* value = script->compiler.lookup(name);
5305 if (value) {
5306 *address = value;
5307 } else {
5308 script->setError(ACC_INVALID_VALUE);
5309 }
5310}
5311
Jack Palevicheedf9d22009-06-04 16:23:40 -07005312extern "C"
5313void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5314 ACCsizei maxStringCount, ACCchar** strings){
5315 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5316}
5317
-b master422972c2009-06-17 19:13:52 -07005318extern "C"
5319void accDisassemble(ACCscript* script) {
5320 script->compiler.disassemble(stderr);
5321}
5322
Jack Palevicheedf9d22009-06-04 16:23:40 -07005323
Jack Palevich1cdef202009-05-22 12:06:27 -07005324} // namespace acc
5325