blob: 7ba30a9c310511061fa1a15f1d1763274fb625ad [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
51// #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 {
136 TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
137 TY_POINTER, TY_FUNC, TY_PARAM
138 };
139
140 struct Type {
141 TypeTag tag;
142 tokenid_t id; // For function arguments
143 Type* pHead;
144 Type* pTail;
145 };
Jack Palevich9eed7a22009-07-06 17:24:34 -0700146
Jack Palevich21a15a22009-05-11 14:49:29 -0700147 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -0700148 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -0700149 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700150 ErrorSink* mErrorSink;
151 int mSize;
Jack Palevich0a280a02009-06-11 10:53:51 -0700152 bool mOverflowed;
Jack Palevichf0cbc922009-05-08 16:35:13 -0700153
Jack Palevich21a15a22009-05-11 14:49:29 -0700154 void release() {
155 if (pProgramBase != 0) {
156 free(pProgramBase);
157 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -0700158 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700159 }
160
Jack Palevich0a280a02009-06-11 10:53:51 -0700161 bool check(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700162 int newSize = ind - pProgramBase + n;
Jack Palevich0a280a02009-06-11 10:53:51 -0700163 bool overflow = newSize > mSize;
164 if (overflow && !mOverflowed) {
165 mOverflowed = true;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700166 if (mErrorSink) {
167 mErrorSink->error("Code too large: %d bytes", newSize);
168 }
169 }
Jack Palevich0a280a02009-06-11 10:53:51 -0700170 return overflow;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700171 }
172
Jack Palevich21a15a22009-05-11 14:49:29 -0700173 public:
174 CodeBuf() {
175 pProgramBase = 0;
176 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700177 mErrorSink = 0;
178 mSize = 0;
Jack Palevich0a280a02009-06-11 10:53:51 -0700179 mOverflowed = false;
Jack Palevich21a15a22009-05-11 14:49:29 -0700180 }
181
182 ~CodeBuf() {
183 release();
184 }
185
186 void init(int size) {
187 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700188 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -0700189 pProgramBase = (char*) calloc(1, size);
190 ind = pProgramBase;
191 }
192
Jack Palevichac0e95e2009-05-29 13:53:44 -0700193 void setErrorSink(ErrorSink* pErrorSink) {
194 mErrorSink = pErrorSink;
195 }
196
Jack Palevich546b2242009-05-13 15:10:04 -0700197 int o4(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700198 if(check(4)) {
199 return 0;
200 }
Jack Palevich8b0624c2009-05-20 12:12:06 -0700201 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700202 * (int*) ind = n;
203 ind += 4;
204 return result;
205 }
206
Jack Palevich21a15a22009-05-11 14:49:29 -0700207 /*
208 * Output a byte. Handles all values, 0..ff.
209 */
210 void ob(int n) {
Jack Palevich0a280a02009-06-11 10:53:51 -0700211 if(check(1)) {
212 return;
213 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700214 *ind++ = n;
215 }
216
Jack Palevich21a15a22009-05-11 14:49:29 -0700217 inline void* getBase() {
218 return (void*) pProgramBase;
219 }
220
Jack Palevich8b0624c2009-05-20 12:12:06 -0700221 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700222 return ind - pProgramBase;
223 }
224
Jack Palevich8b0624c2009-05-20 12:12:06 -0700225 intptr_t getPC() {
226 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700227 }
228 };
229
Jack Palevich1cdef202009-05-22 12:06:27 -0700230 /**
231 * A code generator creates an in-memory program, generating the code on
232 * the fly. There is one code generator implementation for each supported
233 * architecture.
234 *
235 * The code generator implements the following abstract machine:
Jack Palevich9eed7a22009-07-06 17:24:34 -0700236 * R0 - the accumulator.
Jack Palevich1cdef202009-05-22 12:06:27 -0700237 * FP - a frame pointer for accessing function arguments and local
238 * variables.
239 * SP - a stack pointer for storing intermediate results while evaluating
240 * expressions. The stack pointer grows downwards.
241 *
242 * The function calling convention is that all arguments are placed on the
243 * stack such that the first argument has the lowest address.
244 * After the call, the result is in R0. The caller is responsible for
245 * removing the arguments from the stack.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700246 * The R0 register is not saved across function calls. The
Jack Palevich1cdef202009-05-22 12:06:27 -0700247 * FP and SP registers are saved.
248 */
249
Jack Palevich21a15a22009-05-11 14:49:29 -0700250 class CodeGenerator {
251 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700252 CodeGenerator() {
253 mErrorSink = 0;
254 pCodeBuf = 0;
Jack Palevich8df46192009-07-07 14:48:51 -0700255 pushType();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700256 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700257 virtual ~CodeGenerator() {}
258
Jack Palevich22305132009-05-13 10:58:45 -0700259 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700260 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700261 pCodeBuf->setErrorSink(mErrorSink);
262 }
263
Jack Palevichb67b18f2009-06-11 21:12:23 -0700264 virtual void setErrorSink(ErrorSink* pErrorSink) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700265 mErrorSink = pErrorSink;
266 if (pCodeBuf) {
267 pCodeBuf->setErrorSink(mErrorSink);
268 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700269 }
270
Jack Palevicha8f427f2009-07-13 18:40:08 -0700271 void setTypes(Type* pInt) {
272 mkpInt = pInt;
273 }
274
Jack Palevich1cdef202009-05-22 12:06:27 -0700275 /* Emit a function prolog.
Jack Palevichb7718b92009-07-09 22:00:24 -0700276 * pDecl is the function declaration, which gives the arguments.
Jack Palevich1cdef202009-05-22 12:06:27 -0700277 * Save the old value of the FP.
278 * Set the new value of the FP.
279 * Convert from the native platform calling convention to
280 * our stack-based calling convention. This may require
281 * pushing arguments from registers to the stack.
282 * Allocate "N" bytes of stack space. N isn't known yet, so
283 * just emit the instructions for adjusting the stack, and return
284 * the address to patch up. The patching will be done in
285 * functionExit().
286 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700287 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700288 virtual int functionEntry(Type* pDecl) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700289
Jack Palevich1cdef202009-05-22 12:06:27 -0700290 /* Emit a function epilog.
291 * Restore the old SP and FP register values.
292 * Return to the calling function.
293 * argCount - the number of arguments to the function.
294 * localVariableAddress - returned from functionEntry()
295 * localVariableSize - the size in bytes of the local variables.
296 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700297 virtual void functionExit(Type* pDecl, int localVariableAddress,
Jack Palevich1cdef202009-05-22 12:06:27 -0700298 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700299
Jack Palevich1cdef202009-05-22 12:06:27 -0700300 /* load immediate value to R0 */
Jack Palevich8df46192009-07-07 14:48:51 -0700301 virtual void li(int i, Type* pType) = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700302
Jack Palevich1a539db2009-07-08 13:04:41 -0700303 /* Load floating point value from global address. */
304 virtual void loadFloat(int address, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700305
Jack Palevich1cdef202009-05-22 12:06:27 -0700306 /* Jump to a target, and return the address of the word that
307 * holds the target data, in case it needs to be fixed up later.
308 */
Jack Palevich22305132009-05-13 10:58:45 -0700309 virtual int gjmp(int t) = 0;
310
Jack Palevich1cdef202009-05-22 12:06:27 -0700311 /* Test R0 and jump to a target if the test succeeds.
312 * l = 0: je, l == 1: jne
313 * Return the address of the word that holds the targed data, in
314 * case it needs to be fixed up later.
315 */
Jack Palevich22305132009-05-13 10:58:45 -0700316 virtual int gtst(bool l, int t) = 0;
317
Jack Palevich9eed7a22009-07-06 17:24:34 -0700318 /* Compare TOS against R0, and store the boolean result in R0.
319 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700320 * op specifies the comparison.
321 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700322 virtual void gcmp(int op, Type* pResultType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700323
Jack Palevich9eed7a22009-07-06 17:24:34 -0700324 /* Perform the arithmetic op specified by op. TOS is the
Jack Palevich1cdef202009-05-22 12:06:27 -0700325 * left argument, R0 is the right argument.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700326 * Pops TOS.
Jack Palevich1cdef202009-05-22 12:06:27 -0700327 */
Jack Palevich546b2242009-05-13 15:10:04 -0700328 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700329
Jack Palevich9eed7a22009-07-06 17:24:34 -0700330 /* Compare 0 against R0, and store the boolean result in R0.
331 * op specifies the comparison.
Jack Palevich1cdef202009-05-22 12:06:27 -0700332 */
Jack Palevicha39749f2009-07-08 20:40:31 -0700333 virtual void gUnaryCmp(int op, Type* pResultType) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700334
335 /* Perform the arithmetic op specified by op. 0 is the
336 * left argument, R0 is the right argument.
337 */
338 virtual void genUnaryOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700339
Jack Palevich1cdef202009-05-22 12:06:27 -0700340 /* Push R0 onto the stack.
341 */
342 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700343
Jack Palevich9eed7a22009-07-06 17:24:34 -0700344 /* Store R0 to the address stored in TOS.
345 * The TOS is popped.
346 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700347 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700348 virtual void storeR0ToTOS(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700349
Jack Palevich1cdef202009-05-22 12:06:27 -0700350 /* Load R0 from the address stored in R0.
Jack Palevich9eed7a22009-07-06 17:24:34 -0700351 * pPointerType is the type of the pointer (of the input R0).
Jack Palevich1cdef202009-05-22 12:06:27 -0700352 */
Jack Palevich9eed7a22009-07-06 17:24:34 -0700353 virtual void loadR0FromR0(Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700354
Jack Palevich1cdef202009-05-22 12:06:27 -0700355 /* Load the absolute address of a variable to R0.
356 * If ea <= LOCAL, then this is a local variable, or an
357 * argument, addressed relative to FP.
358 * else it is an absolute global address.
359 */
Jack Palevich8df46192009-07-07 14:48:51 -0700360 virtual void leaR0(int ea, Type* pPointerType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700361
Jack Palevich1cdef202009-05-22 12:06:27 -0700362 /* Store R0 to a variable.
363 * If ea <= LOCAL, then this is a local variable, or an
364 * argument, addressed relative to FP.
365 * else it is an absolute global address.
366 */
Jack Palevich9cbd2262009-07-08 16:48:41 -0700367 virtual void storeR0(int ea, Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700368
Jack Palevich1cdef202009-05-22 12:06:27 -0700369 /* load R0 from a variable.
370 * If ea <= LOCAL, then this is a local variable, or an
371 * argument, addressed relative to FP.
372 * else it is an absolute global address.
373 * If isIncDec is true, then the stored variable's value
374 * should be post-incremented or post-decremented, based
375 * on the value of op.
376 */
Jack Palevich8df46192009-07-07 14:48:51 -0700377 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) = 0;
378
379 /**
380 * Convert R0 to the given type.
381 */
382 virtual void convertR0(Type* pType) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700383
Jack Palevich1cdef202009-05-22 12:06:27 -0700384 /* Emit code to adjust the stack for a function call. Return the
385 * label for the address of the instruction that adjusts the
386 * stack size. This will be passed as argument "a" to
387 * endFunctionCallArguments.
388 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700389 virtual int beginFunctionCallArguments() = 0;
390
Jack Palevich1cdef202009-05-22 12:06:27 -0700391 /* Emit code to store R0 to the stack at byte offset l.
Jack Palevich1a539db2009-07-08 13:04:41 -0700392 * Returns stack size of object (typically 4 or 8 bytes)
Jack Palevich1cdef202009-05-22 12:06:27 -0700393 */
Jack Palevich1a539db2009-07-08 13:04:41 -0700394 virtual size_t storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700395
Jack Palevich1cdef202009-05-22 12:06:27 -0700396 /* Patch the function call preamble.
397 * a is the address returned from beginFunctionCallArguments
398 * l is the number of bytes the arguments took on the stack.
399 * Typically you would also emit code to convert the argument
400 * list into whatever the native function calling convention is.
401 * On ARM for example you would pop the first 5 arguments into
402 * R0..R4
403 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700404 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700405
Jack Palevich1cdef202009-05-22 12:06:27 -0700406 /* Emit a call to an unknown function. The argument "symbol" needs to
407 * be stored in the location where the address should go. It forms
408 * a chain. The address will be patched later.
409 * Return the address of the word that has to be patched.
410 */
Jack Palevich8df46192009-07-07 14:48:51 -0700411 virtual int callForward(int symbol, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700412
Jack Palevich1cdef202009-05-22 12:06:27 -0700413 /* Call a function using PC-relative addressing. t is the PC-relative
414 * address of the function. It has already been adjusted for the
415 * architectural jump offset, so just store it as-is.
416 */
Jack Palevich8df46192009-07-07 14:48:51 -0700417 virtual void callRelative(int t, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700418
Jack Palevich1cdef202009-05-22 12:06:27 -0700419 /* Call a function pointer. L is the number of bytes the arguments
420 * take on the stack. The address of the function is stored at
421 * location SP + l.
422 */
Jack Palevich8df46192009-07-07 14:48:51 -0700423 virtual void callIndirect(int l, Type* pFunc) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700424
Jack Palevich1cdef202009-05-22 12:06:27 -0700425 /* Adjust SP after returning from a function call. l is the
426 * number of bytes of arguments stored on the stack. isIndirect
427 * is true if this was an indirect call. (In which case the
428 * address of the function is stored at location SP + l.)
429 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700430 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700431
Jack Palevich1cdef202009-05-22 12:06:27 -0700432 /* Print a disassembly of the assembled code to out. Return
433 * non-zero if there is an error.
434 */
Jack Palevicha6535612009-05-13 16:24:17 -0700435 virtual int disassemble(FILE* out) = 0;
436
Jack Palevich1cdef202009-05-22 12:06:27 -0700437 /* Generate a symbol at the current PC. t is the head of a
438 * linked list of addresses to patch.
439 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700440 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700441
Jack Palevich1cdef202009-05-22 12:06:27 -0700442 /*
443 * Do any cleanup work required at the end of a compile.
444 * For example, an instruction cache might need to be
445 * invalidated.
446 * Return non-zero if there is an error.
447 */
448 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700449
Jack Palevicha6535612009-05-13 16:24:17 -0700450 /**
451 * Adjust relative branches by this amount.
452 */
453 virtual int jumpOffset() = 0;
454
Jack Palevich9eed7a22009-07-06 17:24:34 -0700455 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -0700456 * Memory alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -0700457 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700458 virtual size_t alignmentOf(Type* type) = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700459
460 /**
461 * Array element alignment (in bytes) for this type of data.
462 */
463 virtual size_t sizeOf(Type* type) = 0;
464
Jack Palevich9cbd2262009-07-08 16:48:41 -0700465 /**
466 * Stack argument size of this data type.
467 */
468 virtual size_t stackSizeOf(Type* pType) = 0;
469
Jack Palevich1a539db2009-07-08 13:04:41 -0700470 virtual Type* getR0Type() {
471 return mExpressionStack.back();
472 }
473
Jack Palevich21a15a22009-05-11 14:49:29 -0700474 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700475 /*
476 * Output a byte. Handles all values, 0..ff.
477 */
478 void ob(int n) {
479 pCodeBuf->ob(n);
480 }
481
Jack Palevich8b0624c2009-05-20 12:12:06 -0700482 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700483 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700484 }
485
Jack Palevich8b0624c2009-05-20 12:12:06 -0700486 intptr_t getBase() {
487 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700488 }
489
Jack Palevich8b0624c2009-05-20 12:12:06 -0700490 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700491 return pCodeBuf->getPC();
492 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700493
494 intptr_t getSize() {
495 return pCodeBuf->getSize();
496 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700497
498 void error(const char* fmt,...) {
499 va_list ap;
500 va_start(ap, fmt);
501 mErrorSink->verror(fmt, ap);
502 va_end(ap);
503 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700504
505 void assert(bool test) {
506 if (!test) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700507 * (char*) 0 = 0;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700508 error("code generator assertion failed.");
509 }
510 }
Jack Palevich8df46192009-07-07 14:48:51 -0700511
512 void setR0Type(Type* pType) {
513 mExpressionStack.back() = pType;
514 }
515
Jack Palevich8df46192009-07-07 14:48:51 -0700516 Type* getTOSType() {
517 return mExpressionStack[mExpressionStack.size()-2];
518 }
519
520 void pushType() {
521 mExpressionStack.push_back(NULL);
522 }
523
524 void popType() {
525 mExpressionStack.pop_back();
526 }
527
528 bool bitsSame(Type* pA, Type* pB) {
529 return collapseType(pA->tag) == collapseType(pB->tag);
530 }
531
532 TypeTag collapseType(TypeTag tag) {
533 static const TypeTag collapsedTag[] = {
534 TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT,
535 TY_VOID, TY_VOID};
536 return collapsedTag[tag];
537 }
538
Jack Palevich1a539db2009-07-08 13:04:41 -0700539 TypeTag collapseTypeR0() {
540 return collapseType(getR0Type()->tag);
541 }
542
543 bool isFloatType(Type* pType) {
Jack Palevich128ad2d2009-07-08 14:51:31 -0700544 return isFloatTag(pType->tag);
545 }
546
547 bool isFloatTag(TypeTag tag) {
Jack Palevich1a539db2009-07-08 13:04:41 -0700548 return tag == TY_FLOAT || tag == TY_DOUBLE;
549 }
550
Jack Palevicha8f427f2009-07-13 18:40:08 -0700551 Type* mkpInt;
552
Jack Palevich21a15a22009-05-11 14:49:29 -0700553 private:
Jack Palevich8df46192009-07-07 14:48:51 -0700554 Vector<Type*> mExpressionStack;
Jack Palevich21a15a22009-05-11 14:49:29 -0700555 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700556 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700557 };
558
Jack Paleviche7b59062009-05-19 17:12:17 -0700559#ifdef PROVIDE_ARM_CODEGEN
560
Jack Palevich22305132009-05-13 10:58:45 -0700561 class ARMCodeGenerator : public CodeGenerator {
562 public:
563 ARMCodeGenerator() {}
-b master422972c2009-06-17 19:13:52 -0700564
Jack Palevich22305132009-05-13 10:58:45 -0700565 virtual ~ARMCodeGenerator() {}
566
567 /* returns address to patch with local variable size
568 */
Jack Palevichb7718b92009-07-09 22:00:24 -0700569 virtual int functionEntry(Type* pDecl) {
570 LOG_API("functionEntry(%d);\n", pDecl);
-b master422972c2009-06-17 19:13:52 -0700571 mStackUse = 0;
Jack Palevich69796b62009-05-14 15:42:26 -0700572 // sp -> arg4 arg5 ...
573 // Push our register-based arguments back on the stack
Jack Palevichb7718b92009-07-09 22:00:24 -0700574 int regArgCount = calcRegArgCount(pDecl);
575 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -0700576 mStackUse += regArgCount * 4;
Jack Palevichb7718b92009-07-09 22:00:24 -0700577 o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {}
Jack Palevich69796b62009-05-14 15:42:26 -0700578 }
579 // sp -> arg0 arg1 ...
580 o4(0xE92D4800); // stmfd sp!, {fp, lr}
-b master422972c2009-06-17 19:13:52 -0700581 mStackUse += 2 * 4;
Jack Palevich69796b62009-05-14 15:42:26 -0700582 // sp, fp -> oldfp, retadr, arg0 arg1 ....
583 o4(0xE1A0B00D); // mov fp, sp
-b master422972c2009-06-17 19:13:52 -0700584 LOG_STACK("functionEntry: %d\n", mStackUse);
Jack Palevich69796b62009-05-14 15:42:26 -0700585 return o4(0xE24DD000); // sub sp, sp, # <local variables>
-b master422972c2009-06-17 19:13:52 -0700586 // We don't know how many local variables we are going to use,
587 // but we will round the allocation up to a multiple of
588 // STACK_ALIGNMENT, so it won't affect the stack alignment.
Jack Palevich22305132009-05-13 10:58:45 -0700589 }
590
Jack Palevichb7718b92009-07-09 22:00:24 -0700591 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700592 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
-b master422972c2009-06-17 19:13:52 -0700593 // Round local variable size up to a multiple of stack alignment
594 localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
595 STACK_ALIGNMENT) * STACK_ALIGNMENT;
Jack Palevich69796b62009-05-14 15:42:26 -0700596 // Patch local variable allocation code:
597 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700598 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700599 }
Jack Palevich69796b62009-05-14 15:42:26 -0700600 *(char*) (localVariableAddress) = localVariableSize;
601
602 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
603 o4(0xE1A0E00B); // mov lr, fp
604 o4(0xE59BB000); // ldr fp, [fp]
605 o4(0xE28ED004); // add sp, lr, #4
606 // sp -> retadr, arg0, ...
607 o4(0xE8BD4000); // ldmfd sp!, {lr}
608 // sp -> arg0 ....
Jack Palevichb7718b92009-07-09 22:00:24 -0700609
610 // We store the PC into the lr so we can adjust the sp before
611 // returning. We need to pull off the registers we pushed
612 // earlier. We don't need to actually store them anywhere,
613 // just adjust the stack.
614 int regArgCount = calcRegArgCount(pDecl);
615 if (regArgCount) {
Jack Palevich69796b62009-05-14 15:42:26 -0700616 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
617 }
618 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700619 }
620
621 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -0700622 virtual void li(int t, Type* pType) {
Jack Palevicha8f427f2009-07-13 18:40:08 -0700623 liReg(t, 0);
Jack Palevich8df46192009-07-07 14:48:51 -0700624 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -0700625 }
626
Jack Palevich1a539db2009-07-08 13:04:41 -0700627 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -0700628 setR0Type(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -0700629 // Global, absolute address
630 o4(0xE59F0000); // ldr r0, .L1
631 o4(0xEA000000); // b .L99
632 o4(address); // .L1: .word ea
633 // .L99:
634
635 switch (pType->tag) {
636 case TY_FLOAT:
637 o4(0xE5900000); // ldr r0, [r0]
638 break;
639 case TY_DOUBLE:
640 o4(0xE1C000D0); // ldrd r0, [r0]
641 break;
642 default:
643 assert(false);
644 break;
645 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -0700646 }
647
Jack Palevich22305132009-05-13 10:58:45 -0700648 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700649 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700650 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700651 }
652
653 /* l = 0: je, l == 1: jne */
654 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700655 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevichb7718b92009-07-09 22:00:24 -0700656 Type* pR0Type = getR0Type();
657 TypeTag tagR0 = pR0Type->tag;
658 switch(tagR0) {
659 case TY_FLOAT:
660 callRuntime((void*) runtime_is_non_zero_f);
661 break;
662 case TY_DOUBLE:
663 callRuntime((void*) runtime_is_non_zero_d);
664 break;
665 default:
666 break;
667 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700668 o4(0xE3500000); // cmp r0,#0
669 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
670 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700671 }
672
Jack Palevicha39749f2009-07-08 20:40:31 -0700673 virtual void gcmp(int op, Type* pResultType) {
Jack Palevich09555c72009-05-27 12:25:55 -0700674 LOG_API("gcmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700675 Type* pR0Type = getR0Type();
676 Type* pTOSType = getTOSType();
677 TypeTag tagR0 = collapseType(pR0Type->tag);
678 TypeTag tagTOS = collapseType(pTOSType->tag);
679 if (tagR0 == TY_INT && tagTOS == TY_INT) {
680 o4(0xE8BD0002); // ldmfd sp!,{r1}
681 mStackUse -= 4;
682 o4(0xE1510000); // cmp r1, r1
683 switch(op) {
684 case OP_EQUALS:
685 o4(0x03A00001); // moveq r0,#1
686 o4(0x13A00000); // movne r0,#0
687 break;
688 case OP_NOT_EQUALS:
689 o4(0x03A00000); // moveq r0,#0
690 o4(0x13A00001); // movne r0,#1
691 break;
692 case OP_LESS_EQUAL:
693 o4(0xD3A00001); // movle r0,#1
694 o4(0xC3A00000); // movgt r0,#0
695 break;
696 case OP_GREATER:
697 o4(0xD3A00000); // movle r0,#0
698 o4(0xC3A00001); // movgt r0,#1
699 break;
700 case OP_GREATER_EQUAL:
701 o4(0xA3A00001); // movge r0,#1
702 o4(0xB3A00000); // movlt r0,#0
703 break;
704 case OP_LESS:
705 o4(0xA3A00000); // movge r0,#0
706 o4(0xB3A00001); // movlt r0,#1
707 break;
708 default:
709 error("Unknown comparison op %d", op);
710 break;
711 }
712 popType();
713 } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
714 setupDoubleArgs();
715 switch(op) {
716 case OP_EQUALS:
717 callRuntime((void*) runtime_cmp_eq_dd);
718 break;
719 case OP_NOT_EQUALS:
720 callRuntime((void*) runtime_cmp_ne_dd);
721 break;
722 case OP_LESS_EQUAL:
723 callRuntime((void*) runtime_cmp_le_dd);
724 break;
725 case OP_GREATER:
726 callRuntime((void*) runtime_cmp_gt_dd);
727 break;
728 case OP_GREATER_EQUAL:
729 callRuntime((void*) runtime_cmp_ge_dd);
730 break;
731 case OP_LESS:
732 callRuntime((void*) runtime_cmp_lt_dd);
733 break;
734 default:
735 error("Unknown comparison op %d", op);
736 break;
737 }
738 } else {
739 setupFloatArgs();
740 switch(op) {
741 case OP_EQUALS:
742 callRuntime((void*) runtime_cmp_eq_ff);
743 break;
744 case OP_NOT_EQUALS:
745 callRuntime((void*) runtime_cmp_ne_ff);
746 break;
747 case OP_LESS_EQUAL:
748 callRuntime((void*) runtime_cmp_le_ff);
749 break;
750 case OP_GREATER:
751 callRuntime((void*) runtime_cmp_gt_ff);
752 break;
753 case OP_GREATER_EQUAL:
754 callRuntime((void*) runtime_cmp_ge_ff);
755 break;
756 case OP_LESS:
757 callRuntime((void*) runtime_cmp_lt_ff);
758 break;
759 default:
760 error("Unknown comparison op %d", op);
761 break;
762 }
Jack Palevich8de461d2009-05-14 17:21:45 -0700763 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700764 setR0Type(pResultType);
Jack Palevich22305132009-05-13 10:58:45 -0700765 }
766
Jack Palevich546b2242009-05-13 15:10:04 -0700767 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700768 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700769 Type* pR0Type = getR0Type();
770 Type* pTOSType = getTOSType();
Jack Palevicha8f427f2009-07-13 18:40:08 -0700771 TypeTag tagR0 = pR0Type->tag;
772 TypeTag tagTOS = pTOSType->tag;
773 bool isFloatR0 = isFloatTag(tagR0);
774 bool isFloatTOS = isFloatTag(tagTOS);
775 if (!isFloatR0 && !isFloatTOS) {
776 bool isPtrR0 = tagR0 == TY_POINTER;
777 bool isPtrTOS = tagTOS == TY_POINTER;
778 if (isPtrR0 || isPtrTOS) {
779 if (isPtrR0 && isPtrTOS) {
780 if (op != OP_MINUS) {
781 error("Unsupported pointer-pointer operation %d.", op);
782 }
783 if (! typeEqual(pR0Type, pTOSType)) {
784 error("Incompatible pointer types for subtraction.");
785 }
786 o4(0xE8BD0002); // ldmfd sp!,{r1}
787 o4(0xE0410000); // sub r0,r1,r0
788 popType();
789 setR0Type(mkpInt);
790 int size = sizeOf(pR0Type->pHead);
791 if (size != 1) {
792 pushR0();
793 li(size, mkpInt);
794 // TODO: Optimize for power-of-two.
795 genOp(OP_DIV);
796 }
797 } else {
798 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
799 error("Unsupported pointer-scalar operation %d", op);
800 }
801 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
802 o4(0xE8BD0002); // ldmfd sp!,{r1}
803 int size = sizeOf(pPtrType->pHead);
804 if (size != 1) {
805 // TODO: Optimize for power-of-two.
806 liReg(size, 2);
807 if (isPtrR0) {
808 o4(0x0E0010192); // mul r1,r2,r1
809 } else {
810 o4(0x0E0000092); // mul r0,r2,r0
811 }
812 }
813 switch(op) {
814 case OP_PLUS:
815 o4(0xE0810000); // add r0,r1,r0
816 break;
817 case OP_MINUS:
818 o4(0xE0410000); // sub r0,r1,r0
819 break;
820 }
821 popType();
822 setR0Type(pPtrType);
823 }
824 } else {
825 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevichb7718b92009-07-09 22:00:24 -0700826 mStackUse -= 4;
Jack Palevicha8f427f2009-07-13 18:40:08 -0700827 switch(op) {
828 case OP_MUL:
829 o4(0x0E0000091); // mul r0,r1,r0
830 break;
831 case OP_DIV:
832 callRuntime((void*) runtime_DIV);
833 break;
834 case OP_MOD:
835 callRuntime((void*) runtime_MOD);
836 break;
837 case OP_PLUS:
838 o4(0xE0810000); // add r0,r1,r0
839 break;
840 case OP_MINUS:
841 o4(0xE0410000); // sub r0,r1,r0
842 break;
843 case OP_SHIFT_LEFT:
844 o4(0xE1A00011); // lsl r0,r1,r0
845 break;
846 case OP_SHIFT_RIGHT:
847 o4(0xE1A00051); // asr r0,r1,r0
848 break;
849 case OP_BIT_AND:
850 o4(0xE0010000); // and r0,r1,r0
851 break;
852 case OP_BIT_XOR:
853 o4(0xE0210000); // eor r0,r1,r0
854 break;
855 case OP_BIT_OR:
856 o4(0xE1810000); // orr r0,r1,r0
857 break;
858 case OP_BIT_NOT:
859 o4(0xE1E00000); // mvn r0, r0
860 break;
861 default:
862 error("Unimplemented op %d\n", op);
863 break;
864 }
865 popType();
Jack Palevichb7718b92009-07-09 22:00:24 -0700866 }
Jack Palevichb7718b92009-07-09 22:00:24 -0700867 } else {
868 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
869 if (pResultType->tag == TY_DOUBLE) {
870 setupDoubleArgs();
871 switch(op) {
872 case OP_MUL:
873 callRuntime((void*) runtime_op_mul_dd);
874 break;
875 case OP_DIV:
876 callRuntime((void*) runtime_op_div_dd);
877 break;
878 case OP_PLUS:
879 callRuntime((void*) runtime_op_add_dd);
880 break;
881 case OP_MINUS:
882 callRuntime((void*) runtime_op_sub_dd);
883 break;
884 default:
885 error("Unsupported binary floating operation %d\n", op);
886 break;
887 }
888 } else {
889 setupFloatArgs();
890 switch(op) {
891 case OP_MUL:
892 callRuntime((void*) runtime_op_mul_ff);
893 break;
894 case OP_DIV:
895 callRuntime((void*) runtime_op_div_ff);
896 break;
897 case OP_PLUS:
898 callRuntime((void*) runtime_op_add_ff);
899 break;
900 case OP_MINUS:
901 callRuntime((void*) runtime_op_sub_ff);
902 break;
903 default:
904 error("Unsupported binary floating operation %d\n", op);
905 break;
906 }
907 }
908 setR0Type(pResultType);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700909 }
Jack Palevich22305132009-05-13 10:58:45 -0700910 }
911
Jack Palevicha39749f2009-07-08 20:40:31 -0700912 virtual void gUnaryCmp(int op, Type* pResultType) {
913 LOG_API("gUnaryCmp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700914 if (op != OP_LOGICAL_NOT) {
915 error("Unknown unary cmp %d", op);
916 } else {
917 Type* pR0Type = getR0Type();
918 TypeTag tag = collapseType(pR0Type->tag);
919 switch(tag) {
920 case TY_INT:
921 o4(0xE3A01000); // mov r1, #0
Jack Palevicha8f427f2009-07-13 18:40:08 -0700922 o4(0xE1510000); // cmp r1, r0
923 o4(0x03A00001); // moveq r0,#1
924 o4(0x13A00000); // movne r0,#0
Jack Palevichb7718b92009-07-09 22:00:24 -0700925 break;
926 case TY_FLOAT:
927 callRuntime((void*) runtime_is_zero_f);
928 break;
929 case TY_DOUBLE:
930 callRuntime((void*) runtime_is_zero_d);
931 break;
932 default:
933 error("gUnaryCmp unsupported type");
934 break;
935 }
Jack Palevich9eed7a22009-07-06 17:24:34 -0700936 }
Jack Palevicha39749f2009-07-08 20:40:31 -0700937 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -0700938 }
939
940 virtual void genUnaryOp(int op) {
941 LOG_API("genOp(%d);\n", op);
Jack Palevichb7718b92009-07-09 22:00:24 -0700942 Type* pR0Type = getR0Type();
943 TypeTag tag = collapseType(pR0Type->tag);
944 switch(tag) {
945 case TY_INT:
946 switch(op) {
947 case OP_MINUS:
948 o4(0xE3A01000); // mov r1, #0
949 o4(0xE0410000); // sub r0,r1,r0
950 break;
951 case OP_BIT_NOT:
952 o4(0xE1E00000); // mvn r0, r0
953 break;
954 default:
955 error("Unknown unary op %d\n", op);
956 break;
957 }
958 break;
959 case TY_FLOAT:
960 case TY_DOUBLE:
961 switch (op) {
962 case OP_MINUS:
963 if (tag == TY_FLOAT) {
964 callRuntime((void*) runtime_op_neg_f);
965 } else {
966 callRuntime((void*) runtime_op_neg_d);
967 }
968 break;
969 case OP_BIT_NOT:
970 error("Can't apply '~' operator to a float or double.");
971 break;
972 default:
973 error("Unknown unary op %d\n", op);
974 break;
975 }
976 break;
977 default:
978 error("genUnaryOp unsupported type");
979 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -0700980 }
Jack Palevich22305132009-05-13 10:58:45 -0700981 }
982
Jack Palevich1cdef202009-05-22 12:06:27 -0700983 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700984 LOG_API("pushR0();\n");
Jack Palevichb7718b92009-07-09 22:00:24 -0700985 Type* pR0Type = getR0Type();
986 TypeTag r0ct = collapseType(pR0Type->tag);
987 if (r0ct != TY_DOUBLE) {
988 o4(0xE92D0001); // stmfd sp!,{r0}
989 mStackUse += 4;
990 } else {
991 o4(0xE92D0003); // stmfd sp!,{r0,r1}
992 mStackUse += 8;
993 }
Jack Palevich8df46192009-07-07 14:48:51 -0700994 pushType();
-b master422972c2009-06-17 19:13:52 -0700995 LOG_STACK("pushR0: %d\n", mStackUse);
Jack Palevich22305132009-05-13 10:58:45 -0700996 }
997
Jack Palevich9eed7a22009-07-06 17:24:34 -0700998 virtual void storeR0ToTOS(Type* pPointerType) {
999 LOG_API("storeR0ToTOS(%d);\n", isInt);
1000 assert(pPointerType->tag == TY_POINTER);
Jack Palevichb7718b92009-07-09 22:00:24 -07001001 o4(0xE8BD0004); // ldmfd sp!,{r2}
1002 popType();
-b master422972c2009-06-17 19:13:52 -07001003 mStackUse -= 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001004 switch (pPointerType->pHead->tag) {
1005 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001006 case TY_FLOAT:
1007 o4(0xE5820000); // str r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001008 break;
1009 case TY_CHAR:
Jack Palevichb7718b92009-07-09 22:00:24 -07001010 o4(0xE5C20000); // strb r0, [r2]
1011 break;
1012 case TY_DOUBLE:
1013 o4(0xE1C200F0); // strd r0, [r2]
Jack Palevich9eed7a22009-07-06 17:24:34 -07001014 break;
1015 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001016 error("storeR0ToTOS: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001017 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001018 }
Jack Palevich22305132009-05-13 10:58:45 -07001019 }
1020
Jack Palevich9eed7a22009-07-06 17:24:34 -07001021 virtual void loadR0FromR0(Type* pPointerType) {
1022 LOG_API("loadR0FromR0(%d);\n", pPointerType);
1023 assert(pPointerType->tag == TY_POINTER);
1024 switch (pPointerType->pHead->tag) {
1025 case TY_INT:
Jack Palevichb7718b92009-07-09 22:00:24 -07001026 case TY_FLOAT:
Jack Palevich9eed7a22009-07-06 17:24:34 -07001027 o4(0xE5900000); // ldr r0, [r0]
1028 break;
1029 case TY_CHAR:
1030 o4(0xE5D00000); // ldrb r0, [r0]
1031 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001032 case TY_DOUBLE:
1033 o4(0xE1C000D0); // ldrd r0, [r0]
1034 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07001035 default:
Jack Palevich8df46192009-07-07 14:48:51 -07001036 error("loadR0FromR0: unimplemented type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07001037 break;
1038 }
Jack Palevich8df46192009-07-07 14:48:51 -07001039 setR0Type(pPointerType->pHead);
Jack Palevich22305132009-05-13 10:58:45 -07001040 }
1041
Jack Palevich8df46192009-07-07 14:48:51 -07001042 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001043 LOG_API("leaR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001044 if (ea > -LOCAL && ea < LOCAL) {
Jack Palevich4d93f302009-05-15 13:30:00 -07001045 // Local, fp relative
1046 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
1047 error("Offset out of range: %08x", ea);
1048 }
1049 if (ea < 0) {
1050 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
1051 } else {
1052 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
1053 }
Jack Palevichbd894902009-05-14 19:35:31 -07001054 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -07001055 // Global, absolute.
1056 o4(0xE59F0000); // ldr r0, .L1
1057 o4(0xEA000000); // b .L99
1058 o4(ea); // .L1: .word 0
1059 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -07001060 }
Jack Palevich8df46192009-07-07 14:48:51 -07001061 setR0Type(pPointerType);
Jack Palevich22305132009-05-13 10:58:45 -07001062 }
1063
Jack Palevich9cbd2262009-07-08 16:48:41 -07001064 virtual void storeR0(int ea, Type* pType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001065 LOG_API("storeR0(%d);\n", ea);
Jack Palevichb7718b92009-07-09 22:00:24 -07001066 TypeTag tag = pType->tag;
1067 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001068 case TY_CHAR:
1069 if (ea > -LOCAL && ea < LOCAL) {
1070 // Local, fp relative
1071 if (ea < -4095 || ea > 4095) {
1072 error("Offset out of range: %08x", ea);
1073 }
1074 if (ea < 0) {
1075 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1076 } else {
1077 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1078 }
1079 } else{
1080 // Global, absolute
1081 o4(0xE59F1000); // ldr r1, .L1
1082 o4(0xEA000000); // b .L99
1083 o4(ea); // .L1: .word 0
1084 o4(0xE5C10000); // .L99: strb r0, [r1]
1085 }
1086 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001087 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001088 case TY_INT:
1089 case TY_FLOAT:
1090 if (ea > -LOCAL && ea < LOCAL) {
1091 // Local, fp relative
1092 if (ea < -4095 || ea > 4095) {
1093 error("Offset out of range: %08x", ea);
1094 }
1095 if (ea < 0) {
1096 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1097 } else {
1098 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1099 }
1100 } else{
1101 // Global, absolute
1102 o4(0xE59F1000); // ldr r1, .L1
1103 o4(0xEA000000); // b .L99
1104 o4(ea); // .L1: .word 0
1105 o4(0xE5810000); // .L99: str r0, [r1]
1106 }
1107 break;
1108 case TY_DOUBLE:
1109 if ((ea & 0x7) != 0) {
1110 error("double address is not aligned: %d", ea);
1111 }
1112 if (ea > -LOCAL && ea < LOCAL) {
1113 // Local, fp relative
1114 if (ea < -4095 || ea > 4095) {
1115 error("Offset out of range: %08x", ea);
1116 }
1117 if (ea < 0) {
1118 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1119 o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4]
1120#if 0
1121 // strd doesn't seem to work. Is encoding wrong?
1122 } else if (ea < 0) {
1123 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1124 } else if (ea < 256) {
1125 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1126#endif
1127 } else {
1128 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1129 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1130 }
1131 } else{
1132 // Global, absolute
1133 o4(0xE59F2000); // ldr r2, .L1
1134 o4(0xEA000000); // b .L99
1135 o4(ea); // .L1: .word 0
1136 o4(0xE1C200F0); // .L99: strd r0, [r2]
1137 }
1138 break;
1139 default:
1140 error("Unable to store to type %d", tag);
1141 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001142 }
Jack Palevich22305132009-05-13 10:58:45 -07001143 }
1144
Jack Palevich8df46192009-07-07 14:48:51 -07001145 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001146 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich25c0cca2009-07-13 16:56:28 -07001147 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001148 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001149 case TY_CHAR:
1150 if (ea < LOCAL) {
1151 // Local, fp relative
1152 if (ea < -4095 || ea > 4095) {
1153 error("Offset out of range: %08x", ea);
1154 }
1155 if (ea < 0) {
1156 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1157 } else {
1158 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1159 }
1160 } else {
1161 // Global, absolute
1162 o4(0xE59F2000); // ldr r2, .L1
1163 o4(0xEA000000); // b .L99
1164 o4(ea); // .L1: .word ea
1165 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1166 }
1167
1168 if (isIncDec) {
1169 error("inc/dec not implemented for char.");
1170 }
1171 break;
1172 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001173 case TY_INT:
1174 case TY_FLOAT:
1175 if (ea < LOCAL) {
1176 // Local, fp relative
1177 if (ea < -4095 || ea > 4095) {
1178 error("Offset out of range: %08x", ea);
1179 }
1180 if (ea < 0) {
1181 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1182 } else {
1183 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1184 }
1185 } else {
1186 // Global, absolute
1187 o4(0xE59F2000); // ldr r2, .L1
1188 o4(0xEA000000); // b .L99
1189 o4(ea); // .L1: .word ea
1190 o4(0xE5920000); // .L99: ldr r0, [r2]
1191 }
Jack Palevich22305132009-05-13 10:58:45 -07001192
Jack Palevichb7718b92009-07-09 22:00:24 -07001193 if (isIncDec) {
1194 if (tag == TY_INT) {
1195 switch (op) {
1196 case OP_INCREMENT:
1197 o4(0xE2801001); // add r1, r0, #1
1198 break;
1199 case OP_DECREMENT:
1200 o4(0xE2401001); // sub r1, r0, #1
1201 break;
1202 default:
1203 error("unknown opcode: %d", op);
1204 }
1205 if (ea < LOCAL) {
1206 // Local, fp relative
1207 // Don't need range check, was already checked above
1208 if (ea < 0) {
1209 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1210 } else {
1211 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1212 }
1213 } else{
1214 // Global, absolute
1215 // r2 is already set up from before.
1216 o4(0xE5821000); // str r1, [r2]
1217 }
1218 }
1219 else {
1220 error("inc/dec not implemented for float.");
1221 }
1222 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001223 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001224 case TY_DOUBLE:
1225 if ((ea & 0x7) != 0) {
1226 error("double address is not aligned: %d", ea);
1227 }
1228 if (ea < LOCAL) {
1229 // Local, fp relative
1230 if (ea < -4095 || ea > 4095) {
1231 error("Offset out of range: %08x", ea);
1232 }
1233 if (ea < 0) {
1234 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1235 o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4]
1236 } else {
1237 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1238 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1239 }
1240 } else {
1241 // Global, absolute
1242 o4(0xE59F2000); // ldr r2, .L1
1243 o4(0xEA000000); // b .L99
1244 o4(ea); // .L1: .word ea
1245 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1246 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001247 break;
1248 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001249 error("Unable to load type %d", tag);
1250 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001251 }
Jack Palevich8df46192009-07-07 14:48:51 -07001252 setR0Type(pType);
1253 }
1254
1255 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001256 Type* pR0Type = getR0Type();
1257 if (bitsSame(pType, pR0Type)) {
1258 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001259 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001260 TypeTag r0Tag = collapseType(pR0Type->tag);
1261 TypeTag destTag = collapseType(pType->tag);
1262 if (r0Tag == TY_INT) {
1263 if (destTag == TY_FLOAT) {
1264 callRuntime((void*) runtime_int_to_float);
1265 } else {
1266 assert(destTag == TY_DOUBLE);
1267 callRuntime((void*) runtime_int_to_double);
1268 }
1269 } else if (r0Tag == TY_FLOAT) {
1270 if (destTag == TY_INT) {
1271 callRuntime((void*) runtime_float_to_int);
1272 } else {
1273 assert(destTag == TY_DOUBLE);
1274 callRuntime((void*) runtime_float_to_double);
1275 }
1276 } else {
1277 assert (r0Tag == TY_DOUBLE);
1278 if (destTag == TY_INT) {
1279 callRuntime((void*) runtime_double_to_int);
1280 } else {
1281 assert(destTag == TY_FLOAT);
1282 callRuntime((void*) runtime_double_to_float);
1283 }
1284 }
Jack Palevich8df46192009-07-07 14:48:51 -07001285 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001286 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001287 }
1288
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001289 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001290 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001291 return o4(0xE24DDF00); // Placeholder
1292 }
1293
Jack Palevich1a539db2009-07-08 13:04:41 -07001294 virtual size_t storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001295 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevichb7718b92009-07-09 22:00:24 -07001296 Type* pR0Type = getR0Type();
1297 TypeTag r0ct = collapseType(pR0Type->tag);
1298 switch(r0ct) {
1299 case TY_INT:
1300 case TY_FLOAT:
1301 if (l < 0 || l > 4096-4) {
1302 error("l out of range for stack offset: 0x%08x", l);
1303 }
1304 o4(0xE58D0000 + l); // str r0, [sp, #l]
1305 return 4;
1306 case TY_DOUBLE: {
1307 // Align to 8 byte boundary
1308 int l2 = (l + 7) & ~7;
1309 if (l2 < 0 || l2 > 4096-8) {
1310 error("l out of range for stack offset: 0x%08x", l);
1311 }
1312 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1313 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1314 return (l2 - l) + 8;
1315 }
1316 default:
1317 assert(false);
1318 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001319 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001320 }
1321
Jack Palevichb7718b92009-07-09 22:00:24 -07001322 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001323 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001324 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001325 // Have to calculate register arg count from actual stack size,
1326 // in order to properly handle ... functions.
1327 int regArgCount = l >> 2;
1328 if (regArgCount > 4) {
1329 regArgCount = 4;
1330 }
1331 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001332 argumentStackUse -= regArgCount * 4;
1333 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1334 }
1335 mStackUse += argumentStackUse;
1336
1337 // Align stack.
1338 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1339 * STACK_ALIGNMENT);
1340 mStackAlignmentAdjustment = 0;
1341 if (missalignment > 0) {
1342 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1343 }
1344 l += mStackAlignmentAdjustment;
1345
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001346 if (l < 0 || l > 0x3FC) {
1347 error("L out of range for stack adjustment: 0x%08x", l);
1348 }
1349 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001350 mStackUse += mStackAlignmentAdjustment;
1351 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1352 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001353 }
1354
Jack Palevich8df46192009-07-07 14:48:51 -07001355 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001356 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001357 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001358 // Forward calls are always short (local)
1359 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001360 }
1361
Jack Palevich8df46192009-07-07 14:48:51 -07001362 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001363 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001364 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001365 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001366 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001367 if (t >= - (1 << 25) && t < (1 << 25)) {
1368 o4(0xEB000000 | encodeAddress(t));
1369 } else {
1370 // Long call.
1371 o4(0xE59FC000); // ldr r12, .L1
1372 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001373 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001374 o4(0xE08CC00F); // .L99: add r12,pc
1375 o4(0xE12FFF3C); // blx r12
1376 }
Jack Palevich22305132009-05-13 10:58:45 -07001377 }
1378
Jack Palevich8df46192009-07-07 14:48:51 -07001379 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001380 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001381 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001382 int argCount = l >> 2;
1383 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001384 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001385 if (adjustedL < 0 || adjustedL > 4096-4) {
1386 error("l out of range for stack offset: 0x%08x", l);
1387 }
1388 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1389 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001390 }
1391
Jack Palevichb7718b92009-07-09 22:00:24 -07001392 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001393 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001394 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001395 // Have to calculate register arg count from actual stack size,
1396 // in order to properly handle ... functions.
1397 int regArgCount = l >> 2;
1398 if (regArgCount > 4) {
1399 regArgCount = 4;
1400 }
1401 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001402 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1403 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001404 if (stackUse) {
1405 if (stackUse < 0 || stackUse > 255) {
1406 error("L out of range for stack adjustment: 0x%08x", l);
1407 }
1408 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001409 mStackUse -= stackUse * 4;
1410 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001411 }
Jack Palevich22305132009-05-13 10:58:45 -07001412 }
1413
Jack Palevicha6535612009-05-13 16:24:17 -07001414 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001415 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001416 }
1417
1418 /* output a symbol and patch all calls to it */
1419 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001420 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001421 int n;
1422 int base = getBase();
1423 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001424 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001425 while (t) {
1426 int data = * (int*) t;
1427 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1428 if (decodedOffset == 0) {
1429 n = 0;
1430 } else {
1431 n = base + decodedOffset; /* next value */
1432 }
1433 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1434 | encodeRelAddress(pc - t - 8);
1435 t = n;
1436 }
1437 }
1438
Jack Palevich1cdef202009-05-22 12:06:27 -07001439 virtual int finishCompile() {
1440#if defined(__arm__)
1441 const long base = long(getBase());
1442 const long curr = long(getPC());
1443 int err = cacheflush(base, curr, 0);
1444 return err;
1445#else
1446 return 0;
1447#endif
1448 }
1449
Jack Palevicha6535612009-05-13 16:24:17 -07001450 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001451#ifdef ENABLE_ARM_DISASSEMBLY
1452 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001453 disasm_interface_t di;
1454 di.di_readword = disassemble_readword;
1455 di.di_printaddr = disassemble_printaddr;
1456 di.di_printf = disassemble_printf;
1457
1458 int base = getBase();
1459 int pc = getPC();
1460 for(int i = base; i < pc; i += 4) {
1461 fprintf(out, "%08x: %08x ", i, *(int*) i);
1462 ::disasm(&di, i, 0);
1463 }
Jack Palevich09555c72009-05-27 12:25:55 -07001464#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001465 return 0;
1466 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001467
Jack Palevich9eed7a22009-07-06 17:24:34 -07001468 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001469 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001470 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001471 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001472 switch(pType->tag) {
1473 case TY_DOUBLE:
1474 return 8;
1475 default:
1476 return 4;
1477 }
1478 }
1479
1480 /**
1481 * Array element alignment (in bytes) for this type of data.
1482 */
1483 virtual size_t sizeOf(Type* pType){
1484 switch(pType->tag) {
1485 case TY_INT:
1486 return 4;
1487 case TY_CHAR:
1488 return 1;
1489 default:
1490 return 0;
1491 case TY_FLOAT:
1492 return 4;
1493 case TY_DOUBLE:
1494 return 8;
1495 case TY_POINTER:
1496 return 4;
1497 }
1498 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001499
1500 virtual size_t stackSizeOf(Type* pType) {
1501 switch(pType->tag) {
1502 case TY_DOUBLE:
1503 return 8;
1504 default:
1505 return 4;
1506 }
1507 }
1508
Jack Palevich22305132009-05-13 10:58:45 -07001509 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001510 static FILE* disasmOut;
1511
1512 static u_int
1513 disassemble_readword(u_int address)
1514 {
1515 return(*((u_int *)address));
1516 }
1517
1518 static void
1519 disassemble_printaddr(u_int address)
1520 {
1521 fprintf(disasmOut, "0x%08x", address);
1522 }
1523
1524 static void
1525 disassemble_printf(const char *fmt, ...) {
1526 va_list ap;
1527 va_start(ap, fmt);
1528 vfprintf(disasmOut, fmt, ap);
1529 va_end(ap);
1530 }
1531
1532 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1533
1534 /** Encode a relative address that might also be
1535 * a label.
1536 */
1537 int encodeAddress(int value) {
1538 int base = getBase();
1539 if (value >= base && value <= getPC() ) {
1540 // This is a label, encode it relative to the base.
1541 value = value - base;
1542 }
1543 return encodeRelAddress(value);
1544 }
1545
1546 int encodeRelAddress(int value) {
1547 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1548 }
Jack Palevich22305132009-05-13 10:58:45 -07001549
Jack Palevichb7718b92009-07-09 22:00:24 -07001550 int calcRegArgCount(Type* pDecl) {
1551 int reg = 0;
1552 Type* pArgs = pDecl->pTail;
1553 while (pArgs && reg < 4) {
1554 Type* pArg = pArgs->pHead;
1555 if ( pArg->tag == TY_DOUBLE) {
1556 int evenReg = (reg + 1) & ~1;
1557 if (evenReg >= 4) {
1558 break;
1559 }
1560 reg = evenReg + 2;
1561 } else {
1562 reg++;
1563 }
1564 pArgs = pArgs->pTail;
1565 }
1566 return reg;
1567 }
1568
1569 /* Pop TOS to R1
1570 * Make sure both R0 and TOS are floats. (Could be ints)
1571 * We know that at least one of R0 and TOS is already a float
1572 */
1573 void setupFloatArgs() {
1574 Type* pR0Type = getR0Type();
1575 Type* pTOSType = getTOSType();
1576 TypeTag tagR0 = collapseType(pR0Type->tag);
1577 TypeTag tagTOS = collapseType(pTOSType->tag);
1578 if (tagR0 != TY_FLOAT) {
1579 assert(tagR0 == TY_INT);
1580 callRuntime((void*) runtime_int_to_float);
1581 }
1582 if (tagTOS != TY_FLOAT) {
1583 assert(tagTOS == TY_INT);
1584 assert(tagR0 == TY_FLOAT);
1585 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1586 o4(0xE59D0004); // ldr r0, [sp, #4]
1587 callRuntime((void*) runtime_int_to_float);
1588 o4(0xE1A01000); // mov r1, r0
1589 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1590 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1591 } else {
1592 // Pop TOS
1593 o4(0xE8BD0002); // ldmfd sp!,{r1}
1594 }
1595 mStackUse -= 4;
1596 popType();
1597 }
1598
1599 /* Pop TOS into R2..R3
1600 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1601 * We know that at least one of R0 and TOS are already a double.
1602 */
1603
1604 void setupDoubleArgs() {
1605 Type* pR0Type = getR0Type();
1606 Type* pTOSType = getTOSType();
1607 TypeTag tagR0 = collapseType(pR0Type->tag);
1608 TypeTag tagTOS = collapseType(pTOSType->tag);
1609 if (tagR0 != TY_DOUBLE) {
1610 if (tagR0 == TY_INT) {
1611 callRuntime((void*) runtime_int_to_double);
1612 } else {
1613 assert(tagR0 == TY_FLOAT);
1614 callRuntime((void*) runtime_float_to_double);
1615 }
1616 }
1617 if (tagTOS != TY_DOUBLE) {
1618 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1619 o4(0xE59D0008); // ldr r0, [sp, #8]
1620 if (tagTOS == TY_INT) {
1621 callRuntime((void*) runtime_int_to_double);
1622 } else {
1623 assert(tagTOS == TY_FLOAT);
1624 callRuntime((void*) runtime_float_to_double);
1625 }
1626 o4(0xE1A02000); // mov r2, r0
1627 o4(0xE1A03001); // mov r3, r1
1628 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1629 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1630 mStackUse -= 4;
1631 } else {
1632 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1633 mStackUse -= 8;
1634 }
1635 popType();
1636 }
1637
Jack Palevicha8f427f2009-07-13 18:40:08 -07001638 void liReg(int t, int reg) {
1639 assert(reg >= 0 && reg < 16);
1640 int rN = (reg & 0xf) << 12;
1641 if (t >= 0 && t < 255) {
1642 o4((0xE3A00000 + t) | rN); // mov rN, #0
1643 } else if (t >= -256 && t < 0) {
1644 // mvn means move constant ^ ~0
1645 o4((0xE3E00001 - t) | rN); // mvn rN, #0
1646 } else {
1647 o4(0xE51F0000 | rN); // ldr rN, .L3
1648 o4(0xEA000000); // b .L99
1649 o4(t); // .L3: .word 0
1650 // .L99:
1651 }
1652 }
1653
Jack Palevichb7718b92009-07-09 22:00:24 -07001654 void callRuntime(void* fn) {
1655 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001656 o4(0xEA000000); // b .L99
1657 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001658 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001659 }
1660
Jack Palevichb7718b92009-07-09 22:00:24 -07001661 // Integer math:
1662
1663 static int runtime_DIV(int b, int a) {
1664 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001665 }
1666
Jack Palevichb7718b92009-07-09 22:00:24 -07001667 static int runtime_MOD(int b, int a) {
1668 return a % b;
1669 }
1670
1671 // Comparison to zero
1672
1673 static int runtime_is_non_zero_f(float a) {
1674 return a != 0;
1675 }
1676
1677 static int runtime_is_non_zero_d(double a) {
1678 return a != 0;
1679 }
1680
1681 // Comparison to zero
1682
1683 static int runtime_is_zero_f(float a) {
1684 return a == 0;
1685 }
1686
1687 static int runtime_is_zero_d(double a) {
1688 return a == 0;
1689 }
1690
1691 // Type conversion
1692
1693 static int runtime_float_to_int(float a) {
1694 return (int) a;
1695 }
1696
1697 static double runtime_float_to_double(float a) {
1698 return (double) a;
1699 }
1700
1701 static int runtime_double_to_int(double a) {
1702 return (int) a;
1703 }
1704
1705 static float runtime_double_to_float(double a) {
1706 return (float) a;
1707 }
1708
1709 static float runtime_int_to_float(int a) {
1710 return (float) a;
1711 }
1712
1713 static double runtime_int_to_double(int a) {
1714 return (double) a;
1715 }
1716
1717 // Comparisons float
1718
1719 static int runtime_cmp_eq_ff(float b, float a) {
1720 return a == b;
1721 }
1722
1723 static int runtime_cmp_ne_ff(float b, float a) {
1724 return a != b;
1725 }
1726
1727 static int runtime_cmp_lt_ff(float b, float a) {
1728 return a < b;
1729 }
1730
1731 static int runtime_cmp_le_ff(float b, float a) {
1732 return a <= b;
1733 }
1734
1735 static int runtime_cmp_ge_ff(float b, float a) {
1736 return a >= b;
1737 }
1738
1739 static int runtime_cmp_gt_ff(float b, float a) {
1740 return a > b;
1741 }
1742
1743 // Comparisons double
1744
1745 static int runtime_cmp_eq_dd(double b, double a) {
1746 return a == b;
1747 }
1748
1749 static int runtime_cmp_ne_dd(double b, double a) {
1750 return a != b;
1751 }
1752
1753 static int runtime_cmp_lt_dd(double b, double a) {
1754 return a < b;
1755 }
1756
1757 static int runtime_cmp_le_dd(double b, double a) {
1758 return a <= b;
1759 }
1760
1761 static int runtime_cmp_ge_dd(double b, double a) {
1762 return a >= b;
1763 }
1764
1765 static int runtime_cmp_gt_dd(double b, double a) {
1766 return a > b;
1767 }
1768
1769 // Math float
1770
1771 static float runtime_op_add_ff(float b, float a) {
1772 return a + b;
1773 }
1774
1775 static float runtime_op_sub_ff(float b, float a) {
1776 return a - b;
1777 }
1778
1779 static float runtime_op_mul_ff(float b, float a) {
1780 return a * b;
1781 }
1782
1783 static float runtime_op_div_ff(float b, float a) {
1784 return a / b;
1785 }
1786
1787 static float runtime_op_neg_f(float a) {
1788 return -a;
1789 }
1790
1791 // Math double
1792
1793 static double runtime_op_add_dd(double b, double a) {
1794 return a + b;
1795 }
1796
1797 static double runtime_op_sub_dd(double b, double a) {
1798 return a - b;
1799 }
1800
1801 static double runtime_op_mul_dd(double b, double a) {
1802 return a * b;
1803 }
1804
1805 static double runtime_op_div_dd(double b, double a) {
1806 return a / b;
1807 }
1808
1809 static double runtime_op_neg_d(double a) {
1810 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001811 }
-b master422972c2009-06-17 19:13:52 -07001812
1813 static const int STACK_ALIGNMENT = 8;
1814 int mStackUse;
1815 // This variable holds the amount we adjusted the stack in the most
1816 // recent endFunctionCallArguments call. It's examined by the
1817 // following adjustStackAfterCall call.
1818 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001819 };
1820
Jack Palevich09555c72009-05-27 12:25:55 -07001821#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001822
1823#ifdef PROVIDE_X86_CODEGEN
1824
Jack Palevich21a15a22009-05-11 14:49:29 -07001825 class X86CodeGenerator : public CodeGenerator {
1826 public:
1827 X86CodeGenerator() {}
1828 virtual ~X86CodeGenerator() {}
1829
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001830 /* returns address to patch with local variable size
1831 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001832 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001833 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1834 return oad(0xec81, 0); /* sub $xxx, %esp */
1835 }
1836
Jack Palevichb7718b92009-07-09 22:00:24 -07001837 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001838 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001839 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001840 }
1841
Jack Palevich21a15a22009-05-11 14:49:29 -07001842 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001843 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001844 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001845 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001846 }
1847
Jack Palevich1a539db2009-07-08 13:04:41 -07001848 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001849 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001850 switch (pType->tag) {
1851 case TY_FLOAT:
1852 oad(0x05D9, address); // flds
1853 break;
1854 case TY_DOUBLE:
1855 oad(0x05DD, address); // fldl
1856 break;
1857 default:
1858 assert(false);
1859 break;
1860 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001861 }
1862
Jack Palevich22305132009-05-13 10:58:45 -07001863 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001864 return psym(0xe9, t);
1865 }
1866
1867 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001868 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001869 Type* pR0Type = getR0Type();
1870 TypeTag tagR0 = pR0Type->tag;
1871 bool isFloatR0 = isFloatTag(tagR0);
1872 if (isFloatR0) {
1873 o(0xeed9); // fldz
1874 o(0xe9da); // fucompp
1875 o(0xe0df); // fnstsw %ax
1876 o(0x9e); // sahf
1877 } else {
1878 o(0xc085); // test %eax, %eax
1879 }
1880 // Use two output statements to generate one instruction.
1881 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001882 return psym(0x84 + l, t);
1883 }
1884
Jack Palevicha39749f2009-07-08 20:40:31 -07001885 virtual void gcmp(int op, Type* pResultType) {
1886 Type* pR0Type = getR0Type();
1887 Type* pTOSType = getTOSType();
1888 TypeTag tagR0 = pR0Type->tag;
1889 TypeTag tagTOS = pTOSType->tag;
1890 bool isFloatR0 = isFloatTag(tagR0);
1891 bool isFloatTOS = isFloatTag(tagTOS);
1892 if (!isFloatR0 && !isFloatTOS) {
1893 int t = decodeOp(op);
1894 o(0x59); /* pop %ecx */
1895 o(0xc139); /* cmp %eax,%ecx */
1896 li(0, NULL);
1897 o(0x0f); /* setxx %al */
1898 o(t + 0x90);
1899 o(0xc0);
1900 popType();
1901 } else {
1902 setupFloatOperands();
1903 switch (op) {
1904 case OP_EQUALS:
1905 o(0xe9da); // fucompp
1906 o(0xe0df); // fnstsw %ax
1907 o(0x9e); // sahf
1908 o(0xc0940f); // sete %al
1909 o(0xc29b0f); // setnp %dl
1910 o(0xd021); // andl %edx, %eax
1911 break;
1912 case OP_NOT_EQUALS:
1913 o(0xe9da); // fucompp
1914 o(0xe0df); // fnstsw %ax
1915 o(0x9e); // sahf
1916 o(0xc0950f); // setne %al
1917 o(0xc29a0f); // setp %dl
1918 o(0xd009); // orl %edx, %eax
1919 break;
1920 case OP_GREATER_EQUAL:
1921 o(0xe9da); // fucompp
1922 o(0xe0df); // fnstsw %ax
1923 o(0x05c4f6); // testb $5, %ah
1924 o(0xc0940f); // sete %al
1925 break;
1926 case OP_LESS:
1927 o(0xc9d9); // fxch %st(1)
1928 o(0xe9da); // fucompp
1929 o(0xe0df); // fnstsw %ax
1930 o(0x9e); // sahf
1931 o(0xc0970f); // seta %al
1932 break;
1933 case OP_LESS_EQUAL:
1934 o(0xc9d9); // fxch %st(1)
1935 o(0xe9da); // fucompp
1936 o(0xe0df); // fnstsw %ax
1937 o(0x9e); // sahf
1938 o(0xc0930f); // setea %al
1939 break;
1940 case OP_GREATER:
1941 o(0xe9da); // fucompp
1942 o(0xe0df); // fnstsw %ax
1943 o(0x45c4f6); // testb $69, %ah
1944 o(0xc0940f); // sete %al
1945 break;
1946 default:
1947 error("Unknown comparison op");
1948 }
1949 o(0xc0b60f); // movzbl %al, %eax
1950 }
1951 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001952 }
1953
Jack Palevich546b2242009-05-13 15:10:04 -07001954 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001955 Type* pR0Type = getR0Type();
1956 Type* pTOSType = getTOSType();
1957 TypeTag tagR0 = pR0Type->tag;
1958 TypeTag tagTOS = pTOSType->tag;
1959 bool isFloatR0 = isFloatTag(tagR0);
1960 bool isFloatTOS = isFloatTag(tagTOS);
1961 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001962 bool isPtrR0 = tagR0 == TY_POINTER;
1963 bool isPtrTOS = tagTOS == TY_POINTER;
1964 if (isPtrR0 || isPtrTOS) {
1965 if (isPtrR0 && isPtrTOS) {
1966 if (op != OP_MINUS) {
1967 error("Unsupported pointer-pointer operation %d.", op);
1968 }
1969 if (! typeEqual(pR0Type, pTOSType)) {
1970 error("Incompatible pointer types for subtraction.");
1971 }
1972 o(0x59); /* pop %ecx */
1973 o(decodeOp(op));
1974 popType();
1975 setR0Type(mkpInt);
1976 int size = sizeOf(pR0Type->pHead);
1977 if (size != 1) {
1978 pushR0();
1979 li(size, mkpInt);
1980 // TODO: Optimize for power-of-two.
1981 genOp(OP_DIV);
1982 }
1983 } else {
1984 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1985 error("Unsupported pointer-scalar operation %d", op);
1986 }
1987 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1988 o(0x59); /* pop %ecx */
1989 int size = sizeOf(pPtrType->pHead);
1990 if (size != 1) {
1991 // TODO: Optimize for power-of-two.
1992 if (isPtrR0) {
1993 oad(0xC969, size); // imull $size, %ecx
1994 } else {
1995 oad(0xC069, size); // mul $size, %eax
1996 }
1997 }
1998 o(decodeOp(op));
1999 popType();
2000 setR0Type(pPtrType);
2001 }
2002 } else {
2003 o(0x59); /* pop %ecx */
2004 o(decodeOp(op));
2005 if (op == OP_MOD)
2006 o(0x92); /* xchg %edx, %eax */
2007 popType();
2008 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002009 } else {
2010 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2011 setupFloatOperands();
2012 // Both float. x87 R0 == left hand, x87 R1 == right hand
2013 switch (op) {
2014 case OP_MUL:
2015 o(0xc9de); // fmulp
2016 break;
2017 case OP_DIV:
2018 o(0xf1de); // fdivp
2019 break;
2020 case OP_PLUS:
2021 o(0xc1de); // faddp
2022 break;
2023 case OP_MINUS:
2024 o(0xe1de); // fsubp
2025 break;
2026 default:
2027 error("Unsupported binary floating operation.");
2028 break;
2029 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002030 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002031 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002032 }
2033
Jack Palevicha39749f2009-07-08 20:40:31 -07002034 virtual void gUnaryCmp(int op, Type* pResultType) {
2035 if (op != OP_LOGICAL_NOT) {
2036 error("Unknown unary cmp %d", op);
2037 } else {
2038 Type* pR0Type = getR0Type();
2039 TypeTag tag = collapseType(pR0Type->tag);
2040 switch(tag) {
2041 case TY_INT: {
2042 oad(0xb9, 0); /* movl $0, %ecx */
2043 int t = decodeOp(op);
2044 o(0xc139); /* cmp %eax,%ecx */
2045 li(0, NULL);
2046 o(0x0f); /* setxx %al */
2047 o(t + 0x90);
2048 o(0xc0);
2049 }
2050 break;
2051 case TY_FLOAT:
2052 case TY_DOUBLE:
2053 o(0xeed9); // fldz
2054 o(0xe9da); // fucompp
2055 o(0xe0df); // fnstsw %ax
2056 o(0x9e); // sahf
2057 o(0xc0950f); // setne %al
2058 o(0xc29a0f); // setp %dl
2059 o(0xd009); // orl %edx, %eax
2060 o(0xc0b60f); // movzbl %al, %eax
2061 o(0x01f083); // xorl $1, %eax
2062 break;
2063 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002064 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002065 break;
2066 }
2067 }
2068 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002069 }
2070
2071 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002072 Type* pR0Type = getR0Type();
2073 TypeTag tag = collapseType(pR0Type->tag);
2074 switch(tag) {
2075 case TY_INT:
2076 oad(0xb9, 0); /* movl $0, %ecx */
2077 o(decodeOp(op));
2078 break;
2079 case TY_FLOAT:
2080 case TY_DOUBLE:
2081 switch (op) {
2082 case OP_MINUS:
2083 o(0xe0d9); // fchs
2084 break;
2085 case OP_BIT_NOT:
2086 error("Can't apply '~' operator to a float or double.");
2087 break;
2088 default:
2089 error("Unknown unary op %d\n", op);
2090 break;
2091 }
2092 break;
2093 default:
2094 error("genUnaryOp unsupported type");
2095 break;
2096 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002097 }
2098
Jack Palevich1cdef202009-05-22 12:06:27 -07002099 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002100 Type* pR0Type = getR0Type();
2101 TypeTag r0ct = collapseType(pR0Type->tag);
2102 switch(r0ct) {
2103 case TY_INT:
2104 o(0x50); /* push %eax */
2105 break;
2106 case TY_FLOAT:
2107 o(0x50); /* push %eax */
2108 o(0x241cd9); // fstps 0(%esp)
2109 break;
2110 case TY_DOUBLE:
2111 o(0x50); /* push %eax */
2112 o(0x50); /* push %eax */
2113 o(0x241cdd); // fstpl 0(%esp)
2114 break;
2115 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002116 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002117 break;
2118 }
Jack Palevich8df46192009-07-07 14:48:51 -07002119 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002120 }
2121
Jack Palevich9eed7a22009-07-06 17:24:34 -07002122 virtual void storeR0ToTOS(Type* pPointerType) {
2123 assert(pPointerType->tag == TY_POINTER);
Jack Palevich21a15a22009-05-11 14:49:29 -07002124 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002125 popType();
Jack Palevich9eed7a22009-07-06 17:24:34 -07002126 switch (pPointerType->pHead->tag) {
2127 case TY_INT:
2128 o(0x0189); /* movl %eax/%al, (%ecx) */
2129 break;
2130 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 Palevich8df46192009-07-07 14:48:51 -07002140 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002141 break;
2142 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002143 }
2144
Jack Palevich9eed7a22009-07-06 17:24:34 -07002145 virtual void loadR0FromR0(Type* pPointerType) {
2146 assert(pPointerType->tag == TY_POINTER);
2147 switch (pPointerType->pHead->tag) {
2148 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002149 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002150 break;
2151 case TY_CHAR:
2152 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002153 ob(0); /* add zero in code */
2154 break;
2155 case TY_FLOAT:
2156 o2(0x00d9); // flds (%eax)
2157 break;
2158 case TY_DOUBLE:
2159 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002160 break;
2161 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002162 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002163 break;
2164 }
Jack Palevich8df46192009-07-07 14:48:51 -07002165 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002166 }
2167
Jack Palevich8df46192009-07-07 14:48:51 -07002168 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002169 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002170 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002171 }
2172
Jack Palevich9cbd2262009-07-08 16:48:41 -07002173 virtual void storeR0(int ea, Type* pType) {
2174 TypeTag tag = pType->tag;
2175 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002176 case TY_CHAR:
2177 if (ea < -LOCAL || ea > LOCAL) {
2178 oad(0xa2, ea); // movb %al,ea
2179 } else {
2180 oad(0x8588, ea); // movb %al,ea(%ebp)
2181 }
2182 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002183 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002184 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002185 gmov(6, ea); /* mov %eax, EA */
2186 break;
2187 case TY_FLOAT:
2188 if (ea < -LOCAL || ea > LOCAL) {
2189 oad(0x1dd9, ea); // fstps ea
2190 } else {
2191 oad(0x9dd9, ea); // fstps ea(%ebp)
2192 }
2193 break;
2194 case TY_DOUBLE:
2195 if (ea < -LOCAL || ea > LOCAL) {
2196 oad(0x1ddd, ea); // fstpl ea
2197 } else {
2198 oad(0x9ddd, ea); // fstpl ea(%ebp)
2199 }
2200 break;
2201 default:
2202 error("Unable to store to type %d", tag);
2203 break;
2204 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002205 }
2206
Jack Palevich8df46192009-07-07 14:48:51 -07002207 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002208 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002209 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002210 case TY_CHAR:
2211 if (ea < -LOCAL || ea > LOCAL) {
2212 oad(0x05BE0F, ea); // movsbl ea,%eax
2213 } else {
2214 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2215 }
2216 if (isIncDec) {
2217 error("inc/dec not implemented for char.");
2218 }
2219 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002220 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002221 case TY_POINTER:
2222 if (tag == TY_CHAR) {
2223 } else {
2224 gmov(8, ea); /* mov EA, %eax */
2225 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002226 if (isIncDec) {
2227 /* Implement post-increment or post decrement.
2228 */
2229 gmov(0, ea); /* 83 ADD */
2230 o(decodeOp(op));
2231 }
2232 break;
2233 case TY_FLOAT:
2234 if (ea < -LOCAL || ea > LOCAL) {
2235 oad(0x05d9, ea); // flds ea
2236 } else {
2237 oad(0x85d9, ea); // flds ea(%ebp)
2238 }
2239 if (isIncDec) {
2240 error("inc/dec not implemented for float.");
2241 }
2242 break;
2243 case TY_DOUBLE:
2244 if (ea < -LOCAL || ea > LOCAL) {
2245 oad(0x05dd, ea); // fldl ea
2246 } else {
2247 oad(0x85dd, ea); // fldl ea(%ebp)
2248 }
2249 if (isIncDec) {
2250 error("inc/dec not implemented for double.");
2251 }
2252 break;
2253 default:
2254 error("Unable to load type %d", tag);
2255 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002256 }
Jack Palevich8df46192009-07-07 14:48:51 -07002257 setR0Type(pType);
2258 }
2259
2260 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002261 Type* pR0Type = getR0Type();
2262 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002263 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002264 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002265 return;
2266 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002267 if (bitsSame(pType, pR0Type)) {
2268 // do nothing special
2269 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2270 // do nothing special, both held in same register on x87.
2271 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002272 TypeTag r0Tag = collapseType(pR0Type->tag);
2273 TypeTag destTag = collapseType(pType->tag);
2274 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2275 // Convert R0 from int to float
2276 o(0x50); // push %eax
2277 o(0x2404DB); // fildl 0(%esp)
2278 o(0x58); // pop %eax
2279 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2280 // Convert R0 from float to int. Complicated because
2281 // need to save and restore the rounding mode.
2282 o(0x50); // push %eax
2283 o(0x50); // push %eax
2284 o(0x02247cD9); // fnstcw 2(%esp)
2285 o(0x2444b70f); // movzwl 2(%esp), %eax
2286 o(0x02);
2287 o(0x0cb4); // movb $12, %ah
2288 o(0x24048966); // movw %ax, 0(%esp)
2289 o(0x242cd9); // fldcw 0(%esp)
2290 o(0x04245cdb); // fistpl 4(%esp)
2291 o(0x02246cd9); // fldcw 2(%esp)
2292 o(0x58); // pop %eax
2293 o(0x58); // pop %eax
2294 } else {
2295 error("Incompatible types old: %d new: %d",
2296 pR0Type->tag, pType->tag);
2297 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002298 }
2299 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002300 }
2301
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002302 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002303 return oad(0xec81, 0); /* sub $xxx, %esp */
2304 }
2305
Jack Palevich1a539db2009-07-08 13:04:41 -07002306 virtual size_t storeR0ToArg(int l) {
2307 Type* pR0Type = getR0Type();
2308 TypeTag r0ct = collapseType(pR0Type->tag);
2309 switch(r0ct) {
2310 case TY_INT:
2311 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2312 return 4;
2313 case TY_FLOAT:
2314 oad(0x249CD9, l); /* fstps xxx(%esp) */
2315 return 4;
2316 case TY_DOUBLE:
2317 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2318 return 8;
2319 default:
2320 assert(false);
2321 return 0;
2322 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002323 }
2324
Jack Palevichb7718b92009-07-09 22:00:24 -07002325 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002326 * (int*) a = l;
2327 }
2328
Jack Palevich8df46192009-07-07 14:48:51 -07002329 virtual int callForward(int symbol, Type* pFunc) {
2330 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002331 return psym(0xe8, symbol); /* call xxx */
2332 }
2333
Jack Palevich8df46192009-07-07 14:48:51 -07002334 virtual void callRelative(int t, Type* pFunc) {
2335 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002336 psym(0xe8, t); /* call xxx */
2337 }
2338
Jack Palevich8df46192009-07-07 14:48:51 -07002339 virtual void callIndirect(int l, Type* pFunc) {
2340 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002341 oad(0x2494ff, l); /* call *xxx(%esp) */
2342 }
2343
Jack Palevichb7718b92009-07-09 22:00:24 -07002344 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002345 if (isIndirect) {
2346 l += 4;
2347 }
-b master422972c2009-06-17 19:13:52 -07002348 if (l > 0) {
2349 oad(0xc481, l); /* add $xxx, %esp */
2350 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002351 }
2352
Jack Palevicha6535612009-05-13 16:24:17 -07002353 virtual int jumpOffset() {
2354 return 5;
2355 }
2356
2357 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002358 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002359 }
2360
Jack Paleviche7b59062009-05-19 17:12:17 -07002361 /* output a symbol and patch all calls to it */
2362 virtual void gsym(int t) {
2363 int n;
2364 int pc = getPC();
2365 while (t) {
2366 n = *(int *) t; /* next value */
2367 *(int *) t = pc - t - 4;
2368 t = n;
2369 }
2370 }
2371
Jack Palevich1cdef202009-05-22 12:06:27 -07002372 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002373 size_t pagesize = 4096;
2374 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2375 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2376 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2377 if (err) {
2378 error("mprotect() failed: %d", errno);
2379 }
2380 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002381 }
2382
Jack Palevich9eed7a22009-07-06 17:24:34 -07002383 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002384 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002385 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002386 virtual size_t alignmentOf(Type* pType){
2387 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002388 }
2389
2390 /**
2391 * Array element alignment (in bytes) for this type of data.
2392 */
2393 virtual size_t sizeOf(Type* pType){
2394 switch(pType->tag) {
2395 case TY_INT:
2396 return 4;
2397 case TY_CHAR:
2398 return 1;
2399 default:
2400 return 0;
2401 case TY_FLOAT:
2402 return 4;
2403 case TY_DOUBLE:
2404 return 8;
2405 case TY_POINTER:
2406 return 4;
2407 }
2408 }
2409
Jack Palevich9cbd2262009-07-08 16:48:41 -07002410 virtual size_t stackSizeOf(Type* pType) {
2411 switch(pType->tag) {
2412 case TY_DOUBLE:
2413 return 8;
2414 default:
2415 return 4;
2416 }
2417 }
2418
Jack Palevich21a15a22009-05-11 14:49:29 -07002419 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002420
2421 /** Output 1 to 4 bytes.
2422 *
2423 */
2424 void o(int n) {
2425 /* cannot use unsigned, so we must do a hack */
2426 while (n && n != -1) {
2427 ob(n & 0xff);
2428 n = n >> 8;
2429 }
2430 }
2431
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002432 /* Output exactly 2 bytes
2433 */
2434 void o2(int n) {
2435 ob(n & 0xff);
2436 ob(0xff & (n >> 8));
2437 }
2438
Jack Paleviche7b59062009-05-19 17:12:17 -07002439 /* psym is used to put an instruction with a data field which is a
2440 reference to a symbol. It is in fact the same as oad ! */
2441 int psym(int n, int t) {
2442 return oad(n, t);
2443 }
2444
2445 /* instruction + address */
2446 int oad(int n, int t) {
2447 o(n);
2448 int result = getPC();
2449 o4(t);
2450 return result;
2451 }
2452
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002453 static const int operatorHelper[];
2454
2455 int decodeOp(int op) {
2456 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002457 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002458 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002459 }
2460 return operatorHelper[op];
2461 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002462
Jack Palevich546b2242009-05-13 15:10:04 -07002463 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002464 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002465 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002466 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002467
2468 void setupFloatOperands() {
2469 Type* pR0Type = getR0Type();
2470 Type* pTOSType = getTOSType();
2471 TypeTag tagR0 = pR0Type->tag;
2472 TypeTag tagTOS = pTOSType->tag;
2473 bool isFloatR0 = isFloatTag(tagR0);
2474 bool isFloatTOS = isFloatTag(tagTOS);
2475 if (! isFloatR0) {
2476 // Convert R0 from int to float
2477 o(0x50); // push %eax
2478 o(0x2404DB); // fildl 0(%esp)
2479 o(0x58); // pop %eax
2480 }
2481 if (! isFloatTOS){
2482 o(0x2404DB); // fildl 0(%esp);
2483 o(0x58); // pop %eax
2484 } else {
2485 if (tagTOS == TY_FLOAT) {
2486 o(0x2404d9); // flds (%esp)
2487 o(0x58); // pop %eax
2488 } else {
2489 o(0x2404dd); // fldl (%esp)
2490 o(0x58); // pop %eax
2491 o(0x58); // pop %eax
2492 }
2493 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002494 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002495 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002496 };
2497
Jack Paleviche7b59062009-05-19 17:12:17 -07002498#endif // PROVIDE_X86_CODEGEN
2499
Jack Palevichb67b18f2009-06-11 21:12:23 -07002500#ifdef PROVIDE_TRACE_CODEGEN
2501 class TraceCodeGenerator : public CodeGenerator {
2502 private:
2503 CodeGenerator* mpBase;
2504
2505 public:
2506 TraceCodeGenerator(CodeGenerator* pBase) {
2507 mpBase = pBase;
2508 }
2509
2510 virtual ~TraceCodeGenerator() {
2511 delete mpBase;
2512 }
2513
2514 virtual void init(CodeBuf* pCodeBuf) {
2515 mpBase->init(pCodeBuf);
2516 }
2517
2518 void setErrorSink(ErrorSink* pErrorSink) {
2519 mpBase->setErrorSink(pErrorSink);
2520 }
2521
2522 /* returns address to patch with local variable size
2523 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002524 virtual int functionEntry(Type* pDecl) {
2525 int result = mpBase->functionEntry(pDecl);
2526 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002527 return result;
2528 }
2529
Jack Palevichb7718b92009-07-09 22:00:24 -07002530 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2531 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2532 localVariableAddress, localVariableSize);
2533 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002534 }
2535
2536 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002537 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002538 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002539 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002540 }
2541
Jack Palevich1a539db2009-07-08 13:04:41 -07002542 virtual void loadFloat(int address, Type* pType) {
2543 fprintf(stderr, "loadFloat(%d, type)\n", address);
2544 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002545 }
2546
Jack Palevichb67b18f2009-06-11 21:12:23 -07002547 virtual int gjmp(int t) {
2548 int result = mpBase->gjmp(t);
2549 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2550 return result;
2551 }
2552
2553 /* l = 0: je, l == 1: jne */
2554 virtual int gtst(bool l, int t) {
2555 int result = mpBase->gtst(l, t);
2556 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2557 return result;
2558 }
2559
Jack Palevicha39749f2009-07-08 20:40:31 -07002560 virtual void gcmp(int op, Type* pResultType) {
2561 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2562 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002563 }
2564
2565 virtual void genOp(int op) {
2566 fprintf(stderr, "genOp(%d)\n", op);
2567 mpBase->genOp(op);
2568 }
2569
Jack Palevich9eed7a22009-07-06 17:24:34 -07002570
Jack Palevicha39749f2009-07-08 20:40:31 -07002571 virtual void gUnaryCmp(int op, Type* pResultType) {
2572 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2573 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002574 }
2575
2576 virtual void genUnaryOp(int op) {
2577 fprintf(stderr, "genUnaryOp(%d)\n", op);
2578 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002579 }
2580
2581 virtual void pushR0() {
2582 fprintf(stderr, "pushR0()\n");
2583 mpBase->pushR0();
2584 }
2585
Jack Palevich9eed7a22009-07-06 17:24:34 -07002586 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002587 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002588 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002589 }
2590
Jack Palevich9eed7a22009-07-06 17:24:34 -07002591 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002592 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002593 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002594 }
2595
Jack Palevich8df46192009-07-07 14:48:51 -07002596 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002597 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002598 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002599 }
2600
Jack Palevich9cbd2262009-07-08 16:48:41 -07002601 virtual void storeR0(int ea, Type* pType) {
2602 fprintf(stderr, "storeR0(%d, pType)\n", ea);
2603 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002604 }
2605
Jack Palevich8df46192009-07-07 14:48:51 -07002606 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002607 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002608 mpBase->loadR0(ea, isIncDec, op, pType);
2609 }
2610
2611 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002612 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002613 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002614 }
2615
2616 virtual int beginFunctionCallArguments() {
2617 int result = mpBase->beginFunctionCallArguments();
2618 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2619 return result;
2620 }
2621
Jack Palevich1a539db2009-07-08 13:04:41 -07002622 virtual size_t storeR0ToArg(int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002623 fprintf(stderr, "storeR0ToArg(%d)\n", l);
Jack Palevich1a539db2009-07-08 13:04:41 -07002624 return mpBase->storeR0ToArg(l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002625 }
2626
Jack Palevichb7718b92009-07-09 22:00:24 -07002627 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002628 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002629 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002630 }
2631
Jack Palevich8df46192009-07-07 14:48:51 -07002632 virtual int callForward(int symbol, Type* pFunc) {
2633 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002634 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2635 return result;
2636 }
2637
Jack Palevich8df46192009-07-07 14:48:51 -07002638 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002639 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002640 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002641 }
2642
Jack Palevich8df46192009-07-07 14:48:51 -07002643 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002644 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002645 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002646 }
2647
Jack Palevichb7718b92009-07-09 22:00:24 -07002648 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2649 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2650 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002651 }
2652
2653 virtual int jumpOffset() {
2654 return mpBase->jumpOffset();
2655 }
2656
2657 virtual int disassemble(FILE* out) {
2658 return mpBase->disassemble(out);
2659 }
2660
2661 /* output a symbol and patch all calls to it */
2662 virtual void gsym(int t) {
2663 fprintf(stderr, "gsym(%d)\n", t);
2664 mpBase->gsym(t);
2665 }
2666
2667 virtual int finishCompile() {
2668 int result = mpBase->finishCompile();
2669 fprintf(stderr, "finishCompile() = %d\n", result);
2670 return result;
2671 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002672
2673 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002674 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002675 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002676 virtual size_t alignmentOf(Type* pType){
2677 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002678 }
2679
2680 /**
2681 * Array element alignment (in bytes) for this type of data.
2682 */
2683 virtual size_t sizeOf(Type* pType){
2684 return mpBase->sizeOf(pType);
2685 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002686
Jack Palevich9cbd2262009-07-08 16:48:41 -07002687
2688 virtual size_t stackSizeOf(Type* pType) {
2689 return mpBase->stackSizeOf(pType);
2690 }
2691
2692
Jack Palevich1a539db2009-07-08 13:04:41 -07002693 virtual Type* getR0Type() {
2694 return mpBase->getR0Type();
2695 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002696 };
2697
2698#endif // PROVIDE_TRACE_CODEGEN
2699
Jack Palevich569f1352009-06-29 14:29:08 -07002700 class Arena {
2701 public:
2702 // Used to record a given allocation amount.
2703 // Used:
2704 // Mark mark = arena.mark();
2705 // ... lots of arena.allocate()
2706 // arena.free(mark);
2707
2708 struct Mark {
2709 size_t chunk;
2710 size_t offset;
2711 };
2712
2713 Arena() {
2714 mCurrentChunk = 0;
2715 Chunk start(CHUNK_SIZE);
2716 mData.push_back(start);
2717 }
2718
2719 ~Arena() {
2720 for(size_t i = 0; i < mData.size(); i++) {
2721 mData[i].free();
2722 }
2723 }
2724
2725 // Alloc using the standard alignment size safe for any variable
2726 void* alloc(size_t size) {
2727 return alloc(size, 8);
2728 }
2729
2730 Mark mark(){
2731 Mark result;
2732 result.chunk = mCurrentChunk;
2733 result.offset = mData[mCurrentChunk].mOffset;
2734 return result;
2735 }
2736
2737 void freeToMark(const Mark& mark) {
2738 mCurrentChunk = mark.chunk;
2739 mData[mCurrentChunk].mOffset = mark.offset;
2740 }
2741
2742 private:
2743 // Allocate memory aligned to a given size
2744 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2745 // Memory is not zero filled.
2746
2747 void* alloc(size_t size, size_t alignment) {
2748 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2749 if (mCurrentChunk + 1 < mData.size()) {
2750 mCurrentChunk++;
2751 } else {
2752 size_t allocSize = CHUNK_SIZE;
2753 if (allocSize < size + alignment - 1) {
2754 allocSize = size + alignment - 1;
2755 }
2756 Chunk chunk(allocSize);
2757 mData.push_back(chunk);
2758 mCurrentChunk++;
2759 }
2760 }
2761 return mData[mCurrentChunk].allocate(size, alignment);
2762 }
2763
2764 static const size_t CHUNK_SIZE = 128*1024;
2765 // Note: this class does not deallocate its
2766 // memory when it's destroyed. It depends upon
2767 // its parent to deallocate the memory.
2768 struct Chunk {
2769 Chunk() {
2770 mpData = 0;
2771 mSize = 0;
2772 mOffset = 0;
2773 }
2774
2775 Chunk(size_t size) {
2776 mSize = size;
2777 mpData = (char*) malloc(size);
2778 mOffset = 0;
2779 }
2780
2781 ~Chunk() {
2782 // Doesn't deallocate memory.
2783 }
2784
2785 void* allocate(size_t size, size_t alignment) {
2786 size_t alignedOffset = aligned(mOffset, alignment);
2787 void* result = mpData + alignedOffset;
2788 mOffset = alignedOffset + size;
2789 return result;
2790 }
2791
2792 void free() {
2793 if (mpData) {
2794 ::free(mpData);
2795 mpData = 0;
2796 }
2797 }
2798
2799 size_t remainingCapacity(size_t alignment) {
2800 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2801 }
2802
2803 // Assume alignment is a power of two
2804 inline size_t aligned(size_t v, size_t alignment) {
2805 size_t mask = alignment-1;
2806 return (v + mask) & ~mask;
2807 }
2808
2809 char* mpData;
2810 size_t mSize;
2811 size_t mOffset;
2812 };
2813
2814 size_t mCurrentChunk;
2815
2816 Vector<Chunk> mData;
2817 };
2818
Jack Palevich569f1352009-06-29 14:29:08 -07002819 struct VariableInfo;
2820
2821 struct Token {
2822 int hash;
2823 size_t length;
2824 char* pText;
2825 tokenid_t id;
2826
2827 // Current values for the token
2828 char* mpMacroDefinition;
2829 VariableInfo* mpVariableInfo;
2830 };
2831
2832 class TokenTable {
2833 public:
2834 // Don't use 0..0xff, allows characters and operators to be tokens too.
2835
2836 static const int TOKEN_BASE = 0x100;
2837 TokenTable() {
2838 mpMap = hashmapCreate(128, hashFn, equalsFn);
2839 }
2840
2841 ~TokenTable() {
2842 hashmapFree(mpMap);
2843 }
2844
2845 void setArena(Arena* pArena) {
2846 mpArena = pArena;
2847 }
2848
2849 // Returns a token for a given string of characters.
2850 tokenid_t intern(const char* pText, size_t length) {
2851 Token probe;
2852 int hash = hashmapHash((void*) pText, length);
2853 {
2854 Token probe;
2855 probe.hash = hash;
2856 probe.length = length;
2857 probe.pText = (char*) pText;
2858 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2859 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002860 return pValue->id;
2861 }
2862 }
2863
2864 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2865 memset(pToken, 0, sizeof(*pToken));
2866 pToken->hash = hash;
2867 pToken->length = length;
2868 pToken->pText = (char*) mpArena->alloc(length + 1);
2869 memcpy(pToken->pText, pText, length);
2870 pToken->pText[length] = 0;
2871 pToken->id = mTokens.size() + TOKEN_BASE;
2872 mTokens.push_back(pToken);
2873 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002874 return pToken->id;
2875 }
2876
2877 // Return the Token for a given tokenid.
2878 Token& operator[](tokenid_t id) {
2879 return *mTokens[id - TOKEN_BASE];
2880 }
2881
2882 inline size_t size() {
2883 return mTokens.size();
2884 }
2885
2886 private:
2887
2888 static int hashFn(void* pKey) {
2889 Token* pToken = (Token*) pKey;
2890 return pToken->hash;
2891 }
2892
2893 static bool equalsFn(void* keyA, void* keyB) {
2894 Token* pTokenA = (Token*) keyA;
2895 Token* pTokenB = (Token*) keyB;
2896 // Don't need to compare hash values, they should always be equal
2897 return pTokenA->length == pTokenB->length
2898 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2899 }
2900
2901 Hashmap* mpMap;
2902 Vector<Token*> mTokens;
2903 Arena* mpArena;
2904 };
2905
Jack Palevich1cdef202009-05-22 12:06:27 -07002906 class InputStream {
2907 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002908 virtual ~InputStream() {}
Jack Palevicheedf9d22009-06-04 16:23:40 -07002909 int getChar() {
2910 if (bumpLine) {
2911 line++;
2912 bumpLine = false;
2913 }
2914 int ch = get();
2915 if (ch == '\n') {
2916 bumpLine = true;
2917 }
2918 return ch;
2919 }
2920 int getLine() {
2921 return line;
2922 }
2923 protected:
2924 InputStream() :
2925 line(1), bumpLine(false) {
2926 }
2927 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002928 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07002929 int line;
2930 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07002931 };
2932
2933 class FileInputStream : public InputStream {
2934 public:
2935 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07002936 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07002937 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07002938 FILE* f;
2939 };
2940
2941 class TextInputStream : public InputStream {
2942 public:
2943 TextInputStream(const char* text, size_t textLength)
2944 : pText(text), mTextLength(textLength), mPosition(0) {
2945 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002946
2947 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002948 virtual int get() {
2949 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2950 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002951
Jack Palevich1cdef202009-05-22 12:06:27 -07002952 const char* pText;
2953 size_t mTextLength;
2954 size_t mPosition;
2955 };
2956
Jack Palevicheedf9d22009-06-04 16:23:40 -07002957 class String {
2958 public:
2959 String() {
2960 mpBase = 0;
2961 mUsed = 0;
2962 mSize = 0;
2963 }
2964
Jack Palevich303d8ff2009-06-11 19:06:24 -07002965 String(const char* item, int len, bool adopt) {
2966 if (len < 0) {
2967 len = strlen(item);
2968 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002969 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002970 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002971 mUsed = len;
2972 mSize = len + 1;
2973 } else {
2974 mpBase = 0;
2975 mUsed = 0;
2976 mSize = 0;
2977 appendBytes(item, len);
2978 }
2979 }
2980
Jack Palevich303d8ff2009-06-11 19:06:24 -07002981 String(const String& other) {
2982 mpBase = 0;
2983 mUsed = 0;
2984 mSize = 0;
2985 appendBytes(other.getUnwrapped(), other.len());
2986 }
2987
Jack Palevicheedf9d22009-06-04 16:23:40 -07002988 ~String() {
2989 if (mpBase) {
2990 free(mpBase);
2991 }
2992 }
2993
Jack Palevicha6baa232009-06-12 11:25:59 -07002994 String& operator=(const String& other) {
2995 clear();
2996 appendBytes(other.getUnwrapped(), other.len());
2997 return *this;
2998 }
2999
Jack Palevich303d8ff2009-06-11 19:06:24 -07003000 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003001 return mpBase;
3002 }
3003
Jack Palevich303d8ff2009-06-11 19:06:24 -07003004 void clear() {
3005 mUsed = 0;
3006 if (mSize > 0) {
3007 mpBase[0] = 0;
3008 }
3009 }
3010
Jack Palevicheedf9d22009-06-04 16:23:40 -07003011 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003012 appendBytes(s, strlen(s));
3013 }
3014
3015 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003016 memcpy(ensure(n), s, n + 1);
3017 }
3018
3019 void append(char c) {
3020 * ensure(1) = c;
3021 }
3022
Jack Palevich86351982009-06-30 18:09:56 -07003023 void append(String& other) {
3024 appendBytes(other.getUnwrapped(), other.len());
3025 }
3026
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003027 char* orphan() {
3028 char* result = mpBase;
3029 mpBase = 0;
3030 mUsed = 0;
3031 mSize = 0;
3032 return result;
3033 }
3034
Jack Palevicheedf9d22009-06-04 16:23:40 -07003035 void printf(const char* fmt,...) {
3036 va_list ap;
3037 va_start(ap, fmt);
3038 vprintf(fmt, ap);
3039 va_end(ap);
3040 }
3041
3042 void vprintf(const char* fmt, va_list ap) {
3043 char* temp;
3044 int numChars = vasprintf(&temp, fmt, ap);
3045 memcpy(ensure(numChars), temp, numChars+1);
3046 free(temp);
3047 }
3048
Jack Palevich303d8ff2009-06-11 19:06:24 -07003049 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003050 return mUsed;
3051 }
3052
3053 private:
3054 char* ensure(int n) {
3055 size_t newUsed = mUsed + n;
3056 if (newUsed > mSize) {
3057 size_t newSize = mSize * 2 + 10;
3058 if (newSize < newUsed) {
3059 newSize = newUsed;
3060 }
3061 mpBase = (char*) realloc(mpBase, newSize + 1);
3062 mSize = newSize;
3063 }
3064 mpBase[newUsed] = '\0';
3065 char* result = mpBase + mUsed;
3066 mUsed = newUsed;
3067 return result;
3068 }
3069
3070 char* mpBase;
3071 size_t mUsed;
3072 size_t mSize;
3073 };
3074
Jack Palevich569f1352009-06-29 14:29:08 -07003075 void internKeywords() {
3076 // Note: order has to match TOK_ constants
3077 static const char* keywords[] = {
3078 "int",
3079 "char",
3080 "void",
3081 "if",
3082 "else",
3083 "while",
3084 "break",
3085 "return",
3086 "for",
3087 "pragma",
3088 "define",
3089 "auto",
3090 "case",
3091 "const",
3092 "continue",
3093 "default",
3094 "do",
3095 "double",
3096 "enum",
3097 "extern",
3098 "float",
3099 "goto",
3100 "long",
3101 "register",
3102 "short",
3103 "signed",
3104 "sizeof",
3105 "static",
3106 "struct",
3107 "switch",
3108 "typedef",
3109 "union",
3110 "unsigned",
3111 "volatile",
3112 "_Bool",
3113 "_Complex",
3114 "_Imaginary",
3115 "inline",
3116 "restrict",
3117 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003118
Jack Palevich569f1352009-06-29 14:29:08 -07003119 for(int i = 0; keywords[i]; i++) {
3120 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003121 }
Jack Palevich569f1352009-06-29 14:29:08 -07003122 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003123
Jack Palevich36d94142009-06-08 15:55:32 -07003124 struct InputState {
3125 InputStream* pStream;
3126 int oldCh;
3127 };
3128
Jack Palevich2db168f2009-06-11 14:29:47 -07003129 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003130 void* pAddress;
3131 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003132 tokenid_t tok;
3133 size_t level;
3134 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003135 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003136 };
3137
Jack Palevich303d8ff2009-06-11 19:06:24 -07003138 class SymbolStack {
3139 public:
3140 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003141 mpArena = 0;
3142 mpTokenTable = 0;
3143 }
3144
3145 void setArena(Arena* pArena) {
3146 mpArena = pArena;
3147 }
3148
3149 void setTokenTable(TokenTable* pTokenTable) {
3150 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003151 }
3152
3153 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003154 Mark mark;
3155 mark.mArenaMark = mpArena->mark();
3156 mark.mSymbolHead = mStack.size();
3157 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003158 }
3159
3160 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003161 // Undo any shadowing that was done:
3162 Mark mark = mLevelStack.back();
3163 mLevelStack.pop_back();
3164 while (mStack.size() > mark.mSymbolHead) {
3165 VariableInfo* pV = mStack.back();
3166 mStack.pop_back();
3167 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003168 }
Jack Palevich569f1352009-06-29 14:29:08 -07003169 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003170 }
3171
Jack Palevich569f1352009-06-29 14:29:08 -07003172 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3173 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3174 return pV && pV->level == level();
3175 }
3176
3177 VariableInfo* add(tokenid_t tok) {
3178 Token& token = (*mpTokenTable)[tok];
3179 VariableInfo* pOldV = token.mpVariableInfo;
3180 VariableInfo* pNewV =
3181 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3182 memset(pNewV, 0, sizeof(VariableInfo));
3183 pNewV->tok = tok;
3184 pNewV->level = level();
3185 pNewV->pOldDefinition = pOldV;
3186 token.mpVariableInfo = pNewV;
3187 mStack.push_back(pNewV);
3188 return pNewV;
3189 }
3190
Jack Palevich86351982009-06-30 18:09:56 -07003191 VariableInfo* add(Type* pType) {
3192 VariableInfo* pVI = add(pType->id);
3193 pVI->pType = pType;
3194 return pVI;
3195 }
3196
Jack Palevich569f1352009-06-29 14:29:08 -07003197 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3198 for (size_t i = 0; i < mStack.size(); i++) {
3199 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003200 break;
3201 }
3202 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003203 }
3204
Jack Palevich303d8ff2009-06-11 19:06:24 -07003205 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003206 inline size_t level() {
3207 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003208 }
3209
Jack Palevich569f1352009-06-29 14:29:08 -07003210 struct Mark {
3211 Arena::Mark mArenaMark;
3212 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003213 };
3214
Jack Palevich569f1352009-06-29 14:29:08 -07003215 Arena* mpArena;
3216 TokenTable* mpTokenTable;
3217 Vector<VariableInfo*> mStack;
3218 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003219 };
Jack Palevich36d94142009-06-08 15:55:32 -07003220
3221 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003222 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003223 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003224 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003225 int tokl; // token operator level
3226 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003227 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003228 intptr_t loc; // local variable index
3229 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003230 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003231 char* dptr; // Macro state: Points to macro text during macro playback.
3232 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003233 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003234 ACCSymbolLookupFn mpSymbolLookupFn;
3235 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003236
3237 // Arena for the duration of the compile
3238 Arena mGlobalArena;
3239 // Arena for data that's only needed when compiling a single function
3240 Arena mLocalArena;
3241
3242 TokenTable mTokenTable;
3243 SymbolStack mGlobals;
3244 SymbolStack mLocals;
3245
Jack Palevich40600de2009-07-01 15:32:35 -07003246 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003247 Type* mkpInt; // int
3248 Type* mkpChar; // char
3249 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003250 Type* mkpFloat;
3251 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003252 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003253 Type* mkpIntPtr;
3254 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003255 Type* mkpFloatPtr;
3256 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003257 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003258
Jack Palevich36d94142009-06-08 15:55:32 -07003259 InputStream* file;
3260
3261 CodeBuf codeBuf;
3262 CodeGenerator* pGen;
3263
Jack Palevicheedf9d22009-06-04 16:23:40 -07003264 String mErrorBuf;
3265
Jack Palevicheedf9d22009-06-04 16:23:40 -07003266 String mPragmas;
3267 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003268 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003269
Jack Palevich21a15a22009-05-11 14:49:29 -07003270 static const int ALLOC_SIZE = 99999;
3271
Jack Palevich303d8ff2009-06-11 19:06:24 -07003272 static const int TOK_DUMMY = 1;
3273 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003274 static const int TOK_NUM_FLOAT = 3;
3275 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003276
3277 // 3..255 are character and/or operators
3278
Jack Palevich2db168f2009-06-11 14:29:47 -07003279 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003280 // Order has to match string list in "internKeywords".
3281 enum {
3282 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3283 TOK_INT = TOK_KEYWORD,
3284 TOK_CHAR,
3285 TOK_VOID,
3286 TOK_IF,
3287 TOK_ELSE,
3288 TOK_WHILE,
3289 TOK_BREAK,
3290 TOK_RETURN,
3291 TOK_FOR,
3292 TOK_PRAGMA,
3293 TOK_DEFINE,
3294 TOK_AUTO,
3295 TOK_CASE,
3296 TOK_CONST,
3297 TOK_CONTINUE,
3298 TOK_DEFAULT,
3299 TOK_DO,
3300 TOK_DOUBLE,
3301 TOK_ENUM,
3302 TOK_EXTERN,
3303 TOK_FLOAT,
3304 TOK_GOTO,
3305 TOK_LONG,
3306 TOK_REGISTER,
3307 TOK_SHORT,
3308 TOK_SIGNED,
3309 TOK_SIZEOF,
3310 TOK_STATIC,
3311 TOK_STRUCT,
3312 TOK_SWITCH,
3313 TOK_TYPEDEF,
3314 TOK_UNION,
3315 TOK_UNSIGNED,
3316 TOK_VOLATILE,
3317 TOK__BOOL,
3318 TOK__COMPLEX,
3319 TOK__IMAGINARY,
3320 TOK_INLINE,
3321 TOK_RESTRICT,
3322 // Symbols start after tokens
3323 TOK_SYMBOL
3324 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003325
3326 static const int LOCAL = 0x200;
3327
3328 static const int SYM_FORWARD = 0;
3329 static const int SYM_DEFINE = 1;
3330
3331 /* tokens in string heap */
3332 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003333
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003334 static const int OP_INCREMENT = 0;
3335 static const int OP_DECREMENT = 1;
3336 static const int OP_MUL = 2;
3337 static const int OP_DIV = 3;
3338 static const int OP_MOD = 4;
3339 static const int OP_PLUS = 5;
3340 static const int OP_MINUS = 6;
3341 static const int OP_SHIFT_LEFT = 7;
3342 static const int OP_SHIFT_RIGHT = 8;
3343 static const int OP_LESS_EQUAL = 9;
3344 static const int OP_GREATER_EQUAL = 10;
3345 static const int OP_LESS = 11;
3346 static const int OP_GREATER = 12;
3347 static const int OP_EQUALS = 13;
3348 static const int OP_NOT_EQUALS = 14;
3349 static const int OP_LOGICAL_AND = 15;
3350 static const int OP_LOGICAL_OR = 16;
3351 static const int OP_BIT_AND = 17;
3352 static const int OP_BIT_XOR = 18;
3353 static const int OP_BIT_OR = 19;
3354 static const int OP_BIT_NOT = 20;
3355 static const int OP_LOGICAL_NOT = 21;
3356 static const int OP_COUNT = 22;
3357
3358 /* Operators are searched from front, the two-character operators appear
3359 * before the single-character operators with the same first character.
3360 * @ is used to pad out single-character operators.
3361 */
3362 static const char* operatorChars;
3363 static const char operatorLevel[];
3364
Jack Palevich569f1352009-06-29 14:29:08 -07003365 /* Called when we detect an internal problem. Does nothing in production.
3366 *
3367 */
3368 void internalError() {
3369 * (char*) 0 = 0;
3370 }
3371
Jack Palevich86351982009-06-30 18:09:56 -07003372 void assert(bool isTrue) {
3373 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003374 internalError();
3375 }
Jack Palevich86351982009-06-30 18:09:56 -07003376 }
3377
Jack Palevich40600de2009-07-01 15:32:35 -07003378 bool isSymbol(tokenid_t t) {
3379 return t >= TOK_SYMBOL &&
3380 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3381 }
3382
3383 bool isSymbolOrKeyword(tokenid_t t) {
3384 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003385 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003386 }
3387
Jack Palevich86351982009-06-30 18:09:56 -07003388 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003389 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003390 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3391 if (pV && pV->tok != t) {
3392 internalError();
3393 }
3394 return pV;
3395 }
3396
3397 inline bool isDefined(tokenid_t t) {
3398 return t >= TOK_SYMBOL && VI(t) != 0;
3399 }
3400
Jack Palevich40600de2009-07-01 15:32:35 -07003401 const char* nameof(tokenid_t t) {
3402 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003403 return mTokenTable[t].pText;
3404 }
3405
Jack Palevich21a15a22009-05-11 14:49:29 -07003406 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003407 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003408 }
3409
3410 void inp() {
3411 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003412 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003413 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003414 dptr = 0;
3415 ch = dch;
3416 }
3417 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07003418 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07003419#if 0
3420 printf("ch='%c' 0x%x\n", ch, ch);
3421#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003422 }
3423
3424 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003425 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003426 }
3427
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003428 int decodeHex(int c) {
3429 if (isdigit(c)) {
3430 c -= '0';
3431 } else if (c <= 'F') {
3432 c = c - 'A' + 10;
3433 } else {
3434 c =c - 'a' + 10;
3435 }
3436 return c;
3437 }
3438
Jack Palevichb4758ff2009-06-12 12:49:14 -07003439 /* read a character constant, advances ch to after end of constant */
3440 int getq() {
3441 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003442 if (ch == '\\') {
3443 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003444 if (isoctal(ch)) {
3445 // 1 to 3 octal characters.
3446 val = 0;
3447 for(int i = 0; i < 3; i++) {
3448 if (isoctal(ch)) {
3449 val = (val << 3) + ch - '0';
3450 inp();
3451 }
3452 }
3453 return val;
3454 } else if (ch == 'x' || ch == 'X') {
3455 // N hex chars
3456 inp();
3457 if (! isxdigit(ch)) {
3458 error("'x' character escape requires at least one digit.");
3459 } else {
3460 val = 0;
3461 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003462 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003463 inp();
3464 }
3465 }
3466 } else {
3467 int val = ch;
3468 switch (ch) {
3469 case 'a':
3470 val = '\a';
3471 break;
3472 case 'b':
3473 val = '\b';
3474 break;
3475 case 'f':
3476 val = '\f';
3477 break;
3478 case 'n':
3479 val = '\n';
3480 break;
3481 case 'r':
3482 val = '\r';
3483 break;
3484 case 't':
3485 val = '\t';
3486 break;
3487 case 'v':
3488 val = '\v';
3489 break;
3490 case '\\':
3491 val = '\\';
3492 break;
3493 case '\'':
3494 val = '\'';
3495 break;
3496 case '"':
3497 val = '"';
3498 break;
3499 case '?':
3500 val = '?';
3501 break;
3502 default:
3503 error("Undefined character escape %c", ch);
3504 break;
3505 }
3506 inp();
3507 return val;
3508 }
3509 } else {
3510 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003511 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003512 return val;
3513 }
3514
3515 static bool isoctal(int ch) {
3516 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003517 }
3518
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003519 bool acceptCh(int c) {
3520 bool result = c == ch;
3521 if (result) {
3522 pdef(ch);
3523 inp();
3524 }
3525 return result;
3526 }
3527
3528 bool acceptDigitsCh() {
3529 bool result = false;
3530 while (isdigit(ch)) {
3531 result = true;
3532 pdef(ch);
3533 inp();
3534 }
3535 return result;
3536 }
3537
3538 void parseFloat() {
3539 tok = TOK_NUM_DOUBLE;
3540 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003541 if(mTokenString.len() == 0) {
3542 mTokenString.append('0');
3543 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003544 acceptCh('.');
3545 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003546 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003547 acceptCh('-') || acceptCh('+');
3548 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003549 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003550 if (ch == 'f' || ch == 'F') {
3551 tok = TOK_NUM_FLOAT;
3552 inp();
3553 } else if (ch == 'l' || ch == 'L') {
3554 inp();
3555 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003556 }
3557 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003558 char* pEnd = pText + strlen(pText);
3559 char* pEndPtr = 0;
3560 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003561 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003562 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003563 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003564 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003565 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003566 if (errno || pEndPtr != pEnd) {
3567 error("Can't parse constant: %s", pText);
3568 }
3569 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003570 }
3571
Jack Palevich21a15a22009-05-11 14:49:29 -07003572 void next() {
3573 int l, a;
3574
Jack Palevich546b2242009-05-13 15:10:04 -07003575 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003576 if (ch == '#') {
3577 inp();
3578 next();
3579 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003580 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003581 } else if (tok == TOK_PRAGMA) {
3582 doPragma();
3583 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003584 error("Unsupported preprocessor directive \"%s\"",
3585 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003586 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003587 }
3588 inp();
3589 }
3590 tokl = 0;
3591 tok = ch;
3592 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003593 if (isdigit(ch) || ch == '.') {
3594 // Start of a numeric constant. Could be integer, float, or
3595 // double, won't know until we look further.
3596 mTokenString.clear();
3597 pdef(ch);
3598 inp();
3599 int base = 10;
3600 if (tok == '0') {
3601 if (ch == 'x' || ch == 'X') {
3602 base = 16;
3603 tok = TOK_NUM;
3604 tokc = 0;
3605 inp();
3606 while ( isxdigit(ch) ) {
3607 tokc = (tokc << 4) + decodeHex(ch);
3608 inp();
3609 }
3610 } else if (isoctal(ch)){
3611 base = 8;
3612 tok = TOK_NUM;
3613 tokc = 0;
3614 while ( isoctal(ch) ) {
3615 tokc = (tokc << 3) + (ch - '0');
3616 inp();
3617 }
3618 }
3619 } else if (isdigit(tok)){
3620 acceptDigitsCh();
3621 }
3622 if (base == 10) {
3623 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3624 parseFloat();
3625 } else {
3626 // It's an integer constant
3627 char* pText = mTokenString.getUnwrapped();
3628 char* pEnd = pText + strlen(pText);
3629 char* pEndPtr = 0;
3630 errno = 0;
3631 tokc = strtol(pText, &pEndPtr, base);
3632 if (errno || pEndPtr != pEnd) {
3633 error("Can't parse constant: %s %d %d", pText, base, errno);
3634 }
3635 tok = TOK_NUM;
3636 }
3637 }
3638 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003639 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003640 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003641 pdef(ch);
3642 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003643 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003644 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3645 // Is this a macro?
3646 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3647 if (pMacroDefinition) {
3648 // Yes, it is a macro
3649 dptr = pMacroDefinition;
3650 dch = ch;
3651 inp();
3652 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003653 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003654 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003655 inp();
3656 if (tok == '\'') {
3657 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003658 tokc = getq();
3659 if (ch != '\'') {
3660 error("Expected a ' character, got %c", ch);
3661 } else {
3662 inp();
3663 }
Jack Palevich546b2242009-05-13 15:10:04 -07003664 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003665 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003666 while (ch && ch != EOF) {
3667 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003668 inp();
3669 inp();
3670 if (ch == '/')
3671 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003672 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003673 if (ch == EOF) {
3674 error("End of file inside comment.");
3675 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003676 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003677 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003678 } else if ((tok == '/') & (ch == '/')) {
3679 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003680 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003681 inp();
3682 }
3683 inp();
3684 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003685 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003686 const char* t = operatorChars;
3687 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003688 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003689 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003690 tokl = operatorLevel[opIndex];
3691 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003692 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003693#if 0
3694 printf("%c%c -> tokl=%d tokc=0x%x\n",
3695 l, a, tokl, tokc);
3696#endif
3697 if (a == ch) {
3698 inp();
3699 tok = TOK_DUMMY; /* dummy token for double tokens */
3700 }
3701 break;
3702 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003703 opIndex++;
3704 }
3705 if (l == 0) {
3706 tokl = 0;
3707 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003708 }
3709 }
3710 }
3711#if 0
3712 {
Jack Palevich569f1352009-06-29 14:29:08 -07003713 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003714 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003715 fprintf(stderr, "%s\n", buf.getUnwrapped());
3716 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003717#endif
3718 }
3719
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003720 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003721 next();
3722 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003723 String* pName = new String();
3724 while (isspace(ch)) {
3725 inp();
3726 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003727 if (ch == '(') {
3728 delete pName;
3729 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003730 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003731 }
3732 while (isspace(ch)) {
3733 inp();
3734 }
Jack Palevich569f1352009-06-29 14:29:08 -07003735 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003736 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003737 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003738 inp();
3739 }
Jack Palevich569f1352009-06-29 14:29:08 -07003740 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3741 memcpy(pDefn, value.getUnwrapped(), value.len());
3742 pDefn[value.len()] = 0;
3743 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003744 }
3745
Jack Palevicheedf9d22009-06-04 16:23:40 -07003746 void doPragma() {
3747 // # pragma name(val)
3748 int state = 0;
3749 while(ch != EOF && ch != '\n' && state < 10) {
3750 switch(state) {
3751 case 0:
3752 if (isspace(ch)) {
3753 inp();
3754 } else {
3755 state++;
3756 }
3757 break;
3758 case 1:
3759 if (isalnum(ch)) {
3760 mPragmas.append(ch);
3761 inp();
3762 } else if (ch == '(') {
3763 mPragmas.append(0);
3764 inp();
3765 state++;
3766 } else {
3767 state = 11;
3768 }
3769 break;
3770 case 2:
3771 if (isalnum(ch)) {
3772 mPragmas.append(ch);
3773 inp();
3774 } else if (ch == ')') {
3775 mPragmas.append(0);
3776 inp();
3777 state = 10;
3778 } else {
3779 state = 11;
3780 }
3781 break;
3782 }
3783 }
3784 if(state != 10) {
3785 error("Unexpected pragma syntax");
3786 }
3787 mPragmaStringCount += 2;
3788 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003789
Jack Palevichac0e95e2009-05-29 13:53:44 -07003790 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003791 mErrorBuf.printf("%ld: ", file->getLine());
3792 mErrorBuf.vprintf(fmt, ap);
3793 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003794 }
3795
Jack Palevich8b0624c2009-05-20 12:12:06 -07003796 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003797 if (tok != c) {
3798 error("'%c' expected", c);
3799 }
3800 next();
3801 }
3802
Jack Palevich86351982009-06-30 18:09:56 -07003803 bool accept(intptr_t c) {
3804 if (tok == c) {
3805 next();
3806 return true;
3807 }
3808 return false;
3809 }
3810
Jack Palevich40600de2009-07-01 15:32:35 -07003811 bool acceptStringLiteral() {
3812 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003813 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003814 // This while loop merges multiple adjacent string constants.
3815 while (tok == '"') {
3816 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003817 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003818 }
3819 if (ch != '"') {
3820 error("Unterminated string constant.");
3821 }
3822 inp();
3823 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003824 }
Jack Palevich40600de2009-07-01 15:32:35 -07003825 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003826 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003827 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003828 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003829
3830 return true;
3831 }
3832 return false;
3833 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003834
Jack Palevichb1544ca2009-07-16 15:09:20 -07003835 void linkGlobal(tokenid_t t, bool isFunction) {
3836 VariableInfo* pVI = VI(t);
3837 void* n = NULL;
3838 if (mpSymbolLookupFn) {
3839 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3840 }
3841 if (pVI->pType == NULL) {
3842 if (isFunction) {
3843 pVI->pType = mkpIntFn;
3844 } else {
3845 pVI->pType = mkpInt;
3846 }
3847 }
3848 pVI->pAddress = n;
3849 }
3850
Jack Palevich40600de2009-07-01 15:32:35 -07003851 /* Parse and evaluate a unary expression.
3852 * allowAssignment is true if '=' parsing wanted (quick hack)
3853 */
3854 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003855 tokenid_t t;
3856 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003857 t = 0;
3858 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3859 if (acceptStringLiteral()) {
3860 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003861 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003862 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003863 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003864 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003865 t = tok;
3866 next();
3867 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003868 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003869 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003870 // Align to 4-byte boundary
3871 glo = (char*) (((intptr_t) glo + 3) & -4);
3872 * (float*) glo = (float) ad;
3873 pGen->loadFloat((int) glo, mkpFloat);
3874 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003875 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003876 // Align to 8-byte boundary
3877 glo = (char*) (((intptr_t) glo + 7) & -8);
3878 * (double*) glo = ad;
3879 pGen->loadFloat((int) glo, mkpDouble);
3880 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003881 } else if (c == 2) {
3882 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003883 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003884 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003885 pGen->gUnaryCmp(a, mkpInt);
3886 else if (t == '+') {
3887 // ignore unary plus.
3888 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003889 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003890 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003891 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003892 // It's either a cast or an expression
3893 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3894 if (pCast) {
3895 skip(')');
3896 unary(false);
3897 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003898 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003899 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003900 skip(')');
3901 }
3902 } else if (t == '*') {
3903 /* This is a pointer dereference.
3904 */
3905 unary(false);
3906 Type* pR0Type = pGen->getR0Type();
3907 if (pR0Type->tag != TY_POINTER) {
3908 error("Expected a pointer type.");
3909 } else {
3910 if (pR0Type->pHead->tag == TY_FUNC) {
3911 t = 0;
3912 }
3913 if (accept('=')) {
3914 pGen->pushR0();
3915 expr();
3916 pGen->storeR0ToTOS(pR0Type);
3917 } else if (t) {
3918 pGen->loadR0FromR0(pR0Type);
3919 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003920 }
Jack Palevich3f226492009-07-02 14:46:19 -07003921 // Else we fall through to the function call below, with
3922 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003923 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003924 VariableInfo* pVI = VI(tok);
3925 pGen->leaR0((int) pVI->pAddress,
3926 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003927 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003928 } else if (t == EOF ) {
3929 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003930 } else if (t == ';') {
3931 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003932 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003933 // Don't have to do anything special here, the error
3934 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003935 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003936 if (!isDefined(t)) {
3937 mGlobals.add(t);
3938 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003939 }
Jack Palevich8df46192009-07-07 14:48:51 -07003940 VariableInfo* pVI = VI(t);
3941 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003942 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003943 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003944 linkGlobal(t, tok == '(');
3945 n = (intptr_t) pVI->pAddress;
3946 if (!n && tok != '(') {
3947 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003948 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003949 }
Jack Palevich40600de2009-07-01 15:32:35 -07003950 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003951 /* assignment */
3952 next();
3953 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003954 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003955 } else if (tok != '(') {
3956 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003957 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003958 linkGlobal(t, false);
3959 n = (intptr_t) pVI->pAddress;
3960 if (!n) {
3961 error("Undeclared variable %s\n", nameof(t));
3962 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003963 }
Jack Palevich8df46192009-07-07 14:48:51 -07003964 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003965 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003966 next();
3967 }
3968 }
3969 }
3970 }
3971
3972 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003973 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003974 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003975 VariableInfo* pVI = NULL;
3976 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003977 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003978 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003979 } else {
3980 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003981 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003982 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003983 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003984 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003985 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003986 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003987 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003988 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003989 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003990 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07003991 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07003992 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003993 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003994 Type* pTargetType;
3995 if (pArgList) {
3996 pTargetType = pArgList->pHead;
3997 pArgList = pArgList->pTail;
3998 } else {
3999 pTargetType = pGen->getR0Type();
4000 if (pTargetType->tag == TY_FLOAT) {
4001 pTargetType = mkpDouble;
4002 }
4003 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004004 if (pTargetType->tag == TY_VOID) {
4005 error("Can't pass void value for argument %d",
4006 argCount + 1);
4007 } else {
4008 pGen->convertR0(pTargetType);
4009 l += pGen->storeR0ToArg(l);
4010 }
Jack Palevich95727a02009-07-06 12:07:15 -07004011 if (accept(',')) {
4012 // fine
4013 } else if ( tok != ')') {
4014 error("Expected ',' or ')'");
4015 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004016 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004017 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004018 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004019 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004020 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004021 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004022 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004023 if (!n) {
4024 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004025 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4026 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004027 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004028 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004029 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004030 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4031 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004032 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004033 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004034 }
4035 }
4036
Jack Palevich40600de2009-07-01 15:32:35 -07004037 /* Recursive descent parser for binary operations.
4038 */
4039 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004040 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004041 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004042 if (level-- == 1)
4043 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004044 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004045 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004046 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004047 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004048 t = tokc;
4049 next();
4050
Jack Palevich40600de2009-07-01 15:32:35 -07004051 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004052 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004053 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004054 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004055 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004056 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004057 // Check for syntax error.
4058 if (pGen->getR0Type() == NULL) {
4059 // We failed to parse a right-hand argument.
4060 // Push a dummy value so we don't fail
4061 pGen->li(0, mkpInt);
4062 }
Jack Palevich40600de2009-07-01 15:32:35 -07004063 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004064 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004065 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004066 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004067 }
4068 }
4069 }
4070 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004071 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004072 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004073 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004074 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004075 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004076 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004077 }
4078 }
4079 }
4080
4081 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004082 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004083 }
4084
4085 int test_expr() {
4086 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004087 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004088 }
4089
Jack Palevicha6baa232009-06-12 11:25:59 -07004090 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004091 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004092
Jack Palevich95727a02009-07-06 12:07:15 -07004093 Type* pBaseType;
4094 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004095 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004096 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004097 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004098 next();
4099 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004100 a = test_expr();
4101 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004102 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004103 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004104 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004105 n = pGen->gjmp(0); /* jmp */
4106 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004107 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004108 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004109 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004110 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004111 }
Jack Palevich546b2242009-05-13 15:10:04 -07004112 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004113 t = tok;
4114 next();
4115 skip('(');
4116 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004117 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004118 a = test_expr();
4119 } else {
4120 if (tok != ';')
4121 expr();
4122 skip(';');
4123 n = codeBuf.getPC();
4124 a = 0;
4125 if (tok != ';')
4126 a = test_expr();
4127 skip(';');
4128 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004129 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004130 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004131 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004132 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004133 n = t + 4;
4134 }
4135 }
4136 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004137 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004138 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004139 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004140 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004141 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004142 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004143 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004144 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004145 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004146 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004147 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004148 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004149 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004150 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004151 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004152 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004153 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004154 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004155 if (pReturnType->tag == TY_VOID) {
4156 error("Must not return a value from a void function");
4157 } else {
4158 pGen->convertR0(pReturnType);
4159 }
4160 } else {
4161 if (pReturnType->tag != TY_VOID) {
4162 error("Must specify a value here");
4163 }
Jack Palevich8df46192009-07-07 14:48:51 -07004164 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004165 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004166 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004167 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004168 } else if (tok != ';')
4169 expr();
4170 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004171 }
4172 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004173
Jack Palevicha8f427f2009-07-13 18:40:08 -07004174 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004175 if (a == b) {
4176 return true;
4177 }
4178 if (a == NULL || b == NULL) {
4179 return false;
4180 }
4181 TypeTag at = a->tag;
4182 if (at != b->tag) {
4183 return false;
4184 }
4185 if (at == TY_POINTER) {
4186 return typeEqual(a->pHead, b->pHead);
4187 } else if (at == TY_FUNC || at == TY_PARAM) {
4188 return typeEqual(a->pHead, b->pHead)
4189 && typeEqual(a->pTail, b->pTail);
4190 }
4191 return true;
4192 }
4193
Jack Palevich86351982009-06-30 18:09:56 -07004194 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4195 assert(tag >= TY_INT && tag <= TY_PARAM);
4196 Type* pType = (Type*) arena.alloc(sizeof(Type));
4197 memset(pType, 0, sizeof(*pType));
4198 pType->tag = tag;
4199 pType->pHead = pHead;
4200 pType->pTail = pTail;
4201 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004202 }
4203
Jack Palevich3f226492009-07-02 14:46:19 -07004204 Type* createPtrType(Type* pType, Arena& arena) {
4205 return createType(TY_POINTER, pType, NULL, arena);
4206 }
4207
4208 /**
4209 * Try to print a type in declaration order
4210 */
Jack Palevich86351982009-06-30 18:09:56 -07004211 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004212 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004213 if (pType == NULL) {
4214 buffer.appendCStr("null");
4215 return;
4216 }
Jack Palevich3f226492009-07-02 14:46:19 -07004217 decodeTypeImp(buffer, pType);
4218 }
4219
4220 void decodeTypeImp(String& buffer, Type* pType) {
4221 decodeTypeImpPrefix(buffer, pType);
4222
Jack Palevich86351982009-06-30 18:09:56 -07004223 String temp;
4224 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004225 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004226 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004227 }
4228
4229 decodeTypeImpPostfix(buffer, pType);
4230 }
4231
4232 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4233 TypeTag tag = pType->tag;
4234
Jack Palevich37c54bd2009-07-14 18:35:36 -07004235 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004236 switch (tag) {
4237 case TY_INT:
4238 buffer.appendCStr("int");
4239 break;
4240 case TY_CHAR:
4241 buffer.appendCStr("char");
4242 break;
4243 case TY_VOID:
4244 buffer.appendCStr("void");
4245 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004246 case TY_FLOAT:
4247 buffer.appendCStr("float");
4248 break;
4249 case TY_DOUBLE:
4250 buffer.appendCStr("double");
4251 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004252 default:
4253 break;
4254 }
Jack Palevich86351982009-06-30 18:09:56 -07004255 buffer.append(' ');
4256 }
Jack Palevich3f226492009-07-02 14:46:19 -07004257
4258 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004259 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004260 break;
4261 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004262 break;
4263 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004264 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004265 case TY_FLOAT:
4266 break;
4267 case TY_DOUBLE:
4268 break;
Jack Palevich86351982009-06-30 18:09:56 -07004269 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004270 decodeTypeImpPrefix(buffer, pType->pHead);
4271 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4272 buffer.append('(');
4273 }
4274 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004275 break;
4276 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004277 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004278 break;
4279 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004280 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004281 break;
4282 default:
4283 String temp;
4284 temp.printf("Unknown tag %d", pType->tag);
4285 buffer.append(temp);
4286 break;
4287 }
Jack Palevich3f226492009-07-02 14:46:19 -07004288 }
4289
4290 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4291 TypeTag tag = pType->tag;
4292
4293 switch(tag) {
4294 case TY_POINTER:
4295 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4296 buffer.append(')');
4297 }
4298 decodeTypeImpPostfix(buffer, pType->pHead);
4299 break;
4300 case TY_FUNC:
4301 buffer.append('(');
4302 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4303 decodeTypeImp(buffer, pArg);
4304 if (pArg->pTail) {
4305 buffer.appendCStr(", ");
4306 }
4307 }
4308 buffer.append(')');
4309 break;
4310 default:
4311 break;
Jack Palevich86351982009-06-30 18:09:56 -07004312 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004313 }
4314
Jack Palevich86351982009-06-30 18:09:56 -07004315 void printType(Type* pType) {
4316 String buffer;
4317 decodeType(buffer, pType);
4318 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004319 }
4320
Jack Palevich86351982009-06-30 18:09:56 -07004321 Type* acceptPrimitiveType(Arena& arena) {
4322 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004323 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004324 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004325 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004326 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004327 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004328 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004329 } else if (tok == TOK_FLOAT) {
4330 pType = mkpFloat;
4331 } else if (tok == TOK_DOUBLE) {
4332 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004333 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004334 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004335 }
4336 next();
Jack Palevich86351982009-06-30 18:09:56 -07004337 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004338 }
4339
Jack Palevich3f226492009-07-02 14:46:19 -07004340 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4341 Arena& arena) {
4342 tokenid_t declName = 0;
4343 pType = acceptDecl2(pType, declName, nameAllowed,
4344 nameRequired, arena);
4345 if (declName) {
4346 // Clone the parent type so we can set a unique ID
4347 pType = createType(pType->tag, pType->pHead,
4348 pType->pTail, arena);
4349
Jack Palevich86351982009-06-30 18:09:56 -07004350 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004351 }
Jack Palevich3f226492009-07-02 14:46:19 -07004352 // fprintf(stderr, "Parsed a declaration: ");
4353 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004354 return pType;
4355 }
4356
Jack Palevich3f226492009-07-02 14:46:19 -07004357 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4358 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004359 if (! pType) {
4360 error("Expected a declaration");
4361 }
4362 return pType;
4363 }
4364
Jack Palevich3f226492009-07-02 14:46:19 -07004365 /* Used for accepting types that appear in casts */
4366 Type* acceptCastTypeDeclaration(Arena& arena) {
4367 Type* pType = acceptPrimitiveType(arena);
4368 if (pType) {
4369 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004370 }
Jack Palevich86351982009-06-30 18:09:56 -07004371 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004372 }
4373
Jack Palevich3f226492009-07-02 14:46:19 -07004374 Type* expectCastTypeDeclaration(Arena& arena) {
4375 Type* pType = acceptCastTypeDeclaration(arena);
4376 if (! pType) {
4377 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004378 }
Jack Palevich3f226492009-07-02 14:46:19 -07004379 return pType;
4380 }
4381
4382 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4383 bool nameAllowed, bool nameRequired, Arena& arena) {
4384 int ptrCounter = 0;
4385 while (accept('*')) {
4386 ptrCounter++;
4387 }
4388 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4389 while (ptrCounter-- > 0) {
4390 pType = createType(TY_POINTER, pType, NULL, arena);
4391 }
4392 return pType;
4393 }
4394
4395 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4396 bool nameAllowed, bool nameRequired, Arena& arena) {
4397 // direct-dcl :
4398 // name
4399 // (dcl)
4400 // direct-dcl()
4401 // direct-dcl[]
4402 Type* pNewHead = NULL;
4403 if (accept('(')) {
4404 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4405 nameRequired, arena);
4406 skip(')');
4407 } else if ((declName = acceptSymbol()) != 0) {
4408 if (nameAllowed == false && declName) {
4409 error("Symbol %s not allowed here", nameof(declName));
4410 } else if (nameRequired && ! declName) {
4411 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004412 decodeToken(temp, tok, true);
Jack Palevich3f226492009-07-02 14:46:19 -07004413 error("Expected symbol. Got %s", temp.getUnwrapped());
4414 }
4415 }
4416 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004417 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004418 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004419 pType = createType(TY_FUNC, pType, pTail, arena);
4420 skip(')');
4421 }
Jack Palevich3f226492009-07-02 14:46:19 -07004422
4423 if (pNewHead) {
4424 Type* pA = pNewHead;
4425 while (pA->pHead) {
4426 pA = pA->pHead;
4427 }
4428 pA->pHead = pType;
4429 pType = pNewHead;
4430 }
Jack Palevich86351982009-06-30 18:09:56 -07004431 return pType;
4432 }
4433
Jack Palevich3f226492009-07-02 14:46:19 -07004434 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004435 Type* pHead = NULL;
4436 Type* pTail = NULL;
4437 for(;;) {
4438 Type* pBaseArg = acceptPrimitiveType(arena);
4439 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004440 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4441 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004442 if (pArg) {
4443 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4444 if (!pHead) {
4445 pHead = pParam;
4446 pTail = pParam;
4447 } else {
4448 pTail->pTail = pParam;
4449 pTail = pParam;
4450 }
4451 }
4452 }
4453 if (! accept(',')) {
4454 break;
4455 }
4456 }
4457 return pHead;
4458 }
4459
4460 Type* expectPrimitiveType(Arena& arena) {
4461 Type* pType = acceptPrimitiveType(arena);
4462 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004463 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004464 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004465 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004466 }
Jack Palevich86351982009-06-30 18:09:56 -07004467 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004468 }
4469
Jack Palevich86351982009-06-30 18:09:56 -07004470 void addGlobalSymbol(Type* pDecl) {
4471 tokenid_t t = pDecl->id;
4472 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004473 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004474 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004475 }
Jack Palevich86351982009-06-30 18:09:56 -07004476 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004477 }
4478
Jack Palevich86351982009-06-30 18:09:56 -07004479 void reportDuplicate(tokenid_t t) {
4480 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004481 }
4482
Jack Palevich86351982009-06-30 18:09:56 -07004483 void addLocalSymbol(Type* pDecl) {
4484 tokenid_t t = pDecl->id;
4485 if (mLocals.isDefinedAtCurrentLevel(t)) {
4486 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004487 }
Jack Palevich86351982009-06-30 18:09:56 -07004488 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004489 }
4490
Jack Palevich95727a02009-07-06 12:07:15 -07004491 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004492 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004493
Jack Palevich95727a02009-07-06 12:07:15 -07004494 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004495 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004496 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4497 if (!pDecl) {
4498 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004499 }
Jack Palevich86351982009-06-30 18:09:56 -07004500 int variableAddress = 0;
4501 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004502 size_t alignment = pGen->alignmentOf(pDecl);
4503 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004504 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004505 variableAddress = -loc;
4506 VI(pDecl->id)->pAddress = (void*) variableAddress;
4507 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004508 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004509 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004510 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004511 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004512 if (tok == ',')
4513 next();
4514 }
4515 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004516 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004517 }
4518 }
4519
Jack Palevichf1728be2009-06-12 13:53:51 -07004520 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004521 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004522 }
4523
Jack Palevich37c54bd2009-07-14 18:35:36 -07004524 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004525 if (token == EOF ) {
4526 buffer.printf("EOF");
4527 } else if (token == TOK_NUM) {
4528 buffer.printf("numeric constant");
4529 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004530 if (token < 32) {
4531 buffer.printf("'\\x%02x'", token);
4532 } else {
4533 buffer.printf("'%c'", token);
4534 }
Jack Palevich569f1352009-06-29 14:29:08 -07004535 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004536 if (quote) {
4537 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4538 buffer.printf("keyword \"%s\"", nameof(token));
4539 } else {
4540 buffer.printf("symbol \"%s\"", nameof(token));
4541 }
4542 } else {
4543 buffer.printf("%s", nameof(token));
4544 }
Jack Palevich569f1352009-06-29 14:29:08 -07004545 }
4546 }
4547
Jack Palevich40600de2009-07-01 15:32:35 -07004548 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004549 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004550 if (!result) {
4551 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004552 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004553 error("Expected symbol. Got %s", temp.getUnwrapped());
4554 }
4555 return result;
4556 }
4557
Jack Palevich86351982009-06-30 18:09:56 -07004558 tokenid_t acceptSymbol() {
4559 tokenid_t result = 0;
4560 if (tok >= TOK_SYMBOL) {
4561 result = tok;
4562 next();
Jack Palevich86351982009-06-30 18:09:56 -07004563 }
4564 return result;
4565 }
4566
Jack Palevichb7c81e92009-06-04 19:56:13 -07004567 void globalDeclarations() {
4568 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004569 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4570 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004571 break;
4572 }
Jack Palevich86351982009-06-30 18:09:56 -07004573 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4574 if (!pDecl) {
4575 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004576 }
Jack Palevich86351982009-06-30 18:09:56 -07004577 if (! isDefined(pDecl->id)) {
4578 addGlobalSymbol(pDecl);
4579 }
4580 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004581 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004582 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004583 }
Jack Palevich86351982009-06-30 18:09:56 -07004584 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004585 // it's a variable declaration
4586 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004587 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004588 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004589 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004590 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004591 }
Jack Palevich86351982009-06-30 18:09:56 -07004592 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004593 if (tok == TOK_NUM) {
4594 if (name) {
4595 * (int*) name->pAddress = tokc;
4596 }
4597 next();
4598 } else {
4599 error("Expected an integer constant");
4600 }
4601 }
Jack Palevich86351982009-06-30 18:09:56 -07004602 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004603 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004604 }
Jack Palevich86351982009-06-30 18:09:56 -07004605 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4606 if (!pDecl) {
4607 break;
4608 }
4609 if (! isDefined(pDecl->id)) {
4610 addGlobalSymbol(pDecl);
4611 }
4612 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004613 }
4614 skip(';');
4615 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004616 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004617 if (accept(';')) {
4618 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004619 } else if (tok != '{') {
4620 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004621 } else {
4622 if (name) {
4623 /* patch forward references (XXX: does not work for function
4624 pointers) */
4625 pGen->gsym((int) name->pForward);
4626 /* put function address */
4627 name->pAddress = (void*) codeBuf.getPC();
4628 }
4629 // Calculate stack offsets for parameters
4630 mLocals.pushLevel();
4631 intptr_t a = 8;
4632 int argCount = 0;
4633 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4634 Type* pArg = pP->pHead;
4635 addLocalSymbol(pArg);
4636 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004637 size_t alignment = pGen->alignmentOf(pArg);
4638 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004639 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004640 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004641 argCount++;
4642 }
4643 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004644 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004645 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004646 block(0, true);
4647 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004648 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004649 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004650 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004651 }
4652 }
4653 }
4654
Jack Palevich9cbd2262009-07-08 16:48:41 -07004655 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4656 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4657 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004658 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004659 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004660 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004661 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004662 char* result = (char*) base;
4663 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004664 return result;
4665 }
4666
Jack Palevich21a15a22009-05-11 14:49:29 -07004667 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004668 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004669 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004670 pGlobalBase = 0;
4671 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004672 if (pGen) {
4673 delete pGen;
4674 pGen = 0;
4675 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004676 if (file) {
4677 delete file;
4678 file = 0;
4679 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004680 }
4681
Jack Palevich8c246a92009-07-14 21:14:10 -07004682 // One-time initialization, when class is constructed.
4683 void init() {
4684 mpSymbolLookupFn = 0;
4685 mpSymbolLookupContext = 0;
4686 }
4687
Jack Palevich21a15a22009-05-11 14:49:29 -07004688 void clear() {
4689 tok = 0;
4690 tokc = 0;
4691 tokl = 0;
4692 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004693 rsym = 0;
4694 loc = 0;
4695 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004696 dptr = 0;
4697 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004698 file = 0;
4699 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004700 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004701 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004702 mCompileResult = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004703 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004704
Jack Palevich22305132009-05-13 10:58:45 -07004705 void setArchitecture(const char* architecture) {
4706 delete pGen;
4707 pGen = 0;
4708
4709 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004710#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004711 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004712 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004713 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004714#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004715#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004716 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004717 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004718 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004719#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004720 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004721 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004722 }
4723 }
4724
4725 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004726#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004727 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004728#elif defined(DEFAULT_X86_CODEGEN)
4729 pGen = new X86CodeGenerator();
4730#endif
4731 }
4732 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004733 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004734 } else {
4735 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004736 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004737 }
4738 }
4739
Jack Palevich77ae76e2009-05-10 19:59:24 -07004740public:
Jack Palevich22305132009-05-13 10:58:45 -07004741 struct args {
4742 args() {
4743 architecture = 0;
4744 }
4745 const char* architecture;
4746 };
4747
Jack Paleviche7b59062009-05-19 17:12:17 -07004748 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004749 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004750 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004751 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004752
Jack Paleviche7b59062009-05-19 17:12:17 -07004753 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004754 cleanup();
4755 }
4756
Jack Palevich8c246a92009-07-14 21:14:10 -07004757 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4758 mpSymbolLookupFn = pFn;
4759 mpSymbolLookupContext = pContext;
4760 }
4761
Jack Palevich1cdef202009-05-22 12:06:27 -07004762 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004763 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004764
Jack Palevicha8f427f2009-07-13 18:40:08 -07004765 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004766 cleanup();
4767 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004768 mTokenTable.setArena(&mGlobalArena);
4769 mGlobals.setArena(&mGlobalArena);
4770 mGlobals.setTokenTable(&mTokenTable);
4771 mLocals.setArena(&mLocalArena);
4772 mLocals.setTokenTable(&mTokenTable);
4773
4774 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004775 codeBuf.init(ALLOC_SIZE);
4776 setArchitecture(NULL);
4777 if (!pGen) {
4778 return -1;
4779 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004780#ifdef PROVIDE_TRACE_CODEGEN
4781 pGen = new TraceCodeGenerator(pGen);
4782#endif
4783 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004784 pGen->init(&codeBuf);
4785 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004786 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4787 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004788 inp();
4789 next();
4790 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004791 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004792 result = pGen->finishCompile();
4793 if (result == 0) {
4794 if (mErrorBuf.len()) {
4795 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004796 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004797 }
Jack Palevichce105a92009-07-16 14:30:33 -07004798 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004799 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004800 }
4801
Jack Palevich86351982009-06-30 18:09:56 -07004802 void createPrimitiveTypes() {
4803 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4804 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4805 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004806 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4807 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004808 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004809 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4810 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004811 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4812 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004813 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004814 }
4815
Jack Palevicha6baa232009-06-12 11:25:59 -07004816 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004817 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004818 }
4819
Jack Palevich569f1352009-06-29 14:29:08 -07004820 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004821 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004822 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004823 }
4824
Jack Palevich569f1352009-06-29 14:29:08 -07004825 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004826 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004827 error("Undefined forward reference: %s",
4828 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004829 }
4830 return true;
4831 }
4832
Jack Palevich21a15a22009-05-11 14:49:29 -07004833 int dump(FILE* out) {
4834 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4835 return 0;
4836 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004837
Jack Palevicha6535612009-05-13 16:24:17 -07004838 int disassemble(FILE* out) {
4839 return pGen->disassemble(out);
4840 }
4841
Jack Palevich1cdef202009-05-22 12:06:27 -07004842 /* Look through the symbol table to find a symbol.
4843 * If found, return its value.
4844 */
4845 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004846 if (mCompileResult == 0) {
4847 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4848 VariableInfo* pVariableInfo = VI(tok);
4849 if (pVariableInfo) {
4850 return pVariableInfo->pAddress;
4851 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004852 }
4853 return NULL;
4854 }
4855
Jack Palevicheedf9d22009-06-04 16:23:40 -07004856 void getPragmas(ACCsizei* actualStringCount,
4857 ACCsizei maxStringCount, ACCchar** strings) {
4858 int stringCount = mPragmaStringCount;
4859 if (actualStringCount) {
4860 *actualStringCount = stringCount;
4861 }
4862 if (stringCount > maxStringCount) {
4863 stringCount = maxStringCount;
4864 }
4865 if (strings) {
4866 char* pPragmas = mPragmas.getUnwrapped();
4867 while (stringCount-- > 0) {
4868 *strings++ = pPragmas;
4869 pPragmas += strlen(pPragmas) + 1;
4870 }
4871 }
4872 }
4873
Jack Palevichac0e95e2009-05-29 13:53:44 -07004874 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004875 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004876 }
4877
Jack Palevich77ae76e2009-05-10 19:59:24 -07004878};
4879
Jack Paleviche7b59062009-05-19 17:12:17 -07004880const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004881 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4882
Jack Paleviche7b59062009-05-19 17:12:17 -07004883const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004884 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4885 5, 5, /* ==, != */
4886 9, 10, /* &&, || */
4887 6, 7, 8, /* & ^ | */
4888 2, 2 /* ~ ! */
4889 };
4890
Jack Palevich8b0624c2009-05-20 12:12:06 -07004891#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004892FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004893#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004894
Jack Palevich8b0624c2009-05-20 12:12:06 -07004895#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004896const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004897 0x1, // ++
4898 0xff, // --
4899 0xc1af0f, // *
4900 0xf9f79991, // /
4901 0xf9f79991, // % (With manual assist to swap results)
4902 0xc801, // +
4903 0xd8f7c829, // -
4904 0xe0d391, // <<
4905 0xf8d391, // >>
4906 0xe, // <=
4907 0xd, // >=
4908 0xc, // <
4909 0xf, // >
4910 0x4, // ==
4911 0x5, // !=
4912 0x0, // &&
4913 0x1, // ||
4914 0xc821, // &
4915 0xc831, // ^
4916 0xc809, // |
4917 0xd0f7, // ~
4918 0x4 // !
4919};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004920#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004921
Jack Palevich1cdef202009-05-22 12:06:27 -07004922struct ACCscript {
4923 ACCscript() {
4924 text = 0;
4925 textLength = 0;
4926 accError = ACC_NO_ERROR;
4927 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004928
Jack Palevich1cdef202009-05-22 12:06:27 -07004929 ~ACCscript() {
4930 delete text;
4931 }
Jack Palevich546b2242009-05-13 15:10:04 -07004932
Jack Palevich8c246a92009-07-14 21:14:10 -07004933 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4934 compiler.registerSymbolCallback(pFn, pContext);
4935 }
4936
Jack Palevich1cdef202009-05-22 12:06:27 -07004937 void setError(ACCenum error) {
4938 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4939 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004940 }
4941 }
4942
Jack Palevich1cdef202009-05-22 12:06:27 -07004943 ACCenum getError() {
4944 ACCenum result = accError;
4945 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004946 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004947 }
4948
Jack Palevich1cdef202009-05-22 12:06:27 -07004949 Compiler compiler;
4950 char* text;
4951 int textLength;
4952 ACCenum accError;
4953};
4954
4955
4956extern "C"
4957ACCscript* accCreateScript() {
4958 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004959}
Jack Palevich1cdef202009-05-22 12:06:27 -07004960
4961extern "C"
4962ACCenum accGetError( ACCscript* script ) {
4963 return script->getError();
4964}
4965
4966extern "C"
4967void accDeleteScript(ACCscript* script) {
4968 delete script;
4969}
4970
4971extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004972void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4973 ACCvoid* pContext) {
4974 script->registerSymbolCallback(pFn, pContext);
4975}
4976
4977extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004978void accScriptSource(ACCscript* script,
4979 ACCsizei count,
4980 const ACCchar ** string,
4981 const ACCint * length) {
4982 int totalLength = 0;
4983 for(int i = 0; i < count; i++) {
4984 int len = -1;
4985 const ACCchar* s = string[i];
4986 if (length) {
4987 len = length[i];
4988 }
4989 if (len < 0) {
4990 len = strlen(s);
4991 }
4992 totalLength += len;
4993 }
4994 delete script->text;
4995 char* text = new char[totalLength + 1];
4996 script->text = text;
4997 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07004998 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07004999 for(int i = 0; i < count; i++) {
5000 int len = -1;
5001 const ACCchar* s = string[i];
5002 if (length) {
5003 len = length[i];
5004 }
5005 if (len < 0) {
5006 len = strlen(s);
5007 }
Jack Palevich09555c72009-05-27 12:25:55 -07005008 memcpy(dest, s, len);
5009 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005010 }
5011 text[totalLength] = '\0';
5012}
5013
5014extern "C"
5015void accCompileScript(ACCscript* script) {
5016 int result = script->compiler.compile(script->text, script->textLength);
5017 if (result) {
5018 script->setError(ACC_INVALID_OPERATION);
5019 }
5020}
5021
5022extern "C"
5023void accGetScriptiv(ACCscript* script,
5024 ACCenum pname,
5025 ACCint * params) {
5026 switch (pname) {
5027 case ACC_INFO_LOG_LENGTH:
5028 *params = 0;
5029 break;
5030 }
5031}
5032
5033extern "C"
5034void accGetScriptInfoLog(ACCscript* script,
5035 ACCsizei maxLength,
5036 ACCsizei * length,
5037 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005038 char* message = script->compiler.getErrorMessage();
5039 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005040 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005041 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005042 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005043 if (infoLog && maxLength > 0) {
5044 int trimmedLength = maxLength < messageLength ?
5045 maxLength : messageLength;
5046 memcpy(infoLog, message, trimmedLength);
5047 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005048 }
5049}
5050
5051extern "C"
5052void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5053 ACCvoid ** address) {
5054 void* value = script->compiler.lookup(name);
5055 if (value) {
5056 *address = value;
5057 } else {
5058 script->setError(ACC_INVALID_VALUE);
5059 }
5060}
5061
Jack Palevicheedf9d22009-06-04 16:23:40 -07005062extern "C"
5063void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5064 ACCsizei maxStringCount, ACCchar** strings){
5065 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5066}
5067
-b master422972c2009-06-17 19:13:52 -07005068extern "C"
5069void accDisassemble(ACCscript* script) {
5070 script->compiler.disassemble(stderr);
5071}
5072
Jack Palevicheedf9d22009-06-04 16:23:40 -07005073
Jack Palevich1cdef202009-05-22 12:06:27 -07005074} // namespace acc
5075