blob: 313bf1c501091bdd7504616f8ba82b6010ca1efb [file] [log] [blame]
Jack Palevichae54f1f2009-05-08 14:54:15 -07001/*
Jack Paleviche7b59062009-05-19 17:12:17 -07002 * Android "Almost" C Compiler.
3 * This is a compiler for a small subset of the C language, intended for use
4 * in scripting environments where speed and memory footprint are important.
5 *
6 * This code is based upon the "unobfuscated" version of the
Jack Palevich1cdef202009-05-22 12:06:27 -07007 * Obfuscated Tiny C compiler, see the file LICENSE for details.
Jack Paleviche7b59062009-05-19 17:12:17 -07008 *
9 */
10
Jack Palevich77ae76e2009-05-10 19:59:24 -070011#include <ctype.h>
Jack Palevich8dc662e2009-06-09 22:53:47 +000012#include <errno.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070013#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070014#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070015#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070016#include <stdlib.h>
17#include <string.h>
Jack Palevich2d11dfb2009-06-08 14:34:26 -070018#include <cutils/hashmap.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich8dc662e2009-06-09 22:53:47 +000020#if defined(__i386__)
21#include <sys/mman.h>
22#endif
23
Jack Palevich546b2242009-05-13 15:10:04 -070024#if defined(__arm__)
25#include <unistd.h>
26#endif
27
Jack Paleviche7b59062009-05-19 17:12:17 -070028#if defined(__arm__)
29#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070030#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070031#elif defined(__i386__)
32#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070033#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070034#elif defined(__x86_64__)
35#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070036#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
38
Jack Paleviche7b59062009-05-19 17:12:17 -070039#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070040#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070041#endif
Jack Palevicha6535612009-05-13 16:24:17 -070042
Jack Palevich1cdef202009-05-22 12:06:27 -070043#include <acc/acc.h>
44
Jack Palevich09555c72009-05-27 12:25:55 -070045#define LOG_API(...) do {} while(0)
46// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070047
-b master422972c2009-06-17 19:13:52 -070048#define LOG_STACK(...) do {} while(0)
49// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
50
Jack Palevich9f51a262009-07-29 16:22:26 -070051#define ENABLE_ARM_DISASSEMBLY
Jack Palevichb67b18f2009-06-11 21:12:23 -070052// #define PROVIDE_TRACE_CODEGEN
53
Jack Palevichbbf8ab52009-05-11 11:54:30 -070054namespace acc {
55
Jack Palevich8df46192009-07-07 14:48:51 -070056// Subset of STL vector.
57template<class E> class Vector {
58 public:
59 Vector() {
60 mpBase = 0;
61 mUsed = 0;
62 mSize = 0;
63 }
64
65 ~Vector() {
66 if (mpBase) {
67 for(size_t i = 0; i < mUsed; i++) {
68 mpBase[mUsed].~E();
69 }
70 free(mpBase);
71 }
72 }
73
74 inline E& operator[](size_t i) {
75 return mpBase[i];
76 }
77
78 inline E& front() {
79 return mpBase[0];
80 }
81
82 inline E& back() {
83 return mpBase[mUsed - 1];
84 }
85
86 void pop_back() {
87 mUsed -= 1;
88 mpBase[mUsed].~E();
89 }
90
91 void push_back(const E& item) {
92 * ensure(1) = item;
93 }
94
95 size_t size() {
96 return mUsed;
97 }
98
99private:
100 E* ensure(int n) {
101 size_t newUsed = mUsed + n;
102 if (newUsed > mSize) {
103 size_t newSize = mSize * 2 + 10;
104 if (newSize < newUsed) {
105 newSize = newUsed;
106 }
107 mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
108 mSize = newSize;
109 }
110 E* result = mpBase + mUsed;
111 mUsed = newUsed;
112 return result;
113 }
114
115 E* mpBase;
116 size_t mUsed;
117 size_t mSize;
118};
119
Jack Palevichac0e95e2009-05-29 13:53:44 -0700120class ErrorSink {
121public:
122 void error(const char *fmt, ...) {
123 va_list ap;
124 va_start(ap, fmt);
125 verror(fmt, ap);
126 va_end(ap);
127 }
128
Marco Nelisseneea5ae92009-07-08 16:59:18 -0700129 virtual ~ErrorSink() {}
Jack Palevichac0e95e2009-05-29 13:53:44 -0700130 virtual void verror(const char* fmt, va_list ap) = 0;
131};
132
133class Compiler : public ErrorSink {
Jack Palevich8df46192009-07-07 14:48:51 -0700134 typedef int tokenid_t;
135 enum TypeTag {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700136 TY_INT, // 0
137 TY_CHAR, // 1
138 TY_SHORT, // 2
139 TY_VOID, // 3
140 TY_FLOAT, // 4
141 TY_DOUBLE, // 5
142 TY_POINTER, // 6
143 TY_ARRAY, // 7
144 TY_STRUCT, // 8
145 TY_FUNC, // 9
146 TY_PARAM // 10
Jack Palevich8df46192009-07-07 14:48:51 -0700147 };
148
149 struct Type {
150 TypeTag tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700151 tokenid_t id; // For function arguments (stores length for array)
Jack Palevich8df46192009-07-07 14:48:51 -0700152 Type* pHead;
153 Type* pTail;
154 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700155
Jack Palevichba929a42009-07-17 10:20:32 -0700156 enum ExpressionType {
157 ET_RVALUE,
158 ET_LVALUE
159 };
160
161 struct ExpressionValue {
162 ExpressionValue() {
163 et = ET_RVALUE;
164 pType = NULL;
165 }
166 ExpressionType et;
167 Type* pType;
168 };
169
Jack Palevich21a15a22009-05-11 14:49:29 -0700170 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700171 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700172 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700173 ErrorSink* mErrorSink;
174 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700175 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700176
Jack Palevich21a15a22009-05-11 14:49:29 -0700177 void release() {
178 if (pProgramBase != 0) {
179 free(pProgramBase);
180 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700181 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700182 }
183
Jack Palevich0a280a02009-06-11 10:53:51 -0700184 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700185 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700186 bool overflow = newSize > mSize;
187 if (overflow && !mOverflowed) {
188 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700189 if (mErrorSink) {
190 mErrorSink->error("Code too large: %d bytes", newSize);
191 }
192 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700193 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700194 }
195
Jack Palevich21a15a22009-05-11 14:49:29 -0700196 public:
197 CodeBuf() {
198 pProgramBase = 0;
199 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700200 mErrorSink = 0;
201 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700202 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700203 }
204
205 ~CodeBuf() {
206 release();
207 }
208
209 void init(int size) {
210 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700211 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700212 pProgramBase = (char*) calloc(1, size);
213 ind = pProgramBase;
214 }
215
Jack Palevichac0e95e2009-05-29 13:53:44 -0700216 void setErrorSink(ErrorSink* pErrorSink) {
217 mErrorSink = pErrorSink;
218 }
219
Jack Palevich546b2242009-05-13 15:10:04 -0700220 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700221 if(check(4)) {
222 return 0;
223 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700224 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700225 * (int*) ind = n;
226 ind += 4;
227 return result;
228 }
229
Jack Palevich21a15a22009-05-11 14:49:29 -0700230 /*
231 * Output a byte. Handles all values, 0..ff.
232 */
233 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700234 if(check(1)) {
235 return;
236 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700237 *ind++ = n;
238 }
239
Jack Palevich21a15a22009-05-11 14:49:29 -0700240 inline void* getBase() {
241 return (void*) pProgramBase;
242 }
243
Jack Palevich8b0624c2009-05-20 12:12:06 -0700244 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700245 return ind - pProgramBase;
246 }
247
Jack Palevich8b0624c2009-05-20 12:12:06 -0700248 intptr_t getPC() {
249 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 }
251 };
252
Jack Palevich1cdef202009-05-22 12:06:27 -0700253 /**
254 * A code generator creates an in-memory program, generating the code on
255 * the fly. There is one code generator implementation for each supported
256 * architecture.
257 *
258 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700259 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700260 * FP - a frame pointer for accessing function arguments and local
261 * variables.
262 * SP - a stack pointer for storing intermediate results while evaluating
263 * expressions. The stack pointer grows downwards.
264 *
265 * The function calling convention is that all arguments are placed on the
266 * stack such that the first argument has the lowest address.
267 * After the call, the result is in R0. The caller is responsible for
268 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700269 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700270 * FP and SP registers are saved.
271 */
272
Jack Palevich21a15a22009-05-11 14:49:29 -0700273 class CodeGenerator {
274 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700275 CodeGenerator() {
276 mErrorSink = 0;
277 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700278 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700279 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700280 virtual ~CodeGenerator() {}
281
Jack Palevich22305132009-05-13 10:58:45 -0700282 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700283 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700284 pCodeBuf->setErrorSink(mErrorSink);
285 }
286
Jack Palevichb67b18f2009-06-11 21:12:23 -0700287 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700288 mErrorSink = pErrorSink;
289 if (pCodeBuf) {
290 pCodeBuf->setErrorSink(mErrorSink);
291 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700292 }
293
Jack Palevich58c30ee2009-07-17 16:35:23 -0700294 /* Give the code generator some utility types so it can
295 * use its own types as needed for the results of some
296 * operations like gcmp.
297 */
298
Jack Palevicha8f427f2009-07-13 18:40:08 -0700299 void setTypes(Type* pInt) {
300 mkpInt = pInt;
301 }
302
Jack Palevich1cdef202009-05-22 12:06:27 -0700303 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700304 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700305 * Save the old value of the FP.
306 * Set the new value of the FP.
307 * Convert from the native platform calling convention to
308 * our stack-based calling convention. This may require
309 * pushing arguments from registers to the stack.
310 * Allocate "N" bytes of stack space. N isn't known yet, so
311 * just emit the instructions for adjusting the stack, and return
312 * the address to patch up. The patching will be done in
313 * functionExit().
314 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700315 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700316 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700317
Jack Palevich1cdef202009-05-22 12:06:27 -0700318 /* Emit a function epilog.
319 * Restore the old SP and FP register values.
320 * Return to the calling function.
321 * argCount - the number of arguments to the function.
322 * localVariableAddress - returned from functionEntry()
323 * localVariableSize - the size in bytes of the local variables.
324 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700325 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700326 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700327
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 /* load immediate value to R0 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700329 virtual void li(int i) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700330
Jack Palevich1a539db2009-07-08 13:04:41 -0700331 /* Load floating point value from global address. */
332 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700333
Jack Palevich1cdef202009-05-22 12:06:27 -0700334 /* Jump to a target, and return the address of the word that
335 * holds the target data, in case it needs to be fixed up later.
336 */
Jack Palevich22305132009-05-13 10:58:45 -0700337 virtual int gjmp(int t) = 0;
338
Jack Palevich1cdef202009-05-22 12:06:27 -0700339 /* Test R0 and jump to a target if the test succeeds.
340 * l = 0: je, l == 1: jne
341 * Return the address of the word that holds the targed data, in
342 * case it needs to be fixed up later.
343 */
Jack Palevich22305132009-05-13 10:58:45 -0700344 virtual int gtst(bool l, int t) = 0;
345
Jack Palevich9eed7a22009-07-06 17:24:34 -0700346 /* Compare TOS against R0, and store the boolean result in R0.
347 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700348 * op specifies the comparison.
349 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700350 virtual void gcmp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700351
Jack Palevich9eed7a22009-07-06 17:24:34 -0700352 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700353 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700354 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700355 */
Jack Palevich546b2242009-05-13 15:10:04 -0700356 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700357
Jack Palevich9eed7a22009-07-06 17:24:34 -0700358 /* Compare 0 against R0, and store the boolean result in R0.
359 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700360 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700361 virtual void gUnaryCmp(int op) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700362
363 /* Perform the arithmetic op specified by op. 0 is the
364 * left argument, R0 is the right argument.
365 */
366 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700367
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700368 /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 */
370 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700371
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700372 /* Turn R0, TOS into R0 TOS R0 */
373
374 virtual void over() = 0;
375
376 /* Pop R0 from the stack. (Also known as "drop")
Jack Palevich58c30ee2009-07-17 16:35:23 -0700377 */
378 virtual void popR0() = 0;
379
Jack Palevich9eed7a22009-07-06 17:24:34 -0700380 /* Store R0 to the address stored in TOS.
381 * The TOS is popped.
Jack Palevich1cdef202009-05-22 12:06:27 -0700382 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700383 virtual void storeR0ToTOS() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700384
Jack Palevich1cdef202009-05-22 12:06:27 -0700385 /* Load R0 from the address stored in R0.
Jack Palevich1cdef202009-05-22 12:06:27 -0700386 */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700387 virtual void loadR0FromR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700388
Jack Palevich1cdef202009-05-22 12:06:27 -0700389 /* Load the absolute address of a variable to R0.
390 * If ea <= LOCAL, then this is a local variable, or an
391 * argument, addressed relative to FP.
392 * else it is an absolute global address.
Jack Palevich9f51a262009-07-29 16:22:26 -0700393 *
Jack Palevichb5e33312009-07-30 19:06:34 -0700394 * et is ET_RVALUE for things like string constants, ET_LVALUE for
395 * variables.
Jack Palevich1cdef202009-05-22 12:06:27 -0700396 */
Jack Palevichb5e33312009-07-30 19:06:34 -0700397 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700398
Jack Palevich9f51a262009-07-29 16:22:26 -0700399 /* Load the pc-relative address of a forward-referenced variable to R0.
400 * Return the address of the 4-byte constant so that it can be filled
401 * in later.
402 */
403 virtual int leaForward(int ea, Type* pPointerType) = 0;
404
Jack Palevich8df46192009-07-07 14:48:51 -0700405 /**
406 * Convert R0 to the given type.
407 */
408 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700409
Jack Palevich1cdef202009-05-22 12:06:27 -0700410 /* Emit code to adjust the stack for a function call. Return the
411 * label for the address of the instruction that adjusts the
412 * stack size. This will be passed as argument "a" to
413 * endFunctionCallArguments.
414 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700415 virtual int beginFunctionCallArguments() = 0;
416
Jack Palevich1cdef202009-05-22 12:06:27 -0700417 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700418 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700419 */
Jack Palevich8148c5b2009-07-16 18:24:47 -0700420 virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700421
Jack Palevich1cdef202009-05-22 12:06:27 -0700422 /* Patch the function call preamble.
423 * a is the address returned from beginFunctionCallArguments
424 * l is the number of bytes the arguments took on the stack.
425 * Typically you would also emit code to convert the argument
426 * list into whatever the native function calling convention is.
427 * On ARM for example you would pop the first 5 arguments into
428 * R0..R4
429 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700430 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700431
Jack Palevich1cdef202009-05-22 12:06:27 -0700432 /* Emit a call to an unknown function. The argument "symbol" needs to
433 * be stored in the location where the address should go. It forms
434 * a chain. The address will be patched later.
435 * Return the address of the word that has to be patched.
436 */
Jack Palevich8df46192009-07-07 14:48:51 -0700437 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700438
Jack Palevich1cdef202009-05-22 12:06:27 -0700439 /* Call a function pointer. L is the number of bytes the arguments
440 * take on the stack. The address of the function is stored at
441 * location SP + l.
442 */
Jack Palevich8df46192009-07-07 14:48:51 -0700443 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700444
Jack Palevich1cdef202009-05-22 12:06:27 -0700445 /* Adjust SP after returning from a function call. l is the
446 * number of bytes of arguments stored on the stack. isIndirect
447 * is true if this was an indirect call. (In which case the
448 * address of the function is stored at location SP + l.)
449 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700450 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700451
Jack Palevich1cdef202009-05-22 12:06:27 -0700452 /* Print a disassembly of the assembled code to out. Return
453 * non-zero if there is an error.
454 */
Jack Palevicha6535612009-05-13 16:24:17 -0700455 virtual int disassemble(FILE* out) = 0;
456
Jack Palevich1cdef202009-05-22 12:06:27 -0700457 /* Generate a symbol at the current PC. t is the head of a
458 * linked list of addresses to patch.
459 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700460 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700461
Jack Palevich9f51a262009-07-29 16:22:26 -0700462 /* Resolve a forward reference function at the current PC.
463 * t is the head of a
464 * linked list of addresses to patch.
465 * (Like gsym, but using absolute address, not PC relative address.)
466 */
467 virtual void resolveForward(int t) = 0;
468
Jack Palevich1cdef202009-05-22 12:06:27 -0700469 /*
470 * Do any cleanup work required at the end of a compile.
471 * For example, an instruction cache might need to be
472 * invalidated.
473 * Return non-zero if there is an error.
474 */
475 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700476
Jack Palevicha6535612009-05-13 16:24:17 -0700477 /**
478 * Adjust relative branches by this amount.
479 */
480 virtual int jumpOffset() = 0;
481
Jack Palevich9eed7a22009-07-06 17:24:34 -0700482 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700483 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700484 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700485 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700486
487 /**
488 * Array element alignment (in bytes) for this type of data.
489 */
490 virtual size_t sizeOf(Type* type) = 0;
491
Jack Palevich9cbd2262009-07-08 16:48:41 -0700492 /**
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700493 * Stack alignment of this type of data
494 */
495 virtual size_t stackAlignmentOf(Type* pType) = 0;
496
497 /**
498 * Argument stack argument size of this data type.
Jack Palevich9cbd2262009-07-08 16:48:41 -0700499 */
500 virtual size_t stackSizeOf(Type* pType) = 0;
501
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700502 virtual Type* getR0Type() {
Jack Palevichba929a42009-07-17 10:20:32 -0700503 return mExpressionStack.back().pType;
Jack Palevich1a539db2009-07-08 13:04:41 -0700504 }
505
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700506 virtual ExpressionType getR0ExpressionType() {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700507 return mExpressionStack.back().et;
508 }
509
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700510 virtual void setR0ExpressionType(ExpressionType et) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -0700511 mExpressionStack.back().et = et;
512 }
513
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700514 virtual size_t getExpressionStackDepth() {
515 return mExpressionStack.size();
516 }
517
Jack Palevichb5e33312009-07-30 19:06:34 -0700518 virtual void forceR0RVal() {
519 if (getR0ExpressionType() == ET_LVALUE) {
520 loadR0FromR0();
521 }
522 }
523
Jack Palevich21a15a22009-05-11 14:49:29 -0700524 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700525 /*
526 * Output a byte. Handles all values, 0..ff.
527 */
528 void ob(int n) {
529 pCodeBuf->ob(n);
530 }
531
Jack Palevich8b0624c2009-05-20 12:12:06 -0700532 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700533 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700534 }
535
Jack Palevich8b0624c2009-05-20 12:12:06 -0700536 intptr_t getBase() {
537 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700538 }
539
Jack Palevich8b0624c2009-05-20 12:12:06 -0700540 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700541 return pCodeBuf->getPC();
542 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700543
544 intptr_t getSize() {
545 return pCodeBuf->getSize();
546 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700547
548 void error(const char* fmt,...) {
549 va_list ap;
550 va_start(ap, fmt);
551 mErrorSink->verror(fmt, ap);
552 va_end(ap);
553 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700554
555 void assert(bool test) {
556 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700557 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700558 error("code generator assertion failed.");
559 }
560 }
Jack Palevich8df46192009-07-07 14:48:51 -0700561
562 void setR0Type(Type* pType) {
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700563 assert(pType != NULL);
Jack Palevichba929a42009-07-17 10:20:32 -0700564 mExpressionStack.back().pType = pType;
Jack Palevichb5e33312009-07-30 19:06:34 -0700565 mExpressionStack.back().et = ET_RVALUE;
566 }
567
568 void setR0Type(Type* pType, ExpressionType et) {
569 assert(pType != NULL);
570 mExpressionStack.back().pType = pType;
571 mExpressionStack.back().et = et;
Jack Palevich8df46192009-07-07 14:48:51 -0700572 }
573
Jack Palevich8df46192009-07-07 14:48:51 -0700574 Type* getTOSType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700575 return mExpressionStack[mExpressionStack.size()-2].pType;
Jack Palevich8df46192009-07-07 14:48:51 -0700576 }
577
578 void pushType() {
Jack Palevichba929a42009-07-17 10:20:32 -0700579 if (mExpressionStack.size()) {
580 mExpressionStack.push_back(mExpressionStack.back());
581 } else {
582 mExpressionStack.push_back(ExpressionValue());
583 }
584
Jack Palevich8df46192009-07-07 14:48:51 -0700585 }
586
Jack Palevichddf7c9c2009-07-29 10:28:18 -0700587 void overType() {
588 size_t size = mExpressionStack.size();
589 if (size >= 2) {
590 mExpressionStack.push_back(mExpressionStack.back());
591 mExpressionStack[size-1] = mExpressionStack[size-2];
592 mExpressionStack[size-2] = mExpressionStack[size];
593 }
594 }
595
Jack Palevich8df46192009-07-07 14:48:51 -0700596 void popType() {
597 mExpressionStack.pop_back();
598 }
599
600 bool bitsSame(Type* pA, Type* pB) {
601 return collapseType(pA->tag) == collapseType(pB->tag);
602 }
603
604 TypeTag collapseType(TypeTag tag) {
605 static const TypeTag collapsedTag[] = {
Jack Palevichc9b8ffc2009-08-03 14:42:57 -0700606 TY_INT,
607 TY_INT,
608 TY_INT,
609 TY_VOID,
610 TY_FLOAT,
611 TY_DOUBLE,
612 TY_INT,
613 TY_INT,
614 TY_VOID,
615 TY_VOID,
616 TY_VOID
617 };
Jack Palevich8df46192009-07-07 14:48:51 -0700618 return collapsedTag[tag];
619 }
620
Jack Palevich1a539db2009-07-08 13:04:41 -0700621 TypeTag collapseTypeR0() {
622 return collapseType(getR0Type()->tag);
623 }
624
625 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700626 return isFloatTag(pType->tag);
627 }
628
629 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700630 return tag == TY_FLOAT || tag == TY_DOUBLE;
631 }
632
Jack Palevicha8f427f2009-07-13 18:40:08 -0700633 Type* mkpInt;
634
Jack Palevich21a15a22009-05-11 14:49:29 -0700635 private:
Jack Palevichba929a42009-07-17 10:20:32 -0700636 Vector<ExpressionValue> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700637 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700638 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700639 };
640
Jack Paleviche7b59062009-05-19 17:12:17 -0700641#ifdef PROVIDE_ARM_CODEGEN
642
Jack Palevich22305132009-05-13 10:58:45 -0700643 class ARMCodeGenerator : public CodeGenerator {
644 public:
645 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700646
Jack Palevich22305132009-05-13 10:58:45 -0700647 virtual ~ARMCodeGenerator() {}
648
649 /* returns address to patch with local variable size
650 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700651 virtual int functionEntry(Type* pDecl) {
-b master422972c2009-06-17 19:13:52 -0700652 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700653 // sp -> arg4 arg5 ...
654 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700655 int regArgCount = calcRegArgCount(pDecl);
656 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700657 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700658 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700659 }
660 // sp -> arg0 arg1 ...
661 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700662 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700663 // sp, fp -> oldfp, retadr, arg0 arg1 ....
664 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700665 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700666 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700667 // We don't know how many local variables we are going to use,
668 // but we will round the allocation up to a multiple of
669 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700670 }
671
Jack Palevichb7718b92009-07-09 22:00:24 -0700672 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
-b master422972c2009-06-17 19:13:52 -0700673 // Round local variable size up to a multiple of stack alignment
674 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
675 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700676 // Patch local variable allocation code:
677 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700678 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700679 }
Jack Palevich69796b62009-05-14 15:42:26 -0700680 *(char*) (localVariableAddress) = localVariableSize;
681
682 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
683 o4(0xE1A0E00B); // mov lr, fp
684 o4(0xE59BB000); // ldr fp, [fp]
685 o4(0xE28ED004); // add sp, lr, #4
686 // sp -> retadr, arg0, ...
687 o4(0xE8BD4000); // ldmfd sp!, {lr}
688 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700689
690 // We store the PC into the lr so we can adjust the sp before
691 // returning. We need to pull off the registers we pushed
692 // earlier. We don't need to actually store them anywhere,
693 // just adjust the stack.
694 int regArgCount = calcRegArgCount(pDecl);
695 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700696 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
697 }
698 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700699 }
700
701 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -0700702 virtual void li(int t) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700703 liReg(t, 0);
Jack Palevich58c30ee2009-07-17 16:35:23 -0700704 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700705 }
706
Jack Palevich1a539db2009-07-08 13:04:41 -0700707 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700708 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700709 // Global, absolute address
710 o4(0xE59F0000); // ldr r0, .L1
711 o4(0xEA000000); // b .L99
712 o4(address); // .L1: .word ea
713 // .L99:
714
715 switch (pType->tag) {
716 case TY_FLOAT:
717 o4(0xE5900000); // ldr r0, [r0]
718 break;
719 case TY_DOUBLE:
720 o4(0xE1C000D0); // ldrd r0, [r0]
721 break;
722 default:
723 assert(false);
724 break;
725 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700726 }
727
Jack Palevich22305132009-05-13 10:58:45 -0700728 virtual int gjmp(int t) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700729 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700730 }
731
732 /* l = 0: je, l == 1: jne */
733 virtual int gtst(bool l, int t) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700734 Type* pR0Type = getR0Type();
735 TypeTag tagR0 = pR0Type->tag;
736 switch(tagR0) {
737 case TY_FLOAT:
738 callRuntime((void*) runtime_is_non_zero_f);
739 break;
740 case TY_DOUBLE:
741 callRuntime((void*) runtime_is_non_zero_d);
742 break;
743 default:
744 break;
745 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700746 o4(0xE3500000); // cmp r0,#0
747 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
748 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700749 }
750
Jack Palevich58c30ee2009-07-17 16:35:23 -0700751 virtual void gcmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700752 Type* pR0Type = getR0Type();
753 Type* pTOSType = getTOSType();
754 TypeTag tagR0 = collapseType(pR0Type->tag);
755 TypeTag tagTOS = collapseType(pTOSType->tag);
756 if (tagR0 == TY_INT && tagTOS == TY_INT) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700757 setupIntPtrArgs();
Jack Palevichb7718b92009-07-09 22:00:24 -0700758 o4(0xE1510000); // cmp r1, r1
759 switch(op) {
760 case OP_EQUALS:
761 o4(0x03A00001); // moveq r0,#1
762 o4(0x13A00000); // movne r0,#0
763 break;
764 case OP_NOT_EQUALS:
765 o4(0x03A00000); // moveq r0,#0
766 o4(0x13A00001); // movne r0,#1
767 break;
768 case OP_LESS_EQUAL:
769 o4(0xD3A00001); // movle r0,#1
770 o4(0xC3A00000); // movgt r0,#0
771 break;
772 case OP_GREATER:
773 o4(0xD3A00000); // movle r0,#0
774 o4(0xC3A00001); // movgt r0,#1
775 break;
776 case OP_GREATER_EQUAL:
777 o4(0xA3A00001); // movge r0,#1
778 o4(0xB3A00000); // movlt r0,#0
779 break;
780 case OP_LESS:
781 o4(0xA3A00000); // movge r0,#0
782 o4(0xB3A00001); // movlt r0,#1
783 break;
784 default:
785 error("Unknown comparison op %d", op);
786 break;
787 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700788 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
789 setupDoubleArgs();
790 switch(op) {
791 case OP_EQUALS:
792 callRuntime((void*) runtime_cmp_eq_dd);
793 break;
794 case OP_NOT_EQUALS:
795 callRuntime((void*) runtime_cmp_ne_dd);
796 break;
797 case OP_LESS_EQUAL:
798 callRuntime((void*) runtime_cmp_le_dd);
799 break;
800 case OP_GREATER:
801 callRuntime((void*) runtime_cmp_gt_dd);
802 break;
803 case OP_GREATER_EQUAL:
804 callRuntime((void*) runtime_cmp_ge_dd);
805 break;
806 case OP_LESS:
807 callRuntime((void*) runtime_cmp_lt_dd);
808 break;
809 default:
810 error("Unknown comparison op %d", op);
811 break;
812 }
813 } else {
814 setupFloatArgs();
815 switch(op) {
816 case OP_EQUALS:
817 callRuntime((void*) runtime_cmp_eq_ff);
818 break;
819 case OP_NOT_EQUALS:
820 callRuntime((void*) runtime_cmp_ne_ff);
821 break;
822 case OP_LESS_EQUAL:
823 callRuntime((void*) runtime_cmp_le_ff);
824 break;
825 case OP_GREATER:
826 callRuntime((void*) runtime_cmp_gt_ff);
827 break;
828 case OP_GREATER_EQUAL:
829 callRuntime((void*) runtime_cmp_ge_ff);
830 break;
831 case OP_LESS:
832 callRuntime((void*) runtime_cmp_lt_ff);
833 break;
834 default:
835 error("Unknown comparison op %d", op);
836 break;
837 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700838 }
Jack Palevich58c30ee2009-07-17 16:35:23 -0700839 setR0Type(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -0700840 }
841
Jack Palevich546b2242009-05-13 15:10:04 -0700842 virtual void genOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700843 Type* pR0Type = getR0Type();
844 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700845 TypeTag tagR0 = pR0Type->tag;
846 TypeTag tagTOS = pTOSType->tag;
847 bool isFloatR0 = isFloatTag(tagR0);
848 bool isFloatTOS = isFloatTag(tagTOS);
849 if (!isFloatR0 && !isFloatTOS) {
Jack Palevich58c30ee2009-07-17 16:35:23 -0700850 setupIntPtrArgs();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700851 bool isPtrR0 = tagR0 == TY_POINTER;
852 bool isPtrTOS = tagTOS == TY_POINTER;
853 if (isPtrR0 || isPtrTOS) {
854 if (isPtrR0 && isPtrTOS) {
855 if (op != OP_MINUS) {
856 error("Unsupported pointer-pointer operation %d.", op);
857 }
858 if (! typeEqual(pR0Type, pTOSType)) {
859 error("Incompatible pointer types for subtraction.");
860 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700861 o4(0xE0410000); // sub r0,r1,r0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700862 setR0Type(mkpInt);
863 int size = sizeOf(pR0Type->pHead);
864 if (size != 1) {
865 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -0700866 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -0700867 // TODO: Optimize for power-of-two.
868 genOp(OP_DIV);
869 }
870 } else {
871 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
872 error("Unsupported pointer-scalar operation %d", op);
873 }
874 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700875 int size = sizeOf(pPtrType->pHead);
876 if (size != 1) {
877 // TODO: Optimize for power-of-two.
878 liReg(size, 2);
879 if (isPtrR0) {
880 o4(0x0E0010192); // mul r1,r2,r1
881 } else {
882 o4(0x0E0000092); // mul r0,r2,r0
883 }
884 }
885 switch(op) {
886 case OP_PLUS:
887 o4(0xE0810000); // add r0,r1,r0
888 break;
889 case OP_MINUS:
890 o4(0xE0410000); // sub r0,r1,r0
891 break;
892 }
Jack Palevicha8f427f2009-07-13 18:40:08 -0700893 setR0Type(pPtrType);
894 }
895 } else {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700896 switch(op) {
897 case OP_MUL:
898 o4(0x0E0000091); // mul r0,r1,r0
899 break;
900 case OP_DIV:
901 callRuntime((void*) runtime_DIV);
902 break;
903 case OP_MOD:
904 callRuntime((void*) runtime_MOD);
905 break;
906 case OP_PLUS:
907 o4(0xE0810000); // add r0,r1,r0
908 break;
909 case OP_MINUS:
910 o4(0xE0410000); // sub r0,r1,r0
911 break;
912 case OP_SHIFT_LEFT:
913 o4(0xE1A00011); // lsl r0,r1,r0
914 break;
915 case OP_SHIFT_RIGHT:
916 o4(0xE1A00051); // asr r0,r1,r0
917 break;
918 case OP_BIT_AND:
919 o4(0xE0010000); // and r0,r1,r0
920 break;
921 case OP_BIT_XOR:
922 o4(0xE0210000); // eor r0,r1,r0
923 break;
924 case OP_BIT_OR:
925 o4(0xE1810000); // orr r0,r1,r0
926 break;
927 case OP_BIT_NOT:
928 o4(0xE1E00000); // mvn r0, r0
929 break;
930 default:
931 error("Unimplemented op %d\n", op);
932 break;
933 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700934 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700935 } else {
936 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
937 if (pResultType->tag == TY_DOUBLE) {
938 setupDoubleArgs();
939 switch(op) {
940 case OP_MUL:
941 callRuntime((void*) runtime_op_mul_dd);
942 break;
943 case OP_DIV:
944 callRuntime((void*) runtime_op_div_dd);
945 break;
946 case OP_PLUS:
947 callRuntime((void*) runtime_op_add_dd);
948 break;
949 case OP_MINUS:
950 callRuntime((void*) runtime_op_sub_dd);
951 break;
952 default:
953 error("Unsupported binary floating operation %d\n", op);
954 break;
955 }
956 } else {
957 setupFloatArgs();
958 switch(op) {
959 case OP_MUL:
960 callRuntime((void*) runtime_op_mul_ff);
961 break;
962 case OP_DIV:
963 callRuntime((void*) runtime_op_div_ff);
964 break;
965 case OP_PLUS:
966 callRuntime((void*) runtime_op_add_ff);
967 break;
968 case OP_MINUS:
969 callRuntime((void*) runtime_op_sub_ff);
970 break;
971 default:
972 error("Unsupported binary floating operation %d\n", op);
973 break;
974 }
975 }
976 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700977 }
Jack Palevich22305132009-05-13 10:58:45 -0700978 }
979
Jack Palevich58c30ee2009-07-17 16:35:23 -0700980 virtual void gUnaryCmp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -0700981 if (op != OP_LOGICAL_NOT) {
982 error("Unknown unary cmp %d", op);
983 } else {
984 Type* pR0Type = getR0Type();
985 TypeTag tag = collapseType(pR0Type->tag);
986 switch(tag) {
987 case TY_INT:
988 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700989 o4(0xE1510000); // cmp r1, r0
990 o4(0x03A00001); // moveq r0,#1
991 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700992 break;
993 case TY_FLOAT:
994 callRuntime((void*) runtime_is_zero_f);
995 break;
996 case TY_DOUBLE:
997 callRuntime((void*) runtime_is_zero_d);
998 break;
999 default:
1000 error("gUnaryCmp unsupported type");
1001 break;
1002 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07001003 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001004 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001005 }
1006
1007 virtual void genUnaryOp(int op) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001008 Type* pR0Type = getR0Type();
1009 TypeTag tag = collapseType(pR0Type->tag);
1010 switch(tag) {
1011 case TY_INT:
1012 switch(op) {
1013 case OP_MINUS:
1014 o4(0xE3A01000); // mov r1, #0
1015 o4(0xE0410000); // sub r0,r1,r0
1016 break;
1017 case OP_BIT_NOT:
1018 o4(0xE1E00000); // mvn r0, r0
1019 break;
1020 default:
1021 error("Unknown unary op %d\n", op);
1022 break;
1023 }
1024 break;
1025 case TY_FLOAT:
1026 case TY_DOUBLE:
1027 switch (op) {
1028 case OP_MINUS:
1029 if (tag == TY_FLOAT) {
1030 callRuntime((void*) runtime_op_neg_f);
1031 } else {
1032 callRuntime((void*) runtime_op_neg_d);
1033 }
1034 break;
1035 case OP_BIT_NOT:
1036 error("Can't apply '~' operator to a float or double.");
1037 break;
1038 default:
1039 error("Unknown unary op %d\n", op);
1040 break;
1041 }
1042 break;
1043 default:
1044 error("genUnaryOp unsupported type");
1045 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001046 }
Jack Palevich22305132009-05-13 10:58:45 -07001047 }
1048
Jack Palevich1cdef202009-05-22 12:06:27 -07001049 virtual void pushR0() {
Jack Palevichb7718b92009-07-09 22:00:24 -07001050 Type* pR0Type = getR0Type();
1051 TypeTag r0ct = collapseType(pR0Type->tag);
1052 if (r0ct != TY_DOUBLE) {
1053 o4(0xE92D0001); // stmfd sp!,{r0}
1054 mStackUse += 4;
1055 } else {
1056 o4(0xE92D0003); // stmfd sp!,{r0,r1}
1057 mStackUse += 8;
1058 }
Jack Palevich8df46192009-07-07 14:48:51 -07001059 pushType();
-b master422972c2009-06-17 19:13:52 -07001060 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -07001061 }
1062
Jack Palevichddf7c9c2009-07-29 10:28:18 -07001063 virtual void over() {
1064 // We know it's only used for int-ptr ops (++/--)
1065
1066 Type* pR0Type = getR0Type();
1067 TypeTag r0ct = collapseType(pR0Type->tag);
1068
1069 Type* pTOSType = getTOSType();
1070 TypeTag tosct = collapseType(pTOSType->tag);
1071
1072 assert (r0ct == TY_INT && tosct == TY_INT);
1073
1074 o4(0xE8BD0002); // ldmfd sp!,{r1}
1075 o4(0xE92D0001); // stmfd sp!,{r0}
1076 o4(0xE92D0002); // stmfd sp!,{r1}
1077 overType();
1078 mStackUse += 4;
1079 }
1080
Jack Palevich58c30ee2009-07-17 16:35:23 -07001081 virtual void popR0() {
1082 Type* pTOSType = getTOSType();
1083 switch (collapseType(pTOSType->tag)){
1084 case TY_INT:
1085 case TY_FLOAT:
1086 o4(0xE8BD0001); // ldmfd sp!,{r0}
1087 mStackUse -= 4;
1088 break;
1089 case TY_DOUBLE:
1090 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1091 mStackUse -= 8;
1092 break;
1093 default:
1094 error("Can't pop this type.");
1095 break;
1096 }
1097 popType();
1098 LOG_STACK("popR0: %d\n", mStackUse);
1099 }
1100
1101 virtual void storeR0ToTOS() {
1102 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001103 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8968e8e2009-07-30 16:57:33 -07001104 Type* pDestType = pPointerType->pHead;
1105 convertR0(pDestType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001106 o4(0xE8BD0004); // ldmfd sp!,{r2}
1107 popType();
-b master422972c2009-06-17 19:13:52 -07001108 mStackUse -= 4;
Jack Palevich8968e8e2009-07-30 16:57:33 -07001109 switch (pDestType->tag) {
1110 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001111 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001112 case TY_FLOAT:
1113 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001114 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001115 case TY_SHORT:
1116 o4(0xE1C200B0); // strh r0, [r2]
1117 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001118 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001119 o4(0xE5C20000); // strb r0, [r2]
1120 break;
1121 case TY_DOUBLE:
1122 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001123 break;
1124 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07001125 error("storeR0ToTOS: unimplemented type %d",
1126 pDestType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07001127 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001128 }
Jack Palevich22305132009-05-13 10:58:45 -07001129 }
1130
Jack Palevich58c30ee2009-07-17 16:35:23 -07001131 virtual void loadR0FromR0() {
1132 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07001133 assert(pPointerType->tag == TY_POINTER);
1134 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07001135 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001136 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001137 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001138 o4(0xE5900000); // ldr r0, [r0]
1139 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001140 case TY_SHORT:
1141 o4(0xE1D000F0); // ldrsh r0, [r0]
1142 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001143 case TY_CHAR:
1144 o4(0xE5D00000); // ldrb r0, [r0]
1145 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001146 case TY_DOUBLE:
Jack Palevicha7813bd2009-07-29 11:36:04 -07001147 o4(0xE1C000D0); // ldrd r0, [r0]
Jack Palevichb7718b92009-07-09 22:00:24 -07001148 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001149 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001150 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001151 break;
1152 }
Jack Palevich8df46192009-07-07 14:48:51 -07001153 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001154 }
1155
Jack Palevichb5e33312009-07-30 19:06:34 -07001156 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevichb7718b92009-07-09 22:00:24 -07001157 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001158 // Local, fp relative
1159 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1160 error("Offset out of range: %08x", ea);
1161 }
1162 if (ea < 0) {
1163 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1164 } else {
1165 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1166 }
Jack Palevichbd894902009-05-14 19:35:31 -07001167 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001168 // Global, absolute.
1169 o4(0xE59F0000); // ldr r0, .L1
1170 o4(0xEA000000); // b .L99
1171 o4(ea); // .L1: .word 0
1172 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001173 }
Jack Palevichb5e33312009-07-30 19:06:34 -07001174 setR0Type(pPointerType, et);
Jack Palevich22305132009-05-13 10:58:45 -07001175 }
1176
Jack Palevich9f51a262009-07-29 16:22:26 -07001177 virtual int leaForward(int ea, Type* pPointerType) {
1178 setR0Type(pPointerType);
1179 int result = ea;
1180 int pc = getPC();
1181 int offset = 0;
1182 if (ea) {
1183 offset = (pc - ea - 8) >> 2;
1184 if ((offset & 0xffff) != offset) {
1185 error("function forward reference out of bounds");
1186 }
1187 } else {
1188 offset = 0;
1189 }
1190 o4(0xE59F0000 | offset); // ldr r0, .L1
1191
1192 if (ea == 0) {
1193 o4(0xEA000000); // b .L99
1194 result = o4(ea); // .L1: .word 0
1195 // .L99:
1196 }
1197 return result;
1198 }
1199
Jack Palevich8df46192009-07-07 14:48:51 -07001200 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001201 Type* pR0Type = getR0Type();
1202 if (bitsSame(pType, pR0Type)) {
1203 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001204 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001205 TypeTag r0Tag = collapseType(pR0Type->tag);
1206 TypeTag destTag = collapseType(pType->tag);
1207 if (r0Tag == TY_INT) {
1208 if (destTag == TY_FLOAT) {
1209 callRuntime((void*) runtime_int_to_float);
1210 } else {
1211 assert(destTag == TY_DOUBLE);
1212 callRuntime((void*) runtime_int_to_double);
1213 }
1214 } else if (r0Tag == TY_FLOAT) {
1215 if (destTag == TY_INT) {
1216 callRuntime((void*) runtime_float_to_int);
1217 } else {
1218 assert(destTag == TY_DOUBLE);
1219 callRuntime((void*) runtime_float_to_double);
1220 }
1221 } else {
1222 assert (r0Tag == TY_DOUBLE);
1223 if (destTag == TY_INT) {
1224 callRuntime((void*) runtime_double_to_int);
1225 } else {
1226 assert(destTag == TY_FLOAT);
1227 callRuntime((void*) runtime_double_to_float);
1228 }
1229 }
Jack Palevich8df46192009-07-07 14:48:51 -07001230 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001231 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001232 }
1233
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001234 virtual int beginFunctionCallArguments() {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001235 return o4(0xE24DDF00); // Placeholder
1236 }
1237
Jack Palevich8148c5b2009-07-16 18:24:47 -07001238 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001239 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001240 Type* pR0Type = getR0Type();
1241 TypeTag r0ct = collapseType(pR0Type->tag);
1242 switch(r0ct) {
1243 case TY_INT:
1244 case TY_FLOAT:
1245 if (l < 0 || l > 4096-4) {
1246 error("l out of range for stack offset: 0x%08x", l);
1247 }
1248 o4(0xE58D0000 + l); // str r0, [sp, #l]
1249 return 4;
1250 case TY_DOUBLE: {
1251 // Align to 8 byte boundary
1252 int l2 = (l + 7) & ~7;
1253 if (l2 < 0 || l2 > 4096-8) {
1254 error("l out of range for stack offset: 0x%08x", l);
1255 }
1256 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1257 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1258 return (l2 - l) + 8;
1259 }
1260 default:
1261 assert(false);
1262 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001263 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001264 }
1265
Jack Palevichb7718b92009-07-09 22:00:24 -07001266 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
-b master422972c2009-06-17 19:13:52 -07001267 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001268 // Have to calculate register arg count from actual stack size,
1269 // in order to properly handle ... functions.
1270 int regArgCount = l >> 2;
1271 if (regArgCount > 4) {
1272 regArgCount = 4;
1273 }
1274 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001275 argumentStackUse -= regArgCount * 4;
1276 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1277 }
1278 mStackUse += argumentStackUse;
1279
1280 // Align stack.
1281 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1282 * STACK_ALIGNMENT);
1283 mStackAlignmentAdjustment = 0;
1284 if (missalignment > 0) {
1285 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1286 }
1287 l += mStackAlignmentAdjustment;
1288
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001289 if (l < 0 || l > 0x3FC) {
1290 error("L out of range for stack adjustment: 0x%08x", l);
1291 }
1292 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001293 mStackUse += mStackAlignmentAdjustment;
1294 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1295 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001296 }
1297
Jack Palevich8df46192009-07-07 14:48:51 -07001298 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich8df46192009-07-07 14:48:51 -07001299 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001300 // Forward calls are always short (local)
1301 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001302 }
1303
Jack Palevich8df46192009-07-07 14:48:51 -07001304 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07001305 assert(pFunc->tag == TY_FUNC);
1306 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07001307 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001308 int argCount = l >> 2;
1309 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001310 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001311 if (adjustedL < 0 || adjustedL > 4096-4) {
1312 error("l out of range for stack offset: 0x%08x", l);
1313 }
1314 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1315 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001316 }
1317
Jack Palevichb7718b92009-07-09 22:00:24 -07001318 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001319 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001320 // Have to calculate register arg count from actual stack size,
1321 // in order to properly handle ... functions.
1322 int regArgCount = l >> 2;
1323 if (regArgCount > 4) {
1324 regArgCount = 4;
1325 }
1326 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001327 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1328 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001329 if (stackUse) {
1330 if (stackUse < 0 || stackUse > 255) {
1331 error("L out of range for stack adjustment: 0x%08x", l);
1332 }
1333 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001334 mStackUse -= stackUse * 4;
1335 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001336 }
Jack Palevich22305132009-05-13 10:58:45 -07001337 }
1338
Jack Palevicha6535612009-05-13 16:24:17 -07001339 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001340 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001341 }
1342
1343 /* output a symbol and patch all calls to it */
1344 virtual void gsym(int t) {
Jack Palevicha6535612009-05-13 16:24:17 -07001345 int n;
1346 int base = getBase();
1347 int pc = getPC();
Jack Palevicha6535612009-05-13 16:24:17 -07001348 while (t) {
1349 int data = * (int*) t;
1350 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1351 if (decodedOffset == 0) {
1352 n = 0;
1353 } else {
1354 n = base + decodedOffset; /* next value */
1355 }
1356 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1357 | encodeRelAddress(pc - t - 8);
1358 t = n;
1359 }
1360 }
1361
Jack Palevich9f51a262009-07-29 16:22:26 -07001362 /* output a symbol and patch all calls to it */
1363 virtual void resolveForward(int t) {
1364 if (t) {
1365 int pc = getPC();
1366 *(int *) t = pc;
1367 }
1368 }
1369
Jack Palevich1cdef202009-05-22 12:06:27 -07001370 virtual int finishCompile() {
1371#if defined(__arm__)
1372 const long base = long(getBase());
1373 const long curr = long(getPC());
1374 int err = cacheflush(base, curr, 0);
1375 return err;
1376#else
1377 return 0;
1378#endif
1379 }
1380
Jack Palevicha6535612009-05-13 16:24:17 -07001381 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001382#ifdef ENABLE_ARM_DISASSEMBLY
1383 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001384 disasm_interface_t di;
1385 di.di_readword = disassemble_readword;
1386 di.di_printaddr = disassemble_printaddr;
1387 di.di_printf = disassemble_printf;
1388
1389 int base = getBase();
1390 int pc = getPC();
1391 for(int i = base; i < pc; i += 4) {
1392 fprintf(out, "%08x: %08x ", i, *(int*) i);
1393 ::disasm(&di, i, 0);
1394 }
Jack Palevich09555c72009-05-27 12:25:55 -07001395#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001396 return 0;
1397 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001398
Jack Palevich9eed7a22009-07-06 17:24:34 -07001399 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001400 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001401 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001402 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001403 switch(pType->tag) {
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001404 case TY_CHAR:
1405 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001406 case TY_SHORT:
1407 return 1;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001408 case TY_DOUBLE:
1409 return 8;
1410 default:
1411 return 4;
1412 }
1413 }
1414
1415 /**
1416 * Array element alignment (in bytes) for this type of data.
1417 */
1418 virtual size_t sizeOf(Type* pType){
1419 switch(pType->tag) {
1420 case TY_INT:
1421 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07001422 case TY_SHORT:
1423 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001424 case TY_CHAR:
1425 return 1;
1426 default:
1427 return 0;
1428 case TY_FLOAT:
1429 return 4;
1430 case TY_DOUBLE:
1431 return 8;
1432 case TY_POINTER:
1433 return 4;
1434 }
1435 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001436
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07001437 virtual size_t stackAlignmentOf(Type* pType) {
1438 switch(pType->tag) {
1439 case TY_DOUBLE:
1440 return 8;
1441 default:
1442 return 4;
1443 }
1444 }
1445
Jack Palevich9cbd2262009-07-08 16:48:41 -07001446 virtual size_t stackSizeOf(Type* pType) {
1447 switch(pType->tag) {
1448 case TY_DOUBLE:
1449 return 8;
1450 default:
1451 return 4;
1452 }
1453 }
1454
Jack Palevich22305132009-05-13 10:58:45 -07001455 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001456 static FILE* disasmOut;
1457
1458 static u_int
1459 disassemble_readword(u_int address)
1460 {
1461 return(*((u_int *)address));
1462 }
1463
1464 static void
1465 disassemble_printaddr(u_int address)
1466 {
1467 fprintf(disasmOut, "0x%08x", address);
1468 }
1469
1470 static void
1471 disassemble_printf(const char *fmt, ...) {
1472 va_list ap;
1473 va_start(ap, fmt);
1474 vfprintf(disasmOut, fmt, ap);
1475 va_end(ap);
1476 }
1477
1478 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1479
1480 /** Encode a relative address that might also be
1481 * a label.
1482 */
1483 int encodeAddress(int value) {
1484 int base = getBase();
1485 if (value >= base && value <= getPC() ) {
1486 // This is a label, encode it relative to the base.
1487 value = value - base;
1488 }
1489 return encodeRelAddress(value);
1490 }
1491
1492 int encodeRelAddress(int value) {
1493 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1494 }
Jack Palevich22305132009-05-13 10:58:45 -07001495
Jack Palevichb7718b92009-07-09 22:00:24 -07001496 int calcRegArgCount(Type* pDecl) {
1497 int reg = 0;
1498 Type* pArgs = pDecl->pTail;
1499 while (pArgs && reg < 4) {
1500 Type* pArg = pArgs->pHead;
1501 if ( pArg->tag == TY_DOUBLE) {
1502 int evenReg = (reg + 1) & ~1;
1503 if (evenReg >= 4) {
1504 break;
1505 }
1506 reg = evenReg + 2;
1507 } else {
1508 reg++;
1509 }
1510 pArgs = pArgs->pTail;
1511 }
1512 return reg;
1513 }
1514
Jack Palevich58c30ee2009-07-17 16:35:23 -07001515 void setupIntPtrArgs() {
1516 o4(0xE8BD0002); // ldmfd sp!,{r1}
1517 mStackUse -= 4;
1518 popType();
1519 }
1520
Jack Palevichb7718b92009-07-09 22:00:24 -07001521 /* Pop TOS to R1
1522 * Make sure both R0 and TOS are floats. (Could be ints)
1523 * We know that at least one of R0 and TOS is already a float
1524 */
1525 void setupFloatArgs() {
1526 Type* pR0Type = getR0Type();
1527 Type* pTOSType = getTOSType();
1528 TypeTag tagR0 = collapseType(pR0Type->tag);
1529 TypeTag tagTOS = collapseType(pTOSType->tag);
1530 if (tagR0 != TY_FLOAT) {
1531 assert(tagR0 == TY_INT);
1532 callRuntime((void*) runtime_int_to_float);
1533 }
1534 if (tagTOS != TY_FLOAT) {
1535 assert(tagTOS == TY_INT);
1536 assert(tagR0 == TY_FLOAT);
1537 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1538 o4(0xE59D0004); // ldr r0, [sp, #4]
1539 callRuntime((void*) runtime_int_to_float);
1540 o4(0xE1A01000); // mov r1, r0
1541 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1542 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1543 } else {
1544 // Pop TOS
1545 o4(0xE8BD0002); // ldmfd sp!,{r1}
1546 }
1547 mStackUse -= 4;
1548 popType();
1549 }
1550
1551 /* Pop TOS into R2..R3
1552 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1553 * We know that at least one of R0 and TOS are already a double.
1554 */
1555
1556 void setupDoubleArgs() {
1557 Type* pR0Type = getR0Type();
1558 Type* pTOSType = getTOSType();
1559 TypeTag tagR0 = collapseType(pR0Type->tag);
1560 TypeTag tagTOS = collapseType(pTOSType->tag);
1561 if (tagR0 != TY_DOUBLE) {
1562 if (tagR0 == TY_INT) {
1563 callRuntime((void*) runtime_int_to_double);
1564 } else {
1565 assert(tagR0 == TY_FLOAT);
1566 callRuntime((void*) runtime_float_to_double);
1567 }
1568 }
1569 if (tagTOS != TY_DOUBLE) {
1570 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1571 o4(0xE59D0008); // ldr r0, [sp, #8]
1572 if (tagTOS == TY_INT) {
1573 callRuntime((void*) runtime_int_to_double);
1574 } else {
1575 assert(tagTOS == TY_FLOAT);
1576 callRuntime((void*) runtime_float_to_double);
1577 }
1578 o4(0xE1A02000); // mov r2, r0
1579 o4(0xE1A03001); // mov r3, r1
1580 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1581 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1582 mStackUse -= 4;
1583 } else {
1584 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1585 mStackUse -= 8;
1586 }
1587 popType();
1588 }
1589
Jack Palevicha8f427f2009-07-13 18:40:08 -07001590 void liReg(int t, int reg) {
1591 assert(reg >= 0 && reg < 16);
1592 int rN = (reg & 0xf) << 12;
1593 if (t >= 0 && t < 255) {
1594 o4((0xE3A00000 + t) | rN); // mov rN, #0
1595 } else if (t >= -256 && t < 0) {
1596 // mvn means move constant ^ ~0
Jack Palevich89baa202009-07-23 11:45:15 -07001597 o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -07001598 } else {
1599 o4(0xE51F0000 | rN); // ldr rN, .L3
1600 o4(0xEA000000); // b .L99
1601 o4(t); // .L3: .word 0
1602 // .L99:
1603 }
1604 }
1605
Jack Palevichb7718b92009-07-09 22:00:24 -07001606 void callRuntime(void* fn) {
1607 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001608 o4(0xEA000000); // b .L99
1609 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001610 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001611 }
1612
Jack Palevichb7718b92009-07-09 22:00:24 -07001613 // Integer math:
1614
1615 static int runtime_DIV(int b, int a) {
1616 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001617 }
1618
Jack Palevichb7718b92009-07-09 22:00:24 -07001619 static int runtime_MOD(int b, int a) {
1620 return a % b;
1621 }
1622
1623 // Comparison to zero
1624
1625 static int runtime_is_non_zero_f(float a) {
1626 return a != 0;
1627 }
1628
1629 static int runtime_is_non_zero_d(double a) {
1630 return a != 0;
1631 }
1632
1633 // Comparison to zero
1634
1635 static int runtime_is_zero_f(float a) {
1636 return a == 0;
1637 }
1638
1639 static int runtime_is_zero_d(double a) {
1640 return a == 0;
1641 }
1642
1643 // Type conversion
1644
1645 static int runtime_float_to_int(float a) {
1646 return (int) a;
1647 }
1648
1649 static double runtime_float_to_double(float a) {
1650 return (double) a;
1651 }
1652
1653 static int runtime_double_to_int(double a) {
1654 return (int) a;
1655 }
1656
1657 static float runtime_double_to_float(double a) {
1658 return (float) a;
1659 }
1660
1661 static float runtime_int_to_float(int a) {
1662 return (float) a;
1663 }
1664
1665 static double runtime_int_to_double(int a) {
1666 return (double) a;
1667 }
1668
1669 // Comparisons float
1670
1671 static int runtime_cmp_eq_ff(float b, float a) {
1672 return a == b;
1673 }
1674
1675 static int runtime_cmp_ne_ff(float b, float a) {
1676 return a != b;
1677 }
1678
1679 static int runtime_cmp_lt_ff(float b, float a) {
1680 return a < b;
1681 }
1682
1683 static int runtime_cmp_le_ff(float b, float a) {
1684 return a <= b;
1685 }
1686
1687 static int runtime_cmp_ge_ff(float b, float a) {
1688 return a >= b;
1689 }
1690
1691 static int runtime_cmp_gt_ff(float b, float a) {
1692 return a > b;
1693 }
1694
1695 // Comparisons double
1696
1697 static int runtime_cmp_eq_dd(double b, double a) {
1698 return a == b;
1699 }
1700
1701 static int runtime_cmp_ne_dd(double b, double a) {
1702 return a != b;
1703 }
1704
1705 static int runtime_cmp_lt_dd(double b, double a) {
1706 return a < b;
1707 }
1708
1709 static int runtime_cmp_le_dd(double b, double a) {
1710 return a <= b;
1711 }
1712
1713 static int runtime_cmp_ge_dd(double b, double a) {
1714 return a >= b;
1715 }
1716
1717 static int runtime_cmp_gt_dd(double b, double a) {
1718 return a > b;
1719 }
1720
1721 // Math float
1722
1723 static float runtime_op_add_ff(float b, float a) {
1724 return a + b;
1725 }
1726
1727 static float runtime_op_sub_ff(float b, float a) {
1728 return a - b;
1729 }
1730
1731 static float runtime_op_mul_ff(float b, float a) {
1732 return a * b;
1733 }
1734
1735 static float runtime_op_div_ff(float b, float a) {
1736 return a / b;
1737 }
1738
1739 static float runtime_op_neg_f(float a) {
1740 return -a;
1741 }
1742
1743 // Math double
1744
1745 static double runtime_op_add_dd(double b, double a) {
1746 return a + b;
1747 }
1748
1749 static double runtime_op_sub_dd(double b, double a) {
1750 return a - b;
1751 }
1752
1753 static double runtime_op_mul_dd(double b, double a) {
1754 return a * b;
1755 }
1756
1757 static double runtime_op_div_dd(double b, double a) {
1758 return a / b;
1759 }
1760
1761 static double runtime_op_neg_d(double a) {
1762 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001763 }
-b master422972c2009-06-17 19:13:52 -07001764
1765 static const int STACK_ALIGNMENT = 8;
1766 int mStackUse;
1767 // This variable holds the amount we adjusted the stack in the most
1768 // recent endFunctionCallArguments call. It's examined by the
1769 // following adjustStackAfterCall call.
1770 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001771 };
1772
Jack Palevich09555c72009-05-27 12:25:55 -07001773#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001774
1775#ifdef PROVIDE_X86_CODEGEN
1776
Jack Palevich21a15a22009-05-11 14:49:29 -07001777 class X86CodeGenerator : public CodeGenerator {
1778 public:
1779 X86CodeGenerator() {}
1780 virtual ~X86CodeGenerator() {}
1781
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001782 /* returns address to patch with local variable size
1783 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001784 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001785 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1786 return oad(0xec81, 0); /* sub $xxx, %esp */
1787 }
1788
Jack Palevichb7718b92009-07-09 22:00:24 -07001789 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001790 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001791 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001792 }
1793
Jack Palevich21a15a22009-05-11 14:49:29 -07001794 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001795 virtual void li(int i) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001796 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001797 setR0Type(mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001798 }
1799
Jack Palevich1a539db2009-07-08 13:04:41 -07001800 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001801 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001802 switch (pType->tag) {
1803 case TY_FLOAT:
1804 oad(0x05D9, address); // flds
1805 break;
1806 case TY_DOUBLE:
1807 oad(0x05DD, address); // fldl
1808 break;
1809 default:
1810 assert(false);
1811 break;
1812 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001813 }
1814
Jack Palevich22305132009-05-13 10:58:45 -07001815 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001816 return psym(0xe9, t);
1817 }
1818
1819 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001820 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001821 Type* pR0Type = getR0Type();
1822 TypeTag tagR0 = pR0Type->tag;
1823 bool isFloatR0 = isFloatTag(tagR0);
1824 if (isFloatR0) {
1825 o(0xeed9); // fldz
1826 o(0xe9da); // fucompp
1827 o(0xe0df); // fnstsw %ax
1828 o(0x9e); // sahf
1829 } else {
1830 o(0xc085); // test %eax, %eax
1831 }
1832 // Use two output statements to generate one instruction.
1833 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001834 return psym(0x84 + l, t);
1835 }
1836
Jack Palevich58c30ee2009-07-17 16:35:23 -07001837 virtual void gcmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001838 Type* pR0Type = getR0Type();
1839 Type* pTOSType = getTOSType();
1840 TypeTag tagR0 = pR0Type->tag;
1841 TypeTag tagTOS = pTOSType->tag;
1842 bool isFloatR0 = isFloatTag(tagR0);
1843 bool isFloatTOS = isFloatTag(tagTOS);
1844 if (!isFloatR0 && !isFloatTOS) {
1845 int t = decodeOp(op);
1846 o(0x59); /* pop %ecx */
1847 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001848 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001849 o(0x0f); /* setxx %al */
1850 o(t + 0x90);
1851 o(0xc0);
1852 popType();
1853 } else {
1854 setupFloatOperands();
1855 switch (op) {
1856 case OP_EQUALS:
1857 o(0xe9da); // fucompp
1858 o(0xe0df); // fnstsw %ax
1859 o(0x9e); // sahf
1860 o(0xc0940f); // sete %al
1861 o(0xc29b0f); // setnp %dl
1862 o(0xd021); // andl %edx, %eax
1863 break;
1864 case OP_NOT_EQUALS:
1865 o(0xe9da); // fucompp
1866 o(0xe0df); // fnstsw %ax
1867 o(0x9e); // sahf
1868 o(0xc0950f); // setne %al
1869 o(0xc29a0f); // setp %dl
1870 o(0xd009); // orl %edx, %eax
1871 break;
1872 case OP_GREATER_EQUAL:
1873 o(0xe9da); // fucompp
1874 o(0xe0df); // fnstsw %ax
1875 o(0x05c4f6); // testb $5, %ah
1876 o(0xc0940f); // sete %al
1877 break;
1878 case OP_LESS:
1879 o(0xc9d9); // fxch %st(1)
1880 o(0xe9da); // fucompp
1881 o(0xe0df); // fnstsw %ax
1882 o(0x9e); // sahf
1883 o(0xc0970f); // seta %al
1884 break;
1885 case OP_LESS_EQUAL:
1886 o(0xc9d9); // fxch %st(1)
1887 o(0xe9da); // fucompp
1888 o(0xe0df); // fnstsw %ax
1889 o(0x9e); // sahf
1890 o(0xc0930f); // setea %al
1891 break;
1892 case OP_GREATER:
1893 o(0xe9da); // fucompp
1894 o(0xe0df); // fnstsw %ax
1895 o(0x45c4f6); // testb $69, %ah
1896 o(0xc0940f); // sete %al
1897 break;
1898 default:
1899 error("Unknown comparison op");
1900 }
1901 o(0xc0b60f); // movzbl %al, %eax
1902 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07001903 setR0Type(mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07001904 }
1905
Jack Palevich546b2242009-05-13 15:10:04 -07001906 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001907 Type* pR0Type = getR0Type();
1908 Type* pTOSType = getTOSType();
1909 TypeTag tagR0 = pR0Type->tag;
1910 TypeTag tagTOS = pTOSType->tag;
1911 bool isFloatR0 = isFloatTag(tagR0);
1912 bool isFloatTOS = isFloatTag(tagTOS);
1913 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001914 bool isPtrR0 = tagR0 == TY_POINTER;
1915 bool isPtrTOS = tagTOS == TY_POINTER;
1916 if (isPtrR0 || isPtrTOS) {
1917 if (isPtrR0 && isPtrTOS) {
1918 if (op != OP_MINUS) {
1919 error("Unsupported pointer-pointer operation %d.", op);
1920 }
1921 if (! typeEqual(pR0Type, pTOSType)) {
1922 error("Incompatible pointer types for subtraction.");
1923 }
1924 o(0x59); /* pop %ecx */
1925 o(decodeOp(op));
1926 popType();
1927 setR0Type(mkpInt);
1928 int size = sizeOf(pR0Type->pHead);
1929 if (size != 1) {
1930 pushR0();
Jack Palevich58c30ee2009-07-17 16:35:23 -07001931 li(size);
Jack Palevicha8f427f2009-07-13 18:40:08 -07001932 // TODO: Optimize for power-of-two.
1933 genOp(OP_DIV);
1934 }
1935 } else {
1936 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1937 error("Unsupported pointer-scalar operation %d", op);
1938 }
1939 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1940 o(0x59); /* pop %ecx */
1941 int size = sizeOf(pPtrType->pHead);
1942 if (size != 1) {
1943 // TODO: Optimize for power-of-two.
1944 if (isPtrR0) {
1945 oad(0xC969, size); // imull $size, %ecx
1946 } else {
1947 oad(0xC069, size); // mul $size, %eax
1948 }
1949 }
1950 o(decodeOp(op));
1951 popType();
1952 setR0Type(pPtrType);
1953 }
1954 } else {
1955 o(0x59); /* pop %ecx */
1956 o(decodeOp(op));
1957 if (op == OP_MOD)
1958 o(0x92); /* xchg %edx, %eax */
1959 popType();
1960 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001961 } else {
1962 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1963 setupFloatOperands();
1964 // Both float. x87 R0 == left hand, x87 R1 == right hand
1965 switch (op) {
1966 case OP_MUL:
1967 o(0xc9de); // fmulp
1968 break;
1969 case OP_DIV:
1970 o(0xf1de); // fdivp
1971 break;
1972 case OP_PLUS:
1973 o(0xc1de); // faddp
1974 break;
1975 case OP_MINUS:
1976 o(0xe1de); // fsubp
1977 break;
1978 default:
1979 error("Unsupported binary floating operation.");
1980 break;
1981 }
Jack Palevicha39749f2009-07-08 20:40:31 -07001982 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07001983 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001984 }
1985
Jack Palevich58c30ee2009-07-17 16:35:23 -07001986 virtual void gUnaryCmp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001987 if (op != OP_LOGICAL_NOT) {
1988 error("Unknown unary cmp %d", op);
1989 } else {
1990 Type* pR0Type = getR0Type();
1991 TypeTag tag = collapseType(pR0Type->tag);
1992 switch(tag) {
1993 case TY_INT: {
1994 oad(0xb9, 0); /* movl $0, %ecx */
1995 int t = decodeOp(op);
1996 o(0xc139); /* cmp %eax,%ecx */
Jack Palevich58c30ee2009-07-17 16:35:23 -07001997 li(0);
Jack Palevicha39749f2009-07-08 20:40:31 -07001998 o(0x0f); /* setxx %al */
1999 o(t + 0x90);
2000 o(0xc0);
2001 }
2002 break;
2003 case TY_FLOAT:
2004 case TY_DOUBLE:
2005 o(0xeed9); // fldz
2006 o(0xe9da); // fucompp
2007 o(0xe0df); // fnstsw %ax
2008 o(0x9e); // sahf
2009 o(0xc0950f); // setne %al
2010 o(0xc29a0f); // setp %dl
2011 o(0xd009); // orl %edx, %eax
2012 o(0xc0b60f); // movzbl %al, %eax
2013 o(0x01f083); // xorl $1, %eax
2014 break;
2015 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002016 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002017 break;
2018 }
2019 }
Jack Palevich58c30ee2009-07-17 16:35:23 -07002020 setR0Type(mkpInt);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002021 }
2022
2023 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002024 Type* pR0Type = getR0Type();
2025 TypeTag tag = collapseType(pR0Type->tag);
2026 switch(tag) {
2027 case TY_INT:
2028 oad(0xb9, 0); /* movl $0, %ecx */
2029 o(decodeOp(op));
2030 break;
2031 case TY_FLOAT:
2032 case TY_DOUBLE:
2033 switch (op) {
2034 case OP_MINUS:
2035 o(0xe0d9); // fchs
2036 break;
2037 case OP_BIT_NOT:
2038 error("Can't apply '~' operator to a float or double.");
2039 break;
2040 default:
2041 error("Unknown unary op %d\n", op);
2042 break;
2043 }
2044 break;
2045 default:
2046 error("genUnaryOp unsupported type");
2047 break;
2048 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002049 }
2050
Jack Palevich1cdef202009-05-22 12:06:27 -07002051 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002052 Type* pR0Type = getR0Type();
2053 TypeTag r0ct = collapseType(pR0Type->tag);
2054 switch(r0ct) {
2055 case TY_INT:
2056 o(0x50); /* push %eax */
2057 break;
2058 case TY_FLOAT:
2059 o(0x50); /* push %eax */
2060 o(0x241cd9); // fstps 0(%esp)
2061 break;
2062 case TY_DOUBLE:
2063 o(0x50); /* push %eax */
2064 o(0x50); /* push %eax */
2065 o(0x241cdd); // fstpl 0(%esp)
2066 break;
2067 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002068 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002069 break;
2070 }
Jack Palevich8df46192009-07-07 14:48:51 -07002071 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002072 }
2073
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002074 virtual void over() {
2075 // We know it's only used for int-ptr ops (++/--)
2076
2077 Type* pR0Type = getR0Type();
2078 TypeTag r0ct = collapseType(pR0Type->tag);
2079
2080 Type* pTOSType = getTOSType();
2081 TypeTag tosct = collapseType(pTOSType->tag);
2082
2083 assert (r0ct == TY_INT && tosct == TY_INT);
2084
2085 o(0x59); /* pop %ecx */
2086 o(0x50); /* push %eax */
2087 o(0x51); /* push %ecx */
2088
2089 overType();
2090 }
2091
Jack Palevich58c30ee2009-07-17 16:35:23 -07002092 virtual void popR0() {
2093 Type* pR0Type = getR0Type();
2094 TypeTag r0ct = collapseType(pR0Type->tag);
2095 switch(r0ct) {
2096 case TY_INT:
2097 o(0x58); /* popl %eax */
2098 break;
2099 case TY_FLOAT:
2100 o(0x2404d9); // flds (%esp)
2101 o(0x58); /* popl %eax */
2102 break;
2103 case TY_DOUBLE:
2104 o(0x2404dd); // fldl (%esp)
2105 o(0x58); /* popl %eax */
2106 o(0x58); /* popl %eax */
2107 break;
2108 default:
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002109 error("popR0 unsupported type %d", r0ct);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002110 break;
2111 }
2112 popType();
2113 }
2114
2115 virtual void storeR0ToTOS() {
2116 Type* pPointerType = getTOSType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002117 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002118 Type* pTargetType = pPointerType->pHead;
2119 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002120 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002121 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002122 switch (pTargetType->tag) {
Jack Palevich8968e8e2009-07-30 16:57:33 -07002123 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002124 case TY_INT:
2125 o(0x0189); /* movl %eax/%al, (%ecx) */
2126 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002127 case TY_SHORT:
2128 o(0x018966); /* movw %ax, (%ecx) */
2129 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002130 case TY_CHAR:
2131 o(0x0188); /* movl %eax/%al, (%ecx) */
2132 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002133 case TY_FLOAT:
2134 o(0x19d9); /* fstps (%ecx) */
2135 break;
2136 case TY_DOUBLE:
2137 o(0x19dd); /* fstpl (%ecx) */
2138 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002139 default:
Jack Palevichb5e33312009-07-30 19:06:34 -07002140 error("storeR0ToTOS: unsupported type %d",
2141 pTargetType->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002142 break;
2143 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002144 }
2145
Jack Palevich58c30ee2009-07-17 16:35:23 -07002146 virtual void loadR0FromR0() {
2147 Type* pPointerType = getR0Type();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002148 assert(pPointerType->tag == TY_POINTER);
2149 switch (pPointerType->pHead->tag) {
Jack Palevicha7813bd2009-07-29 11:36:04 -07002150 case TY_POINTER:
Jack Palevich9eed7a22009-07-06 17:24:34 -07002151 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002152 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002153 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002154 case TY_SHORT:
2155 o(0xbf0f); /* movswl (%eax), %eax */
2156 ob(0);
2157 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002158 case TY_CHAR:
2159 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002160 ob(0); /* add zero in code */
2161 break;
2162 case TY_FLOAT:
2163 o2(0x00d9); // flds (%eax)
2164 break;
2165 case TY_DOUBLE:
2166 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002167 break;
2168 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002169 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002170 break;
2171 }
Jack Palevich8df46192009-07-07 14:48:51 -07002172 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002173 }
2174
Jack Palevichb5e33312009-07-30 19:06:34 -07002175 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002176 gmov(10, ea); /* leal EA, %eax */
Jack Palevichb5e33312009-07-30 19:06:34 -07002177 setR0Type(pPointerType, et);
Jack Palevich21a15a22009-05-11 14:49:29 -07002178 }
2179
Jack Palevich9f51a262009-07-29 16:22:26 -07002180 virtual int leaForward(int ea, Type* pPointerType) {
2181 oad(0xb8, ea); /* mov $xx, %eax */
2182 setR0Type(pPointerType);
2183 return getPC() - 4;
2184 }
2185
Jack Palevich8df46192009-07-07 14:48:51 -07002186 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002187 Type* pR0Type = getR0Type();
2188 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002189 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002190 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002191 return;
2192 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002193 if (bitsSame(pType, pR0Type)) {
2194 // do nothing special
2195 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2196 // do nothing special, both held in same register on x87.
2197 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002198 TypeTag r0Tag = collapseType(pR0Type->tag);
2199 TypeTag destTag = collapseType(pType->tag);
2200 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2201 // Convert R0 from int to float
2202 o(0x50); // push %eax
2203 o(0x2404DB); // fildl 0(%esp)
2204 o(0x58); // pop %eax
2205 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2206 // Convert R0 from float to int. Complicated because
2207 // need to save and restore the rounding mode.
2208 o(0x50); // push %eax
2209 o(0x50); // push %eax
2210 o(0x02247cD9); // fnstcw 2(%esp)
2211 o(0x2444b70f); // movzwl 2(%esp), %eax
2212 o(0x02);
2213 o(0x0cb4); // movb $12, %ah
2214 o(0x24048966); // movw %ax, 0(%esp)
2215 o(0x242cd9); // fldcw 0(%esp)
2216 o(0x04245cdb); // fistpl 4(%esp)
2217 o(0x02246cd9); // fldcw 2(%esp)
2218 o(0x58); // pop %eax
2219 o(0x58); // pop %eax
2220 } else {
2221 error("Incompatible types old: %d new: %d",
2222 pR0Type->tag, pType->tag);
2223 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002224 }
2225 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002226 }
2227
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002228 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002229 return oad(0xec81, 0); /* sub $xxx, %esp */
2230 }
2231
Jack Palevich8148c5b2009-07-16 18:24:47 -07002232 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2233 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002234 Type* pR0Type = getR0Type();
2235 TypeTag r0ct = collapseType(pR0Type->tag);
2236 switch(r0ct) {
2237 case TY_INT:
2238 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2239 return 4;
2240 case TY_FLOAT:
2241 oad(0x249CD9, l); /* fstps xxx(%esp) */
2242 return 4;
2243 case TY_DOUBLE:
2244 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2245 return 8;
2246 default:
2247 assert(false);
2248 return 0;
2249 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002250 }
2251
Jack Palevichb7718b92009-07-09 22:00:24 -07002252 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002253 * (int*) a = l;
2254 }
2255
Jack Palevich8df46192009-07-07 14:48:51 -07002256 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002257 assert(pFunc->tag == TY_FUNC);
Jack Palevich8df46192009-07-07 14:48:51 -07002258 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002259 return psym(0xe8, symbol); /* call xxx */
2260 }
2261
Jack Palevich8df46192009-07-07 14:48:51 -07002262 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002263 assert(pFunc->tag == TY_FUNC);
Jack Palevichb5e33312009-07-30 19:06:34 -07002264 popType(); // Get rid of indirect fn pointer type
Jack Palevich8df46192009-07-07 14:48:51 -07002265 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002266 oad(0x2494ff, l); /* call *xxx(%esp) */
2267 }
2268
Jack Palevichb7718b92009-07-09 22:00:24 -07002269 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002270 assert(pDecl->tag == TY_FUNC);
Jack Palevich7810bc92009-05-15 14:31:47 -07002271 if (isIndirect) {
2272 l += 4;
2273 }
-b master422972c2009-06-17 19:13:52 -07002274 if (l > 0) {
2275 oad(0xc481, l); /* add $xxx, %esp */
2276 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002277 }
2278
Jack Palevicha6535612009-05-13 16:24:17 -07002279 virtual int jumpOffset() {
2280 return 5;
2281 }
2282
2283 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002284 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002285 }
2286
Jack Paleviche7b59062009-05-19 17:12:17 -07002287 /* output a symbol and patch all calls to it */
2288 virtual void gsym(int t) {
2289 int n;
2290 int pc = getPC();
2291 while (t) {
2292 n = *(int *) t; /* next value */
2293 *(int *) t = pc - t - 4;
2294 t = n;
2295 }
2296 }
2297
Jack Palevich9f51a262009-07-29 16:22:26 -07002298 /* output a symbol and patch all calls to it, using absolute address */
2299 virtual void resolveForward(int t) {
2300 int n;
2301 int pc = getPC();
2302 while (t) {
2303 n = *(int *) t; /* next value */
2304 *(int *) t = pc;
2305 t = n;
2306 }
2307 }
2308
Jack Palevich1cdef202009-05-22 12:06:27 -07002309 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002310 size_t pagesize = 4096;
2311 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2312 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2313 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2314 if (err) {
2315 error("mprotect() failed: %d", errno);
2316 }
2317 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002318 }
2319
Jack Palevich9eed7a22009-07-06 17:24:34 -07002320 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002321 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002322 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002323 virtual size_t alignmentOf(Type* pType){
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002324 switch (pType->tag) {
2325 case TY_CHAR:
2326 return 1;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002327 case TY_SHORT:
2328 return 2;
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002329 default:
2330 return 4;
2331 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002332 }
2333
2334 /**
2335 * Array element alignment (in bytes) for this type of data.
2336 */
2337 virtual size_t sizeOf(Type* pType){
2338 switch(pType->tag) {
2339 case TY_INT:
2340 return 4;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07002341 case TY_SHORT:
2342 return 2;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002343 case TY_CHAR:
2344 return 1;
2345 default:
2346 return 0;
2347 case TY_FLOAT:
2348 return 4;
2349 case TY_DOUBLE:
2350 return 8;
2351 case TY_POINTER:
2352 return 4;
2353 }
2354 }
2355
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07002356 virtual size_t stackAlignmentOf(Type* pType){
2357 return 4;
2358 }
2359
Jack Palevich9cbd2262009-07-08 16:48:41 -07002360 virtual size_t stackSizeOf(Type* pType) {
2361 switch(pType->tag) {
2362 case TY_DOUBLE:
2363 return 8;
2364 default:
2365 return 4;
2366 }
2367 }
2368
Jack Palevich21a15a22009-05-11 14:49:29 -07002369 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002370
2371 /** Output 1 to 4 bytes.
2372 *
2373 */
2374 void o(int n) {
2375 /* cannot use unsigned, so we must do a hack */
2376 while (n && n != -1) {
2377 ob(n & 0xff);
2378 n = n >> 8;
2379 }
2380 }
2381
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002382 /* Output exactly 2 bytes
2383 */
2384 void o2(int n) {
2385 ob(n & 0xff);
2386 ob(0xff & (n >> 8));
2387 }
2388
Jack Paleviche7b59062009-05-19 17:12:17 -07002389 /* psym is used to put an instruction with a data field which is a
2390 reference to a symbol. It is in fact the same as oad ! */
2391 int psym(int n, int t) {
2392 return oad(n, t);
2393 }
2394
2395 /* instruction + address */
2396 int oad(int n, int t) {
2397 o(n);
2398 int result = getPC();
2399 o4(t);
2400 return result;
2401 }
2402
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002403 static const int operatorHelper[];
2404
2405 int decodeOp(int op) {
2406 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002407 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002408 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002409 }
2410 return operatorHelper[op];
2411 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002412
Jack Palevich546b2242009-05-13 15:10:04 -07002413 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002414 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002415 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002416 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002417
2418 void setupFloatOperands() {
2419 Type* pR0Type = getR0Type();
2420 Type* pTOSType = getTOSType();
2421 TypeTag tagR0 = pR0Type->tag;
2422 TypeTag tagTOS = pTOSType->tag;
2423 bool isFloatR0 = isFloatTag(tagR0);
2424 bool isFloatTOS = isFloatTag(tagTOS);
2425 if (! isFloatR0) {
2426 // Convert R0 from int to float
2427 o(0x50); // push %eax
2428 o(0x2404DB); // fildl 0(%esp)
2429 o(0x58); // pop %eax
2430 }
2431 if (! isFloatTOS){
2432 o(0x2404DB); // fildl 0(%esp);
2433 o(0x58); // pop %eax
2434 } else {
2435 if (tagTOS == TY_FLOAT) {
2436 o(0x2404d9); // flds (%esp)
2437 o(0x58); // pop %eax
2438 } else {
2439 o(0x2404dd); // fldl (%esp)
2440 o(0x58); // pop %eax
2441 o(0x58); // pop %eax
2442 }
2443 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002444 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002445 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002446 };
2447
Jack Paleviche7b59062009-05-19 17:12:17 -07002448#endif // PROVIDE_X86_CODEGEN
2449
Jack Palevichb67b18f2009-06-11 21:12:23 -07002450#ifdef PROVIDE_TRACE_CODEGEN
2451 class TraceCodeGenerator : public CodeGenerator {
2452 private:
2453 CodeGenerator* mpBase;
2454
2455 public:
2456 TraceCodeGenerator(CodeGenerator* pBase) {
2457 mpBase = pBase;
2458 }
2459
2460 virtual ~TraceCodeGenerator() {
2461 delete mpBase;
2462 }
2463
2464 virtual void init(CodeBuf* pCodeBuf) {
2465 mpBase->init(pCodeBuf);
2466 }
2467
2468 void setErrorSink(ErrorSink* pErrorSink) {
2469 mpBase->setErrorSink(pErrorSink);
2470 }
2471
2472 /* returns address to patch with local variable size
2473 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002474 virtual int functionEntry(Type* pDecl) {
2475 int result = mpBase->functionEntry(pDecl);
2476 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002477 return result;
2478 }
2479
Jack Palevichb7718b92009-07-09 22:00:24 -07002480 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2481 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2482 localVariableAddress, localVariableSize);
2483 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002484 }
2485
2486 /* load immediate value */
Jack Palevich58c30ee2009-07-17 16:35:23 -07002487 virtual void li(int t) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002488 fprintf(stderr, "li(%d)\n", t);
Jack Palevich58c30ee2009-07-17 16:35:23 -07002489 mpBase->li(t);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002490 }
2491
Jack Palevich1a539db2009-07-08 13:04:41 -07002492 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002493 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002494 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002495 }
2496
Jack Palevichb67b18f2009-06-11 21:12:23 -07002497 virtual int gjmp(int t) {
2498 int result = mpBase->gjmp(t);
2499 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2500 return result;
2501 }
2502
2503 /* l = 0: je, l == 1: jne */
2504 virtual int gtst(bool l, int t) {
2505 int result = mpBase->gtst(l, t);
2506 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2507 return result;
2508 }
2509
Jack Palevich58c30ee2009-07-17 16:35:23 -07002510 virtual void gcmp(int op) {
2511 fprintf(stderr, "gcmp(%d)\n", op);
2512 mpBase->gcmp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002513 }
2514
2515 virtual void genOp(int op) {
2516 fprintf(stderr, "genOp(%d)\n", op);
2517 mpBase->genOp(op);
2518 }
2519
Jack Palevich9eed7a22009-07-06 17:24:34 -07002520
Jack Palevich58c30ee2009-07-17 16:35:23 -07002521 virtual void gUnaryCmp(int op) {
2522 fprintf(stderr, "gUnaryCmp(%d)\n", op);
2523 mpBase->gUnaryCmp(op);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002524 }
2525
2526 virtual void genUnaryOp(int op) {
2527 fprintf(stderr, "genUnaryOp(%d)\n", op);
2528 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002529 }
2530
2531 virtual void pushR0() {
2532 fprintf(stderr, "pushR0()\n");
2533 mpBase->pushR0();
2534 }
2535
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002536 virtual void over() {
2537 fprintf(stderr, "over()\n");
2538 mpBase->over();
2539 }
2540
Jack Palevich58c30ee2009-07-17 16:35:23 -07002541 virtual void popR0() {
2542 fprintf(stderr, "popR0()\n");
2543 mpBase->popR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002544 }
2545
Jack Palevich58c30ee2009-07-17 16:35:23 -07002546 virtual void storeR0ToTOS() {
2547 fprintf(stderr, "storeR0ToTOS()\n");
2548 mpBase->storeR0ToTOS();
2549 }
2550
2551 virtual void loadR0FromR0() {
2552 fprintf(stderr, "loadR0FromR0()\n");
2553 mpBase->loadR0FromR0();
Jack Palevichb67b18f2009-06-11 21:12:23 -07002554 }
2555
Jack Palevichb5e33312009-07-30 19:06:34 -07002556 virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2557 fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
2558 pPointerType->pHead->tag, et);
2559 mpBase->leaR0(ea, pPointerType, et);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002560 }
2561
Jack Palevich9f51a262009-07-29 16:22:26 -07002562 virtual int leaForward(int ea, Type* pPointerType) {
2563 fprintf(stderr, "leaForward(%d)\n", ea);
2564 return mpBase->leaForward(ea, pPointerType);
2565 }
2566
Jack Palevich8df46192009-07-07 14:48:51 -07002567 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002568 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002569 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002570 }
2571
2572 virtual int beginFunctionCallArguments() {
2573 int result = mpBase->beginFunctionCallArguments();
2574 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2575 return result;
2576 }
2577
Jack Palevich8148c5b2009-07-16 18:24:47 -07002578 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2579 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2580 pArgType->tag);
2581 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002582 }
2583
Jack Palevichb7718b92009-07-09 22:00:24 -07002584 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002585 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002586 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002587 }
2588
Jack Palevich8df46192009-07-07 14:48:51 -07002589 virtual int callForward(int symbol, Type* pFunc) {
2590 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002591 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2592 return result;
2593 }
2594
Jack Palevich8df46192009-07-07 14:48:51 -07002595 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich9f51a262009-07-29 16:22:26 -07002596 fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
2597 pFunc->pHead->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002598 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002599 }
2600
Jack Palevichb7718b92009-07-09 22:00:24 -07002601 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2602 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2603 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002604 }
2605
2606 virtual int jumpOffset() {
2607 return mpBase->jumpOffset();
2608 }
2609
2610 virtual int disassemble(FILE* out) {
2611 return mpBase->disassemble(out);
2612 }
2613
2614 /* output a symbol and patch all calls to it */
2615 virtual void gsym(int t) {
2616 fprintf(stderr, "gsym(%d)\n", t);
2617 mpBase->gsym(t);
2618 }
2619
Jack Palevich9f51a262009-07-29 16:22:26 -07002620 virtual void resolveForward(int t) {
2621 mpBase->resolveForward(t);
2622 }
2623
Jack Palevichb67b18f2009-06-11 21:12:23 -07002624 virtual int finishCompile() {
2625 int result = mpBase->finishCompile();
2626 fprintf(stderr, "finishCompile() = %d\n", result);
2627 return result;
2628 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002629
2630 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002631 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002632 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002633 virtual size_t alignmentOf(Type* pType){
2634 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002635 }
2636
2637 /**
2638 * Array element alignment (in bytes) for this type of data.
2639 */
2640 virtual size_t sizeOf(Type* pType){
2641 return mpBase->sizeOf(pType);
2642 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002643
Jack Palevich9cbd2262009-07-08 16:48:41 -07002644
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002645 virtual size_t stackAlignmentOf(Type* pType) {
2646 return mpBase->stackAlignmentOf(pType);
2647 }
2648
2649
Jack Palevich9cbd2262009-07-08 16:48:41 -07002650 virtual size_t stackSizeOf(Type* pType) {
2651 return mpBase->stackSizeOf(pType);
2652 }
2653
Jack Palevich1a539db2009-07-08 13:04:41 -07002654 virtual Type* getR0Type() {
2655 return mpBase->getR0Type();
2656 }
Jack Palevichddf7c9c2009-07-29 10:28:18 -07002657
2658 virtual ExpressionType getR0ExpressionType() {
2659 return mpBase->getR0ExpressionType();
2660 }
2661
2662 virtual void setR0ExpressionType(ExpressionType et) {
2663 mpBase->setR0ExpressionType(et);
2664 }
2665
2666 virtual size_t getExpressionStackDepth() {
2667 return mpBase->getExpressionStackDepth();
2668 }
Jack Palevichb5e33312009-07-30 19:06:34 -07002669
2670 virtual void forceR0RVal() {
2671 return mpBase->forceR0RVal();
2672 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002673 };
2674
2675#endif // PROVIDE_TRACE_CODEGEN
2676
Jack Palevich569f1352009-06-29 14:29:08 -07002677 class Arena {
2678 public:
2679 // Used to record a given allocation amount.
2680 // Used:
2681 // Mark mark = arena.mark();
2682 // ... lots of arena.allocate()
2683 // arena.free(mark);
2684
2685 struct Mark {
2686 size_t chunk;
2687 size_t offset;
2688 };
2689
2690 Arena() {
2691 mCurrentChunk = 0;
2692 Chunk start(CHUNK_SIZE);
2693 mData.push_back(start);
2694 }
2695
2696 ~Arena() {
2697 for(size_t i = 0; i < mData.size(); i++) {
2698 mData[i].free();
2699 }
2700 }
2701
2702 // Alloc using the standard alignment size safe for any variable
2703 void* alloc(size_t size) {
2704 return alloc(size, 8);
2705 }
2706
2707 Mark mark(){
2708 Mark result;
2709 result.chunk = mCurrentChunk;
2710 result.offset = mData[mCurrentChunk].mOffset;
2711 return result;
2712 }
2713
2714 void freeToMark(const Mark& mark) {
2715 mCurrentChunk = mark.chunk;
2716 mData[mCurrentChunk].mOffset = mark.offset;
2717 }
2718
2719 private:
2720 // Allocate memory aligned to a given size
2721 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2722 // Memory is not zero filled.
2723
2724 void* alloc(size_t size, size_t alignment) {
2725 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2726 if (mCurrentChunk + 1 < mData.size()) {
2727 mCurrentChunk++;
2728 } else {
2729 size_t allocSize = CHUNK_SIZE;
2730 if (allocSize < size + alignment - 1) {
2731 allocSize = size + alignment - 1;
2732 }
2733 Chunk chunk(allocSize);
2734 mData.push_back(chunk);
2735 mCurrentChunk++;
2736 }
2737 }
2738 return mData[mCurrentChunk].allocate(size, alignment);
2739 }
2740
2741 static const size_t CHUNK_SIZE = 128*1024;
2742 // Note: this class does not deallocate its
2743 // memory when it's destroyed. It depends upon
2744 // its parent to deallocate the memory.
2745 struct Chunk {
2746 Chunk() {
2747 mpData = 0;
2748 mSize = 0;
2749 mOffset = 0;
2750 }
2751
2752 Chunk(size_t size) {
2753 mSize = size;
2754 mpData = (char*) malloc(size);
2755 mOffset = 0;
2756 }
2757
2758 ~Chunk() {
2759 // Doesn't deallocate memory.
2760 }
2761
2762 void* allocate(size_t size, size_t alignment) {
2763 size_t alignedOffset = aligned(mOffset, alignment);
2764 void* result = mpData + alignedOffset;
2765 mOffset = alignedOffset + size;
2766 return result;
2767 }
2768
2769 void free() {
2770 if (mpData) {
2771 ::free(mpData);
2772 mpData = 0;
2773 }
2774 }
2775
2776 size_t remainingCapacity(size_t alignment) {
2777 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2778 }
2779
2780 // Assume alignment is a power of two
2781 inline size_t aligned(size_t v, size_t alignment) {
2782 size_t mask = alignment-1;
2783 return (v + mask) & ~mask;
2784 }
2785
2786 char* mpData;
2787 size_t mSize;
2788 size_t mOffset;
2789 };
2790
2791 size_t mCurrentChunk;
2792
2793 Vector<Chunk> mData;
2794 };
2795
Jack Palevich569f1352009-06-29 14:29:08 -07002796 struct VariableInfo;
2797
2798 struct Token {
2799 int hash;
2800 size_t length;
2801 char* pText;
2802 tokenid_t id;
2803
2804 // Current values for the token
2805 char* mpMacroDefinition;
2806 VariableInfo* mpVariableInfo;
2807 };
2808
2809 class TokenTable {
2810 public:
2811 // Don't use 0..0xff, allows characters and operators to be tokens too.
2812
2813 static const int TOKEN_BASE = 0x100;
2814 TokenTable() {
2815 mpMap = hashmapCreate(128, hashFn, equalsFn);
2816 }
2817
2818 ~TokenTable() {
2819 hashmapFree(mpMap);
2820 }
2821
2822 void setArena(Arena* pArena) {
2823 mpArena = pArena;
2824 }
2825
2826 // Returns a token for a given string of characters.
2827 tokenid_t intern(const char* pText, size_t length) {
2828 Token probe;
2829 int hash = hashmapHash((void*) pText, length);
2830 {
2831 Token probe;
2832 probe.hash = hash;
2833 probe.length = length;
2834 probe.pText = (char*) pText;
2835 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2836 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002837 return pValue->id;
2838 }
2839 }
2840
2841 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2842 memset(pToken, 0, sizeof(*pToken));
2843 pToken->hash = hash;
2844 pToken->length = length;
2845 pToken->pText = (char*) mpArena->alloc(length + 1);
2846 memcpy(pToken->pText, pText, length);
2847 pToken->pText[length] = 0;
2848 pToken->id = mTokens.size() + TOKEN_BASE;
2849 mTokens.push_back(pToken);
2850 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002851 return pToken->id;
2852 }
2853
2854 // Return the Token for a given tokenid.
2855 Token& operator[](tokenid_t id) {
2856 return *mTokens[id - TOKEN_BASE];
2857 }
2858
2859 inline size_t size() {
2860 return mTokens.size();
2861 }
2862
2863 private:
2864
2865 static int hashFn(void* pKey) {
2866 Token* pToken = (Token*) pKey;
2867 return pToken->hash;
2868 }
2869
2870 static bool equalsFn(void* keyA, void* keyB) {
2871 Token* pTokenA = (Token*) keyA;
2872 Token* pTokenB = (Token*) keyB;
2873 // Don't need to compare hash values, they should always be equal
2874 return pTokenA->length == pTokenB->length
2875 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2876 }
2877
2878 Hashmap* mpMap;
2879 Vector<Token*> mTokens;
2880 Arena* mpArena;
2881 };
2882
Jack Palevich1cdef202009-05-22 12:06:27 -07002883 class InputStream {
2884 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002885 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002886 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002887 };
2888
2889 class TextInputStream : public InputStream {
2890 public:
2891 TextInputStream(const char* text, size_t textLength)
2892 : pText(text), mTextLength(textLength), mPosition(0) {
2893 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002894
Jack Palevichdc456462009-07-16 16:50:56 -07002895 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002896 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2897 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002898
Jack Palevichdc456462009-07-16 16:50:56 -07002899 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002900 const char* pText;
2901 size_t mTextLength;
2902 size_t mPosition;
2903 };
2904
Jack Palevicheedf9d22009-06-04 16:23:40 -07002905 class String {
2906 public:
2907 String() {
2908 mpBase = 0;
2909 mUsed = 0;
2910 mSize = 0;
2911 }
2912
Jack Palevich303d8ff2009-06-11 19:06:24 -07002913 String(const char* item, int len, bool adopt) {
2914 if (len < 0) {
2915 len = strlen(item);
2916 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002917 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002918 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002919 mUsed = len;
2920 mSize = len + 1;
2921 } else {
2922 mpBase = 0;
2923 mUsed = 0;
2924 mSize = 0;
2925 appendBytes(item, len);
2926 }
2927 }
2928
Jack Palevich303d8ff2009-06-11 19:06:24 -07002929 String(const String& other) {
2930 mpBase = 0;
2931 mUsed = 0;
2932 mSize = 0;
2933 appendBytes(other.getUnwrapped(), other.len());
2934 }
2935
Jack Palevicheedf9d22009-06-04 16:23:40 -07002936 ~String() {
2937 if (mpBase) {
2938 free(mpBase);
2939 }
2940 }
2941
Jack Palevicha6baa232009-06-12 11:25:59 -07002942 String& operator=(const String& other) {
2943 clear();
2944 appendBytes(other.getUnwrapped(), other.len());
2945 return *this;
2946 }
2947
Jack Palevich303d8ff2009-06-11 19:06:24 -07002948 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002949 return mpBase;
2950 }
2951
Jack Palevich303d8ff2009-06-11 19:06:24 -07002952 void clear() {
2953 mUsed = 0;
2954 if (mSize > 0) {
2955 mpBase[0] = 0;
2956 }
2957 }
2958
Jack Palevicheedf9d22009-06-04 16:23:40 -07002959 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002960 appendBytes(s, strlen(s));
2961 }
2962
2963 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002964 memcpy(ensure(n), s, n + 1);
2965 }
2966
2967 void append(char c) {
2968 * ensure(1) = c;
2969 }
2970
Jack Palevich86351982009-06-30 18:09:56 -07002971 void append(String& other) {
2972 appendBytes(other.getUnwrapped(), other.len());
2973 }
2974
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002975 char* orphan() {
2976 char* result = mpBase;
2977 mpBase = 0;
2978 mUsed = 0;
2979 mSize = 0;
2980 return result;
2981 }
2982
Jack Palevicheedf9d22009-06-04 16:23:40 -07002983 void printf(const char* fmt,...) {
2984 va_list ap;
2985 va_start(ap, fmt);
2986 vprintf(fmt, ap);
2987 va_end(ap);
2988 }
2989
2990 void vprintf(const char* fmt, va_list ap) {
2991 char* temp;
2992 int numChars = vasprintf(&temp, fmt, ap);
2993 memcpy(ensure(numChars), temp, numChars+1);
2994 free(temp);
2995 }
2996
Jack Palevich303d8ff2009-06-11 19:06:24 -07002997 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002998 return mUsed;
2999 }
3000
3001 private:
3002 char* ensure(int n) {
3003 size_t newUsed = mUsed + n;
3004 if (newUsed > mSize) {
3005 size_t newSize = mSize * 2 + 10;
3006 if (newSize < newUsed) {
3007 newSize = newUsed;
3008 }
3009 mpBase = (char*) realloc(mpBase, newSize + 1);
3010 mSize = newSize;
3011 }
3012 mpBase[newUsed] = '\0';
3013 char* result = mpBase + mUsed;
3014 mUsed = newUsed;
3015 return result;
3016 }
3017
3018 char* mpBase;
3019 size_t mUsed;
3020 size_t mSize;
3021 };
3022
Jack Palevich569f1352009-06-29 14:29:08 -07003023 void internKeywords() {
3024 // Note: order has to match TOK_ constants
3025 static const char* keywords[] = {
3026 "int",
3027 "char",
3028 "void",
3029 "if",
3030 "else",
3031 "while",
3032 "break",
3033 "return",
3034 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003035 "auto",
3036 "case",
3037 "const",
3038 "continue",
3039 "default",
3040 "do",
3041 "double",
3042 "enum",
3043 "extern",
3044 "float",
3045 "goto",
3046 "long",
3047 "register",
3048 "short",
3049 "signed",
3050 "sizeof",
3051 "static",
3052 "struct",
3053 "switch",
3054 "typedef",
3055 "union",
3056 "unsigned",
3057 "volatile",
3058 "_Bool",
3059 "_Complex",
3060 "_Imaginary",
3061 "inline",
3062 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003063
3064 // predefined tokens that can also be symbols start here:
3065 "pragma",
3066 "define",
3067 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003068 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003069
Jack Palevich569f1352009-06-29 14:29:08 -07003070 for(int i = 0; keywords[i]; i++) {
3071 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003072 }
Jack Palevich569f1352009-06-29 14:29:08 -07003073 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003074
Jack Palevich36d94142009-06-08 15:55:32 -07003075 struct InputState {
3076 InputStream* pStream;
3077 int oldCh;
3078 };
3079
Jack Palevich2db168f2009-06-11 14:29:47 -07003080 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003081 void* pAddress;
3082 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003083 tokenid_t tok;
3084 size_t level;
3085 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003086 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003087 };
3088
Jack Palevich303d8ff2009-06-11 19:06:24 -07003089 class SymbolStack {
3090 public:
3091 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003092 mpArena = 0;
3093 mpTokenTable = 0;
3094 }
3095
3096 void setArena(Arena* pArena) {
3097 mpArena = pArena;
3098 }
3099
3100 void setTokenTable(TokenTable* pTokenTable) {
3101 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003102 }
3103
3104 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003105 Mark mark;
3106 mark.mArenaMark = mpArena->mark();
3107 mark.mSymbolHead = mStack.size();
3108 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003109 }
3110
3111 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003112 // Undo any shadowing that was done:
3113 Mark mark = mLevelStack.back();
3114 mLevelStack.pop_back();
3115 while (mStack.size() > mark.mSymbolHead) {
3116 VariableInfo* pV = mStack.back();
3117 mStack.pop_back();
3118 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003119 }
Jack Palevich569f1352009-06-29 14:29:08 -07003120 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003121 }
3122
Jack Palevich569f1352009-06-29 14:29:08 -07003123 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3124 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3125 return pV && pV->level == level();
3126 }
3127
3128 VariableInfo* add(tokenid_t tok) {
3129 Token& token = (*mpTokenTable)[tok];
3130 VariableInfo* pOldV = token.mpVariableInfo;
3131 VariableInfo* pNewV =
3132 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3133 memset(pNewV, 0, sizeof(VariableInfo));
3134 pNewV->tok = tok;
3135 pNewV->level = level();
3136 pNewV->pOldDefinition = pOldV;
3137 token.mpVariableInfo = pNewV;
3138 mStack.push_back(pNewV);
3139 return pNewV;
3140 }
3141
Jack Palevich86351982009-06-30 18:09:56 -07003142 VariableInfo* add(Type* pType) {
3143 VariableInfo* pVI = add(pType->id);
3144 pVI->pType = pType;
3145 return pVI;
3146 }
3147
Jack Palevich569f1352009-06-29 14:29:08 -07003148 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3149 for (size_t i = 0; i < mStack.size(); i++) {
3150 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003151 break;
3152 }
3153 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003154 }
3155
Jack Palevich303d8ff2009-06-11 19:06:24 -07003156 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003157 inline size_t level() {
3158 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003159 }
3160
Jack Palevich569f1352009-06-29 14:29:08 -07003161 struct Mark {
3162 Arena::Mark mArenaMark;
3163 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003164 };
3165
Jack Palevich569f1352009-06-29 14:29:08 -07003166 Arena* mpArena;
3167 TokenTable* mpTokenTable;
3168 Vector<VariableInfo*> mStack;
3169 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003170 };
Jack Palevich36d94142009-06-08 15:55:32 -07003171
3172 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003173 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003174 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003175 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003176 int tokl; // token operator level
3177 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003178 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003179 intptr_t loc; // local variable index
3180 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003181 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003182 char* dptr; // Macro state: Points to macro text during macro playback.
3183 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003184 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003185 ACCSymbolLookupFn mpSymbolLookupFn;
3186 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003187
3188 // Arena for the duration of the compile
3189 Arena mGlobalArena;
3190 // Arena for data that's only needed when compiling a single function
3191 Arena mLocalArena;
3192
Jack Palevich2ff5c222009-07-23 15:11:22 -07003193 Arena* mpCurrentArena;
3194
Jack Palevich569f1352009-06-29 14:29:08 -07003195 TokenTable mTokenTable;
3196 SymbolStack mGlobals;
3197 SymbolStack mLocals;
3198
Jack Palevich40600de2009-07-01 15:32:35 -07003199 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003200 Type* mkpInt; // int
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07003201 Type* mkpShort; // short
Jack Palevich9eed7a22009-07-06 17:24:34 -07003202 Type* mkpChar; // char
3203 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003204 Type* mkpFloat;
3205 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003206 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003207 Type* mkpIntPtr;
3208 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003209 Type* mkpFloatPtr;
3210 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003211 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003212
Jack Palevich36d94142009-06-08 15:55:32 -07003213 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003214 int mLineNumber;
3215 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003216
3217 CodeBuf codeBuf;
3218 CodeGenerator* pGen;
3219
Jack Palevicheedf9d22009-06-04 16:23:40 -07003220 String mErrorBuf;
3221
Jack Palevicheedf9d22009-06-04 16:23:40 -07003222 String mPragmas;
3223 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003224 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003225
Jack Palevich21a15a22009-05-11 14:49:29 -07003226 static const int ALLOC_SIZE = 99999;
3227
Jack Palevich303d8ff2009-06-11 19:06:24 -07003228 static const int TOK_DUMMY = 1;
3229 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003230 static const int TOK_NUM_FLOAT = 3;
3231 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich0c017742009-07-31 12:00:39 -07003232 static const int TOK_OP_ASSIGNMENT = 5;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003233
3234 // 3..255 are character and/or operators
3235
Jack Palevich2db168f2009-06-11 14:29:47 -07003236 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003237 // Order has to match string list in "internKeywords".
3238 enum {
3239 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3240 TOK_INT = TOK_KEYWORD,
3241 TOK_CHAR,
3242 TOK_VOID,
3243 TOK_IF,
3244 TOK_ELSE,
3245 TOK_WHILE,
3246 TOK_BREAK,
3247 TOK_RETURN,
3248 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003249 TOK_AUTO,
3250 TOK_CASE,
3251 TOK_CONST,
3252 TOK_CONTINUE,
3253 TOK_DEFAULT,
3254 TOK_DO,
3255 TOK_DOUBLE,
3256 TOK_ENUM,
3257 TOK_EXTERN,
3258 TOK_FLOAT,
3259 TOK_GOTO,
3260 TOK_LONG,
3261 TOK_REGISTER,
3262 TOK_SHORT,
3263 TOK_SIGNED,
3264 TOK_SIZEOF,
3265 TOK_STATIC,
3266 TOK_STRUCT,
3267 TOK_SWITCH,
3268 TOK_TYPEDEF,
3269 TOK_UNION,
3270 TOK_UNSIGNED,
3271 TOK_VOLATILE,
3272 TOK__BOOL,
3273 TOK__COMPLEX,
3274 TOK__IMAGINARY,
3275 TOK_INLINE,
3276 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003277
3278 // Symbols start after keywords
3279
3280 TOK_SYMBOL,
3281 TOK_PRAGMA = TOK_SYMBOL,
3282 TOK_DEFINE,
3283 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003284 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003285
3286 static const int LOCAL = 0x200;
3287
3288 static const int SYM_FORWARD = 0;
3289 static const int SYM_DEFINE = 1;
3290
3291 /* tokens in string heap */
3292 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003293
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003294 static const int OP_INCREMENT = 0;
3295 static const int OP_DECREMENT = 1;
3296 static const int OP_MUL = 2;
3297 static const int OP_DIV = 3;
3298 static const int OP_MOD = 4;
3299 static const int OP_PLUS = 5;
3300 static const int OP_MINUS = 6;
3301 static const int OP_SHIFT_LEFT = 7;
3302 static const int OP_SHIFT_RIGHT = 8;
3303 static const int OP_LESS_EQUAL = 9;
3304 static const int OP_GREATER_EQUAL = 10;
3305 static const int OP_LESS = 11;
3306 static const int OP_GREATER = 12;
3307 static const int OP_EQUALS = 13;
3308 static const int OP_NOT_EQUALS = 14;
3309 static const int OP_LOGICAL_AND = 15;
3310 static const int OP_LOGICAL_OR = 16;
3311 static const int OP_BIT_AND = 17;
3312 static const int OP_BIT_XOR = 18;
3313 static const int OP_BIT_OR = 19;
3314 static const int OP_BIT_NOT = 20;
3315 static const int OP_LOGICAL_NOT = 21;
3316 static const int OP_COUNT = 22;
3317
3318 /* Operators are searched from front, the two-character operators appear
3319 * before the single-character operators with the same first character.
3320 * @ is used to pad out single-character operators.
3321 */
3322 static const char* operatorChars;
3323 static const char operatorLevel[];
3324
Jack Palevich569f1352009-06-29 14:29:08 -07003325 /* Called when we detect an internal problem. Does nothing in production.
3326 *
3327 */
3328 void internalError() {
3329 * (char*) 0 = 0;
3330 }
3331
Jack Palevich86351982009-06-30 18:09:56 -07003332 void assert(bool isTrue) {
3333 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003334 internalError();
3335 }
Jack Palevich86351982009-06-30 18:09:56 -07003336 }
3337
Jack Palevich40600de2009-07-01 15:32:35 -07003338 bool isSymbol(tokenid_t t) {
3339 return t >= TOK_SYMBOL &&
3340 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3341 }
3342
3343 bool isSymbolOrKeyword(tokenid_t t) {
3344 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003345 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003346 }
3347
Jack Palevich86351982009-06-30 18:09:56 -07003348 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003349 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003350 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3351 if (pV && pV->tok != t) {
3352 internalError();
3353 }
3354 return pV;
3355 }
3356
3357 inline bool isDefined(tokenid_t t) {
3358 return t >= TOK_SYMBOL && VI(t) != 0;
3359 }
3360
Jack Palevich40600de2009-07-01 15:32:35 -07003361 const char* nameof(tokenid_t t) {
3362 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003363 return mTokenTable[t].pText;
3364 }
3365
Jack Palevich21a15a22009-05-11 14:49:29 -07003366 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003367 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003368 }
3369
3370 void inp() {
3371 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003372 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003373 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003374 dptr = 0;
3375 ch = dch;
3376 }
Jack Palevichdc456462009-07-16 16:50:56 -07003377 } else {
3378 if (mbBumpLine) {
3379 mLineNumber++;
3380 mbBumpLine = false;
3381 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003382 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003383 if (ch == '\n') {
3384 mbBumpLine = true;
3385 }
3386 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003387#if 0
3388 printf("ch='%c' 0x%x\n", ch, ch);
3389#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003390 }
3391
3392 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003393 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003394 }
3395
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003396 int decodeHex(int c) {
3397 if (isdigit(c)) {
3398 c -= '0';
3399 } else if (c <= 'F') {
3400 c = c - 'A' + 10;
3401 } else {
3402 c =c - 'a' + 10;
3403 }
3404 return c;
3405 }
3406
Jack Palevichb4758ff2009-06-12 12:49:14 -07003407 /* read a character constant, advances ch to after end of constant */
3408 int getq() {
3409 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003410 if (ch == '\\') {
3411 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003412 if (isoctal(ch)) {
3413 // 1 to 3 octal characters.
3414 val = 0;
3415 for(int i = 0; i < 3; i++) {
3416 if (isoctal(ch)) {
3417 val = (val << 3) + ch - '0';
3418 inp();
3419 }
3420 }
3421 return val;
3422 } else if (ch == 'x' || ch == 'X') {
3423 // N hex chars
3424 inp();
3425 if (! isxdigit(ch)) {
3426 error("'x' character escape requires at least one digit.");
3427 } else {
3428 val = 0;
3429 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003430 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003431 inp();
3432 }
3433 }
3434 } else {
3435 int val = ch;
3436 switch (ch) {
3437 case 'a':
3438 val = '\a';
3439 break;
3440 case 'b':
3441 val = '\b';
3442 break;
3443 case 'f':
3444 val = '\f';
3445 break;
3446 case 'n':
3447 val = '\n';
3448 break;
3449 case 'r':
3450 val = '\r';
3451 break;
3452 case 't':
3453 val = '\t';
3454 break;
3455 case 'v':
3456 val = '\v';
3457 break;
3458 case '\\':
3459 val = '\\';
3460 break;
3461 case '\'':
3462 val = '\'';
3463 break;
3464 case '"':
3465 val = '"';
3466 break;
3467 case '?':
3468 val = '?';
3469 break;
3470 default:
3471 error("Undefined character escape %c", ch);
3472 break;
3473 }
3474 inp();
3475 return val;
3476 }
3477 } else {
3478 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003479 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003480 return val;
3481 }
3482
3483 static bool isoctal(int ch) {
3484 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003485 }
3486
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003487 bool acceptCh(int c) {
3488 bool result = c == ch;
3489 if (result) {
3490 pdef(ch);
3491 inp();
3492 }
3493 return result;
3494 }
3495
3496 bool acceptDigitsCh() {
3497 bool result = false;
3498 while (isdigit(ch)) {
3499 result = true;
3500 pdef(ch);
3501 inp();
3502 }
3503 return result;
3504 }
3505
3506 void parseFloat() {
3507 tok = TOK_NUM_DOUBLE;
3508 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003509 if(mTokenString.len() == 0) {
3510 mTokenString.append('0');
3511 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003512 acceptCh('.');
3513 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003514 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003515 acceptCh('-') || acceptCh('+');
3516 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003517 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003518 if (ch == 'f' || ch == 'F') {
3519 tok = TOK_NUM_FLOAT;
3520 inp();
3521 } else if (ch == 'l' || ch == 'L') {
3522 inp();
3523 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003524 }
3525 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003526 char* pEnd = pText + strlen(pText);
3527 char* pEndPtr = 0;
3528 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003529 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003530 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003531 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003532 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003533 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003534 if (errno || pEndPtr != pEnd) {
3535 error("Can't parse constant: %s", pText);
3536 }
3537 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003538 }
3539
Jack Palevich21a15a22009-05-11 14:49:29 -07003540 void next() {
3541 int l, a;
3542
Jack Palevich546b2242009-05-13 15:10:04 -07003543 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003544 if (ch == '#') {
3545 inp();
3546 next();
3547 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003548 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003549 } else if (tok == TOK_PRAGMA) {
3550 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003551 } else if (tok == TOK_LINE) {
3552 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003553 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003554 error("Unsupported preprocessor directive \"%s\"",
3555 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003556 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003557 }
3558 inp();
3559 }
3560 tokl = 0;
3561 tok = ch;
3562 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003563 if (isdigit(ch) || ch == '.') {
3564 // Start of a numeric constant. Could be integer, float, or
3565 // double, won't know until we look further.
3566 mTokenString.clear();
3567 pdef(ch);
3568 inp();
3569 int base = 10;
3570 if (tok == '0') {
3571 if (ch == 'x' || ch == 'X') {
3572 base = 16;
3573 tok = TOK_NUM;
3574 tokc = 0;
3575 inp();
3576 while ( isxdigit(ch) ) {
3577 tokc = (tokc << 4) + decodeHex(ch);
3578 inp();
3579 }
3580 } else if (isoctal(ch)){
3581 base = 8;
3582 tok = TOK_NUM;
3583 tokc = 0;
3584 while ( isoctal(ch) ) {
3585 tokc = (tokc << 3) + (ch - '0');
3586 inp();
3587 }
3588 }
3589 } else if (isdigit(tok)){
3590 acceptDigitsCh();
3591 }
3592 if (base == 10) {
3593 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3594 parseFloat();
3595 } else {
3596 // It's an integer constant
3597 char* pText = mTokenString.getUnwrapped();
3598 char* pEnd = pText + strlen(pText);
3599 char* pEndPtr = 0;
3600 errno = 0;
3601 tokc = strtol(pText, &pEndPtr, base);
3602 if (errno || pEndPtr != pEnd) {
3603 error("Can't parse constant: %s %d %d", pText, base, errno);
3604 }
3605 tok = TOK_NUM;
3606 }
3607 }
3608 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003609 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003610 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003611 pdef(ch);
3612 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003613 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003614 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3615 // Is this a macro?
3616 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3617 if (pMacroDefinition) {
3618 // Yes, it is a macro
3619 dptr = pMacroDefinition;
3620 dch = ch;
3621 inp();
3622 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003623 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003624 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003625 inp();
3626 if (tok == '\'') {
3627 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003628 tokc = getq();
3629 if (ch != '\'') {
3630 error("Expected a ' character, got %c", ch);
3631 } else {
3632 inp();
3633 }
Jack Palevich546b2242009-05-13 15:10:04 -07003634 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003635 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003636 while (ch && ch != EOF) {
3637 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003638 inp();
3639 inp();
3640 if (ch == '/')
3641 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003642 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003643 if (ch == EOF) {
3644 error("End of file inside comment.");
3645 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003646 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003647 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003648 } else if ((tok == '/') & (ch == '/')) {
3649 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003650 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003651 inp();
3652 }
3653 inp();
3654 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003656 const char* t = operatorChars;
3657 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003658 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003659 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003660 tokl = operatorLevel[opIndex];
3661 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003662 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003663#if 0
3664 printf("%c%c -> tokl=%d tokc=0x%x\n",
3665 l, a, tokl, tokc);
3666#endif
3667 if (a == ch) {
3668 inp();
3669 tok = TOK_DUMMY; /* dummy token for double tokens */
3670 }
Jack Palevich0c017742009-07-31 12:00:39 -07003671 /* check for op=, valid for * / % + - << >> & ^ | */
3672 if (ch == '=' &&
3673 ((tokl >= 1 && tokl <= 3)
Jack Palevich47cbea92009-07-31 15:25:53 -07003674 || (tokl >=6 && tokl <= 8)) ) {
Jack Palevich0c017742009-07-31 12:00:39 -07003675 inp();
3676 tok = TOK_OP_ASSIGNMENT;
3677 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003678 break;
3679 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003680 opIndex++;
3681 }
3682 if (l == 0) {
3683 tokl = 0;
3684 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003685 }
3686 }
3687 }
3688#if 0
3689 {
Jack Palevich569f1352009-06-29 14:29:08 -07003690 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003691 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003692 fprintf(stderr, "%s\n", buf.getUnwrapped());
3693 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003694#endif
3695 }
3696
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003697 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003698 next();
3699 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003700 String* pName = new String();
3701 while (isspace(ch)) {
3702 inp();
3703 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003704 if (ch == '(') {
3705 delete pName;
3706 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003707 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003708 }
3709 while (isspace(ch)) {
3710 inp();
3711 }
Jack Palevich569f1352009-06-29 14:29:08 -07003712 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003713 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003714 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003715 inp();
3716 }
Jack Palevich569f1352009-06-29 14:29:08 -07003717 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3718 memcpy(pDefn, value.getUnwrapped(), value.len());
3719 pDefn[value.len()] = 0;
3720 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003721 }
3722
Jack Palevicheedf9d22009-06-04 16:23:40 -07003723 void doPragma() {
3724 // # pragma name(val)
3725 int state = 0;
3726 while(ch != EOF && ch != '\n' && state < 10) {
3727 switch(state) {
3728 case 0:
3729 if (isspace(ch)) {
3730 inp();
3731 } else {
3732 state++;
3733 }
3734 break;
3735 case 1:
3736 if (isalnum(ch)) {
3737 mPragmas.append(ch);
3738 inp();
3739 } else if (ch == '(') {
3740 mPragmas.append(0);
3741 inp();
3742 state++;
3743 } else {
3744 state = 11;
3745 }
3746 break;
3747 case 2:
3748 if (isalnum(ch)) {
3749 mPragmas.append(ch);
3750 inp();
3751 } else if (ch == ')') {
3752 mPragmas.append(0);
3753 inp();
3754 state = 10;
3755 } else {
3756 state = 11;
3757 }
3758 break;
3759 }
3760 }
3761 if(state != 10) {
3762 error("Unexpected pragma syntax");
3763 }
3764 mPragmaStringCount += 2;
3765 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003766
Jack Palevichdc456462009-07-16 16:50:56 -07003767 void doLine() {
3768 // # line number { "filename "}
3769 next();
3770 if (tok != TOK_NUM) {
3771 error("Expected a line-number");
3772 } else {
3773 mLineNumber = tokc-1; // The end-of-line will increment it.
3774 }
3775 while(ch != EOF && ch != '\n') {
3776 inp();
3777 }
3778 }
3779
Jack Palevichac0e95e2009-05-29 13:53:44 -07003780 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003781 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003782 mErrorBuf.vprintf(fmt, ap);
3783 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003784 }
3785
Jack Palevich8b0624c2009-05-20 12:12:06 -07003786 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003787 if (tok != c) {
3788 error("'%c' expected", c);
3789 }
3790 next();
3791 }
3792
Jack Palevich86351982009-06-30 18:09:56 -07003793 bool accept(intptr_t c) {
3794 if (tok == c) {
3795 next();
3796 return true;
3797 }
3798 return false;
3799 }
3800
Jack Palevich40600de2009-07-01 15:32:35 -07003801 bool acceptStringLiteral() {
3802 if (tok == '"') {
Jack Palevichb5e33312009-07-30 19:06:34 -07003803 pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
Jack Palevich40600de2009-07-01 15:32:35 -07003804 // This while loop merges multiple adjacent string constants.
3805 while (tok == '"') {
3806 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003807 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003808 }
3809 if (ch != '"') {
3810 error("Unterminated string constant.");
3811 }
3812 inp();
3813 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003814 }
Jack Palevich40600de2009-07-01 15:32:35 -07003815 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003816 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003817 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003818 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003819
3820 return true;
3821 }
3822 return false;
3823 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003824
Jack Palevichb1544ca2009-07-16 15:09:20 -07003825 void linkGlobal(tokenid_t t, bool isFunction) {
3826 VariableInfo* pVI = VI(t);
3827 void* n = NULL;
3828 if (mpSymbolLookupFn) {
3829 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3830 }
3831 if (pVI->pType == NULL) {
3832 if (isFunction) {
3833 pVI->pType = mkpIntFn;
3834 } else {
3835 pVI->pType = mkpInt;
3836 }
3837 }
3838 pVI->pAddress = n;
3839 }
3840
Jack Palevich29daf572009-07-30 19:38:55 -07003841 void unaryOrAssignment() {
3842 unary();
3843 if (accept('=')) {
3844 checkLVal();
3845 pGen->pushR0();
3846 expr();
3847 pGen->forceR0RVal();
3848 pGen->storeR0ToTOS();
Jack Palevich0c017742009-07-31 12:00:39 -07003849 } else if (tok == TOK_OP_ASSIGNMENT) {
3850 int t = tokc;
3851 next();
3852 checkLVal();
3853 pGen->pushR0();
3854 pGen->forceR0RVal();
3855 pGen->pushR0();
3856 expr();
3857 pGen->forceR0RVal();
3858 pGen->genOp(t);
3859 pGen->storeR0ToTOS();
Jack Palevich29daf572009-07-30 19:38:55 -07003860 }
3861 }
3862
Jack Palevich40600de2009-07-01 15:32:35 -07003863 /* Parse and evaluate a unary expression.
Jack Palevich40600de2009-07-01 15:32:35 -07003864 */
Jack Palevich29daf572009-07-30 19:38:55 -07003865 void unary() {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003866 tokenid_t t;
Jack Palevich5b659092009-07-31 14:55:07 -07003867 intptr_t a;
Jack Palevich40600de2009-07-01 15:32:35 -07003868 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07003869 if (acceptStringLiteral()) {
3870 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003871 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003872 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003873 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003874 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003875 t = tok;
3876 next();
3877 if (t == TOK_NUM) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07003878 pGen->li(a);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003879 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003880 // Align to 4-byte boundary
3881 glo = (char*) (((intptr_t) glo + 3) & -4);
3882 * (float*) glo = (float) ad;
3883 pGen->loadFloat((int) glo, mkpFloat);
3884 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003885 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003886 // Align to 8-byte boundary
3887 glo = (char*) (((intptr_t) glo + 7) & -8);
3888 * (double*) glo = ad;
3889 pGen->loadFloat((int) glo, mkpDouble);
3890 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 } else if (c == 2) {
3892 /* -, +, !, ~ */
Jack Palevich29daf572009-07-30 19:38:55 -07003893 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07003894 pGen->forceR0RVal();
Jack Palevich21a15a22009-05-11 14:49:29 -07003895 if (t == '!')
Jack Palevich58c30ee2009-07-17 16:35:23 -07003896 pGen->gUnaryCmp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003897 else if (t == '+') {
3898 // ignore unary plus.
3899 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003900 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003901 }
Jack Palevichaaac9282009-07-31 14:34:34 -07003902 } else if (c == 11) {
3903 // pre increment / pre decrement
3904 unary();
3905 doIncDec(a == OP_INCREMENT, 0);
3906 }
3907 else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003908 // It's either a cast or an expression
Jack Palevich2ff5c222009-07-23 15:11:22 -07003909 Type* pCast = acceptCastTypeDeclaration();
Jack Palevich45431bc2009-07-13 15:57:26 -07003910 if (pCast) {
3911 skip(')');
Jack Palevich29daf572009-07-30 19:38:55 -07003912 unary();
Jack Palevichb5e33312009-07-30 19:06:34 -07003913 pGen->forceR0RVal();
Jack Palevich45431bc2009-07-13 15:57:26 -07003914 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003915 } else {
Jack Palevich43aaee32009-07-31 14:01:37 -07003916 commaExpr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003917 skip(')');
3918 }
3919 } else if (t == '*') {
3920 /* This is a pointer dereference.
3921 */
Jack Palevich29daf572009-07-30 19:38:55 -07003922 unary();
Jack Palevich47cbea92009-07-31 15:25:53 -07003923 doPointer();
Jack Palevich21a15a22009-05-11 14:49:29 -07003924 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003925 VariableInfo* pVI = VI(tok);
Jack Palevichb5e33312009-07-30 19:06:34 -07003926 pGen->leaR0((int) pVI->pAddress, createPtrType(pVI->pType),
3927 ET_RVALUE);
Jack Palevich21a15a22009-05-11 14:49:29 -07003928 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003929 } else if (t == EOF ) {
3930 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003931 } else if (t == ';') {
3932 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003933 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003934 // Don't have to do anything special here, the error
3935 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003936 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003937 if (!isDefined(t)) {
3938 mGlobals.add(t);
3939 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003940 }
Jack Palevich8df46192009-07-07 14:48:51 -07003941 VariableInfo* pVI = VI(t);
Jack Palevich5b659092009-07-31 14:55:07 -07003942 int n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003943 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003944 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003945 linkGlobal(t, tok == '(');
3946 n = (intptr_t) pVI->pAddress;
3947 if (!n && tok != '(') {
3948 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003949 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003950 }
Jack Palevich29daf572009-07-30 19:38:55 -07003951 if (tok != '(') {
Jack Palevich5b659092009-07-31 14:55:07 -07003952 /* variable or function name */
Jack Palevicha6baa232009-06-12 11:25:59 -07003953 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003954 linkGlobal(t, false);
3955 n = (intptr_t) pVI->pAddress;
3956 if (!n) {
3957 error("Undeclared variable %s\n", nameof(t));
3958 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003959 }
Jack Palevich5b659092009-07-31 14:55:07 -07003960 }
3961 // load a variable
3962 Type* pVal = createPtrType(pVI->pType);
3963 if (n) {
3964 ExpressionType et = ET_LVALUE;
3965 if (pVal->pHead->tag == TY_FUNC) {
3966 et = ET_RVALUE;
Jack Palevich21a15a22009-05-11 14:49:29 -07003967 }
Jack Palevich5b659092009-07-31 14:55:07 -07003968 pGen->leaR0(n, pVal, et);
3969 } else {
3970 pVI->pForward = (void*) pGen->leaForward(
3971 (int) pVI->pForward, pVal);
Jack Palevich21a15a22009-05-11 14:49:29 -07003972 }
3973 }
3974 }
3975
Jack Palevich5b659092009-07-31 14:55:07 -07003976 /* Now handle postfix operators */
3977 for(;;) {
3978 if (tokl == 11) {
3979 // post inc / post dec
3980 doIncDec(tokc == OP_INCREMENT, true);
3981 next();
Jack Palevich47cbea92009-07-31 15:25:53 -07003982 } else if (accept('[')) {
3983 // Array reference
3984 pGen->forceR0RVal();
3985 pGen->pushR0();
3986 commaExpr();
3987 pGen->forceR0RVal();
3988 pGen->genOp(OP_PLUS);
3989 doPointer();
3990 skip(']');
Jack Palevich5b659092009-07-31 14:55:07 -07003991 } else if (accept('(')) {
3992 /* function call */
3993 Type* pDecl = NULL;
3994 VariableInfo* pVI = NULL;
Jack Palevich9f51a262009-07-29 16:22:26 -07003995 Type* pFn = pGen->getR0Type();
3996 assert(pFn->tag == TY_POINTER);
3997 assert(pFn->pHead->tag == TY_FUNC);
3998 pDecl = pFn->pHead;
Jack Palevich1cdef202009-05-22 12:06:27 -07003999 pGen->pushR0();
Jack Palevich5b659092009-07-31 14:55:07 -07004000 Type* pArgList = pDecl->pTail;
4001 bool varArgs = pArgList == NULL;
4002 /* push args and invert order */
4003 a = pGen->beginFunctionCallArguments();
4004 int l = 0;
4005 int argCount = 0;
4006 while (tok != ')' && tok != EOF) {
4007 if (! varArgs && !pArgList) {
4008 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004009 }
Jack Palevich5b659092009-07-31 14:55:07 -07004010 expr();
4011 pGen->forceR0RVal();
4012 Type* pTargetType;
4013 if (pArgList) {
4014 pTargetType = pArgList->pHead;
4015 pArgList = pArgList->pTail;
4016 } else {
4017 // This is a ... function, just pass arguments in their
4018 // natural type.
4019 pTargetType = pGen->getR0Type();
4020 if (pTargetType->tag == TY_FLOAT) {
4021 pTargetType = mkpDouble;
4022 }
4023 }
4024 if (pTargetType->tag == TY_VOID) {
4025 error("Can't pass void value for argument %d",
4026 argCount + 1);
4027 } else {
4028 l += pGen->storeR0ToArg(l, pTargetType);
4029 }
4030 if (accept(',')) {
4031 // fine
4032 } else if ( tok != ')') {
4033 error("Expected ',' or ')'");
4034 }
4035 argCount += 1;
Jack Palevich1a539db2009-07-08 13:04:41 -07004036 }
Jack Palevich5b659092009-07-31 14:55:07 -07004037 if (! varArgs && pArgList) {
4038 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004039 }
Jack Palevich5b659092009-07-31 14:55:07 -07004040 pGen->endFunctionCallArguments(pDecl, a, l);
4041 skip(')');
4042 pGen->callIndirect(l, pDecl);
4043 pGen->adjustStackAfterCall(pDecl, l, true);
4044 } else {
4045 break;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004046 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004047 }
4048 }
4049
Jack Palevichaaac9282009-07-31 14:34:34 -07004050 void doIncDec(int isInc, int isPost) {
4051 // R0 already has the lval
4052 checkLVal();
4053 int lit = isInc ? 1 : -1;
4054 pGen->pushR0();
4055 pGen->loadR0FromR0();
4056 int tag = pGen->getR0Type()->tag;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004057 if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4058 tag == TY_POINTER)) {
Jack Palevichaaac9282009-07-31 14:34:34 -07004059 error("++/-- illegal for this type. %d", tag);
4060 }
4061 if (isPost) {
4062 pGen->over();
4063 pGen->pushR0();
4064 pGen->li(lit);
4065 pGen->genOp(OP_PLUS);
4066 pGen->storeR0ToTOS();
4067 pGen->popR0();
4068 } else {
4069 pGen->pushR0();
4070 pGen->li(lit);
4071 pGen->genOp(OP_PLUS);
4072 pGen->over();
4073 pGen->storeR0ToTOS();
4074 pGen->popR0();
4075 }
4076 }
4077
Jack Palevich47cbea92009-07-31 15:25:53 -07004078 void doPointer() {
4079 pGen->forceR0RVal();
4080 Type* pR0Type = pGen->getR0Type();
4081 if (pR0Type->tag != TY_POINTER) {
4082 error("Expected a pointer type.");
4083 } else {
4084 if (pR0Type->pHead->tag != TY_FUNC) {
4085 pGen->setR0ExpressionType(ET_LVALUE);
4086 }
4087 }
4088 }
4089
Jack Palevich40600de2009-07-01 15:32:35 -07004090 /* Recursive descent parser for binary operations.
4091 */
4092 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004093 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004094 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004095 if (level-- == 1)
Jack Palevich29daf572009-07-30 19:38:55 -07004096 unaryOrAssignment();
Jack Palevich21a15a22009-05-11 14:49:29 -07004097 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004098 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004099 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004100 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004101 t = tokc;
4102 next();
Jack Palevichb5e33312009-07-30 19:06:34 -07004103 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004104 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004105 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004106 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004107 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004108 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004109 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004110 // Check for syntax error.
4111 if (pGen->getR0Type() == NULL) {
4112 // We failed to parse a right-hand argument.
4113 // Push a dummy value so we don't fail
Jack Palevich58c30ee2009-07-17 16:35:23 -07004114 pGen->li(0);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004115 }
Jack Palevichb5e33312009-07-30 19:06:34 -07004116 pGen->forceR0RVal();
Jack Palevich40600de2009-07-01 15:32:35 -07004117 if ((level == 4) | (level == 5)) {
Jack Palevich58c30ee2009-07-17 16:35:23 -07004118 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004119 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004120 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004121 }
4122 }
4123 }
4124 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004125 if (a && level > 8) {
Jack Palevichb5e33312009-07-30 19:06:34 -07004126 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004127 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004128 pGen->li(t != OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004129 int b = pGen->gjmp(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004130 pGen->gsym(a);
Jack Palevich58c30ee2009-07-17 16:35:23 -07004131 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich8f361fa2009-07-30 16:19:43 -07004132 pGen->gsym(b);
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 }
4134 }
4135 }
4136
Jack Palevich43aaee32009-07-31 14:01:37 -07004137 void commaExpr() {
4138 for(;;) {
4139 expr();
4140 if (!accept(',')) {
4141 break;
4142 }
4143 }
4144 }
4145
Jack Palevich21a15a22009-05-11 14:49:29 -07004146 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004147 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004148 }
4149
4150 int test_expr() {
Jack Palevich43aaee32009-07-31 14:01:37 -07004151 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004152 pGen->forceR0RVal();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004153 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 }
4155
Jack Palevicha6baa232009-06-12 11:25:59 -07004156 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004157 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004158
Jack Palevich95727a02009-07-06 12:07:15 -07004159 Type* pBaseType;
Jack Palevich2ff5c222009-07-23 15:11:22 -07004160 if ((pBaseType = acceptPrimitiveType())) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004161 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004162 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004163 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004164 next();
4165 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004166 a = test_expr();
4167 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004168 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004169 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004170 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004171 n = pGen->gjmp(0); /* jmp */
4172 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004173 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004174 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004175 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004176 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004177 }
Jack Palevich546b2242009-05-13 15:10:04 -07004178 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004179 t = tok;
4180 next();
4181 skip('(');
4182 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004183 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004184 a = test_expr();
4185 } else {
4186 if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004187 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004188 skip(';');
4189 n = codeBuf.getPC();
4190 a = 0;
4191 if (tok != ';')
4192 a = test_expr();
4193 skip(';');
4194 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004195 t = pGen->gjmp(0);
Jack Palevich43aaee32009-07-31 14:01:37 -07004196 commaExpr();
Jack Palevicha6535612009-05-13 16:24:17 -07004197 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004198 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004199 n = t + 4;
4200 }
4201 }
4202 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004203 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004204 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004205 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004206 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004207 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004208 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004209 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004210 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004211 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004212 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004213 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004214 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004215 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004216 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004217 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004218 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004219 if (tok != ';') {
Jack Palevich43aaee32009-07-31 14:01:37 -07004220 commaExpr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004221 pGen->forceR0RVal();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004222 if (pReturnType->tag == TY_VOID) {
4223 error("Must not return a value from a void function");
4224 } else {
4225 pGen->convertR0(pReturnType);
4226 }
4227 } else {
4228 if (pReturnType->tag != TY_VOID) {
4229 error("Must specify a value here");
4230 }
Jack Palevich8df46192009-07-07 14:48:51 -07004231 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004232 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004233 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004234 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004235 } else if (tok != ';')
Jack Palevich43aaee32009-07-31 14:01:37 -07004236 commaExpr();
Jack Palevich21a15a22009-05-11 14:49:29 -07004237 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004238 }
4239 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004240
Jack Palevicha8f427f2009-07-13 18:40:08 -07004241 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004242 if (a == b) {
4243 return true;
4244 }
4245 if (a == NULL || b == NULL) {
4246 return false;
4247 }
4248 TypeTag at = a->tag;
4249 if (at != b->tag) {
4250 return false;
4251 }
4252 if (at == TY_POINTER) {
4253 return typeEqual(a->pHead, b->pHead);
4254 } else if (at == TY_FUNC || at == TY_PARAM) {
4255 return typeEqual(a->pHead, b->pHead)
4256 && typeEqual(a->pTail, b->pTail);
4257 }
4258 return true;
4259 }
4260
Jack Palevich2ff5c222009-07-23 15:11:22 -07004261 Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
Jack Palevich86351982009-06-30 18:09:56 -07004262 assert(tag >= TY_INT && tag <= TY_PARAM);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004263 Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
Jack Palevich86351982009-06-30 18:09:56 -07004264 memset(pType, 0, sizeof(*pType));
4265 pType->tag = tag;
4266 pType->pHead = pHead;
4267 pType->pTail = pTail;
4268 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004269 }
4270
Jack Palevich2ff5c222009-07-23 15:11:22 -07004271 Type* createPtrType(Type* pType) {
4272 return createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004273 }
4274
4275 /**
4276 * Try to print a type in declaration order
4277 */
Jack Palevich86351982009-06-30 18:09:56 -07004278 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004279 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004280 if (pType == NULL) {
4281 buffer.appendCStr("null");
4282 return;
4283 }
Jack Palevich3f226492009-07-02 14:46:19 -07004284 decodeTypeImp(buffer, pType);
4285 }
4286
4287 void decodeTypeImp(String& buffer, Type* pType) {
4288 decodeTypeImpPrefix(buffer, pType);
4289
Jack Palevich86351982009-06-30 18:09:56 -07004290 String temp;
4291 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004292 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004293 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004294 }
4295
4296 decodeTypeImpPostfix(buffer, pType);
4297 }
4298
4299 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4300 TypeTag tag = pType->tag;
4301
Jack Palevich37c54bd2009-07-14 18:35:36 -07004302 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004303 switch (tag) {
4304 case TY_INT:
4305 buffer.appendCStr("int");
4306 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004307 case TY_SHORT:
4308 buffer.appendCStr("short");
4309 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004310 case TY_CHAR:
4311 buffer.appendCStr("char");
4312 break;
4313 case TY_VOID:
4314 buffer.appendCStr("void");
4315 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004316 case TY_FLOAT:
4317 buffer.appendCStr("float");
4318 break;
4319 case TY_DOUBLE:
4320 buffer.appendCStr("double");
4321 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004322 default:
4323 break;
4324 }
Jack Palevich86351982009-06-30 18:09:56 -07004325 buffer.append(' ');
4326 }
Jack Palevich3f226492009-07-02 14:46:19 -07004327
4328 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004329 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004330 break;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004331 case TY_SHORT:
4332 break;
Jack Palevich86351982009-06-30 18:09:56 -07004333 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004334 break;
4335 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004336 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004337 case TY_FLOAT:
4338 break;
4339 case TY_DOUBLE:
4340 break;
Jack Palevich86351982009-06-30 18:09:56 -07004341 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004342 decodeTypeImpPrefix(buffer, pType->pHead);
4343 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4344 buffer.append('(');
4345 }
4346 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004347 break;
4348 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004349 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004350 break;
4351 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004352 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004353 break;
4354 default:
4355 String temp;
4356 temp.printf("Unknown tag %d", pType->tag);
4357 buffer.append(temp);
4358 break;
4359 }
Jack Palevich3f226492009-07-02 14:46:19 -07004360 }
4361
4362 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4363 TypeTag tag = pType->tag;
4364
4365 switch(tag) {
4366 case TY_POINTER:
4367 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4368 buffer.append(')');
4369 }
4370 decodeTypeImpPostfix(buffer, pType->pHead);
4371 break;
4372 case TY_FUNC:
4373 buffer.append('(');
4374 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4375 decodeTypeImp(buffer, pArg);
4376 if (pArg->pTail) {
4377 buffer.appendCStr(", ");
4378 }
4379 }
4380 buffer.append(')');
4381 break;
4382 default:
4383 break;
Jack Palevich86351982009-06-30 18:09:56 -07004384 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004385 }
4386
Jack Palevich86351982009-06-30 18:09:56 -07004387 void printType(Type* pType) {
4388 String buffer;
4389 decodeType(buffer, pType);
4390 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004391 }
4392
Jack Palevich2ff5c222009-07-23 15:11:22 -07004393 Type* acceptPrimitiveType() {
Jack Palevich86351982009-06-30 18:09:56 -07004394 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004395 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004396 pType = mkpInt;
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004397 } else if (tok == TOK_SHORT) {
4398 pType = mkpShort;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004399 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004400 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004401 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004402 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004403 } else if (tok == TOK_FLOAT) {
4404 pType = mkpFloat;
4405 } else if (tok == TOK_DOUBLE) {
4406 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004407 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004408 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004409 }
4410 next();
Jack Palevich86351982009-06-30 18:09:56 -07004411 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004412 }
4413
Jack Palevich2ff5c222009-07-23 15:11:22 -07004414 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
Jack Palevich3f226492009-07-02 14:46:19 -07004415 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004416 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004417 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004418 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004419 if (declName) {
4420 // Clone the parent type so we can set a unique ID
Jack Palevich2ff5c222009-07-23 15:11:22 -07004421 pType = createType(pType->tag, pType->pHead, pType->pTail);
Jack Palevich3f226492009-07-02 14:46:19 -07004422
Jack Palevich86351982009-06-30 18:09:56 -07004423 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004424 }
Jack Palevich3f226492009-07-02 14:46:19 -07004425 // fprintf(stderr, "Parsed a declaration: ");
4426 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004427 if (reportFailure) {
4428 return NULL;
4429 }
Jack Palevich86351982009-06-30 18:09:56 -07004430 return pType;
4431 }
4432
Jack Palevich2ff5c222009-07-23 15:11:22 -07004433 Type* expectDeclaration(Type* pBaseType) {
4434 Type* pType = acceptDeclaration(pBaseType, true, true);
Jack Palevich86351982009-06-30 18:09:56 -07004435 if (! pType) {
4436 error("Expected a declaration");
4437 }
4438 return pType;
4439 }
4440
Jack Palevich3f226492009-07-02 14:46:19 -07004441 /* Used for accepting types that appear in casts */
Jack Palevich2ff5c222009-07-23 15:11:22 -07004442 Type* acceptCastTypeDeclaration() {
4443 Type* pType = acceptPrimitiveType();
Jack Palevich3f226492009-07-02 14:46:19 -07004444 if (pType) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004445 pType = acceptDeclaration(pType, false, false);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004446 }
Jack Palevich86351982009-06-30 18:09:56 -07004447 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004448 }
4449
Jack Palevich2ff5c222009-07-23 15:11:22 -07004450 Type* expectCastTypeDeclaration() {
4451 Type* pType = acceptCastTypeDeclaration();
Jack Palevich3f226492009-07-02 14:46:19 -07004452 if (! pType) {
4453 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004454 }
Jack Palevich3f226492009-07-02 14:46:19 -07004455 return pType;
4456 }
4457
4458 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004459 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004460 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004461 while (accept('*')) {
Jack Palevich96138992009-07-31 15:58:19 -07004462 pType = createType(TY_POINTER, pType, NULL);
Jack Palevich3f226492009-07-02 14:46:19 -07004463 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004464 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004465 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004466 return pType;
4467 }
4468
4469 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004470 bool nameAllowed, bool nameRequired,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004471 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004472 // direct-dcl :
4473 // name
4474 // (dcl)
4475 // direct-dcl()
4476 // direct-dcl[]
4477 Type* pNewHead = NULL;
4478 if (accept('(')) {
4479 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich2ff5c222009-07-23 15:11:22 -07004480 nameRequired, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004481 skip(')');
4482 } else if ((declName = acceptSymbol()) != 0) {
4483 if (nameAllowed == false && declName) {
4484 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004485 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004486 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004487 } else if (nameRequired && ! declName) {
4488 String temp;
4489 decodeToken(temp, tok, true);
4490 error("Expected name. Got %s", temp.getUnwrapped());
4491 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004492 }
4493 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004494 // Function declaration
Jack Palevich2ff5c222009-07-23 15:11:22 -07004495 Type* pTail = acceptArgs(nameAllowed);
4496 pType = createType(TY_FUNC, pType, pTail);
Jack Palevich86351982009-06-30 18:09:56 -07004497 skip(')');
4498 }
Jack Palevich3f226492009-07-02 14:46:19 -07004499
4500 if (pNewHead) {
4501 Type* pA = pNewHead;
4502 while (pA->pHead) {
4503 pA = pA->pHead;
4504 }
4505 pA->pHead = pType;
4506 pType = pNewHead;
4507 }
Jack Palevich86351982009-06-30 18:09:56 -07004508 return pType;
4509 }
4510
Jack Palevich2ff5c222009-07-23 15:11:22 -07004511 Type* acceptArgs(bool nameAllowed) {
Jack Palevich86351982009-06-30 18:09:56 -07004512 Type* pHead = NULL;
4513 Type* pTail = NULL;
4514 for(;;) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004515 Type* pBaseArg = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004516 if (pBaseArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004517 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
Jack Palevich86351982009-06-30 18:09:56 -07004518 if (pArg) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004519 Type* pParam = createType(TY_PARAM, pArg, NULL);
Jack Palevich86351982009-06-30 18:09:56 -07004520 if (!pHead) {
4521 pHead = pParam;
4522 pTail = pParam;
4523 } else {
4524 pTail->pTail = pParam;
4525 pTail = pParam;
4526 }
4527 }
4528 }
4529 if (! accept(',')) {
4530 break;
4531 }
4532 }
4533 return pHead;
4534 }
4535
Jack Palevich2ff5c222009-07-23 15:11:22 -07004536 Type* expectPrimitiveType() {
4537 Type* pType = acceptPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004538 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004539 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004540 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004541 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004542 }
Jack Palevich86351982009-06-30 18:09:56 -07004543 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004544 }
4545
Jack Palevichb5e33312009-07-30 19:06:34 -07004546 void checkLVal() {
4547 if (pGen->getR0ExpressionType() != ET_LVALUE) {
4548 error("Expected an lval");
4549 }
4550 }
4551
Jack Palevich86351982009-06-30 18:09:56 -07004552 void addGlobalSymbol(Type* pDecl) {
4553 tokenid_t t = pDecl->id;
4554 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004555 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004556 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004557 }
Jack Palevich86351982009-06-30 18:09:56 -07004558 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004559 }
4560
Jack Palevich86351982009-06-30 18:09:56 -07004561 void reportDuplicate(tokenid_t t) {
4562 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004563 }
4564
Jack Palevich86351982009-06-30 18:09:56 -07004565 void addLocalSymbol(Type* pDecl) {
4566 tokenid_t t = pDecl->id;
4567 if (mLocals.isDefinedAtCurrentLevel(t)) {
4568 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004569 }
Jack Palevich86351982009-06-30 18:09:56 -07004570 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004571 }
4572
Jack Palevich95727a02009-07-06 12:07:15 -07004573 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004574 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004575
Jack Palevich95727a02009-07-06 12:07:15 -07004576 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004577 while (tok != ';' && tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004578 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004579 if (!pDecl) {
4580 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004581 }
Jack Palevich86351982009-06-30 18:09:56 -07004582 int variableAddress = 0;
4583 addLocalSymbol(pDecl);
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004584 size_t alignment = pGen->stackAlignmentOf(pDecl);
4585 size_t alignmentMask = ~ (alignment - 1);
4586 size_t sizeOf = pGen->sizeOf(pDecl);
4587 loc = (loc + alignment - 1) & alignmentMask;
4588 size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
4589 loc = loc + alignedSize;
Jack Palevich86351982009-06-30 18:09:56 -07004590 variableAddress = -loc;
4591 VI(pDecl->id)->pAddress = (void*) variableAddress;
4592 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004593 /* assignment */
Jack Palevichb5e33312009-07-30 19:06:34 -07004594 pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
Jack Palevich8968e8e2009-07-30 16:57:33 -07004595 pGen->pushR0();
Jack Palevichd7461a72009-06-12 14:26:58 -07004596 expr();
Jack Palevichb5e33312009-07-30 19:06:34 -07004597 pGen->forceR0RVal();
Jack Palevich8968e8e2009-07-30 16:57:33 -07004598 pGen->storeR0ToTOS();
Jack Palevichd7461a72009-06-12 14:26:58 -07004599 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004600 if (tok == ',')
4601 next();
4602 }
4603 skip(';');
Jack Palevich2ff5c222009-07-23 15:11:22 -07004604 pBaseType = acceptPrimitiveType();
Jack Palevichb7c81e92009-06-04 19:56:13 -07004605 }
4606 }
4607
Jack Palevichf1728be2009-06-12 13:53:51 -07004608 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004609 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004610 }
4611
Jack Palevich37c54bd2009-07-14 18:35:36 -07004612 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004613 if (token == EOF ) {
4614 buffer.printf("EOF");
4615 } else if (token == TOK_NUM) {
4616 buffer.printf("numeric constant");
4617 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004618 if (token < 32) {
4619 buffer.printf("'\\x%02x'", token);
4620 } else {
4621 buffer.printf("'%c'", token);
4622 }
Jack Palevich569f1352009-06-29 14:29:08 -07004623 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004624 if (quote) {
4625 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4626 buffer.printf("keyword \"%s\"", nameof(token));
4627 } else {
4628 buffer.printf("symbol \"%s\"", nameof(token));
4629 }
4630 } else {
4631 buffer.printf("%s", nameof(token));
4632 }
Jack Palevich569f1352009-06-29 14:29:08 -07004633 }
4634 }
4635
Jack Palevich40600de2009-07-01 15:32:35 -07004636 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004637 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004638 if (!result) {
4639 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004640 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004641 error("Expected symbol. Got %s", temp.getUnwrapped());
4642 }
4643 return result;
4644 }
4645
Jack Palevich86351982009-06-30 18:09:56 -07004646 tokenid_t acceptSymbol() {
4647 tokenid_t result = 0;
4648 if (tok >= TOK_SYMBOL) {
4649 result = tok;
4650 next();
Jack Palevich86351982009-06-30 18:09:56 -07004651 }
4652 return result;
4653 }
4654
Jack Palevichb7c81e92009-06-04 19:56:13 -07004655 void globalDeclarations() {
4656 while (tok != EOF) {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004657 Type* pBaseType = expectPrimitiveType();
Jack Palevich86351982009-06-30 18:09:56 -07004658 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004659 break;
4660 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004661 Type* pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004662 if (!pDecl) {
4663 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004664 }
Jack Palevich86351982009-06-30 18:09:56 -07004665 if (! isDefined(pDecl->id)) {
4666 addGlobalSymbol(pDecl);
4667 }
4668 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004669 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004670 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004671 }
Jack Palevich86351982009-06-30 18:09:56 -07004672 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004673 // it's a variable declaration
4674 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004675 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004676 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004677 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004678 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004679 }
Jack Palevich86351982009-06-30 18:09:56 -07004680 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004681 if (tok == TOK_NUM) {
4682 if (name) {
4683 * (int*) name->pAddress = tokc;
4684 }
4685 next();
4686 } else {
4687 error("Expected an integer constant");
4688 }
4689 }
Jack Palevich86351982009-06-30 18:09:56 -07004690 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004691 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004692 }
Jack Palevich2ff5c222009-07-23 15:11:22 -07004693 pDecl = expectDeclaration(pBaseType);
Jack Palevich86351982009-06-30 18:09:56 -07004694 if (!pDecl) {
4695 break;
4696 }
4697 if (! isDefined(pDecl->id)) {
4698 addGlobalSymbol(pDecl);
4699 }
4700 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004701 }
4702 skip(';');
4703 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004704 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004705 if (accept(';')) {
4706 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004707 } else if (tok != '{') {
4708 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004709 } else {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004710 mpCurrentArena = &mLocalArena;
Jack Palevich95727a02009-07-06 12:07:15 -07004711 if (name) {
Jack Palevich9f51a262009-07-29 16:22:26 -07004712 /* patch forward references */
4713 pGen->resolveForward((int) name->pForward);
Jack Palevich95727a02009-07-06 12:07:15 -07004714 /* put function address */
4715 name->pAddress = (void*) codeBuf.getPC();
4716 }
4717 // Calculate stack offsets for parameters
4718 mLocals.pushLevel();
4719 intptr_t a = 8;
4720 int argCount = 0;
4721 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4722 Type* pArg = pP->pHead;
4723 addLocalSymbol(pArg);
4724 /* read param name and compute offset */
Jack Palevich7fcdf1c2009-07-23 18:56:20 -07004725 size_t alignment = pGen->stackAlignmentOf(pArg);
Jack Palevichb7718b92009-07-09 22:00:24 -07004726 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004727 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004728 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004729 argCount++;
4730 }
4731 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004732 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004733 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004734 block(0, true);
4735 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004736 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004737 mLocals.popLevel();
Jack Palevich2ff5c222009-07-23 15:11:22 -07004738 mpCurrentArena = &mGlobalArena;
Jack Palevicha6baa232009-06-12 11:25:59 -07004739 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004740 }
4741 }
4742 }
4743
Jack Palevich9cbd2262009-07-08 16:48:41 -07004744 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4745 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4746 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004747 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004748 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004749 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004750 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004751 char* result = (char*) base;
4752 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004753 return result;
4754 }
4755
Jack Palevich21a15a22009-05-11 14:49:29 -07004756 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004757 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004758 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004759 pGlobalBase = 0;
4760 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004761 if (pGen) {
4762 delete pGen;
4763 pGen = 0;
4764 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004765 if (file) {
4766 delete file;
4767 file = 0;
4768 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004769 }
4770
Jack Palevich8c246a92009-07-14 21:14:10 -07004771 // One-time initialization, when class is constructed.
4772 void init() {
4773 mpSymbolLookupFn = 0;
4774 mpSymbolLookupContext = 0;
4775 }
4776
Jack Palevich21a15a22009-05-11 14:49:29 -07004777 void clear() {
4778 tok = 0;
4779 tokc = 0;
4780 tokl = 0;
4781 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004782 rsym = 0;
4783 loc = 0;
4784 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004785 dptr = 0;
4786 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004787 file = 0;
4788 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004789 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004790 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004791 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004792 mLineNumber = 1;
4793 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004794 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004795
Jack Palevich22305132009-05-13 10:58:45 -07004796 void setArchitecture(const char* architecture) {
4797 delete pGen;
4798 pGen = 0;
4799
4800 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004801#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004802 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004803 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004804 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004805#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004806#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004807 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004808 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004809 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004810#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004811 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004812 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004813 }
4814 }
4815
4816 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004817#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004818 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004819#elif defined(DEFAULT_X86_CODEGEN)
4820 pGen = new X86CodeGenerator();
4821#endif
4822 }
4823 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004824 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004825 } else {
4826 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004827 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004828 }
4829 }
4830
Jack Palevich77ae76e2009-05-10 19:59:24 -07004831public:
Jack Palevich22305132009-05-13 10:58:45 -07004832 struct args {
4833 args() {
4834 architecture = 0;
4835 }
4836 const char* architecture;
4837 };
4838
Jack Paleviche7b59062009-05-19 17:12:17 -07004839 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004840 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004841 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004842 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004843
Jack Paleviche7b59062009-05-19 17:12:17 -07004844 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004845 cleanup();
4846 }
4847
Jack Palevich8c246a92009-07-14 21:14:10 -07004848 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4849 mpSymbolLookupFn = pFn;
4850 mpSymbolLookupContext = pContext;
4851 }
4852
Jack Palevich1cdef202009-05-22 12:06:27 -07004853 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004854 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004855
Jack Palevich2ff5c222009-07-23 15:11:22 -07004856 mpCurrentArena = &mGlobalArena;
Jack Palevicha8f427f2009-07-13 18:40:08 -07004857 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004858 cleanup();
4859 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004860 mTokenTable.setArena(&mGlobalArena);
4861 mGlobals.setArena(&mGlobalArena);
4862 mGlobals.setTokenTable(&mTokenTable);
4863 mLocals.setArena(&mLocalArena);
4864 mLocals.setTokenTable(&mTokenTable);
4865
4866 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004867 codeBuf.init(ALLOC_SIZE);
4868 setArchitecture(NULL);
4869 if (!pGen) {
4870 return -1;
4871 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004872#ifdef PROVIDE_TRACE_CODEGEN
4873 pGen = new TraceCodeGenerator(pGen);
4874#endif
4875 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004876 pGen->init(&codeBuf);
4877 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004878 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4879 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004880 inp();
4881 next();
4882 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004883 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004884 result = pGen->finishCompile();
4885 if (result == 0) {
4886 if (mErrorBuf.len()) {
4887 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004888 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004889 }
Jack Palevichce105a92009-07-16 14:30:33 -07004890 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004891 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004892 }
4893
Jack Palevich86351982009-06-30 18:09:56 -07004894 void createPrimitiveTypes() {
Jack Palevich2ff5c222009-07-23 15:11:22 -07004895 mkpInt = createType(TY_INT, NULL, NULL);
Jack Palevichc9b8ffc2009-08-03 14:42:57 -07004896 mkpShort = createType(TY_SHORT, NULL, NULL);
Jack Palevich2ff5c222009-07-23 15:11:22 -07004897 mkpChar = createType(TY_CHAR, NULL, NULL);
4898 mkpVoid = createType(TY_VOID, NULL, NULL);
4899 mkpFloat = createType(TY_FLOAT, NULL, NULL);
4900 mkpDouble = createType(TY_DOUBLE, NULL, NULL);
4901 mkpIntFn = createType(TY_FUNC, mkpInt, NULL);
4902 mkpIntPtr = createPtrType(mkpInt);
4903 mkpCharPtr = createPtrType(mkpChar);
4904 mkpFloatPtr = createPtrType(mkpFloat);
4905 mkpDoublePtr = createPtrType(mkpDouble);
4906 mkpPtrIntFn = createPtrType(mkpIntFn);
Jack Palevich86351982009-06-30 18:09:56 -07004907 }
4908
Jack Palevicha6baa232009-06-12 11:25:59 -07004909 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004910 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004911 }
4912
Jack Palevich569f1352009-06-29 14:29:08 -07004913 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004914 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004915 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004916 }
4917
Jack Palevich569f1352009-06-29 14:29:08 -07004918 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004919 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004920 error("Undefined forward reference: %s",
4921 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004922 }
4923 return true;
4924 }
4925
Jack Palevich21a15a22009-05-11 14:49:29 -07004926 int dump(FILE* out) {
4927 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4928 return 0;
4929 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004930
Jack Palevicha6535612009-05-13 16:24:17 -07004931 int disassemble(FILE* out) {
4932 return pGen->disassemble(out);
4933 }
4934
Jack Palevich1cdef202009-05-22 12:06:27 -07004935 /* Look through the symbol table to find a symbol.
4936 * If found, return its value.
4937 */
4938 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004939 if (mCompileResult == 0) {
4940 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4941 VariableInfo* pVariableInfo = VI(tok);
4942 if (pVariableInfo) {
4943 return pVariableInfo->pAddress;
4944 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004945 }
4946 return NULL;
4947 }
4948
Jack Palevicheedf9d22009-06-04 16:23:40 -07004949 void getPragmas(ACCsizei* actualStringCount,
4950 ACCsizei maxStringCount, ACCchar** strings) {
4951 int stringCount = mPragmaStringCount;
4952 if (actualStringCount) {
4953 *actualStringCount = stringCount;
4954 }
4955 if (stringCount > maxStringCount) {
4956 stringCount = maxStringCount;
4957 }
4958 if (strings) {
4959 char* pPragmas = mPragmas.getUnwrapped();
4960 while (stringCount-- > 0) {
4961 *strings++ = pPragmas;
4962 pPragmas += strlen(pPragmas) + 1;
4963 }
4964 }
4965 }
4966
Jack Palevichac0e95e2009-05-29 13:53:44 -07004967 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004968 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004969 }
4970
Jack Palevich77ae76e2009-05-10 19:59:24 -07004971};
4972
Jack Paleviche7b59062009-05-19 17:12:17 -07004973const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004974 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4975
Jack Paleviche7b59062009-05-19 17:12:17 -07004976const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004977 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4978 5, 5, /* ==, != */
4979 9, 10, /* &&, || */
4980 6, 7, 8, /* & ^ | */
4981 2, 2 /* ~ ! */
4982 };
4983
Jack Palevich8b0624c2009-05-20 12:12:06 -07004984#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004985FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004986#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004987
Jack Palevich8b0624c2009-05-20 12:12:06 -07004988#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004989const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004990 0x1, // ++
4991 0xff, // --
4992 0xc1af0f, // *
4993 0xf9f79991, // /
4994 0xf9f79991, // % (With manual assist to swap results)
4995 0xc801, // +
4996 0xd8f7c829, // -
4997 0xe0d391, // <<
4998 0xf8d391, // >>
4999 0xe, // <=
5000 0xd, // >=
5001 0xc, // <
5002 0xf, // >
5003 0x4, // ==
5004 0x5, // !=
5005 0x0, // &&
5006 0x1, // ||
5007 0xc821, // &
5008 0xc831, // ^
5009 0xc809, // |
5010 0xd0f7, // ~
5011 0x4 // !
5012};
Jack Palevich8b0624c2009-05-20 12:12:06 -07005013#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07005014
Jack Palevich1cdef202009-05-22 12:06:27 -07005015struct ACCscript {
5016 ACCscript() {
5017 text = 0;
5018 textLength = 0;
5019 accError = ACC_NO_ERROR;
5020 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005021
Jack Palevich1cdef202009-05-22 12:06:27 -07005022 ~ACCscript() {
5023 delete text;
5024 }
Jack Palevich546b2242009-05-13 15:10:04 -07005025
Jack Palevich8c246a92009-07-14 21:14:10 -07005026 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5027 compiler.registerSymbolCallback(pFn, pContext);
5028 }
5029
Jack Palevich1cdef202009-05-22 12:06:27 -07005030 void setError(ACCenum error) {
5031 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5032 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005033 }
5034 }
5035
Jack Palevich1cdef202009-05-22 12:06:27 -07005036 ACCenum getError() {
5037 ACCenum result = accError;
5038 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07005039 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005040 }
5041
Jack Palevich1cdef202009-05-22 12:06:27 -07005042 Compiler compiler;
5043 char* text;
5044 int textLength;
5045 ACCenum accError;
5046};
5047
5048
5049extern "C"
5050ACCscript* accCreateScript() {
5051 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07005052}
Jack Palevich1cdef202009-05-22 12:06:27 -07005053
5054extern "C"
5055ACCenum accGetError( ACCscript* script ) {
5056 return script->getError();
5057}
5058
5059extern "C"
5060void accDeleteScript(ACCscript* script) {
5061 delete script;
5062}
5063
5064extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07005065void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5066 ACCvoid* pContext) {
5067 script->registerSymbolCallback(pFn, pContext);
5068}
5069
5070extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07005071void accScriptSource(ACCscript* script,
5072 ACCsizei count,
5073 const ACCchar ** string,
5074 const ACCint * length) {
5075 int totalLength = 0;
5076 for(int i = 0; i < count; i++) {
5077 int len = -1;
5078 const ACCchar* s = string[i];
5079 if (length) {
5080 len = length[i];
5081 }
5082 if (len < 0) {
5083 len = strlen(s);
5084 }
5085 totalLength += len;
5086 }
5087 delete script->text;
5088 char* text = new char[totalLength + 1];
5089 script->text = text;
5090 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005091 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005092 for(int i = 0; i < count; i++) {
5093 int len = -1;
5094 const ACCchar* s = string[i];
5095 if (length) {
5096 len = length[i];
5097 }
5098 if (len < 0) {
5099 len = strlen(s);
5100 }
Jack Palevich09555c72009-05-27 12:25:55 -07005101 memcpy(dest, s, len);
5102 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005103 }
5104 text[totalLength] = '\0';
5105}
5106
5107extern "C"
5108void accCompileScript(ACCscript* script) {
5109 int result = script->compiler.compile(script->text, script->textLength);
5110 if (result) {
5111 script->setError(ACC_INVALID_OPERATION);
5112 }
5113}
5114
5115extern "C"
5116void accGetScriptiv(ACCscript* script,
5117 ACCenum pname,
5118 ACCint * params) {
5119 switch (pname) {
5120 case ACC_INFO_LOG_LENGTH:
5121 *params = 0;
5122 break;
5123 }
5124}
5125
5126extern "C"
5127void accGetScriptInfoLog(ACCscript* script,
5128 ACCsizei maxLength,
5129 ACCsizei * length,
5130 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005131 char* message = script->compiler.getErrorMessage();
5132 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005133 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005134 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005135 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005136 if (infoLog && maxLength > 0) {
5137 int trimmedLength = maxLength < messageLength ?
5138 maxLength : messageLength;
5139 memcpy(infoLog, message, trimmedLength);
5140 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005141 }
5142}
5143
5144extern "C"
5145void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5146 ACCvoid ** address) {
5147 void* value = script->compiler.lookup(name);
5148 if (value) {
5149 *address = value;
5150 } else {
5151 script->setError(ACC_INVALID_VALUE);
5152 }
5153}
5154
Jack Palevicheedf9d22009-06-04 16:23:40 -07005155extern "C"
5156void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5157 ACCsizei maxStringCount, ACCchar** strings){
5158 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5159}
5160
-b master422972c2009-06-17 19:13:52 -07005161extern "C"
5162void accDisassemble(ACCscript* script) {
5163 script->compiler.disassemble(stderr);
5164}
5165
Jack Palevicheedf9d22009-06-04 16:23:40 -07005166
Jack Palevich1cdef202009-05-22 12:06:27 -07005167} // namespace acc
5168