blob: 6c03657f4df2dde7e841c1d9639ad6e697d64d40 [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();
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003815 if (ch == '(') {
3816 delete pName;
3817 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003818 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003819 }
3820 while (isspace(ch)) {
3821 inp();
3822 }
Jack Palevich569f1352009-06-29 14:29:08 -07003823 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003824 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003825 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003826 inp();
3827 }
Jack Palevich569f1352009-06-29 14:29:08 -07003828 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3829 memcpy(pDefn, value.getUnwrapped(), value.len());
3830 pDefn[value.len()] = 0;
3831 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003832 }
3833
Jack Palevicheedf9d22009-06-04 16:23:40 -07003834 void doPragma() {
3835 // # pragma name(val)
3836 int state = 0;
3837 while(ch != EOF && ch != '\n' && state < 10) {
3838 switch(state) {
3839 case 0:
3840 if (isspace(ch)) {
3841 inp();
3842 } else {
3843 state++;
3844 }
3845 break;
3846 case 1:
3847 if (isalnum(ch)) {
3848 mPragmas.append(ch);
3849 inp();
3850 } else if (ch == '(') {
3851 mPragmas.append(0);
3852 inp();
3853 state++;
3854 } else {
3855 state = 11;
3856 }
3857 break;
3858 case 2:
3859 if (isalnum(ch)) {
3860 mPragmas.append(ch);
3861 inp();
3862 } else if (ch == ')') {
3863 mPragmas.append(0);
3864 inp();
3865 state = 10;
3866 } else {
3867 state = 11;
3868 }
3869 break;
3870 }
3871 }
3872 if(state != 10) {
3873 error("Unexpected pragma syntax");
3874 }
3875 mPragmaStringCount += 2;
3876 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003877
Jack Palevichdc456462009-07-16 16:50:56 -07003878 void doLine() {
3879 // # line number { "filename "}
3880 next();
3881 if (tok != TOK_NUM) {
3882 error("Expected a line-number");
3883 } else {
3884 mLineNumber = tokc-1; // The end-of-line will increment it.
3885 }
3886 while(ch != EOF && ch != '\n') {
3887 inp();
3888 }
3889 }
3890
Jack Palevichac0e95e2009-05-29 13:53:44 -07003891 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003892 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003893 mErrorBuf.vprintf(fmt, ap);
3894 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003895 }
3896
Jack Palevich8b0624c2009-05-20 12:12:06 -07003897 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003898 if (tok != c) {
3899 error("'%c' expected", c);
3900 }
3901 next();
3902 }
3903
Jack Palevich86351982009-06-30 18:09:56 -07003904 bool accept(intptr_t c) {
3905 if (tok == c) {
3906 next();
3907 return true;
3908 }
3909 return false;
3910 }
3911
Jack Palevich40600de2009-07-01 15:32:35 -07003912 bool acceptStringLiteral() {
3913 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003914 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003915 // This while loop merges multiple adjacent string constants.
3916 while (tok == '"') {
3917 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003918 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003919 }
3920 if (ch != '"') {
3921 error("Unterminated string constant.");
3922 }
3923 inp();
3924 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003925 }
Jack Palevich40600de2009-07-01 15:32:35 -07003926 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003927 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003928 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003929 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003930
3931 return true;
3932 }
3933 return false;
3934 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003935
Jack Palevichb1544ca2009-07-16 15:09:20 -07003936 void linkGlobal(tokenid_t t, bool isFunction) {
3937 VariableInfo* pVI = VI(t);
3938 void* n = NULL;
3939 if (mpSymbolLookupFn) {
3940 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3941 }
3942 if (pVI->pType == NULL) {
3943 if (isFunction) {
3944 pVI->pType = mkpIntFn;
3945 } else {
3946 pVI->pType = mkpInt;
3947 }
3948 }
3949 pVI->pAddress = n;
3950 }
3951
Jack Palevich29daf572009-07-30 19:38:55 -07003952 void unaryOrAssignment() {
3953 unary();
3954 if (accept('=')) {
3955 checkLVal();
3956 pGen->pushR0();
3957 expr();
3958 pGen->forceR0RVal();
3959 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003960 } else if (tok == TOK_OP_ASSIGNMENT) {
3961 int t = tokc;
3962 next();
3963 checkLVal();
3964 pGen->pushR0();
3965 pGen->forceR0RVal();
3966 pGen->pushR0();
3967 expr();
3968 pGen->forceR0RVal();
3969 pGen->genOp(t);
3970 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003971 }
3972 }
3973
Jack Palevich40600de2009-07-01 15:32:35 -07003974 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003975 */
Jack Palevich29daf572009-07-30 19:38:55 -07003976 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003977 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07003978 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07003979 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003980 if (acceptStringLiteral()) {
3981 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003982 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003983 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003984 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003985 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003986 t = tok;
3987 next();
3988 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003989 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003990 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003991 // Align to 4-byte boundary
3992 glo = (char*) (((intptr_t) glo + 3) & -4);
3993 * (float*) glo = (float) ad;
3994 pGen->loadFloat((int) glo, mkpFloat);
3995 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003996 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003997 // Align to 8-byte boundary
3998 glo = (char*) (((intptr_t) glo + 7) & -8);
3999 * (double*) glo = ad;
4000 pGen->loadFloat((int) glo, mkpDouble);
4001 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07004002 } else if (c == 2) {
4003 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07004004 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004005 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07004006 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07004007 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004008 else if (t == '+') {
4009 // ignore unary plus.
4010 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07004011 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07004012 }
Jack Palevichaaac9282009-07-31 14:34:34 -07004013 } else if (c == 11) {
4014 // pre increment / pre decrement
4015 unary();
4016 doIncDec(a == OP_INCREMENT, 0);
4017 }
4018 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07004019 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07004020 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07004021 if (pCast) {
4022 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07004023 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07004024 pGen->forceR0RVal();
Jack Palevichb6154502009-08-04 14:56:09 -07004025 pGen->castR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07004026 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07004027 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07004028 skip(')');
4029 }
4030 } else if (t == '*') {
4031 /* This is a pointer dereference.
4032 */
Jack Palevich29daf572009-07-30 19:38:55 -07004033 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07004034 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07004036 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07004037 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
4038 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07004039 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004040 } else if (t == EOF ) {
4041 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07004042 } else if (t == ';') {
4043 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07004044 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004045 // Don't have to do anything special here, the error
4046 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07004047 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07004048 if (!isDefined(t)) {
4049 mGlobals.add(t);
4050 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004051 }
Jack Palevich8df46192009-07-07 14:48:51 -07004052 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07004053 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07004054 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004055 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004056 linkGlobal(t, tok == '(');
4057 n = (intptr_t) pVI->pAddress;
4058 if (!n && tok != '(') {
4059 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07004060 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07004061 }
Jack Palevich29daf572009-07-30 19:38:55 -07004062 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07004063 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07004064 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07004065 linkGlobal(t, false);
4066 n = (intptr_t) pVI->pAddress;
4067 if (!n) {
4068 error("Undeclared variable %s\n", nameof(t));
4069 }
Jack Palevicha6baa232009-06-12 11:25:59 -07004070 }
Jack Palevich5b659092009-07-31 14:55:07 -07004071 }
4072 // load a variable
Jack Palevichb6154502009-08-04 14:56:09 -07004073 Type* pVal;
4074 ExpressionType et;
4075 if (pVI->pType->tag == TY_ARRAY) {
4076 pVal = pVI->pType;
4077 et = ET_RVALUE;
4078 } else {
4079 pVal = createPtrType(pVI->pType);
4080 et = ET_LVALUE;
4081 }
Jack Palevich5b659092009-07-31 14:55:07 -07004082 if (n) {
Jack Palevichb6154502009-08-04 14:56:09 -07004083 int tag = pVal->pHead->tag;
4084 if (tag == TY_FUNC) {
Jack Palevich5b659092009-07-31 14:55:07 -07004085 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07004086 }
Jack Palevich5b659092009-07-31 14:55:07 -07004087 pGen->leaR0(n, pVal, et);
4088 } else {
4089 pVI->pForward = (void*) pGen->leaForward(
4090 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07004091 }
4092 }
4093 }
4094
Jack Palevich5b659092009-07-31 14:55:07 -07004095 /* Now handle postfix operators */
4096 for(;;) {
4097 if (tokl == 11) {
4098 // post inc / post dec
4099 doIncDec(tokc == OP_INCREMENT, true);
4100 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07004101 } else if (accept('[')) {
4102 // Array reference
4103 pGen->forceR0RVal();
4104 pGen->pushR0();
4105 commaExpr();
4106 pGen->forceR0RVal();
4107 pGen->genOp(OP_PLUS);
4108 doPointer();
4109 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07004110 } else if (accept('(')) {
4111 /* function call */
4112 Type* pDecl = NULL;
4113 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07004114 Type* pFn = pGen->getR0Type();
4115 assert(pFn->tag == TY_POINTER);
4116 assert(pFn->pHead->tag == TY_FUNC);
4117 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07004118 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004119 Type* pArgList = pDecl->pTail;
4120 bool varArgs = pArgList == NULL;
4121 /* push args and invert order */
4122 a = pGen->beginFunctionCallArguments();
4123 int l = 0;
4124 int argCount = 0;
4125 while (tok != ')' && tok != EOF) {
4126 if (! varArgs && !pArgList) {
4127 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004128 }
Jack Palevich5b659092009-07-31 14:55:07 -07004129 expr();
4130 pGen->forceR0RVal();
4131 Type* pTargetType;
4132 if (pArgList) {
4133 pTargetType = pArgList->pHead;
4134 pArgList = pArgList->pTail;
4135 } else {
4136 // This is a ... function, just pass arguments in their
4137 // natural type.
4138 pTargetType = pGen->getR0Type();
4139 if (pTargetType->tag == TY_FLOAT) {
4140 pTargetType = mkpDouble;
Jack Palevich80e49722009-08-04 15:39:49 -07004141 } else if (pTargetType->tag == TY_ARRAY) {
4142 // Pass arrays by pointer.
4143 pTargetType = pTargetType->pTail;
Jack Palevich5b659092009-07-31 14:55:07 -07004144 }
4145 }
4146 if (pTargetType->tag == TY_VOID) {
4147 error("Can't pass void value for argument %d",
4148 argCount + 1);
4149 } else {
4150 l += pGen->storeR0ToArg(l, pTargetType);
4151 }
4152 if (accept(',')) {
4153 // fine
4154 } else if ( tok != ')') {
4155 error("Expected ',' or ')'");
4156 }
4157 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004158 }
Jack Palevich5b659092009-07-31 14:55:07 -07004159 if (! varArgs && pArgList) {
4160 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004161 }
Jack Palevich5b659092009-07-31 14:55:07 -07004162 pGen->endFunctionCallArguments(pDecl, a, l);
4163 skip(')');
4164 pGen->callIndirect(l, pDecl);
4165 pGen->adjustStackAfterCall(pDecl, l, true);
4166 } else {
4167 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004168 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004169 }
4170 }
4171
Jack Palevichaaac9282009-07-31 14:34:34 -07004172 void doIncDec(int isInc, int isPost) {
4173 // R0 already has the lval
4174 checkLVal();
4175 int lit = isInc ? 1 : -1;
4176 pGen->pushR0();
4177 pGen->loadR0FromR0();
4178 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004179 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4180 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004181 error("++/-- illegal for this type. %d", tag);
4182 }
4183 if (isPost) {
4184 pGen->over();
4185 pGen->pushR0();
4186 pGen->li(lit);
4187 pGen->genOp(OP_PLUS);
4188 pGen->storeR0ToTOS();
4189 pGen->popR0();
4190 } else {
4191 pGen->pushR0();
4192 pGen->li(lit);
4193 pGen->genOp(OP_PLUS);
4194 pGen->over();
4195 pGen->storeR0ToTOS();
4196 pGen->popR0();
4197 }
4198 }
4199
Jack Palevich47cbea92009-07-31 15:25:53 -07004200 void doPointer() {
4201 pGen->forceR0RVal();
4202 Type* pR0Type = pGen->getR0Type();
4203 if (pR0Type->tag != TY_POINTER) {
4204 error("Expected a pointer type.");
4205 } else {
4206 if (pR0Type->pHead->tag != TY_FUNC) {
4207 pGen->setR0ExpressionType(ET_LVALUE);
4208 }
4209 }
4210 }
4211
Jack Palevich40600de2009-07-01 15:32:35 -07004212 /* Recursive descent parser for binary operations.
4213 */
4214 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004215 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004216 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004217 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004218 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004219 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004220 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004221 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004222 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004223 t = tokc;
4224 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004225 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004226 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004227 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004228 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004229 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004230 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004231 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004232 // Check for syntax error.
4233 if (pGen->getR0Type() == NULL) {
4234 // We failed to parse a right-hand argument.
4235 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004236 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004237 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004238 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004239 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004240 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004241 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004242 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004243 }
4244 }
4245 }
4246 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004247 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004248 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004249 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004250 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004251 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004252 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004253 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004254 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004255 }
4256 }
4257 }
4258
Jack Palevich43aaee32009-07-31 14:01:37 -07004259 void commaExpr() {
4260 for(;;) {
4261 expr();
4262 if (!accept(',')) {
4263 break;
4264 }
4265 }
4266 }
4267
Jack Palevich21a15a22009-05-11 14:49:29 -07004268 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004269 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004270 }
4271
4272 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004273 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004274 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004275 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004276 }
4277
Jack Palevicha6baa232009-06-12 11:25:59 -07004278 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004279 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004280
Jack Palevich95727a02009-07-06 12:07:15 -07004281 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004282 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004283 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004284 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004285 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004286 next();
4287 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004288 a = test_expr();
4289 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004290 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004291 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004292 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004293 n = pGen->gjmp(0); /* jmp */
4294 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004295 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004296 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004297 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004298 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004299 }
Jack Palevich546b2242009-05-13 15:10:04 -07004300 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004301 t = tok;
4302 next();
4303 skip('(');
4304 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004305 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004306 a = test_expr();
4307 } else {
4308 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004309 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004310 skip(';');
4311 n = codeBuf.getPC();
4312 a = 0;
4313 if (tok != ';')
4314 a = test_expr();
4315 skip(';');
4316 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004317 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004318 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004319 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004320 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004321 n = t + 4;
4322 }
4323 }
4324 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004325 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004326 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004327 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004328 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004329 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004330 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004331 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004332 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004333 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004334 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004335 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004336 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004337 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004338 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004339 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004340 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004341 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004342 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004343 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004344 if (pReturnType->tag == TY_VOID) {
4345 error("Must not return a value from a void function");
4346 } else {
4347 pGen->convertR0(pReturnType);
4348 }
4349 } else {
4350 if (pReturnType->tag != TY_VOID) {
4351 error("Must specify a value here");
4352 }
Jack Palevich8df46192009-07-07 14:48:51 -07004353 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004354 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004355 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004356 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004357 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004358 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004359 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004360 }
4361 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004362
Jack Palevicha8f427f2009-07-13 18:40:08 -07004363 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004364 if (a == b) {
4365 return true;
4366 }
4367 if (a == NULL || b == NULL) {
4368 return false;
4369 }
4370 TypeTag at = a->tag;
4371 if (at != b->tag) {
4372 return false;
4373 }
4374 if (at == TY_POINTER) {
4375 return typeEqual(a->pHead, b->pHead);
Jack Palevichb6154502009-08-04 14:56:09 -07004376 } else if (at == TY_ARRAY) {
4377 return a->length == b->length && typeEqual(a->pHead, b->pHead);
Jack Palevich3f226492009-07-02 14:46:19 -07004378 } else if (at == TY_FUNC || at == TY_PARAM) {
4379 return typeEqual(a->pHead, b->pHead)
4380 && typeEqual(a->pTail, b->pTail);
4381 }
4382 return true;
4383 }
4384
Jack Palevich2ff5c222009-07-23 15:11:22 -07004385 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004386 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004387 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004388 memset(pType, 0, sizeof(*pType));
4389 pType->tag = tag;
4390 pType->pHead = pHead;
4391 pType->pTail = pTail;
4392 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004393 }
4394
Jack Palevich2ff5c222009-07-23 15:11:22 -07004395 Type* createPtrType(Type* pType) {
4396 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004397 }
4398
4399 /**
4400 * Try to print a type in declaration order
4401 */
Jack Palevich86351982009-06-30 18:09:56 -07004402 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004403 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004404 if (pType == NULL) {
4405 buffer.appendCStr("null");
4406 return;
4407 }
Jack Palevich3f226492009-07-02 14:46:19 -07004408 decodeTypeImp(buffer, pType);
4409 }
4410
4411 void decodeTypeImp(String& buffer, Type* pType) {
4412 decodeTypeImpPrefix(buffer, pType);
4413
Jack Palevich86351982009-06-30 18:09:56 -07004414 String temp;
4415 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004416 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004417 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004418 }
4419
4420 decodeTypeImpPostfix(buffer, pType);
4421 }
4422
4423 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4424 TypeTag tag = pType->tag;
4425
Jack Palevich37c54bd2009-07-14 18:35:36 -07004426 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004427 switch (tag) {
4428 case TY_INT:
4429 buffer.appendCStr("int");
4430 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004431 case TY_SHORT:
4432 buffer.appendCStr("short");
4433 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004434 case TY_CHAR:
4435 buffer.appendCStr("char");
4436 break;
4437 case TY_VOID:
4438 buffer.appendCStr("void");
4439 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004440 case TY_FLOAT:
4441 buffer.appendCStr("float");
4442 break;
4443 case TY_DOUBLE:
4444 buffer.appendCStr("double");
4445 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004446 default:
4447 break;
4448 }
Jack Palevich86351982009-06-30 18:09:56 -07004449 buffer.append(' ');
4450 }
Jack Palevich3f226492009-07-02 14:46:19 -07004451
4452 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004453 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004454 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004455 case TY_SHORT:
4456 break;
Jack Palevich86351982009-06-30 18:09:56 -07004457 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004458 break;
4459 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004460 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004461 case TY_FLOAT:
4462 break;
4463 case TY_DOUBLE:
4464 break;
Jack Palevich86351982009-06-30 18:09:56 -07004465 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004466 decodeTypeImpPrefix(buffer, pType->pHead);
4467 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4468 buffer.append('(');
4469 }
4470 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004471 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004472 case TY_ARRAY:
4473 decodeTypeImpPrefix(buffer, pType->pHead);
4474 break;
Jack Palevich86351982009-06-30 18:09:56 -07004475 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004476 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004477 break;
4478 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004479 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004480 break;
4481 default:
4482 String temp;
4483 temp.printf("Unknown tag %d", pType->tag);
4484 buffer.append(temp);
4485 break;
4486 }
Jack Palevich3f226492009-07-02 14:46:19 -07004487 }
4488
4489 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4490 TypeTag tag = pType->tag;
4491
4492 switch(tag) {
4493 case TY_POINTER:
4494 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4495 buffer.append(')');
4496 }
4497 decodeTypeImpPostfix(buffer, pType->pHead);
4498 break;
Jack Palevichb6154502009-08-04 14:56:09 -07004499 case TY_ARRAY:
4500 {
4501 String temp;
4502 temp.printf("[%d]", pType->length);
4503 buffer.append(temp);
4504 }
4505 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004506 case TY_FUNC:
4507 buffer.append('(');
4508 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4509 decodeTypeImp(buffer, pArg);
4510 if (pArg->pTail) {
4511 buffer.appendCStr(", ");
4512 }
4513 }
4514 buffer.append(')');
4515 break;
4516 default:
4517 break;
Jack Palevich86351982009-06-30 18:09:56 -07004518 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004519 }
4520
Jack Palevich86351982009-06-30 18:09:56 -07004521 void printType(Type* pType) {
4522 String buffer;
4523 decodeType(buffer, pType);
4524 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004525 }
4526
Jack Palevich2ff5c222009-07-23 15:11:22 -07004527 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004528 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004529 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004530 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004531 } else if (tok == TOK_SHORT) {
4532 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004533 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004534 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004535 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004536 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004537 } else if (tok == TOK_FLOAT) {
4538 pType = mkpFloat;
4539 } else if (tok == TOK_DOUBLE) {
4540 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004541 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004542 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004543 }
4544 next();
Jack Palevich86351982009-06-30 18:09:56 -07004545 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004546 }
4547
Jack Palevich2ff5c222009-07-23 15:11:22 -07004548 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004549 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004550 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004551 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004552 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004553 if (declName) {
4554 // Clone the parent type so we can set a unique ID
Jack Palevichb6154502009-08-04 14:56:09 -07004555 Type* pOldType = pType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004556 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004557
Jack Palevich86351982009-06-30 18:09:56 -07004558 pType->id = declName;
Jack Palevichb6154502009-08-04 14:56:09 -07004559 pType->length = pOldType->length;
4560 } else if (nameRequired) {
4561 error("Expected a variable name");
Jack Palevich86351982009-06-30 18:09:56 -07004562 }
Jack Palevich3f226492009-07-02 14:46:19 -07004563 // fprintf(stderr, "Parsed a declaration: ");
4564 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004565 if (reportFailure) {
4566 return NULL;
4567 }
Jack Palevich86351982009-06-30 18:09:56 -07004568 return pType;
4569 }
4570
Jack Palevich2ff5c222009-07-23 15:11:22 -07004571 Type* expectDeclaration(Type* pBaseType) {
4572 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004573 if (! pType) {
4574 error("Expected a declaration");
4575 }
4576 return pType;
4577 }
4578
Jack Palevich3f226492009-07-02 14:46:19 -07004579 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004580 Type* acceptCastTypeDeclaration() {
4581 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004582 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004583 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004584 }
Jack Palevich86351982009-06-30 18:09:56 -07004585 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004586 }
4587
Jack Palevich2ff5c222009-07-23 15:11:22 -07004588 Type* expectCastTypeDeclaration() {
4589 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004590 if (! pType) {
4591 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004592 }
Jack Palevich3f226492009-07-02 14:46:19 -07004593 return pType;
4594 }
4595
4596 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004597 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004598 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004599 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004600 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004601 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004602 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004603 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004604 return pType;
4605 }
4606
4607 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004608 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004609 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004610 // direct-dcl :
4611 // name
4612 // (dcl)
4613 // direct-dcl()
4614 // direct-dcl[]
4615 Type* pNewHead = NULL;
4616 if (accept('(')) {
4617 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004618 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004619 skip(')');
4620 } else if ((declName = acceptSymbol()) != 0) {
4621 if (nameAllowed == false && declName) {
4622 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004623 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004624 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004625 } else if (nameRequired && ! declName) {
4626 String temp;
4627 decodeToken(temp, tok, true);
4628 error("Expected name. Got %s", temp.getUnwrapped());
4629 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004630 }
Jack Palevichb6154502009-08-04 14:56:09 -07004631 for(;;) {
4632 if (accept('(')) {
4633 // Function declaration
4634 Type* pTail = acceptArgs(nameAllowed);
4635 pType = createType(TY_FUNC, pType, pTail);
4636 skip(')');
4637 } if (accept('[')) {
4638 if (tok != ']') {
4639 if (tok != TOK_NUM || tokc <= 0) {
4640 error("Expected positive integer constant");
4641 } else {
4642 Type* pDecayType = createPtrType(pType);
4643 pType = createType(TY_ARRAY, pType, pDecayType);
4644 pType->length = tokc;
4645 }
4646 next();
4647 }
4648 skip(']');
4649 } else {
4650 break;
4651 }
Jack Palevich86351982009-06-30 18:09:56 -07004652 }
Jack Palevich3f226492009-07-02 14:46:19 -07004653
4654 if (pNewHead) {
4655 Type* pA = pNewHead;
4656 while (pA->pHead) {
4657 pA = pA->pHead;
4658 }
4659 pA->pHead = pType;
4660 pType = pNewHead;
4661 }
Jack Palevich86351982009-06-30 18:09:56 -07004662 return pType;
4663 }
4664
Jack Palevich2ff5c222009-07-23 15:11:22 -07004665 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004666 Type* pHead = NULL;
4667 Type* pTail = NULL;
4668 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004669 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004670 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004671 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004672 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004673 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004674 if (!pHead) {
4675 pHead = pParam;
4676 pTail = pParam;
4677 } else {
4678 pTail->pTail = pParam;
4679 pTail = pParam;
4680 }
4681 }
4682 }
4683 if (! accept(',')) {
4684 break;
4685 }
4686 }
4687 return pHead;
4688 }
4689
Jack Palevich2ff5c222009-07-23 15:11:22 -07004690 Type* expectPrimitiveType() {
4691 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004692 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004693 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004694 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004695 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004696 }
Jack Palevich86351982009-06-30 18:09:56 -07004697 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004698 }
4699
Jack Palevichb5e33312009-07-30 19:06:34 -07004700 void checkLVal() {
4701 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4702 error("Expected an lval");
4703 }
4704 }
4705
Jack Palevich86351982009-06-30 18:09:56 -07004706 void addGlobalSymbol(Type* pDecl) {
4707 tokenid_t t = pDecl->id;
4708 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004709 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004710 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004711 }
Jack Palevich86351982009-06-30 18:09:56 -07004712 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004713 }
4714
Jack Palevich86351982009-06-30 18:09:56 -07004715 void reportDuplicate(tokenid_t t) {
4716 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004717 }
4718
Jack Palevich86351982009-06-30 18:09:56 -07004719 void addLocalSymbol(Type* pDecl) {
4720 tokenid_t t = pDecl->id;
4721 if (mLocals.isDefinedAtCurrentLevel(t)) {
4722 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004723 }
Jack Palevich86351982009-06-30 18:09:56 -07004724 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004725 }
4726
Jack Palevich95727a02009-07-06 12:07:15 -07004727 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004728 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004729
Jack Palevich95727a02009-07-06 12:07:15 -07004730 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004731 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004732 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004733 if (!pDecl) {
4734 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004735 }
Jack Palevich86351982009-06-30 18:09:56 -07004736 int variableAddress = 0;
4737 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004738 size_t alignment = pGen->stackAlignmentOf(pDecl);
4739 size_t alignmentMask = ~ (alignment - 1);
4740 size_t sizeOf = pGen->sizeOf(pDecl);
4741 loc = (loc + alignment - 1) & alignmentMask;
4742 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4743 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004744 variableAddress = -loc;
4745 VI(pDecl->id)->pAddress = (void*) variableAddress;
4746 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004747 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004748 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004749 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004750 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004751 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004752 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004753 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004754 if (tok == ',')
4755 next();
4756 }
4757 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004758 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004759 }
4760 }
4761
Jack Palevichf1728be2009-06-12 13:53:51 -07004762 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004763 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004764 }
4765
Jack Palevich37c54bd2009-07-14 18:35:36 -07004766 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004767 if (token == EOF ) {
4768 buffer.printf("EOF");
4769 } else if (token == TOK_NUM) {
4770 buffer.printf("numeric constant");
4771 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004772 if (token < 32) {
4773 buffer.printf("'\\x%02x'", token);
4774 } else {
4775 buffer.printf("'%c'", token);
4776 }
Jack Palevich569f1352009-06-29 14:29:08 -07004777 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004778 if (quote) {
4779 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4780 buffer.printf("keyword \"%s\"", nameof(token));
4781 } else {
4782 buffer.printf("symbol \"%s\"", nameof(token));
4783 }
4784 } else {
4785 buffer.printf("%s", nameof(token));
4786 }
Jack Palevich569f1352009-06-29 14:29:08 -07004787 }
4788 }
4789
Jack Palevich40600de2009-07-01 15:32:35 -07004790 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004791 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004792 if (!result) {
4793 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004794 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004795 error("Expected symbol. Got %s", temp.getUnwrapped());
4796 }
4797 return result;
4798 }
4799
Jack Palevich86351982009-06-30 18:09:56 -07004800 tokenid_t acceptSymbol() {
4801 tokenid_t result = 0;
4802 if (tok >= TOK_SYMBOL) {
4803 result = tok;
4804 next();
Jack Palevich86351982009-06-30 18:09:56 -07004805 }
4806 return result;
4807 }
4808
Jack Palevichb7c81e92009-06-04 19:56:13 -07004809 void globalDeclarations() {
4810 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004811 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004812 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004813 break;
4814 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004815 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004816 if (!pDecl) {
4817 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004818 }
Jack Palevich86351982009-06-30 18:09:56 -07004819 if (! isDefined(pDecl->id)) {
4820 addGlobalSymbol(pDecl);
4821 }
4822 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004823 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004824 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004825 }
Jack Palevich86351982009-06-30 18:09:56 -07004826 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004827 // it's a variable declaration
4828 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004829 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004830 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004831 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004832 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004833 }
Jack Palevich86351982009-06-30 18:09:56 -07004834 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004835 if (tok == TOK_NUM) {
4836 if (name) {
4837 * (int*) name->pAddress = tokc;
4838 }
4839 next();
4840 } else {
4841 error("Expected an integer constant");
4842 }
4843 }
Jack Palevich86351982009-06-30 18:09:56 -07004844 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004845 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004846 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004847 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004848 if (!pDecl) {
4849 break;
4850 }
4851 if (! isDefined(pDecl->id)) {
4852 addGlobalSymbol(pDecl);
4853 }
4854 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004855 }
4856 skip(';');
4857 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004858 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004859 if (accept(';')) {
4860 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004861 } else if (tok != '{') {
4862 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004863 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004864 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004865 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004866 /* patch forward references */
4867 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004868 /* put function address */
4869 name->pAddress = (void*) codeBuf.getPC();
4870 }
4871 // Calculate stack offsets for parameters
4872 mLocals.pushLevel();
4873 intptr_t a = 8;
4874 int argCount = 0;
4875 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4876 Type* pArg = pP->pHead;
4877 addLocalSymbol(pArg);
4878 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004879 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004880 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004881 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004882 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004883 argCount++;
4884 }
4885 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004886 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004887 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004888 block(0, true);
4889 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004890 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004891 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004892 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004893 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004894 }
4895 }
4896 }
4897
Jack Palevich9cbd2262009-07-08 16:48:41 -07004898 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4899 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4900 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004901 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004902 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004903 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004904 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004905 char* result = (char*) base;
4906 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004907 return result;
4908 }
4909
Jack Palevich21a15a22009-05-11 14:49:29 -07004910 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004911 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004912 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004913 pGlobalBase = 0;
4914 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004915 if (pGen) {
4916 delete pGen;
4917 pGen = 0;
4918 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004919 if (file) {
4920 delete file;
4921 file = 0;
4922 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004923 }
4924
Jack Palevich8c246a92009-07-14 21:14:10 -07004925 // One-time initialization, when class is constructed.
4926 void init() {
4927 mpSymbolLookupFn = 0;
4928 mpSymbolLookupContext = 0;
4929 }
4930
Jack Palevich21a15a22009-05-11 14:49:29 -07004931 void clear() {
4932 tok = 0;
4933 tokc = 0;
4934 tokl = 0;
4935 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004936 rsym = 0;
4937 loc = 0;
4938 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004939 dptr = 0;
4940 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004941 file = 0;
4942 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004943 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004944 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004945 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004946 mLineNumber = 1;
4947 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004948 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004949
Jack Palevich22305132009-05-13 10:58:45 -07004950 void setArchitecture(const char* architecture) {
4951 delete pGen;
4952 pGen = 0;
4953
4954 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004955#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004956 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004957 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004958 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004959#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004960#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004961 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004962 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004963 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004964#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004965 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004966 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004967 }
4968 }
4969
4970 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004971#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004972 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004973#elif defined(DEFAULT_X86_CODEGEN)
4974 pGen = new X86CodeGenerator();
4975#endif
4976 }
4977 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004978 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004979 } else {
4980 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004981 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004982 }
4983 }
4984
Jack Palevich77ae76e2009-05-10 19:59:24 -07004985public:
Jack Palevich22305132009-05-13 10:58:45 -07004986 struct args {
4987 args() {
4988 architecture = 0;
4989 }
4990 const char* architecture;
4991 };
4992
Jack Paleviche7b59062009-05-19 17:12:17 -07004993 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004994 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004995 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004996 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004997
Jack Paleviche7b59062009-05-19 17:12:17 -07004998 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004999 cleanup();
5000 }
5001
Jack Palevich8c246a92009-07-14 21:14:10 -07005002 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5003 mpSymbolLookupFn = pFn;
5004 mpSymbolLookupContext = pContext;
5005 }
5006
Jack Palevich1cdef202009-05-22 12:06:27 -07005007 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005008 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07005009
Jack Palevich2ff5c222009-07-23 15:11:22 -07005010 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07005011 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07005012 cleanup();
5013 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07005014 mTokenTable.setArena(&mGlobalArena);
5015 mGlobals.setArena(&mGlobalArena);
5016 mGlobals.setTokenTable(&mTokenTable);
5017 mLocals.setArena(&mLocalArena);
5018 mLocals.setTokenTable(&mTokenTable);
5019
5020 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07005021 codeBuf.init(ALLOC_SIZE);
5022 setArchitecture(NULL);
5023 if (!pGen) {
5024 return -1;
5025 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07005026#ifdef PROVIDE_TRACE_CODEGEN
5027 pGen = new TraceCodeGenerator(pGen);
5028#endif
5029 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07005030 pGen->init(&codeBuf);
5031 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07005032 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5033 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07005034 inp();
5035 next();
5036 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07005037 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07005038 result = pGen->finishCompile();
5039 if (result == 0) {
5040 if (mErrorBuf.len()) {
5041 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005042 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07005043 }
Jack Palevichce105a92009-07-16 14:30:33 -07005044 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07005045 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07005046 }
5047
Jack Palevich86351982009-06-30 18:09:56 -07005048 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07005049 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07005050 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07005051 mkpChar = createType(TY_CHAR, NULL, NULL);
5052 mkpVoid = createType(TY_VOID, NULL, NULL);
5053 mkpFloat = createType(TY_FLOAT, NULL, NULL);
5054 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5055 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
5056 mkpIntPtr = createPtrType(mkpInt);
5057 mkpCharPtr = createPtrType(mkpChar);
5058 mkpFloatPtr = createPtrType(mkpFloat);
5059 mkpDoublePtr = createPtrType(mkpDouble);
5060 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07005061 }
5062
Jack Palevicha6baa232009-06-12 11:25:59 -07005063 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07005064 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07005065 }
5066
Jack Palevich569f1352009-06-29 14:29:08 -07005067 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005068 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07005069 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07005070 }
5071
Jack Palevich569f1352009-06-29 14:29:08 -07005072 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07005073 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07005074 error("Undefined forward reference: %s",
5075 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07005076 }
5077 return true;
5078 }
5079
Jack Palevich21a15a22009-05-11 14:49:29 -07005080 int dump(FILE* out) {
5081 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5082 return 0;
5083 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07005084
Jack Palevicha6535612009-05-13 16:24:17 -07005085 int disassemble(FILE* out) {
5086 return pGen->disassemble(out);
5087 }
5088
Jack Palevich1cdef202009-05-22 12:06:27 -07005089 /* Look through the symbol table to find a symbol.
5090 * If found, return its value.
5091 */
5092 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07005093 if (mCompileResult == 0) {
5094 tokenid_t tok = mTokenTable.intern(name, strlen(name));
5095 VariableInfo* pVariableInfo = VI(tok);
5096 if (pVariableInfo) {
5097 return pVariableInfo->pAddress;
5098 }
Jack Palevich1cdef202009-05-22 12:06:27 -07005099 }
5100 return NULL;
5101 }
5102
Jack Palevicheedf9d22009-06-04 16:23:40 -07005103 void getPragmas(ACCsizei* actualStringCount,
5104 ACCsizei maxStringCount, ACCchar** strings) {
5105 int stringCount = mPragmaStringCount;
5106 if (actualStringCount) {
5107 *actualStringCount = stringCount;
5108 }
5109 if (stringCount > maxStringCount) {
5110 stringCount = maxStringCount;
5111 }
5112 if (strings) {
5113 char* pPragmas = mPragmas.getUnwrapped();
5114 while (stringCount-- > 0) {
5115 *strings++ = pPragmas;
5116 pPragmas += strlen(pPragmas) + 1;
5117 }
5118 }
5119 }
5120
Jack Palevichac0e95e2009-05-29 13:53:44 -07005121 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07005122 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07005123 }
5124
Jack Palevich77ae76e2009-05-10 19:59:24 -07005125};
5126
Jack Paleviche7b59062009-05-19 17:12:17 -07005127const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005128 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5129
Jack Paleviche7b59062009-05-19 17:12:17 -07005130const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005131 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5132 5, 5, /* ==, != */
5133 9, 10, /* &&, || */
5134 6, 7, 8, /* & ^ | */
5135 2, 2 /* ~ ! */
5136 };
5137
Jack Palevich8b0624c2009-05-20 12:12:06 -07005138#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005139FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07005140#endif
Jack Palevicha6535612009-05-13 16:24:17 -07005141
Jack Palevich8b0624c2009-05-20 12:12:06 -07005142#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07005143const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005144 0x1, // ++
5145 0xff, // --
5146 0xc1af0f, // *
5147 0xf9f79991, // /
5148 0xf9f79991, // % (With manual assist to swap results)
5149 0xc801, // +
5150 0xd8f7c829, // -
5151 0xe0d391, // <<
5152 0xf8d391, // >>
5153 0xe, // <=
5154 0xd, // >=
5155 0xc, // <
5156 0xf, // >
5157 0x4, // ==
5158 0x5, // !=
5159 0x0, // &&
5160 0x1, // ||
5161 0xc821, // &
5162 0xc831, // ^
5163 0xc809, // |
5164 0xd0f7, // ~
5165 0x4 // !
5166};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005167#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005168
Jack Palevich1cdef202009-05-22 12:06:27 -07005169struct ACCscript {
5170 ACCscript() {
5171 text = 0;
5172 textLength = 0;
5173 accError = ACC_NO_ERROR;
5174 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005175
Jack Palevich1cdef202009-05-22 12:06:27 -07005176 ~ACCscript() {
5177 delete text;
5178 }
Jack Palevich546b2242009-05-13 15:10:04 -07005179
Jack Palevich8c246a92009-07-14 21:14:10 -07005180 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5181 compiler.registerSymbolCallback(pFn, pContext);
5182 }
5183
Jack Palevich1cdef202009-05-22 12:06:27 -07005184 void setError(ACCenum error) {
5185 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5186 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005187 }
5188 }
5189
Jack Palevich1cdef202009-05-22 12:06:27 -07005190 ACCenum getError() {
5191 ACCenum result = accError;
5192 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005193 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005194 }
5195
Jack Palevich1cdef202009-05-22 12:06:27 -07005196 Compiler compiler;
5197 char* text;
5198 int textLength;
5199 ACCenum accError;
5200};
5201
5202
5203extern "C"
5204ACCscript* accCreateScript() {
5205 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005206}
Jack Palevich1cdef202009-05-22 12:06:27 -07005207
5208extern "C"
5209ACCenum accGetError( ACCscript* script ) {
5210 return script->getError();
5211}
5212
5213extern "C"
5214void accDeleteScript(ACCscript* script) {
5215 delete script;
5216}
5217
5218extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005219void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5220 ACCvoid* pContext) {
5221 script->registerSymbolCallback(pFn, pContext);
5222}
5223
5224extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005225void accScriptSource(ACCscript* script,
5226 ACCsizei count,
5227 const ACCchar ** string,
5228 const ACCint * length) {
5229 int totalLength = 0;
5230 for(int i = 0; i < count; i++) {
5231 int len = -1;
5232 const ACCchar* s = string[i];
5233 if (length) {
5234 len = length[i];
5235 }
5236 if (len < 0) {
5237 len = strlen(s);
5238 }
5239 totalLength += len;
5240 }
5241 delete script->text;
5242 char* text = new char[totalLength + 1];
5243 script->text = text;
5244 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005245 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005246 for(int i = 0; i < count; i++) {
5247 int len = -1;
5248 const ACCchar* s = string[i];
5249 if (length) {
5250 len = length[i];
5251 }
5252 if (len < 0) {
5253 len = strlen(s);
5254 }
Jack Palevich09555c72009-05-27 12:25:55 -07005255 memcpy(dest, s, len);
5256 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005257 }
5258 text[totalLength] = '\0';
5259}
5260
5261extern "C"
5262void accCompileScript(ACCscript* script) {
5263 int result = script->compiler.compile(script->text, script->textLength);
5264 if (result) {
5265 script->setError(ACC_INVALID_OPERATION);
5266 }
5267}
5268
5269extern "C"
5270void accGetScriptiv(ACCscript* script,
5271 ACCenum pname,
5272 ACCint * params) {
5273 switch (pname) {
5274 case ACC_INFO_LOG_LENGTH:
5275 *params = 0;
5276 break;
5277 }
5278}
5279
5280extern "C"
5281void accGetScriptInfoLog(ACCscript* script,
5282 ACCsizei maxLength,
5283 ACCsizei * length,
5284 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005285 char* message = script->compiler.getErrorMessage();
5286 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005287 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005288 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005289 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005290 if (infoLog && maxLength > 0) {
5291 int trimmedLength = maxLength < messageLength ?
5292 maxLength : messageLength;
5293 memcpy(infoLog, message, trimmedLength);
5294 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005295 }
5296}
5297
5298extern "C"
5299void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5300 ACCvoid ** address) {
5301 void* value = script->compiler.lookup(name);
5302 if (value) {
5303 *address = value;
5304 } else {
5305 script->setError(ACC_INVALID_VALUE);
5306 }
5307}
5308
Jack Palevicheedf9d22009-06-04 16:23:40 -07005309extern "C"
5310void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5311 ACCsizei maxStringCount, ACCchar** strings){
5312 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5313}
5314
-b master422972c2009-06-17 19:13:52 -07005315extern "C"
5316void accDisassemble(ACCscript* script) {
5317 script->compiler.disassemble(stderr);
5318}
5319
Jack Palevicheedf9d22009-06-04 16:23:40 -07005320
Jack Palevich1cdef202009-05-22 12:06:27 -07005321} // namespace acc
5322