blob: 2a7d66ec52fce90c6b6cb6195586dc7fc32f780e [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 Palevich8148c5b2009-07-16 18:24:47 -0700394 virtual size_t storeR0ToArg(int l, Type* pArgType) = 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 Palevich8148c5b2009-07-16 18:24:47 -07001066 convertR0(pType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001067 TypeTag tag = pType->tag;
1068 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001069 case TY_CHAR:
1070 if (ea > -LOCAL && ea < LOCAL) {
1071 // Local, fp relative
1072 if (ea < -4095 || ea > 4095) {
1073 error("Offset out of range: %08x", ea);
1074 }
1075 if (ea < 0) {
1076 o4(0xE54B0000 | (0xfff & (-ea))); // strb r0, [fp,#-ea]
1077 } else {
1078 o4(0xE5CB0000 | (0xfff & ea)); // strb r0, [fp,#ea]
1079 }
1080 } else{
1081 // Global, absolute
1082 o4(0xE59F1000); // ldr r1, .L1
1083 o4(0xEA000000); // b .L99
1084 o4(ea); // .L1: .word 0
1085 o4(0xE5C10000); // .L99: strb r0, [r1]
1086 }
1087 break;
Jack Palevich45431bc2009-07-13 15:57:26 -07001088 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001089 case TY_INT:
1090 case TY_FLOAT:
1091 if (ea > -LOCAL && ea < LOCAL) {
1092 // Local, fp relative
1093 if (ea < -4095 || ea > 4095) {
1094 error("Offset out of range: %08x", ea);
1095 }
1096 if (ea < 0) {
1097 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
1098 } else {
1099 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1100 }
1101 } else{
1102 // Global, absolute
1103 o4(0xE59F1000); // ldr r1, .L1
1104 o4(0xEA000000); // b .L99
1105 o4(ea); // .L1: .word 0
1106 o4(0xE5810000); // .L99: str r0, [r1]
1107 }
1108 break;
1109 case TY_DOUBLE:
1110 if ((ea & 0x7) != 0) {
1111 error("double address is not aligned: %d", ea);
1112 }
1113 if (ea > -LOCAL && ea < LOCAL) {
1114 // Local, fp relative
1115 if (ea < -4095 || ea > 4095) {
1116 error("Offset out of range: %08x", ea);
1117 }
1118 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001119 o4(0xE50B0000 | (0xfff & (4-ea))); // str r0, [fp,#-ea]
1120 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001121#if 0
1122 // strd doesn't seem to work. Is encoding wrong?
1123 } else if (ea < 0) {
1124 o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea]
1125 } else if (ea < 256) {
1126 o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea]
1127#endif
1128 } else {
1129 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
1130 o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4]
1131 }
1132 } else{
1133 // Global, absolute
1134 o4(0xE59F2000); // ldr r2, .L1
1135 o4(0xEA000000); // b .L99
1136 o4(ea); // .L1: .word 0
1137 o4(0xE1C200F0); // .L99: strd r0, [r2]
1138 }
1139 break;
1140 default:
1141 error("Unable to store to type %d", tag);
1142 break;
Jack Palevich69796b62009-05-14 15:42:26 -07001143 }
Jack Palevich22305132009-05-13 10:58:45 -07001144 }
1145
Jack Palevich8df46192009-07-07 14:48:51 -07001146 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07001147 LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType);
Jack Palevich25c0cca2009-07-13 16:56:28 -07001148 TypeTag tag = pType->tag;
Jack Palevichb7718b92009-07-09 22:00:24 -07001149 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07001150 case TY_CHAR:
1151 if (ea < LOCAL) {
1152 // Local, fp relative
1153 if (ea < -4095 || ea > 4095) {
1154 error("Offset out of range: %08x", ea);
1155 }
1156 if (ea < 0) {
1157 o4(0xE55B0000 | (0xfff & (-ea))); // ldrb r0, [fp,#-ea]
1158 } else {
1159 o4(0xE5DB0000 | (0xfff & ea)); // ldrb r0, [fp,#ea]
1160 }
1161 } else {
1162 // Global, absolute
1163 o4(0xE59F2000); // ldr r2, .L1
1164 o4(0xEA000000); // b .L99
1165 o4(ea); // .L1: .word ea
1166 o4(0xE5D20000); // .L99: ldrb r0, [r2]
1167 }
1168
1169 if (isIncDec) {
1170 error("inc/dec not implemented for char.");
1171 }
1172 break;
1173 case TY_POINTER:
Jack Palevichb7718b92009-07-09 22:00:24 -07001174 case TY_INT:
1175 case TY_FLOAT:
1176 if (ea < LOCAL) {
1177 // Local, fp relative
1178 if (ea < -4095 || ea > 4095) {
1179 error("Offset out of range: %08x", ea);
1180 }
1181 if (ea < 0) {
1182 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
1183 } else {
1184 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1185 }
1186 } else {
1187 // Global, absolute
1188 o4(0xE59F2000); // ldr r2, .L1
1189 o4(0xEA000000); // b .L99
1190 o4(ea); // .L1: .word ea
1191 o4(0xE5920000); // .L99: ldr r0, [r2]
1192 }
Jack Palevich22305132009-05-13 10:58:45 -07001193
Jack Palevichb7718b92009-07-09 22:00:24 -07001194 if (isIncDec) {
1195 if (tag == TY_INT) {
1196 switch (op) {
1197 case OP_INCREMENT:
1198 o4(0xE2801001); // add r1, r0, #1
1199 break;
1200 case OP_DECREMENT:
1201 o4(0xE2401001); // sub r1, r0, #1
1202 break;
1203 default:
1204 error("unknown opcode: %d", op);
1205 }
1206 if (ea < LOCAL) {
1207 // Local, fp relative
1208 // Don't need range check, was already checked above
1209 if (ea < 0) {
1210 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
1211 } else {
1212 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
1213 }
1214 } else{
1215 // Global, absolute
1216 // r2 is already set up from before.
1217 o4(0xE5821000); // str r1, [r2]
1218 }
1219 }
1220 else {
1221 error("inc/dec not implemented for float.");
1222 }
1223 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001224 break;
Jack Palevichb7718b92009-07-09 22:00:24 -07001225 case TY_DOUBLE:
1226 if ((ea & 0x7) != 0) {
1227 error("double address is not aligned: %d", ea);
1228 }
1229 if (ea < LOCAL) {
1230 // Local, fp relative
1231 if (ea < -4095 || ea > 4095) {
1232 error("Offset out of range: %08x", ea);
1233 }
1234 if (ea < 0) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07001235 o4(0xE51B0000 | (0xfff & (4-ea))); // ldr r0, [fp,#-ea]
1236 o4(0xE51B1000 | (0xfff & (-ea))); // ldr r1, [fp,#-ea+4]
Jack Palevichb7718b92009-07-09 22:00:24 -07001237 } else {
1238 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
1239 o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4]
1240 }
1241 } else {
1242 // Global, absolute
1243 o4(0xE59F2000); // ldr r2, .L1
1244 o4(0xEA000000); // b .L99
1245 o4(ea); // .L1: .word ea
1246 o4(0xE1C200D0); // .L99: ldrd r0, [r2]
1247 }
Jack Palevich4d93f302009-05-15 13:30:00 -07001248 break;
1249 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07001250 error("Unable to load type %d", tag);
1251 break;
Jack Palevichbd894902009-05-14 19:35:31 -07001252 }
Jack Palevich8df46192009-07-07 14:48:51 -07001253 setR0Type(pType);
1254 }
1255
1256 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07001257 Type* pR0Type = getR0Type();
1258 if (bitsSame(pType, pR0Type)) {
1259 // do nothing special
Jack Palevich1a539db2009-07-08 13:04:41 -07001260 } else {
Jack Palevichb7718b92009-07-09 22:00:24 -07001261 TypeTag r0Tag = collapseType(pR0Type->tag);
1262 TypeTag destTag = collapseType(pType->tag);
1263 if (r0Tag == TY_INT) {
1264 if (destTag == TY_FLOAT) {
1265 callRuntime((void*) runtime_int_to_float);
1266 } else {
1267 assert(destTag == TY_DOUBLE);
1268 callRuntime((void*) runtime_int_to_double);
1269 }
1270 } else if (r0Tag == TY_FLOAT) {
1271 if (destTag == TY_INT) {
1272 callRuntime((void*) runtime_float_to_int);
1273 } else {
1274 assert(destTag == TY_DOUBLE);
1275 callRuntime((void*) runtime_float_to_double);
1276 }
1277 } else {
1278 assert (r0Tag == TY_DOUBLE);
1279 if (destTag == TY_INT) {
1280 callRuntime((void*) runtime_double_to_int);
1281 } else {
1282 assert(destTag == TY_FLOAT);
1283 callRuntime((void*) runtime_double_to_float);
1284 }
1285 }
Jack Palevich8df46192009-07-07 14:48:51 -07001286 }
Jack Palevich1a539db2009-07-08 13:04:41 -07001287 setR0Type(pType);
Jack Palevich22305132009-05-13 10:58:45 -07001288 }
1289
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001290 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -07001291 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001292 return o4(0xE24DDF00); // Placeholder
1293 }
1294
Jack Palevich8148c5b2009-07-16 18:24:47 -07001295 virtual size_t storeR0ToArg(int l, Type* pArgType) {
Jack Palevich09555c72009-05-27 12:25:55 -07001296 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich8148c5b2009-07-16 18:24:47 -07001297 convertR0(pArgType);
Jack Palevichb7718b92009-07-09 22:00:24 -07001298 Type* pR0Type = getR0Type();
1299 TypeTag r0ct = collapseType(pR0Type->tag);
1300 switch(r0ct) {
1301 case TY_INT:
1302 case TY_FLOAT:
1303 if (l < 0 || l > 4096-4) {
1304 error("l out of range for stack offset: 0x%08x", l);
1305 }
1306 o4(0xE58D0000 + l); // str r0, [sp, #l]
1307 return 4;
1308 case TY_DOUBLE: {
1309 // Align to 8 byte boundary
1310 int l2 = (l + 7) & ~7;
1311 if (l2 < 0 || l2 > 4096-8) {
1312 error("l out of range for stack offset: 0x%08x", l);
1313 }
1314 o4(0xE58D0000 + l2); // str r0, [sp, #l]
1315 o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1316 return (l2 - l) + 8;
1317 }
1318 default:
1319 assert(false);
1320 return 0;
Jack Palevich7810bc92009-05-15 14:31:47 -07001321 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001322 }
1323
Jack Palevichb7718b92009-07-09 22:00:24 -07001324 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -07001325 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
-b master422972c2009-06-17 19:13:52 -07001326 int argumentStackUse = l;
Jack Palevichb7718b92009-07-09 22:00:24 -07001327 // Have to calculate register arg count from actual stack size,
1328 // in order to properly handle ... functions.
1329 int regArgCount = l >> 2;
1330 if (regArgCount > 4) {
1331 regArgCount = 4;
1332 }
1333 if (regArgCount > 0) {
-b master422972c2009-06-17 19:13:52 -07001334 argumentStackUse -= regArgCount * 4;
1335 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
1336 }
1337 mStackUse += argumentStackUse;
1338
1339 // Align stack.
1340 int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1341 * STACK_ALIGNMENT);
1342 mStackAlignmentAdjustment = 0;
1343 if (missalignment > 0) {
1344 mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1345 }
1346 l += mStackAlignmentAdjustment;
1347
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001348 if (l < 0 || l > 0x3FC) {
1349 error("L out of range for stack adjustment: 0x%08x", l);
1350 }
1351 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
-b master422972c2009-06-17 19:13:52 -07001352 mStackUse += mStackAlignmentAdjustment;
1353 LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1354 mStackUse, mStackAlignmentAdjustment);
Jack Palevich22305132009-05-13 10:58:45 -07001355 }
1356
Jack Palevich8df46192009-07-07 14:48:51 -07001357 virtual int callForward(int symbol, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001358 LOG_API("callForward(%d);\n", symbol);
Jack Palevich8df46192009-07-07 14:48:51 -07001359 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001360 // Forward calls are always short (local)
1361 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -07001362 }
1363
Jack Palevich8df46192009-07-07 14:48:51 -07001364 virtual void callRelative(int t, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001365 LOG_API("callRelative(%d);\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07001366 setR0Type(pFunc->pHead);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001367 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001368 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001369 if (t >= - (1 << 25) && t < (1 << 25)) {
1370 o4(0xEB000000 | encodeAddress(t));
1371 } else {
1372 // Long call.
1373 o4(0xE59FC000); // ldr r12, .L1
1374 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -07001375 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001376 o4(0xE08CC00F); // .L99: add r12,pc
1377 o4(0xE12FFF3C); // blx r12
1378 }
Jack Palevich22305132009-05-13 10:58:45 -07001379 }
1380
Jack Palevich8df46192009-07-07 14:48:51 -07001381 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevich09555c72009-05-27 12:25:55 -07001382 LOG_API("callIndirect(%d);\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07001383 setR0Type(pFunc->pHead);
Jack Palevich7810bc92009-05-15 14:31:47 -07001384 int argCount = l >> 2;
1385 int poppedArgs = argCount > 4 ? 4 : argCount;
-b master422972c2009-06-17 19:13:52 -07001386 int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
Jack Palevich7810bc92009-05-15 14:31:47 -07001387 if (adjustedL < 0 || adjustedL > 4096-4) {
1388 error("l out of range for stack offset: 0x%08x", l);
1389 }
1390 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
1391 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -07001392 }
1393
Jack Palevichb7718b92009-07-09 22:00:24 -07001394 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -07001395 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001396 int argCount = l >> 2;
Jack Palevichb7718b92009-07-09 22:00:24 -07001397 // Have to calculate register arg count from actual stack size,
1398 // in order to properly handle ... functions.
1399 int regArgCount = l >> 2;
1400 if (regArgCount > 4) {
1401 regArgCount = 4;
1402 }
1403 int stackArgs = argCount - regArgCount;
-b master422972c2009-06-17 19:13:52 -07001404 int stackUse = stackArgs + (isIndirect ? 1 : 0)
1405 + (mStackAlignmentAdjustment >> 2);
Jack Palevich7810bc92009-05-15 14:31:47 -07001406 if (stackUse) {
1407 if (stackUse < 0 || stackUse > 255) {
1408 error("L out of range for stack adjustment: 0x%08x", l);
1409 }
1410 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
-b master422972c2009-06-17 19:13:52 -07001411 mStackUse -= stackUse * 4;
1412 LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001413 }
Jack Palevich22305132009-05-13 10:58:45 -07001414 }
1415
Jack Palevicha6535612009-05-13 16:24:17 -07001416 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -07001417 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -07001418 }
1419
1420 /* output a symbol and patch all calls to it */
1421 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -07001422 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -07001423 int n;
1424 int base = getBase();
1425 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -07001426 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -07001427 while (t) {
1428 int data = * (int*) t;
1429 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1430 if (decodedOffset == 0) {
1431 n = 0;
1432 } else {
1433 n = base + decodedOffset; /* next value */
1434 }
1435 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1436 | encodeRelAddress(pc - t - 8);
1437 t = n;
1438 }
1439 }
1440
Jack Palevich1cdef202009-05-22 12:06:27 -07001441 virtual int finishCompile() {
1442#if defined(__arm__)
1443 const long base = long(getBase());
1444 const long curr = long(getPC());
1445 int err = cacheflush(base, curr, 0);
1446 return err;
1447#else
1448 return 0;
1449#endif
1450 }
1451
Jack Palevicha6535612009-05-13 16:24:17 -07001452 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -07001453#ifdef ENABLE_ARM_DISASSEMBLY
1454 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -07001455 disasm_interface_t di;
1456 di.di_readword = disassemble_readword;
1457 di.di_printaddr = disassemble_printaddr;
1458 di.di_printf = disassemble_printf;
1459
1460 int base = getBase();
1461 int pc = getPC();
1462 for(int i = base; i < pc; i += 4) {
1463 fprintf(out, "%08x: %08x ", i, *(int*) i);
1464 ::disasm(&di, i, 0);
1465 }
Jack Palevich09555c72009-05-27 12:25:55 -07001466#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001467 return 0;
1468 }
Jack Palevich7810bc92009-05-15 14:31:47 -07001469
Jack Palevich9eed7a22009-07-06 17:24:34 -07001470 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07001471 * alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07001472 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001473 virtual size_t alignmentOf(Type* pType){
Jack Palevich9eed7a22009-07-06 17:24:34 -07001474 switch(pType->tag) {
1475 case TY_DOUBLE:
1476 return 8;
1477 default:
1478 return 4;
1479 }
1480 }
1481
1482 /**
1483 * Array element alignment (in bytes) for this type of data.
1484 */
1485 virtual size_t sizeOf(Type* pType){
1486 switch(pType->tag) {
1487 case TY_INT:
1488 return 4;
1489 case TY_CHAR:
1490 return 1;
1491 default:
1492 return 0;
1493 case TY_FLOAT:
1494 return 4;
1495 case TY_DOUBLE:
1496 return 8;
1497 case TY_POINTER:
1498 return 4;
1499 }
1500 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07001501
1502 virtual size_t stackSizeOf(Type* pType) {
1503 switch(pType->tag) {
1504 case TY_DOUBLE:
1505 return 8;
1506 default:
1507 return 4;
1508 }
1509 }
1510
Jack Palevich22305132009-05-13 10:58:45 -07001511 private:
Jack Palevicha6535612009-05-13 16:24:17 -07001512 static FILE* disasmOut;
1513
1514 static u_int
1515 disassemble_readword(u_int address)
1516 {
1517 return(*((u_int *)address));
1518 }
1519
1520 static void
1521 disassemble_printaddr(u_int address)
1522 {
1523 fprintf(disasmOut, "0x%08x", address);
1524 }
1525
1526 static void
1527 disassemble_printf(const char *fmt, ...) {
1528 va_list ap;
1529 va_start(ap, fmt);
1530 vfprintf(disasmOut, fmt, ap);
1531 va_end(ap);
1532 }
1533
1534 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1535
1536 /** Encode a relative address that might also be
1537 * a label.
1538 */
1539 int encodeAddress(int value) {
1540 int base = getBase();
1541 if (value >= base && value <= getPC() ) {
1542 // This is a label, encode it relative to the base.
1543 value = value - base;
1544 }
1545 return encodeRelAddress(value);
1546 }
1547
1548 int encodeRelAddress(int value) {
1549 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1550 }
Jack Palevich22305132009-05-13 10:58:45 -07001551
Jack Palevichb7718b92009-07-09 22:00:24 -07001552 int calcRegArgCount(Type* pDecl) {
1553 int reg = 0;
1554 Type* pArgs = pDecl->pTail;
1555 while (pArgs && reg < 4) {
1556 Type* pArg = pArgs->pHead;
1557 if ( pArg->tag == TY_DOUBLE) {
1558 int evenReg = (reg + 1) & ~1;
1559 if (evenReg >= 4) {
1560 break;
1561 }
1562 reg = evenReg + 2;
1563 } else {
1564 reg++;
1565 }
1566 pArgs = pArgs->pTail;
1567 }
1568 return reg;
1569 }
1570
1571 /* Pop TOS to R1
1572 * Make sure both R0 and TOS are floats. (Could be ints)
1573 * We know that at least one of R0 and TOS is already a float
1574 */
1575 void setupFloatArgs() {
1576 Type* pR0Type = getR0Type();
1577 Type* pTOSType = getTOSType();
1578 TypeTag tagR0 = collapseType(pR0Type->tag);
1579 TypeTag tagTOS = collapseType(pTOSType->tag);
1580 if (tagR0 != TY_FLOAT) {
1581 assert(tagR0 == TY_INT);
1582 callRuntime((void*) runtime_int_to_float);
1583 }
1584 if (tagTOS != TY_FLOAT) {
1585 assert(tagTOS == TY_INT);
1586 assert(tagR0 == TY_FLOAT);
1587 o4(0xE92D0001); // stmfd sp!,{r0} // push R0
1588 o4(0xE59D0004); // ldr r0, [sp, #4]
1589 callRuntime((void*) runtime_int_to_float);
1590 o4(0xE1A01000); // mov r1, r0
1591 o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0
1592 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1593 } else {
1594 // Pop TOS
1595 o4(0xE8BD0002); // ldmfd sp!,{r1}
1596 }
1597 mStackUse -= 4;
1598 popType();
1599 }
1600
1601 /* Pop TOS into R2..R3
1602 * Make sure both R0 and TOS are doubles. Could be floats or ints.
1603 * We know that at least one of R0 and TOS are already a double.
1604 */
1605
1606 void setupDoubleArgs() {
1607 Type* pR0Type = getR0Type();
1608 Type* pTOSType = getTOSType();
1609 TypeTag tagR0 = collapseType(pR0Type->tag);
1610 TypeTag tagTOS = collapseType(pTOSType->tag);
1611 if (tagR0 != TY_DOUBLE) {
1612 if (tagR0 == TY_INT) {
1613 callRuntime((void*) runtime_int_to_double);
1614 } else {
1615 assert(tagR0 == TY_FLOAT);
1616 callRuntime((void*) runtime_float_to_double);
1617 }
1618 }
1619 if (tagTOS != TY_DOUBLE) {
1620 o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1
1621 o4(0xE59D0008); // ldr r0, [sp, #8]
1622 if (tagTOS == TY_INT) {
1623 callRuntime((void*) runtime_int_to_double);
1624 } else {
1625 assert(tagTOS == TY_FLOAT);
1626 callRuntime((void*) runtime_float_to_double);
1627 }
1628 o4(0xE1A02000); // mov r2, r0
1629 o4(0xE1A03001); // mov r3, r1
1630 o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0
1631 o4(0xE28DD004); // add sp, sp, #4 // Pop sp
1632 mStackUse -= 4;
1633 } else {
1634 o4(0xE8BD000C); // ldmfd sp!,{r2,r3}
1635 mStackUse -= 8;
1636 }
1637 popType();
1638 }
1639
Jack Palevicha8f427f2009-07-13 18:40:08 -07001640 void liReg(int t, int reg) {
1641 assert(reg >= 0 && reg < 16);
1642 int rN = (reg & 0xf) << 12;
1643 if (t >= 0 && t < 255) {
1644 o4((0xE3A00000 + t) | rN); // mov rN, #0
1645 } else if (t >= -256 && t < 0) {
1646 // mvn means move constant ^ ~0
1647 o4((0xE3E00001 - t) | rN); // mvn rN, #0
1648 } else {
1649 o4(0xE51F0000 | rN); // ldr rN, .L3
1650 o4(0xEA000000); // b .L99
1651 o4(t); // .L3: .word 0
1652 // .L99:
1653 }
1654 }
1655
Jack Palevichb7718b92009-07-09 22:00:24 -07001656 void callRuntime(void* fn) {
1657 o4(0xE59FC000); // ldr r12, .L1
Jack Palevich3d474a72009-05-15 15:12:38 -07001658 o4(0xEA000000); // b .L99
1659 o4((int) fn); //.L1: .word fn
Jack Palevichb7718b92009-07-09 22:00:24 -07001660 o4(0xE12FFF3C); //.L99: blx r12
Jack Palevich3d474a72009-05-15 15:12:38 -07001661 }
1662
Jack Palevichb7718b92009-07-09 22:00:24 -07001663 // Integer math:
1664
1665 static int runtime_DIV(int b, int a) {
1666 return a / b;
Jack Palevich3d474a72009-05-15 15:12:38 -07001667 }
1668
Jack Palevichb7718b92009-07-09 22:00:24 -07001669 static int runtime_MOD(int b, int a) {
1670 return a % b;
1671 }
1672
1673 // Comparison to zero
1674
1675 static int runtime_is_non_zero_f(float a) {
1676 return a != 0;
1677 }
1678
1679 static int runtime_is_non_zero_d(double a) {
1680 return a != 0;
1681 }
1682
1683 // Comparison to zero
1684
1685 static int runtime_is_zero_f(float a) {
1686 return a == 0;
1687 }
1688
1689 static int runtime_is_zero_d(double a) {
1690 return a == 0;
1691 }
1692
1693 // Type conversion
1694
1695 static int runtime_float_to_int(float a) {
1696 return (int) a;
1697 }
1698
1699 static double runtime_float_to_double(float a) {
1700 return (double) a;
1701 }
1702
1703 static int runtime_double_to_int(double a) {
1704 return (int) a;
1705 }
1706
1707 static float runtime_double_to_float(double a) {
1708 return (float) a;
1709 }
1710
1711 static float runtime_int_to_float(int a) {
1712 return (float) a;
1713 }
1714
1715 static double runtime_int_to_double(int a) {
1716 return (double) a;
1717 }
1718
1719 // Comparisons float
1720
1721 static int runtime_cmp_eq_ff(float b, float a) {
1722 return a == b;
1723 }
1724
1725 static int runtime_cmp_ne_ff(float b, float a) {
1726 return a != b;
1727 }
1728
1729 static int runtime_cmp_lt_ff(float b, float a) {
1730 return a < b;
1731 }
1732
1733 static int runtime_cmp_le_ff(float b, float a) {
1734 return a <= b;
1735 }
1736
1737 static int runtime_cmp_ge_ff(float b, float a) {
1738 return a >= b;
1739 }
1740
1741 static int runtime_cmp_gt_ff(float b, float a) {
1742 return a > b;
1743 }
1744
1745 // Comparisons double
1746
1747 static int runtime_cmp_eq_dd(double b, double a) {
1748 return a == b;
1749 }
1750
1751 static int runtime_cmp_ne_dd(double b, double a) {
1752 return a != b;
1753 }
1754
1755 static int runtime_cmp_lt_dd(double b, double a) {
1756 return a < b;
1757 }
1758
1759 static int runtime_cmp_le_dd(double b, double a) {
1760 return a <= b;
1761 }
1762
1763 static int runtime_cmp_ge_dd(double b, double a) {
1764 return a >= b;
1765 }
1766
1767 static int runtime_cmp_gt_dd(double b, double a) {
1768 return a > b;
1769 }
1770
1771 // Math float
1772
1773 static float runtime_op_add_ff(float b, float a) {
1774 return a + b;
1775 }
1776
1777 static float runtime_op_sub_ff(float b, float a) {
1778 return a - b;
1779 }
1780
1781 static float runtime_op_mul_ff(float b, float a) {
1782 return a * b;
1783 }
1784
1785 static float runtime_op_div_ff(float b, float a) {
1786 return a / b;
1787 }
1788
1789 static float runtime_op_neg_f(float a) {
1790 return -a;
1791 }
1792
1793 // Math double
1794
1795 static double runtime_op_add_dd(double b, double a) {
1796 return a + b;
1797 }
1798
1799 static double runtime_op_sub_dd(double b, double a) {
1800 return a - b;
1801 }
1802
1803 static double runtime_op_mul_dd(double b, double a) {
1804 return a * b;
1805 }
1806
1807 static double runtime_op_div_dd(double b, double a) {
1808 return a / b;
1809 }
1810
1811 static double runtime_op_neg_d(double a) {
1812 return -a;
Jack Palevich3d474a72009-05-15 15:12:38 -07001813 }
-b master422972c2009-06-17 19:13:52 -07001814
1815 static const int STACK_ALIGNMENT = 8;
1816 int mStackUse;
1817 // This variable holds the amount we adjusted the stack in the most
1818 // recent endFunctionCallArguments call. It's examined by the
1819 // following adjustStackAfterCall call.
1820 int mStackAlignmentAdjustment;
Jack Palevich22305132009-05-13 10:58:45 -07001821 };
1822
Jack Palevich09555c72009-05-27 12:25:55 -07001823#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001824
1825#ifdef PROVIDE_X86_CODEGEN
1826
Jack Palevich21a15a22009-05-11 14:49:29 -07001827 class X86CodeGenerator : public CodeGenerator {
1828 public:
1829 X86CodeGenerator() {}
1830 virtual ~X86CodeGenerator() {}
1831
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001832 /* returns address to patch with local variable size
1833 */
Jack Palevichb7718b92009-07-09 22:00:24 -07001834 virtual int functionEntry(Type* pDecl) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001835 o(0xe58955); /* push %ebp, mov %esp, %ebp */
1836 return oad(0xec81, 0); /* sub $xxx, %esp */
1837 }
1838
Jack Palevichb7718b92009-07-09 22:00:24 -07001839 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001840 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -07001841 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001842 }
1843
Jack Palevich21a15a22009-05-11 14:49:29 -07001844 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07001845 virtual void li(int i, Type* pType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001846 oad(0xb8, i); /* mov $xx, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07001847 setR0Type(pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07001848 }
1849
Jack Palevich1a539db2009-07-08 13:04:41 -07001850 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8df46192009-07-07 14:48:51 -07001851 setR0Type(pType);
Jack Palevich1a539db2009-07-08 13:04:41 -07001852 switch (pType->tag) {
1853 case TY_FLOAT:
1854 oad(0x05D9, address); // flds
1855 break;
1856 case TY_DOUBLE:
1857 oad(0x05DD, address); // fldl
1858 break;
1859 default:
1860 assert(false);
1861 break;
1862 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001863 }
1864
Jack Palevich22305132009-05-13 10:58:45 -07001865 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001866 return psym(0xe9, t);
1867 }
1868
1869 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -07001870 virtual int gtst(bool l, int t) {
Jack Palevich2a4e1a92009-07-09 13:34:25 -07001871 Type* pR0Type = getR0Type();
1872 TypeTag tagR0 = pR0Type->tag;
1873 bool isFloatR0 = isFloatTag(tagR0);
1874 if (isFloatR0) {
1875 o(0xeed9); // fldz
1876 o(0xe9da); // fucompp
1877 o(0xe0df); // fnstsw %ax
1878 o(0x9e); // sahf
1879 } else {
1880 o(0xc085); // test %eax, %eax
1881 }
1882 // Use two output statements to generate one instruction.
1883 o(0x0f); // je/jne xxx
Jack Palevich21a15a22009-05-11 14:49:29 -07001884 return psym(0x84 + l, t);
1885 }
1886
Jack Palevicha39749f2009-07-08 20:40:31 -07001887 virtual void gcmp(int op, Type* pResultType) {
1888 Type* pR0Type = getR0Type();
1889 Type* pTOSType = getTOSType();
1890 TypeTag tagR0 = pR0Type->tag;
1891 TypeTag tagTOS = pTOSType->tag;
1892 bool isFloatR0 = isFloatTag(tagR0);
1893 bool isFloatTOS = isFloatTag(tagTOS);
1894 if (!isFloatR0 && !isFloatTOS) {
1895 int t = decodeOp(op);
1896 o(0x59); /* pop %ecx */
1897 o(0xc139); /* cmp %eax,%ecx */
1898 li(0, NULL);
1899 o(0x0f); /* setxx %al */
1900 o(t + 0x90);
1901 o(0xc0);
1902 popType();
1903 } else {
1904 setupFloatOperands();
1905 switch (op) {
1906 case OP_EQUALS:
1907 o(0xe9da); // fucompp
1908 o(0xe0df); // fnstsw %ax
1909 o(0x9e); // sahf
1910 o(0xc0940f); // sete %al
1911 o(0xc29b0f); // setnp %dl
1912 o(0xd021); // andl %edx, %eax
1913 break;
1914 case OP_NOT_EQUALS:
1915 o(0xe9da); // fucompp
1916 o(0xe0df); // fnstsw %ax
1917 o(0x9e); // sahf
1918 o(0xc0950f); // setne %al
1919 o(0xc29a0f); // setp %dl
1920 o(0xd009); // orl %edx, %eax
1921 break;
1922 case OP_GREATER_EQUAL:
1923 o(0xe9da); // fucompp
1924 o(0xe0df); // fnstsw %ax
1925 o(0x05c4f6); // testb $5, %ah
1926 o(0xc0940f); // sete %al
1927 break;
1928 case OP_LESS:
1929 o(0xc9d9); // fxch %st(1)
1930 o(0xe9da); // fucompp
1931 o(0xe0df); // fnstsw %ax
1932 o(0x9e); // sahf
1933 o(0xc0970f); // seta %al
1934 break;
1935 case OP_LESS_EQUAL:
1936 o(0xc9d9); // fxch %st(1)
1937 o(0xe9da); // fucompp
1938 o(0xe0df); // fnstsw %ax
1939 o(0x9e); // sahf
1940 o(0xc0930f); // setea %al
1941 break;
1942 case OP_GREATER:
1943 o(0xe9da); // fucompp
1944 o(0xe0df); // fnstsw %ax
1945 o(0x45c4f6); // testb $69, %ah
1946 o(0xc0940f); // sete %al
1947 break;
1948 default:
1949 error("Unknown comparison op");
1950 }
1951 o(0xc0b60f); // movzbl %al, %eax
1952 }
1953 setR0Type(pResultType);
Jack Palevich21a15a22009-05-11 14:49:29 -07001954 }
1955
Jack Palevich546b2242009-05-13 15:10:04 -07001956 virtual void genOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07001957 Type* pR0Type = getR0Type();
1958 Type* pTOSType = getTOSType();
1959 TypeTag tagR0 = pR0Type->tag;
1960 TypeTag tagTOS = pTOSType->tag;
1961 bool isFloatR0 = isFloatTag(tagR0);
1962 bool isFloatTOS = isFloatTag(tagTOS);
1963 if (!isFloatR0 && !isFloatTOS) {
Jack Palevicha8f427f2009-07-13 18:40:08 -07001964 bool isPtrR0 = tagR0 == TY_POINTER;
1965 bool isPtrTOS = tagTOS == TY_POINTER;
1966 if (isPtrR0 || isPtrTOS) {
1967 if (isPtrR0 && isPtrTOS) {
1968 if (op != OP_MINUS) {
1969 error("Unsupported pointer-pointer operation %d.", op);
1970 }
1971 if (! typeEqual(pR0Type, pTOSType)) {
1972 error("Incompatible pointer types for subtraction.");
1973 }
1974 o(0x59); /* pop %ecx */
1975 o(decodeOp(op));
1976 popType();
1977 setR0Type(mkpInt);
1978 int size = sizeOf(pR0Type->pHead);
1979 if (size != 1) {
1980 pushR0();
1981 li(size, mkpInt);
1982 // TODO: Optimize for power-of-two.
1983 genOp(OP_DIV);
1984 }
1985 } else {
1986 if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1987 error("Unsupported pointer-scalar operation %d", op);
1988 }
1989 Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
1990 o(0x59); /* pop %ecx */
1991 int size = sizeOf(pPtrType->pHead);
1992 if (size != 1) {
1993 // TODO: Optimize for power-of-two.
1994 if (isPtrR0) {
1995 oad(0xC969, size); // imull $size, %ecx
1996 } else {
1997 oad(0xC069, size); // mul $size, %eax
1998 }
1999 }
2000 o(decodeOp(op));
2001 popType();
2002 setR0Type(pPtrType);
2003 }
2004 } else {
2005 o(0x59); /* pop %ecx */
2006 o(decodeOp(op));
2007 if (op == OP_MOD)
2008 o(0x92); /* xchg %edx, %eax */
2009 popType();
2010 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002011 } else {
2012 Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2013 setupFloatOperands();
2014 // Both float. x87 R0 == left hand, x87 R1 == right hand
2015 switch (op) {
2016 case OP_MUL:
2017 o(0xc9de); // fmulp
2018 break;
2019 case OP_DIV:
2020 o(0xf1de); // fdivp
2021 break;
2022 case OP_PLUS:
2023 o(0xc1de); // faddp
2024 break;
2025 case OP_MINUS:
2026 o(0xe1de); // fsubp
2027 break;
2028 default:
2029 error("Unsupported binary floating operation.");
2030 break;
2031 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002032 setR0Type(pResultType);
Jack Palevicha39749f2009-07-08 20:40:31 -07002033 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002034 }
2035
Jack Palevicha39749f2009-07-08 20:40:31 -07002036 virtual void gUnaryCmp(int op, Type* pResultType) {
2037 if (op != OP_LOGICAL_NOT) {
2038 error("Unknown unary cmp %d", op);
2039 } else {
2040 Type* pR0Type = getR0Type();
2041 TypeTag tag = collapseType(pR0Type->tag);
2042 switch(tag) {
2043 case TY_INT: {
2044 oad(0xb9, 0); /* movl $0, %ecx */
2045 int t = decodeOp(op);
2046 o(0xc139); /* cmp %eax,%ecx */
2047 li(0, NULL);
2048 o(0x0f); /* setxx %al */
2049 o(t + 0x90);
2050 o(0xc0);
2051 }
2052 break;
2053 case TY_FLOAT:
2054 case TY_DOUBLE:
2055 o(0xeed9); // fldz
2056 o(0xe9da); // fucompp
2057 o(0xe0df); // fnstsw %ax
2058 o(0x9e); // sahf
2059 o(0xc0950f); // setne %al
2060 o(0xc29a0f); // setp %dl
2061 o(0xd009); // orl %edx, %eax
2062 o(0xc0b60f); // movzbl %al, %eax
2063 o(0x01f083); // xorl $1, %eax
2064 break;
2065 default:
Jack Palevichb7718b92009-07-09 22:00:24 -07002066 error("gUnaryCmp unsupported type");
Jack Palevicha39749f2009-07-08 20:40:31 -07002067 break;
2068 }
2069 }
2070 setR0Type(pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002071 }
2072
2073 virtual void genUnaryOp(int op) {
Jack Palevicha39749f2009-07-08 20:40:31 -07002074 Type* pR0Type = getR0Type();
2075 TypeTag tag = collapseType(pR0Type->tag);
2076 switch(tag) {
2077 case TY_INT:
2078 oad(0xb9, 0); /* movl $0, %ecx */
2079 o(decodeOp(op));
2080 break;
2081 case TY_FLOAT:
2082 case TY_DOUBLE:
2083 switch (op) {
2084 case OP_MINUS:
2085 o(0xe0d9); // fchs
2086 break;
2087 case OP_BIT_NOT:
2088 error("Can't apply '~' operator to a float or double.");
2089 break;
2090 default:
2091 error("Unknown unary op %d\n", op);
2092 break;
2093 }
2094 break;
2095 default:
2096 error("genUnaryOp unsupported type");
2097 break;
2098 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002099 }
2100
Jack Palevich1cdef202009-05-22 12:06:27 -07002101 virtual void pushR0() {
Jack Palevich9cbd2262009-07-08 16:48:41 -07002102 Type* pR0Type = getR0Type();
2103 TypeTag r0ct = collapseType(pR0Type->tag);
2104 switch(r0ct) {
2105 case TY_INT:
2106 o(0x50); /* push %eax */
2107 break;
2108 case TY_FLOAT:
2109 o(0x50); /* push %eax */
2110 o(0x241cd9); // fstps 0(%esp)
2111 break;
2112 case TY_DOUBLE:
2113 o(0x50); /* push %eax */
2114 o(0x50); /* push %eax */
2115 o(0x241cdd); // fstpl 0(%esp)
2116 break;
2117 default:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002118 error("pushR0 unsupported type %d", r0ct);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002119 break;
2120 }
Jack Palevich8df46192009-07-07 14:48:51 -07002121 pushType();
Jack Palevich21a15a22009-05-11 14:49:29 -07002122 }
2123
Jack Palevich9eed7a22009-07-06 17:24:34 -07002124 virtual void storeR0ToTOS(Type* pPointerType) {
2125 assert(pPointerType->tag == TY_POINTER);
Jack Palevich8148c5b2009-07-16 18:24:47 -07002126 Type* pTargetType = pPointerType->pHead;
2127 convertR0(pTargetType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002128 o(0x59); /* pop %ecx */
Jack Palevich8df46192009-07-07 14:48:51 -07002129 popType();
Jack Palevich8148c5b2009-07-16 18:24:47 -07002130 switch (pTargetType->tag) {
Jack Palevich9eed7a22009-07-06 17:24:34 -07002131 case TY_INT:
2132 o(0x0189); /* movl %eax/%al, (%ecx) */
2133 break;
2134 case TY_CHAR:
2135 o(0x0188); /* movl %eax/%al, (%ecx) */
2136 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002137 case TY_FLOAT:
2138 o(0x19d9); /* fstps (%ecx) */
2139 break;
2140 case TY_DOUBLE:
2141 o(0x19dd); /* fstpl (%ecx) */
2142 break;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002143 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002144 error("storeR0ToTOS: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002145 break;
2146 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002147 }
2148
Jack Palevich9eed7a22009-07-06 17:24:34 -07002149 virtual void loadR0FromR0(Type* pPointerType) {
2150 assert(pPointerType->tag == TY_POINTER);
2151 switch (pPointerType->pHead->tag) {
2152 case TY_INT:
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002153 o2(0x008b); /* mov (%eax), %eax */
Jack Palevich9eed7a22009-07-06 17:24:34 -07002154 break;
2155 case TY_CHAR:
2156 o(0xbe0f); /* movsbl (%eax), %eax */
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002157 ob(0); /* add zero in code */
2158 break;
2159 case TY_FLOAT:
2160 o2(0x00d9); // flds (%eax)
2161 break;
2162 case TY_DOUBLE:
2163 o2(0x00dd); // fldl (%eax)
Jack Palevich9eed7a22009-07-06 17:24:34 -07002164 break;
2165 default:
Jack Palevich8df46192009-07-07 14:48:51 -07002166 error("loadR0FromR0: unsupported type");
Jack Palevich9eed7a22009-07-06 17:24:34 -07002167 break;
2168 }
Jack Palevich8df46192009-07-07 14:48:51 -07002169 setR0Type(pPointerType->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002170 }
2171
Jack Palevich8df46192009-07-07 14:48:51 -07002172 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002173 gmov(10, ea); /* leal EA, %eax */
Jack Palevich8df46192009-07-07 14:48:51 -07002174 setR0Type(pPointerType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002175 }
2176
Jack Palevich9cbd2262009-07-08 16:48:41 -07002177 virtual void storeR0(int ea, Type* pType) {
2178 TypeTag tag = pType->tag;
Jack Palevich8148c5b2009-07-16 18:24:47 -07002179 convertR0(pType);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002180 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002181 case TY_CHAR:
2182 if (ea < -LOCAL || ea > LOCAL) {
2183 oad(0xa2, ea); // movb %al,ea
2184 } else {
2185 oad(0x8588, ea); // movb %al,ea(%ebp)
2186 }
2187 break;
Jack Palevich9cbd2262009-07-08 16:48:41 -07002188 case TY_INT:
Jack Palevich45431bc2009-07-13 15:57:26 -07002189 case TY_POINTER:
Jack Palevich9cbd2262009-07-08 16:48:41 -07002190 gmov(6, ea); /* mov %eax, EA */
2191 break;
2192 case TY_FLOAT:
2193 if (ea < -LOCAL || ea > LOCAL) {
2194 oad(0x1dd9, ea); // fstps ea
2195 } else {
2196 oad(0x9dd9, ea); // fstps ea(%ebp)
2197 }
2198 break;
2199 case TY_DOUBLE:
2200 if (ea < -LOCAL || ea > LOCAL) {
2201 oad(0x1ddd, ea); // fstpl ea
2202 } else {
2203 oad(0x9ddd, ea); // fstpl ea(%ebp)
2204 }
2205 break;
2206 default:
2207 error("Unable to store to type %d", tag);
2208 break;
2209 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002210 }
2211
Jack Palevich8df46192009-07-07 14:48:51 -07002212 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002213 TypeTag tag = pType->tag;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002214 switch (tag) {
Jack Palevich25c0cca2009-07-13 16:56:28 -07002215 case TY_CHAR:
2216 if (ea < -LOCAL || ea > LOCAL) {
2217 oad(0x05BE0F, ea); // movsbl ea,%eax
2218 } else {
2219 oad(0x85BE0F, ea); // movsbl ea(%ebp),%eax
2220 }
2221 if (isIncDec) {
2222 error("inc/dec not implemented for char.");
2223 }
2224 break;
Jack Palevich128ad2d2009-07-08 14:51:31 -07002225 case TY_INT:
Jack Palevich25c0cca2009-07-13 16:56:28 -07002226 case TY_POINTER:
2227 if (tag == TY_CHAR) {
2228 } else {
2229 gmov(8, ea); /* mov EA, %eax */
2230 }
Jack Palevich128ad2d2009-07-08 14:51:31 -07002231 if (isIncDec) {
2232 /* Implement post-increment or post decrement.
2233 */
2234 gmov(0, ea); /* 83 ADD */
2235 o(decodeOp(op));
2236 }
2237 break;
2238 case TY_FLOAT:
2239 if (ea < -LOCAL || ea > LOCAL) {
2240 oad(0x05d9, ea); // flds ea
2241 } else {
2242 oad(0x85d9, ea); // flds ea(%ebp)
2243 }
2244 if (isIncDec) {
2245 error("inc/dec not implemented for float.");
2246 }
2247 break;
2248 case TY_DOUBLE:
2249 if (ea < -LOCAL || ea > LOCAL) {
2250 oad(0x05dd, ea); // fldl ea
2251 } else {
2252 oad(0x85dd, ea); // fldl ea(%ebp)
2253 }
2254 if (isIncDec) {
2255 error("inc/dec not implemented for double.");
2256 }
2257 break;
2258 default:
2259 error("Unable to load type %d", tag);
2260 break;
Jack Palevich4d93f302009-05-15 13:30:00 -07002261 }
Jack Palevich8df46192009-07-07 14:48:51 -07002262 setR0Type(pType);
2263 }
2264
2265 virtual void convertR0(Type* pType){
Jack Palevich1a539db2009-07-08 13:04:41 -07002266 Type* pR0Type = getR0Type();
2267 if (pR0Type == NULL) {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002268 assert(false);
Jack Palevich1a539db2009-07-08 13:04:41 -07002269 setR0Type(pType);
Jack Palevich8df46192009-07-07 14:48:51 -07002270 return;
2271 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002272 if (bitsSame(pType, pR0Type)) {
2273 // do nothing special
2274 } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2275 // do nothing special, both held in same register on x87.
2276 } else {
Jack Palevich128ad2d2009-07-08 14:51:31 -07002277 TypeTag r0Tag = collapseType(pR0Type->tag);
2278 TypeTag destTag = collapseType(pType->tag);
2279 if (r0Tag == TY_INT && isFloatTag(destTag)) {
2280 // Convert R0 from int to float
2281 o(0x50); // push %eax
2282 o(0x2404DB); // fildl 0(%esp)
2283 o(0x58); // pop %eax
2284 } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2285 // Convert R0 from float to int. Complicated because
2286 // need to save and restore the rounding mode.
2287 o(0x50); // push %eax
2288 o(0x50); // push %eax
2289 o(0x02247cD9); // fnstcw 2(%esp)
2290 o(0x2444b70f); // movzwl 2(%esp), %eax
2291 o(0x02);
2292 o(0x0cb4); // movb $12, %ah
2293 o(0x24048966); // movw %ax, 0(%esp)
2294 o(0x242cd9); // fldcw 0(%esp)
2295 o(0x04245cdb); // fistpl 4(%esp)
2296 o(0x02246cd9); // fldcw 2(%esp)
2297 o(0x58); // pop %eax
2298 o(0x58); // pop %eax
2299 } else {
2300 error("Incompatible types old: %d new: %d",
2301 pR0Type->tag, pType->tag);
2302 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002303 }
2304 setR0Type(pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07002305 }
2306
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07002307 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -07002308 return oad(0xec81, 0); /* sub $xxx, %esp */
2309 }
2310
Jack Palevich8148c5b2009-07-16 18:24:47 -07002311 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2312 convertR0(pArgType);
Jack Palevich1a539db2009-07-08 13:04:41 -07002313 Type* pR0Type = getR0Type();
2314 TypeTag r0ct = collapseType(pR0Type->tag);
2315 switch(r0ct) {
2316 case TY_INT:
2317 oad(0x248489, l); /* movl %eax, xxx(%esp) */
2318 return 4;
2319 case TY_FLOAT:
2320 oad(0x249CD9, l); /* fstps xxx(%esp) */
2321 return 4;
2322 case TY_DOUBLE:
2323 oad(0x249CDD, l); /* fstpl xxx(%esp) */
2324 return 8;
2325 default:
2326 assert(false);
2327 return 0;
2328 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002329 }
2330
Jack Palevichb7718b92009-07-09 22:00:24 -07002331 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002332 * (int*) a = l;
2333 }
2334
Jack Palevich8df46192009-07-07 14:48:51 -07002335 virtual int callForward(int symbol, Type* pFunc) {
2336 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002337 return psym(0xe8, symbol); /* call xxx */
2338 }
2339
Jack Palevich8df46192009-07-07 14:48:51 -07002340 virtual void callRelative(int t, Type* pFunc) {
2341 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002342 psym(0xe8, t); /* call xxx */
2343 }
2344
Jack Palevich8df46192009-07-07 14:48:51 -07002345 virtual void callIndirect(int l, Type* pFunc) {
2346 setR0Type(pFunc->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07002347 oad(0x2494ff, l); /* call *xxx(%esp) */
2348 }
2349
Jack Palevichb7718b92009-07-09 22:00:24 -07002350 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
Jack Palevich7810bc92009-05-15 14:31:47 -07002351 if (isIndirect) {
2352 l += 4;
2353 }
-b master422972c2009-06-17 19:13:52 -07002354 if (l > 0) {
2355 oad(0xc481, l); /* add $xxx, %esp */
2356 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002357 }
2358
Jack Palevicha6535612009-05-13 16:24:17 -07002359 virtual int jumpOffset() {
2360 return 5;
2361 }
2362
2363 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -07002364 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -07002365 }
2366
Jack Paleviche7b59062009-05-19 17:12:17 -07002367 /* output a symbol and patch all calls to it */
2368 virtual void gsym(int t) {
2369 int n;
2370 int pc = getPC();
2371 while (t) {
2372 n = *(int *) t; /* next value */
2373 *(int *) t = pc - t - 4;
2374 t = n;
2375 }
2376 }
2377
Jack Palevich1cdef202009-05-22 12:06:27 -07002378 virtual int finishCompile() {
Jack Palevich8dc662e2009-06-09 22:53:47 +00002379 size_t pagesize = 4096;
2380 size_t base = (size_t) getBase() & ~ (pagesize - 1);
2381 size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2382 int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2383 if (err) {
2384 error("mprotect() failed: %d", errno);
2385 }
2386 return err;
Jack Palevich1cdef202009-05-22 12:06:27 -07002387 }
2388
Jack Palevich9eed7a22009-07-06 17:24:34 -07002389 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002390 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002391 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002392 virtual size_t alignmentOf(Type* pType){
2393 return 4;
Jack Palevich9eed7a22009-07-06 17:24:34 -07002394 }
2395
2396 /**
2397 * Array element alignment (in bytes) for this type of data.
2398 */
2399 virtual size_t sizeOf(Type* pType){
2400 switch(pType->tag) {
2401 case TY_INT:
2402 return 4;
2403 case TY_CHAR:
2404 return 1;
2405 default:
2406 return 0;
2407 case TY_FLOAT:
2408 return 4;
2409 case TY_DOUBLE:
2410 return 8;
2411 case TY_POINTER:
2412 return 4;
2413 }
2414 }
2415
Jack Palevich9cbd2262009-07-08 16:48:41 -07002416 virtual size_t stackSizeOf(Type* pType) {
2417 switch(pType->tag) {
2418 case TY_DOUBLE:
2419 return 8;
2420 default:
2421 return 4;
2422 }
2423 }
2424
Jack Palevich21a15a22009-05-11 14:49:29 -07002425 private:
Jack Paleviche7b59062009-05-19 17:12:17 -07002426
2427 /** Output 1 to 4 bytes.
2428 *
2429 */
2430 void o(int n) {
2431 /* cannot use unsigned, so we must do a hack */
2432 while (n && n != -1) {
2433 ob(n & 0xff);
2434 n = n >> 8;
2435 }
2436 }
2437
Jack Palevich2a4e1a92009-07-09 13:34:25 -07002438 /* Output exactly 2 bytes
2439 */
2440 void o2(int n) {
2441 ob(n & 0xff);
2442 ob(0xff & (n >> 8));
2443 }
2444
Jack Paleviche7b59062009-05-19 17:12:17 -07002445 /* psym is used to put an instruction with a data field which is a
2446 reference to a symbol. It is in fact the same as oad ! */
2447 int psym(int n, int t) {
2448 return oad(n, t);
2449 }
2450
2451 /* instruction + address */
2452 int oad(int n, int t) {
2453 o(n);
2454 int result = getPC();
2455 o4(t);
2456 return result;
2457 }
2458
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002459 static const int operatorHelper[];
2460
2461 int decodeOp(int op) {
2462 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002463 error("Out-of-range operator: %d\n", op);
Jack Palevich0a280a02009-06-11 10:53:51 -07002464 op = 0;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002465 }
2466 return operatorHelper[op];
2467 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002468
Jack Palevich546b2242009-05-13 15:10:04 -07002469 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07002470 o(l + 0x83);
Jack Palevich8dc662e2009-06-09 22:53:47 +00002471 oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
Jack Palevich21a15a22009-05-11 14:49:29 -07002472 }
Jack Palevicha39749f2009-07-08 20:40:31 -07002473
2474 void setupFloatOperands() {
2475 Type* pR0Type = getR0Type();
2476 Type* pTOSType = getTOSType();
2477 TypeTag tagR0 = pR0Type->tag;
2478 TypeTag tagTOS = pTOSType->tag;
2479 bool isFloatR0 = isFloatTag(tagR0);
2480 bool isFloatTOS = isFloatTag(tagTOS);
2481 if (! isFloatR0) {
2482 // Convert R0 from int to float
2483 o(0x50); // push %eax
2484 o(0x2404DB); // fildl 0(%esp)
2485 o(0x58); // pop %eax
2486 }
2487 if (! isFloatTOS){
2488 o(0x2404DB); // fildl 0(%esp);
2489 o(0x58); // pop %eax
2490 } else {
2491 if (tagTOS == TY_FLOAT) {
2492 o(0x2404d9); // flds (%esp)
2493 o(0x58); // pop %eax
2494 } else {
2495 o(0x2404dd); // fldl (%esp)
2496 o(0x58); // pop %eax
2497 o(0x58); // pop %eax
2498 }
2499 }
Jack Palevichb7718b92009-07-09 22:00:24 -07002500 popType();
Jack Palevicha39749f2009-07-08 20:40:31 -07002501 }
Jack Palevich21a15a22009-05-11 14:49:29 -07002502 };
2503
Jack Paleviche7b59062009-05-19 17:12:17 -07002504#endif // PROVIDE_X86_CODEGEN
2505
Jack Palevichb67b18f2009-06-11 21:12:23 -07002506#ifdef PROVIDE_TRACE_CODEGEN
2507 class TraceCodeGenerator : public CodeGenerator {
2508 private:
2509 CodeGenerator* mpBase;
2510
2511 public:
2512 TraceCodeGenerator(CodeGenerator* pBase) {
2513 mpBase = pBase;
2514 }
2515
2516 virtual ~TraceCodeGenerator() {
2517 delete mpBase;
2518 }
2519
2520 virtual void init(CodeBuf* pCodeBuf) {
2521 mpBase->init(pCodeBuf);
2522 }
2523
2524 void setErrorSink(ErrorSink* pErrorSink) {
2525 mpBase->setErrorSink(pErrorSink);
2526 }
2527
2528 /* returns address to patch with local variable size
2529 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002530 virtual int functionEntry(Type* pDecl) {
2531 int result = mpBase->functionEntry(pDecl);
2532 fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002533 return result;
2534 }
2535
Jack Palevichb7718b92009-07-09 22:00:24 -07002536 virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2537 fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2538 localVariableAddress, localVariableSize);
2539 mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002540 }
2541
2542 /* load immediate value */
Jack Palevich8df46192009-07-07 14:48:51 -07002543 virtual void li(int t, Type* pType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002544 fprintf(stderr, "li(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002545 mpBase->li(t, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002546 }
2547
Jack Palevich1a539db2009-07-08 13:04:41 -07002548 virtual void loadFloat(int address, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002549 fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
Jack Palevich1a539db2009-07-08 13:04:41 -07002550 mpBase->loadFloat(address, pType);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002551 }
2552
Jack Palevichb67b18f2009-06-11 21:12:23 -07002553 virtual int gjmp(int t) {
2554 int result = mpBase->gjmp(t);
2555 fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2556 return result;
2557 }
2558
2559 /* l = 0: je, l == 1: jne */
2560 virtual int gtst(bool l, int t) {
2561 int result = mpBase->gtst(l, t);
2562 fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
2563 return result;
2564 }
2565
Jack Palevicha39749f2009-07-08 20:40:31 -07002566 virtual void gcmp(int op, Type* pResultType) {
2567 fprintf(stderr, "gcmp(%d, pResultType)\n", op);
2568 mpBase->gcmp(op, pResultType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002569 }
2570
2571 virtual void genOp(int op) {
2572 fprintf(stderr, "genOp(%d)\n", op);
2573 mpBase->genOp(op);
2574 }
2575
Jack Palevich9eed7a22009-07-06 17:24:34 -07002576
Jack Palevicha39749f2009-07-08 20:40:31 -07002577 virtual void gUnaryCmp(int op, Type* pResultType) {
2578 fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
2579 mpBase->gUnaryCmp(op, pResultType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002580 }
2581
2582 virtual void genUnaryOp(int op) {
2583 fprintf(stderr, "genUnaryOp(%d)\n", op);
2584 mpBase->genUnaryOp(op);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002585 }
2586
2587 virtual void pushR0() {
2588 fprintf(stderr, "pushR0()\n");
2589 mpBase->pushR0();
2590 }
2591
Jack Palevich9eed7a22009-07-06 17:24:34 -07002592 virtual void storeR0ToTOS(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002593 fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002594 mpBase->storeR0ToTOS(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002595 }
2596
Jack Palevich9eed7a22009-07-06 17:24:34 -07002597 virtual void loadR0FromR0(Type* pPointerType) {
Jack Palevich1aeb87b2009-07-06 18:33:20 -07002598 fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType->pHead->tag);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002599 mpBase->loadR0FromR0(pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002600 }
2601
Jack Palevich8df46192009-07-07 14:48:51 -07002602 virtual void leaR0(int ea, Type* pPointerType) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002603 fprintf(stderr, "leaR0(%d)\n", ea);
Jack Palevich8df46192009-07-07 14:48:51 -07002604 mpBase->leaR0(ea, pPointerType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002605 }
2606
Jack Palevich9cbd2262009-07-08 16:48:41 -07002607 virtual void storeR0(int ea, Type* pType) {
Jack Palevich8148c5b2009-07-16 18:24:47 -07002608 fprintf(stderr, "storeR0(%d, pType=%d)\n", ea, pType->tag);
Jack Palevich9cbd2262009-07-08 16:48:41 -07002609 mpBase->storeR0(ea, pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002610 }
2611
Jack Palevich8df46192009-07-07 14:48:51 -07002612 virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) {
Jack Palevich1a539db2009-07-08 13:04:41 -07002613 fprintf(stderr, "loadR0(%d, %d, %d, pType)\n", ea, isIncDec, op);
Jack Palevich8df46192009-07-07 14:48:51 -07002614 mpBase->loadR0(ea, isIncDec, op, pType);
2615 }
2616
2617 virtual void convertR0(Type* pType){
Jack Palevich37c54bd2009-07-14 18:35:36 -07002618 fprintf(stderr, "convertR0(pType tag=%d)\n", pType->tag);
Jack Palevich8df46192009-07-07 14:48:51 -07002619 mpBase->convertR0(pType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002620 }
2621
2622 virtual int beginFunctionCallArguments() {
2623 int result = mpBase->beginFunctionCallArguments();
2624 fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
2625 return result;
2626 }
2627
Jack Palevich8148c5b2009-07-16 18:24:47 -07002628 virtual size_t storeR0ToArg(int l, Type* pArgType) {
2629 fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
2630 pArgType->tag);
2631 return mpBase->storeR0ToArg(l, pArgType);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002632 }
2633
Jack Palevichb7718b92009-07-09 22:00:24 -07002634 virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002635 fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
Jack Palevichb7718b92009-07-09 22:00:24 -07002636 mpBase->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002637 }
2638
Jack Palevich8df46192009-07-07 14:48:51 -07002639 virtual int callForward(int symbol, Type* pFunc) {
2640 int result = mpBase->callForward(symbol, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002641 fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
2642 return result;
2643 }
2644
Jack Palevich8df46192009-07-07 14:48:51 -07002645 virtual void callRelative(int t, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002646 fprintf(stderr, "callRelative(%d)\n", t);
Jack Palevich8df46192009-07-07 14:48:51 -07002647 mpBase->callRelative(t, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002648 }
2649
Jack Palevich8df46192009-07-07 14:48:51 -07002650 virtual void callIndirect(int l, Type* pFunc) {
Jack Palevichb67b18f2009-06-11 21:12:23 -07002651 fprintf(stderr, "callIndirect(%d)\n", l);
Jack Palevich8df46192009-07-07 14:48:51 -07002652 mpBase->callIndirect(l, pFunc);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002653 }
2654
Jack Palevichb7718b92009-07-09 22:00:24 -07002655 virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2656 fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
2657 mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
Jack Palevichb67b18f2009-06-11 21:12:23 -07002658 }
2659
2660 virtual int jumpOffset() {
2661 return mpBase->jumpOffset();
2662 }
2663
2664 virtual int disassemble(FILE* out) {
2665 return mpBase->disassemble(out);
2666 }
2667
2668 /* output a symbol and patch all calls to it */
2669 virtual void gsym(int t) {
2670 fprintf(stderr, "gsym(%d)\n", t);
2671 mpBase->gsym(t);
2672 }
2673
2674 virtual int finishCompile() {
2675 int result = mpBase->finishCompile();
2676 fprintf(stderr, "finishCompile() = %d\n", result);
2677 return result;
2678 }
Jack Palevich9eed7a22009-07-06 17:24:34 -07002679
2680 /**
Jack Palevich9cbd2262009-07-08 16:48:41 -07002681 * Alignment (in bytes) for this type of data
Jack Palevich9eed7a22009-07-06 17:24:34 -07002682 */
Jack Palevichb7718b92009-07-09 22:00:24 -07002683 virtual size_t alignmentOf(Type* pType){
2684 return mpBase->alignmentOf(pType);
Jack Palevich9eed7a22009-07-06 17:24:34 -07002685 }
2686
2687 /**
2688 * Array element alignment (in bytes) for this type of data.
2689 */
2690 virtual size_t sizeOf(Type* pType){
2691 return mpBase->sizeOf(pType);
2692 }
Jack Palevich1a539db2009-07-08 13:04:41 -07002693
Jack Palevich9cbd2262009-07-08 16:48:41 -07002694
2695 virtual size_t stackSizeOf(Type* pType) {
2696 return mpBase->stackSizeOf(pType);
2697 }
2698
2699
Jack Palevich1a539db2009-07-08 13:04:41 -07002700 virtual Type* getR0Type() {
2701 return mpBase->getR0Type();
2702 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07002703 };
2704
2705#endif // PROVIDE_TRACE_CODEGEN
2706
Jack Palevich569f1352009-06-29 14:29:08 -07002707 class Arena {
2708 public:
2709 // Used to record a given allocation amount.
2710 // Used:
2711 // Mark mark = arena.mark();
2712 // ... lots of arena.allocate()
2713 // arena.free(mark);
2714
2715 struct Mark {
2716 size_t chunk;
2717 size_t offset;
2718 };
2719
2720 Arena() {
2721 mCurrentChunk = 0;
2722 Chunk start(CHUNK_SIZE);
2723 mData.push_back(start);
2724 }
2725
2726 ~Arena() {
2727 for(size_t i = 0; i < mData.size(); i++) {
2728 mData[i].free();
2729 }
2730 }
2731
2732 // Alloc using the standard alignment size safe for any variable
2733 void* alloc(size_t size) {
2734 return alloc(size, 8);
2735 }
2736
2737 Mark mark(){
2738 Mark result;
2739 result.chunk = mCurrentChunk;
2740 result.offset = mData[mCurrentChunk].mOffset;
2741 return result;
2742 }
2743
2744 void freeToMark(const Mark& mark) {
2745 mCurrentChunk = mark.chunk;
2746 mData[mCurrentChunk].mOffset = mark.offset;
2747 }
2748
2749 private:
2750 // Allocate memory aligned to a given size
2751 // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
2752 // Memory is not zero filled.
2753
2754 void* alloc(size_t size, size_t alignment) {
2755 while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
2756 if (mCurrentChunk + 1 < mData.size()) {
2757 mCurrentChunk++;
2758 } else {
2759 size_t allocSize = CHUNK_SIZE;
2760 if (allocSize < size + alignment - 1) {
2761 allocSize = size + alignment - 1;
2762 }
2763 Chunk chunk(allocSize);
2764 mData.push_back(chunk);
2765 mCurrentChunk++;
2766 }
2767 }
2768 return mData[mCurrentChunk].allocate(size, alignment);
2769 }
2770
2771 static const size_t CHUNK_SIZE = 128*1024;
2772 // Note: this class does not deallocate its
2773 // memory when it's destroyed. It depends upon
2774 // its parent to deallocate the memory.
2775 struct Chunk {
2776 Chunk() {
2777 mpData = 0;
2778 mSize = 0;
2779 mOffset = 0;
2780 }
2781
2782 Chunk(size_t size) {
2783 mSize = size;
2784 mpData = (char*) malloc(size);
2785 mOffset = 0;
2786 }
2787
2788 ~Chunk() {
2789 // Doesn't deallocate memory.
2790 }
2791
2792 void* allocate(size_t size, size_t alignment) {
2793 size_t alignedOffset = aligned(mOffset, alignment);
2794 void* result = mpData + alignedOffset;
2795 mOffset = alignedOffset + size;
2796 return result;
2797 }
2798
2799 void free() {
2800 if (mpData) {
2801 ::free(mpData);
2802 mpData = 0;
2803 }
2804 }
2805
2806 size_t remainingCapacity(size_t alignment) {
2807 return aligned(mSize, alignment) - aligned(mOffset, alignment);
2808 }
2809
2810 // Assume alignment is a power of two
2811 inline size_t aligned(size_t v, size_t alignment) {
2812 size_t mask = alignment-1;
2813 return (v + mask) & ~mask;
2814 }
2815
2816 char* mpData;
2817 size_t mSize;
2818 size_t mOffset;
2819 };
2820
2821 size_t mCurrentChunk;
2822
2823 Vector<Chunk> mData;
2824 };
2825
Jack Palevich569f1352009-06-29 14:29:08 -07002826 struct VariableInfo;
2827
2828 struct Token {
2829 int hash;
2830 size_t length;
2831 char* pText;
2832 tokenid_t id;
2833
2834 // Current values for the token
2835 char* mpMacroDefinition;
2836 VariableInfo* mpVariableInfo;
2837 };
2838
2839 class TokenTable {
2840 public:
2841 // Don't use 0..0xff, allows characters and operators to be tokens too.
2842
2843 static const int TOKEN_BASE = 0x100;
2844 TokenTable() {
2845 mpMap = hashmapCreate(128, hashFn, equalsFn);
2846 }
2847
2848 ~TokenTable() {
2849 hashmapFree(mpMap);
2850 }
2851
2852 void setArena(Arena* pArena) {
2853 mpArena = pArena;
2854 }
2855
2856 // Returns a token for a given string of characters.
2857 tokenid_t intern(const char* pText, size_t length) {
2858 Token probe;
2859 int hash = hashmapHash((void*) pText, length);
2860 {
2861 Token probe;
2862 probe.hash = hash;
2863 probe.length = length;
2864 probe.pText = (char*) pText;
2865 Token* pValue = (Token*) hashmapGet(mpMap, &probe);
2866 if (pValue) {
Jack Palevich569f1352009-06-29 14:29:08 -07002867 return pValue->id;
2868 }
2869 }
2870
2871 Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
2872 memset(pToken, 0, sizeof(*pToken));
2873 pToken->hash = hash;
2874 pToken->length = length;
2875 pToken->pText = (char*) mpArena->alloc(length + 1);
2876 memcpy(pToken->pText, pText, length);
2877 pToken->pText[length] = 0;
2878 pToken->id = mTokens.size() + TOKEN_BASE;
2879 mTokens.push_back(pToken);
2880 hashmapPut(mpMap, pToken, pToken);
Jack Palevich569f1352009-06-29 14:29:08 -07002881 return pToken->id;
2882 }
2883
2884 // Return the Token for a given tokenid.
2885 Token& operator[](tokenid_t id) {
2886 return *mTokens[id - TOKEN_BASE];
2887 }
2888
2889 inline size_t size() {
2890 return mTokens.size();
2891 }
2892
2893 private:
2894
2895 static int hashFn(void* pKey) {
2896 Token* pToken = (Token*) pKey;
2897 return pToken->hash;
2898 }
2899
2900 static bool equalsFn(void* keyA, void* keyB) {
2901 Token* pTokenA = (Token*) keyA;
2902 Token* pTokenB = (Token*) keyB;
2903 // Don't need to compare hash values, they should always be equal
2904 return pTokenA->length == pTokenB->length
2905 && strcmp(pTokenA->pText, pTokenB->pText) == 0;
2906 }
2907
2908 Hashmap* mpMap;
2909 Vector<Token*> mTokens;
2910 Arena* mpArena;
2911 };
2912
Jack Palevich1cdef202009-05-22 12:06:27 -07002913 class InputStream {
2914 public:
Marco Nelisseneea5ae92009-07-08 16:59:18 -07002915 virtual ~InputStream() {}
Jack Palevichdc456462009-07-16 16:50:56 -07002916 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002917 };
2918
2919 class TextInputStream : public InputStream {
2920 public:
2921 TextInputStream(const char* text, size_t textLength)
2922 : pText(text), mTextLength(textLength), mPosition(0) {
2923 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002924
Jack Palevichdc456462009-07-16 16:50:56 -07002925 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002926 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2927 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002928
Jack Palevichdc456462009-07-16 16:50:56 -07002929 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002930 const char* pText;
2931 size_t mTextLength;
2932 size_t mPosition;
2933 };
2934
Jack Palevicheedf9d22009-06-04 16:23:40 -07002935 class String {
2936 public:
2937 String() {
2938 mpBase = 0;
2939 mUsed = 0;
2940 mSize = 0;
2941 }
2942
Jack Palevich303d8ff2009-06-11 19:06:24 -07002943 String(const char* item, int len, bool adopt) {
2944 if (len < 0) {
2945 len = strlen(item);
2946 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002947 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002948 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002949 mUsed = len;
2950 mSize = len + 1;
2951 } else {
2952 mpBase = 0;
2953 mUsed = 0;
2954 mSize = 0;
2955 appendBytes(item, len);
2956 }
2957 }
2958
Jack Palevich303d8ff2009-06-11 19:06:24 -07002959 String(const String& other) {
2960 mpBase = 0;
2961 mUsed = 0;
2962 mSize = 0;
2963 appendBytes(other.getUnwrapped(), other.len());
2964 }
2965
Jack Palevicheedf9d22009-06-04 16:23:40 -07002966 ~String() {
2967 if (mpBase) {
2968 free(mpBase);
2969 }
2970 }
2971
Jack Palevicha6baa232009-06-12 11:25:59 -07002972 String& operator=(const String& other) {
2973 clear();
2974 appendBytes(other.getUnwrapped(), other.len());
2975 return *this;
2976 }
2977
Jack Palevich303d8ff2009-06-11 19:06:24 -07002978 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002979 return mpBase;
2980 }
2981
Jack Palevich303d8ff2009-06-11 19:06:24 -07002982 void clear() {
2983 mUsed = 0;
2984 if (mSize > 0) {
2985 mpBase[0] = 0;
2986 }
2987 }
2988
Jack Palevicheedf9d22009-06-04 16:23:40 -07002989 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002990 appendBytes(s, strlen(s));
2991 }
2992
2993 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002994 memcpy(ensure(n), s, n + 1);
2995 }
2996
2997 void append(char c) {
2998 * ensure(1) = c;
2999 }
3000
Jack Palevich86351982009-06-30 18:09:56 -07003001 void append(String& other) {
3002 appendBytes(other.getUnwrapped(), other.len());
3003 }
3004
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003005 char* orphan() {
3006 char* result = mpBase;
3007 mpBase = 0;
3008 mUsed = 0;
3009 mSize = 0;
3010 return result;
3011 }
3012
Jack Palevicheedf9d22009-06-04 16:23:40 -07003013 void printf(const char* fmt,...) {
3014 va_list ap;
3015 va_start(ap, fmt);
3016 vprintf(fmt, ap);
3017 va_end(ap);
3018 }
3019
3020 void vprintf(const char* fmt, va_list ap) {
3021 char* temp;
3022 int numChars = vasprintf(&temp, fmt, ap);
3023 memcpy(ensure(numChars), temp, numChars+1);
3024 free(temp);
3025 }
3026
Jack Palevich303d8ff2009-06-11 19:06:24 -07003027 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003028 return mUsed;
3029 }
3030
3031 private:
3032 char* ensure(int n) {
3033 size_t newUsed = mUsed + n;
3034 if (newUsed > mSize) {
3035 size_t newSize = mSize * 2 + 10;
3036 if (newSize < newUsed) {
3037 newSize = newUsed;
3038 }
3039 mpBase = (char*) realloc(mpBase, newSize + 1);
3040 mSize = newSize;
3041 }
3042 mpBase[newUsed] = '\0';
3043 char* result = mpBase + mUsed;
3044 mUsed = newUsed;
3045 return result;
3046 }
3047
3048 char* mpBase;
3049 size_t mUsed;
3050 size_t mSize;
3051 };
3052
Jack Palevich569f1352009-06-29 14:29:08 -07003053 void internKeywords() {
3054 // Note: order has to match TOK_ constants
3055 static const char* keywords[] = {
3056 "int",
3057 "char",
3058 "void",
3059 "if",
3060 "else",
3061 "while",
3062 "break",
3063 "return",
3064 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003065 "auto",
3066 "case",
3067 "const",
3068 "continue",
3069 "default",
3070 "do",
3071 "double",
3072 "enum",
3073 "extern",
3074 "float",
3075 "goto",
3076 "long",
3077 "register",
3078 "short",
3079 "signed",
3080 "sizeof",
3081 "static",
3082 "struct",
3083 "switch",
3084 "typedef",
3085 "union",
3086 "unsigned",
3087 "volatile",
3088 "_Bool",
3089 "_Complex",
3090 "_Imaginary",
3091 "inline",
3092 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003093
3094 // predefined tokens that can also be symbols start here:
3095 "pragma",
3096 "define",
3097 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003098 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003099
Jack Palevich569f1352009-06-29 14:29:08 -07003100 for(int i = 0; keywords[i]; i++) {
3101 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003102 }
Jack Palevich569f1352009-06-29 14:29:08 -07003103 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003104
Jack Palevich36d94142009-06-08 15:55:32 -07003105 struct InputState {
3106 InputStream* pStream;
3107 int oldCh;
3108 };
3109
Jack Palevich2db168f2009-06-11 14:29:47 -07003110 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003111 void* pAddress;
3112 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003113 tokenid_t tok;
3114 size_t level;
3115 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003116 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003117 };
3118
Jack Palevich303d8ff2009-06-11 19:06:24 -07003119 class SymbolStack {
3120 public:
3121 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003122 mpArena = 0;
3123 mpTokenTable = 0;
3124 }
3125
3126 void setArena(Arena* pArena) {
3127 mpArena = pArena;
3128 }
3129
3130 void setTokenTable(TokenTable* pTokenTable) {
3131 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003132 }
3133
3134 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003135 Mark mark;
3136 mark.mArenaMark = mpArena->mark();
3137 mark.mSymbolHead = mStack.size();
3138 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003139 }
3140
3141 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003142 // Undo any shadowing that was done:
3143 Mark mark = mLevelStack.back();
3144 mLevelStack.pop_back();
3145 while (mStack.size() > mark.mSymbolHead) {
3146 VariableInfo* pV = mStack.back();
3147 mStack.pop_back();
3148 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003149 }
Jack Palevich569f1352009-06-29 14:29:08 -07003150 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003151 }
3152
Jack Palevich569f1352009-06-29 14:29:08 -07003153 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3154 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3155 return pV && pV->level == level();
3156 }
3157
3158 VariableInfo* add(tokenid_t tok) {
3159 Token& token = (*mpTokenTable)[tok];
3160 VariableInfo* pOldV = token.mpVariableInfo;
3161 VariableInfo* pNewV =
3162 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3163 memset(pNewV, 0, sizeof(VariableInfo));
3164 pNewV->tok = tok;
3165 pNewV->level = level();
3166 pNewV->pOldDefinition = pOldV;
3167 token.mpVariableInfo = pNewV;
3168 mStack.push_back(pNewV);
3169 return pNewV;
3170 }
3171
Jack Palevich86351982009-06-30 18:09:56 -07003172 VariableInfo* add(Type* pType) {
3173 VariableInfo* pVI = add(pType->id);
3174 pVI->pType = pType;
3175 return pVI;
3176 }
3177
Jack Palevich569f1352009-06-29 14:29:08 -07003178 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3179 for (size_t i = 0; i < mStack.size(); i++) {
3180 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003181 break;
3182 }
3183 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003184 }
3185
Jack Palevich303d8ff2009-06-11 19:06:24 -07003186 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003187 inline size_t level() {
3188 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003189 }
3190
Jack Palevich569f1352009-06-29 14:29:08 -07003191 struct Mark {
3192 Arena::Mark mArenaMark;
3193 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003194 };
3195
Jack Palevich569f1352009-06-29 14:29:08 -07003196 Arena* mpArena;
3197 TokenTable* mpTokenTable;
3198 Vector<VariableInfo*> mStack;
3199 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003200 };
Jack Palevich36d94142009-06-08 15:55:32 -07003201
3202 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003203 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003204 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003205 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003206 int tokl; // token operator level
3207 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003208 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003209 intptr_t loc; // local variable index
3210 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003211 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003212 char* dptr; // Macro state: Points to macro text during macro playback.
3213 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003214 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003215 ACCSymbolLookupFn mpSymbolLookupFn;
3216 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003217
3218 // Arena for the duration of the compile
3219 Arena mGlobalArena;
3220 // Arena for data that's only needed when compiling a single function
3221 Arena mLocalArena;
3222
3223 TokenTable mTokenTable;
3224 SymbolStack mGlobals;
3225 SymbolStack mLocals;
3226
Jack Palevich40600de2009-07-01 15:32:35 -07003227 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003228 Type* mkpInt; // int
3229 Type* mkpChar; // char
3230 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003231 Type* mkpFloat;
3232 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003233 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003234 Type* mkpIntPtr;
3235 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003236 Type* mkpFloatPtr;
3237 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003238 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003239
Jack Palevich36d94142009-06-08 15:55:32 -07003240 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003241 int mLineNumber;
3242 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003243
3244 CodeBuf codeBuf;
3245 CodeGenerator* pGen;
3246
Jack Palevicheedf9d22009-06-04 16:23:40 -07003247 String mErrorBuf;
3248
Jack Palevicheedf9d22009-06-04 16:23:40 -07003249 String mPragmas;
3250 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003251 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003252
Jack Palevich21a15a22009-05-11 14:49:29 -07003253 static const int ALLOC_SIZE = 99999;
3254
Jack Palevich303d8ff2009-06-11 19:06:24 -07003255 static const int TOK_DUMMY = 1;
3256 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003257 static const int TOK_NUM_FLOAT = 3;
3258 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003259
3260 // 3..255 are character and/or operators
3261
Jack Palevich2db168f2009-06-11 14:29:47 -07003262 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003263 // Order has to match string list in "internKeywords".
3264 enum {
3265 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3266 TOK_INT = TOK_KEYWORD,
3267 TOK_CHAR,
3268 TOK_VOID,
3269 TOK_IF,
3270 TOK_ELSE,
3271 TOK_WHILE,
3272 TOK_BREAK,
3273 TOK_RETURN,
3274 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003275 TOK_AUTO,
3276 TOK_CASE,
3277 TOK_CONST,
3278 TOK_CONTINUE,
3279 TOK_DEFAULT,
3280 TOK_DO,
3281 TOK_DOUBLE,
3282 TOK_ENUM,
3283 TOK_EXTERN,
3284 TOK_FLOAT,
3285 TOK_GOTO,
3286 TOK_LONG,
3287 TOK_REGISTER,
3288 TOK_SHORT,
3289 TOK_SIGNED,
3290 TOK_SIZEOF,
3291 TOK_STATIC,
3292 TOK_STRUCT,
3293 TOK_SWITCH,
3294 TOK_TYPEDEF,
3295 TOK_UNION,
3296 TOK_UNSIGNED,
3297 TOK_VOLATILE,
3298 TOK__BOOL,
3299 TOK__COMPLEX,
3300 TOK__IMAGINARY,
3301 TOK_INLINE,
3302 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003303
3304 // Symbols start after keywords
3305
3306 TOK_SYMBOL,
3307 TOK_PRAGMA = TOK_SYMBOL,
3308 TOK_DEFINE,
3309 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003310 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003311
3312 static const int LOCAL = 0x200;
3313
3314 static const int SYM_FORWARD = 0;
3315 static const int SYM_DEFINE = 1;
3316
3317 /* tokens in string heap */
3318 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003319
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003320 static const int OP_INCREMENT = 0;
3321 static const int OP_DECREMENT = 1;
3322 static const int OP_MUL = 2;
3323 static const int OP_DIV = 3;
3324 static const int OP_MOD = 4;
3325 static const int OP_PLUS = 5;
3326 static const int OP_MINUS = 6;
3327 static const int OP_SHIFT_LEFT = 7;
3328 static const int OP_SHIFT_RIGHT = 8;
3329 static const int OP_LESS_EQUAL = 9;
3330 static const int OP_GREATER_EQUAL = 10;
3331 static const int OP_LESS = 11;
3332 static const int OP_GREATER = 12;
3333 static const int OP_EQUALS = 13;
3334 static const int OP_NOT_EQUALS = 14;
3335 static const int OP_LOGICAL_AND = 15;
3336 static const int OP_LOGICAL_OR = 16;
3337 static const int OP_BIT_AND = 17;
3338 static const int OP_BIT_XOR = 18;
3339 static const int OP_BIT_OR = 19;
3340 static const int OP_BIT_NOT = 20;
3341 static const int OP_LOGICAL_NOT = 21;
3342 static const int OP_COUNT = 22;
3343
3344 /* Operators are searched from front, the two-character operators appear
3345 * before the single-character operators with the same first character.
3346 * @ is used to pad out single-character operators.
3347 */
3348 static const char* operatorChars;
3349 static const char operatorLevel[];
3350
Jack Palevich569f1352009-06-29 14:29:08 -07003351 /* Called when we detect an internal problem. Does nothing in production.
3352 *
3353 */
3354 void internalError() {
3355 * (char*) 0 = 0;
3356 }
3357
Jack Palevich86351982009-06-30 18:09:56 -07003358 void assert(bool isTrue) {
3359 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003360 internalError();
3361 }
Jack Palevich86351982009-06-30 18:09:56 -07003362 }
3363
Jack Palevich40600de2009-07-01 15:32:35 -07003364 bool isSymbol(tokenid_t t) {
3365 return t >= TOK_SYMBOL &&
3366 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3367 }
3368
3369 bool isSymbolOrKeyword(tokenid_t t) {
3370 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003371 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003372 }
3373
Jack Palevich86351982009-06-30 18:09:56 -07003374 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003375 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003376 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3377 if (pV && pV->tok != t) {
3378 internalError();
3379 }
3380 return pV;
3381 }
3382
3383 inline bool isDefined(tokenid_t t) {
3384 return t >= TOK_SYMBOL && VI(t) != 0;
3385 }
3386
Jack Palevich40600de2009-07-01 15:32:35 -07003387 const char* nameof(tokenid_t t) {
3388 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003389 return mTokenTable[t].pText;
3390 }
3391
Jack Palevich21a15a22009-05-11 14:49:29 -07003392 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003393 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003394 }
3395
3396 void inp() {
3397 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003398 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003399 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003400 dptr = 0;
3401 ch = dch;
3402 }
Jack Palevichdc456462009-07-16 16:50:56 -07003403 } else {
3404 if (mbBumpLine) {
3405 mLineNumber++;
3406 mbBumpLine = false;
3407 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003408 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003409 if (ch == '\n') {
3410 mbBumpLine = true;
3411 }
3412 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003413#if 0
3414 printf("ch='%c' 0x%x\n", ch, ch);
3415#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003416 }
3417
3418 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003419 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003420 }
3421
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003422 int decodeHex(int c) {
3423 if (isdigit(c)) {
3424 c -= '0';
3425 } else if (c <= 'F') {
3426 c = c - 'A' + 10;
3427 } else {
3428 c =c - 'a' + 10;
3429 }
3430 return c;
3431 }
3432
Jack Palevichb4758ff2009-06-12 12:49:14 -07003433 /* read a character constant, advances ch to after end of constant */
3434 int getq() {
3435 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003436 if (ch == '\\') {
3437 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003438 if (isoctal(ch)) {
3439 // 1 to 3 octal characters.
3440 val = 0;
3441 for(int i = 0; i < 3; i++) {
3442 if (isoctal(ch)) {
3443 val = (val << 3) + ch - '0';
3444 inp();
3445 }
3446 }
3447 return val;
3448 } else if (ch == 'x' || ch == 'X') {
3449 // N hex chars
3450 inp();
3451 if (! isxdigit(ch)) {
3452 error("'x' character escape requires at least one digit.");
3453 } else {
3454 val = 0;
3455 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003456 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003457 inp();
3458 }
3459 }
3460 } else {
3461 int val = ch;
3462 switch (ch) {
3463 case 'a':
3464 val = '\a';
3465 break;
3466 case 'b':
3467 val = '\b';
3468 break;
3469 case 'f':
3470 val = '\f';
3471 break;
3472 case 'n':
3473 val = '\n';
3474 break;
3475 case 'r':
3476 val = '\r';
3477 break;
3478 case 't':
3479 val = '\t';
3480 break;
3481 case 'v':
3482 val = '\v';
3483 break;
3484 case '\\':
3485 val = '\\';
3486 break;
3487 case '\'':
3488 val = '\'';
3489 break;
3490 case '"':
3491 val = '"';
3492 break;
3493 case '?':
3494 val = '?';
3495 break;
3496 default:
3497 error("Undefined character escape %c", ch);
3498 break;
3499 }
3500 inp();
3501 return val;
3502 }
3503 } else {
3504 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003505 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003506 return val;
3507 }
3508
3509 static bool isoctal(int ch) {
3510 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003511 }
3512
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003513 bool acceptCh(int c) {
3514 bool result = c == ch;
3515 if (result) {
3516 pdef(ch);
3517 inp();
3518 }
3519 return result;
3520 }
3521
3522 bool acceptDigitsCh() {
3523 bool result = false;
3524 while (isdigit(ch)) {
3525 result = true;
3526 pdef(ch);
3527 inp();
3528 }
3529 return result;
3530 }
3531
3532 void parseFloat() {
3533 tok = TOK_NUM_DOUBLE;
3534 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003535 if(mTokenString.len() == 0) {
3536 mTokenString.append('0');
3537 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003538 acceptCh('.');
3539 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003540 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003541 acceptCh('-') || acceptCh('+');
3542 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003543 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003544 if (ch == 'f' || ch == 'F') {
3545 tok = TOK_NUM_FLOAT;
3546 inp();
3547 } else if (ch == 'l' || ch == 'L') {
3548 inp();
3549 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003550 }
3551 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003552 char* pEnd = pText + strlen(pText);
3553 char* pEndPtr = 0;
3554 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003555 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003556 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003557 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003558 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003559 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003560 if (errno || pEndPtr != pEnd) {
3561 error("Can't parse constant: %s", pText);
3562 }
3563 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003564 }
3565
Jack Palevich21a15a22009-05-11 14:49:29 -07003566 void next() {
3567 int l, a;
3568
Jack Palevich546b2242009-05-13 15:10:04 -07003569 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003570 if (ch == '#') {
3571 inp();
3572 next();
3573 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003574 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003575 } else if (tok == TOK_PRAGMA) {
3576 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003577 } else if (tok == TOK_LINE) {
3578 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003579 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003580 error("Unsupported preprocessor directive \"%s\"",
3581 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003582 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003583 }
3584 inp();
3585 }
3586 tokl = 0;
3587 tok = ch;
3588 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003589 if (isdigit(ch) || ch == '.') {
3590 // Start of a numeric constant. Could be integer, float, or
3591 // double, won't know until we look further.
3592 mTokenString.clear();
3593 pdef(ch);
3594 inp();
3595 int base = 10;
3596 if (tok == '0') {
3597 if (ch == 'x' || ch == 'X') {
3598 base = 16;
3599 tok = TOK_NUM;
3600 tokc = 0;
3601 inp();
3602 while ( isxdigit(ch) ) {
3603 tokc = (tokc << 4) + decodeHex(ch);
3604 inp();
3605 }
3606 } else if (isoctal(ch)){
3607 base = 8;
3608 tok = TOK_NUM;
3609 tokc = 0;
3610 while ( isoctal(ch) ) {
3611 tokc = (tokc << 3) + (ch - '0');
3612 inp();
3613 }
3614 }
3615 } else if (isdigit(tok)){
3616 acceptDigitsCh();
3617 }
3618 if (base == 10) {
3619 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3620 parseFloat();
3621 } else {
3622 // It's an integer constant
3623 char* pText = mTokenString.getUnwrapped();
3624 char* pEnd = pText + strlen(pText);
3625 char* pEndPtr = 0;
3626 errno = 0;
3627 tokc = strtol(pText, &pEndPtr, base);
3628 if (errno || pEndPtr != pEnd) {
3629 error("Can't parse constant: %s %d %d", pText, base, errno);
3630 }
3631 tok = TOK_NUM;
3632 }
3633 }
3634 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003635 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003636 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003637 pdef(ch);
3638 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003639 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003640 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3641 // Is this a macro?
3642 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3643 if (pMacroDefinition) {
3644 // Yes, it is a macro
3645 dptr = pMacroDefinition;
3646 dch = ch;
3647 inp();
3648 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003649 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003650 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003651 inp();
3652 if (tok == '\'') {
3653 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003654 tokc = getq();
3655 if (ch != '\'') {
3656 error("Expected a ' character, got %c", ch);
3657 } else {
3658 inp();
3659 }
Jack Palevich546b2242009-05-13 15:10:04 -07003660 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003661 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003662 while (ch && ch != EOF) {
3663 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003664 inp();
3665 inp();
3666 if (ch == '/')
3667 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003668 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003669 if (ch == EOF) {
3670 error("End of file inside comment.");
3671 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003672 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003673 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003674 } else if ((tok == '/') & (ch == '/')) {
3675 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003676 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003677 inp();
3678 }
3679 inp();
3680 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003681 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003682 const char* t = operatorChars;
3683 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003684 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003685 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003686 tokl = operatorLevel[opIndex];
3687 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003688 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003689#if 0
3690 printf("%c%c -> tokl=%d tokc=0x%x\n",
3691 l, a, tokl, tokc);
3692#endif
3693 if (a == ch) {
3694 inp();
3695 tok = TOK_DUMMY; /* dummy token for double tokens */
3696 }
3697 break;
3698 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003699 opIndex++;
3700 }
3701 if (l == 0) {
3702 tokl = 0;
3703 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003704 }
3705 }
3706 }
3707#if 0
3708 {
Jack Palevich569f1352009-06-29 14:29:08 -07003709 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003710 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003711 fprintf(stderr, "%s\n", buf.getUnwrapped());
3712 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003713#endif
3714 }
3715
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003716 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003717 next();
3718 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003719 String* pName = new String();
3720 while (isspace(ch)) {
3721 inp();
3722 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003723 if (ch == '(') {
3724 delete pName;
3725 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003726 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003727 }
3728 while (isspace(ch)) {
3729 inp();
3730 }
Jack Palevich569f1352009-06-29 14:29:08 -07003731 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003732 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003733 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003734 inp();
3735 }
Jack Palevich569f1352009-06-29 14:29:08 -07003736 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3737 memcpy(pDefn, value.getUnwrapped(), value.len());
3738 pDefn[value.len()] = 0;
3739 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003740 }
3741
Jack Palevicheedf9d22009-06-04 16:23:40 -07003742 void doPragma() {
3743 // # pragma name(val)
3744 int state = 0;
3745 while(ch != EOF && ch != '\n' && state < 10) {
3746 switch(state) {
3747 case 0:
3748 if (isspace(ch)) {
3749 inp();
3750 } else {
3751 state++;
3752 }
3753 break;
3754 case 1:
3755 if (isalnum(ch)) {
3756 mPragmas.append(ch);
3757 inp();
3758 } else if (ch == '(') {
3759 mPragmas.append(0);
3760 inp();
3761 state++;
3762 } else {
3763 state = 11;
3764 }
3765 break;
3766 case 2:
3767 if (isalnum(ch)) {
3768 mPragmas.append(ch);
3769 inp();
3770 } else if (ch == ')') {
3771 mPragmas.append(0);
3772 inp();
3773 state = 10;
3774 } else {
3775 state = 11;
3776 }
3777 break;
3778 }
3779 }
3780 if(state != 10) {
3781 error("Unexpected pragma syntax");
3782 }
3783 mPragmaStringCount += 2;
3784 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003785
Jack Palevichdc456462009-07-16 16:50:56 -07003786 void doLine() {
3787 // # line number { "filename "}
3788 next();
3789 if (tok != TOK_NUM) {
3790 error("Expected a line-number");
3791 } else {
3792 mLineNumber = tokc-1; // The end-of-line will increment it.
3793 }
3794 while(ch != EOF && ch != '\n') {
3795 inp();
3796 }
3797 }
3798
Jack Palevichac0e95e2009-05-29 13:53:44 -07003799 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003800 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003801 mErrorBuf.vprintf(fmt, ap);
3802 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003803 }
3804
Jack Palevich8b0624c2009-05-20 12:12:06 -07003805 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003806 if (tok != c) {
3807 error("'%c' expected", c);
3808 }
3809 next();
3810 }
3811
Jack Palevich86351982009-06-30 18:09:56 -07003812 bool accept(intptr_t c) {
3813 if (tok == c) {
3814 next();
3815 return true;
3816 }
3817 return false;
3818 }
3819
Jack Palevich40600de2009-07-01 15:32:35 -07003820 bool acceptStringLiteral() {
3821 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003822 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003823 // This while loop merges multiple adjacent string constants.
3824 while (tok == '"') {
3825 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003826 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003827 }
3828 if (ch != '"') {
3829 error("Unterminated string constant.");
3830 }
3831 inp();
3832 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003833 }
Jack Palevich40600de2009-07-01 15:32:35 -07003834 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003835 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003836 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003837 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003838
3839 return true;
3840 }
3841 return false;
3842 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003843
Jack Palevichb1544ca2009-07-16 15:09:20 -07003844 void linkGlobal(tokenid_t t, bool isFunction) {
3845 VariableInfo* pVI = VI(t);
3846 void* n = NULL;
3847 if (mpSymbolLookupFn) {
3848 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3849 }
3850 if (pVI->pType == NULL) {
3851 if (isFunction) {
3852 pVI->pType = mkpIntFn;
3853 } else {
3854 pVI->pType = mkpInt;
3855 }
3856 }
3857 pVI->pAddress = n;
3858 }
3859
Jack Palevich40600de2009-07-01 15:32:35 -07003860 /* Parse and evaluate a unary expression.
3861 * allowAssignment is true if '=' parsing wanted (quick hack)
3862 */
3863 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003864 tokenid_t t;
3865 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003866 t = 0;
3867 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3868 if (acceptStringLiteral()) {
3869 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003870 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003871 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003872 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003873 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003874 t = tok;
3875 next();
3876 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003877 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003878 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003879 // Align to 4-byte boundary
3880 glo = (char*) (((intptr_t) glo + 3) & -4);
3881 * (float*) glo = (float) ad;
3882 pGen->loadFloat((int) glo, mkpFloat);
3883 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003884 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003885 // Align to 8-byte boundary
3886 glo = (char*) (((intptr_t) glo + 7) & -8);
3887 * (double*) glo = ad;
3888 pGen->loadFloat((int) glo, mkpDouble);
3889 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003890 } else if (c == 2) {
3891 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003892 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003893 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003894 pGen->gUnaryCmp(a, mkpInt);
3895 else if (t == '+') {
3896 // ignore unary plus.
3897 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003898 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003899 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003900 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003901 // It's either a cast or an expression
3902 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3903 if (pCast) {
3904 skip(')');
3905 unary(false);
3906 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003907 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003908 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003909 skip(')');
3910 }
3911 } else if (t == '*') {
3912 /* This is a pointer dereference.
3913 */
3914 unary(false);
3915 Type* pR0Type = pGen->getR0Type();
3916 if (pR0Type->tag != TY_POINTER) {
3917 error("Expected a pointer type.");
3918 } else {
3919 if (pR0Type->pHead->tag == TY_FUNC) {
3920 t = 0;
3921 }
3922 if (accept('=')) {
3923 pGen->pushR0();
3924 expr();
3925 pGen->storeR0ToTOS(pR0Type);
3926 } else if (t) {
3927 pGen->loadR0FromR0(pR0Type);
3928 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003929 }
Jack Palevich3f226492009-07-02 14:46:19 -07003930 // Else we fall through to the function call below, with
3931 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003932 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003933 VariableInfo* pVI = VI(tok);
3934 pGen->leaR0((int) pVI->pAddress,
3935 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003936 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003937 } else if (t == EOF ) {
3938 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003939 } else if (t == ';') {
3940 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003941 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003942 // Don't have to do anything special here, the error
3943 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003944 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003945 if (!isDefined(t)) {
3946 mGlobals.add(t);
3947 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003948 }
Jack Palevich8df46192009-07-07 14:48:51 -07003949 VariableInfo* pVI = VI(t);
3950 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003951 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003952 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003953 linkGlobal(t, tok == '(');
3954 n = (intptr_t) pVI->pAddress;
3955 if (!n && tok != '(') {
3956 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003957 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003958 }
Jack Palevich40600de2009-07-01 15:32:35 -07003959 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003960 /* assignment */
3961 next();
3962 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003963 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003964 } else if (tok != '(') {
3965 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003966 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003967 linkGlobal(t, false);
3968 n = (intptr_t) pVI->pAddress;
3969 if (!n) {
3970 error("Undeclared variable %s\n", nameof(t));
3971 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003972 }
Jack Palevich8df46192009-07-07 14:48:51 -07003973 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003974 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003975 next();
3976 }
3977 }
3978 }
3979 }
3980
3981 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003982 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003983 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003984 VariableInfo* pVI = NULL;
3985 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003986 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003987 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003988 } else {
3989 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003990 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003991 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003992 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003993 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003994 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003995 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003996 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003997 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003998 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003999 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004000 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07004001 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004002 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07004003 Type* pTargetType;
4004 if (pArgList) {
4005 pTargetType = pArgList->pHead;
4006 pArgList = pArgList->pTail;
4007 } else {
4008 pTargetType = pGen->getR0Type();
4009 if (pTargetType->tag == TY_FLOAT) {
4010 pTargetType = mkpDouble;
4011 }
4012 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004013 if (pTargetType->tag == TY_VOID) {
4014 error("Can't pass void value for argument %d",
4015 argCount + 1);
4016 } else {
Jack Palevich8148c5b2009-07-16 18:24:47 -07004017 l += pGen->storeR0ToArg(l, pTargetType);
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004018 }
Jack Palevich95727a02009-07-06 12:07:15 -07004019 if (accept(',')) {
4020 // fine
4021 } else if ( tok != ')') {
4022 error("Expected ',' or ')'");
4023 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004024 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004025 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004026 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004027 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004028 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004029 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004030 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004031 if (!n) {
4032 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004033 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4034 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004035 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004036 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004037 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004038 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4039 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004040 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004041 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004042 }
4043 }
4044
Jack Palevich40600de2009-07-01 15:32:35 -07004045 /* Recursive descent parser for binary operations.
4046 */
4047 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004048 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004049 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004050 if (level-- == 1)
4051 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004052 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004053 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004054 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004055 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 t = tokc;
4057 next();
4058
Jack Palevich40600de2009-07-01 15:32:35 -07004059 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004060 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004061 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004062 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004063 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004064 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004065 // Check for syntax error.
4066 if (pGen->getR0Type() == NULL) {
4067 // We failed to parse a right-hand argument.
4068 // Push a dummy value so we don't fail
4069 pGen->li(0, mkpInt);
4070 }
Jack Palevich40600de2009-07-01 15:32:35 -07004071 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004072 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004073 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004074 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004075 }
4076 }
4077 }
4078 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004079 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004080 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004081 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004082 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004083 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004084 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004085 }
4086 }
4087 }
4088
4089 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004090 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004091 }
4092
4093 int test_expr() {
4094 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004095 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004096 }
4097
Jack Palevicha6baa232009-06-12 11:25:59 -07004098 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004099 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004100
Jack Palevich95727a02009-07-06 12:07:15 -07004101 Type* pBaseType;
4102 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004103 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004104 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004105 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004106 next();
4107 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004108 a = test_expr();
4109 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004110 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004111 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004112 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004113 n = pGen->gjmp(0); /* jmp */
4114 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004115 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004116 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004117 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004118 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004119 }
Jack Palevich546b2242009-05-13 15:10:04 -07004120 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004121 t = tok;
4122 next();
4123 skip('(');
4124 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004125 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004126 a = test_expr();
4127 } else {
4128 if (tok != ';')
4129 expr();
4130 skip(';');
4131 n = codeBuf.getPC();
4132 a = 0;
4133 if (tok != ';')
4134 a = test_expr();
4135 skip(';');
4136 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004137 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004138 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004139 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004140 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004141 n = t + 4;
4142 }
4143 }
4144 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004145 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004146 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004147 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004148 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004149 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004150 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004151 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004152 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004153 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004154 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004155 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004156 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004157 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004158 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004159 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004160 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004161 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004162 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004163 if (pReturnType->tag == TY_VOID) {
4164 error("Must not return a value from a void function");
4165 } else {
4166 pGen->convertR0(pReturnType);
4167 }
4168 } else {
4169 if (pReturnType->tag != TY_VOID) {
4170 error("Must specify a value here");
4171 }
Jack Palevich8df46192009-07-07 14:48:51 -07004172 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004173 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004174 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004175 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004176 } else if (tok != ';')
4177 expr();
4178 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004179 }
4180 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004181
Jack Palevicha8f427f2009-07-13 18:40:08 -07004182 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004183 if (a == b) {
4184 return true;
4185 }
4186 if (a == NULL || b == NULL) {
4187 return false;
4188 }
4189 TypeTag at = a->tag;
4190 if (at != b->tag) {
4191 return false;
4192 }
4193 if (at == TY_POINTER) {
4194 return typeEqual(a->pHead, b->pHead);
4195 } else if (at == TY_FUNC || at == TY_PARAM) {
4196 return typeEqual(a->pHead, b->pHead)
4197 && typeEqual(a->pTail, b->pTail);
4198 }
4199 return true;
4200 }
4201
Jack Palevich86351982009-06-30 18:09:56 -07004202 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4203 assert(tag >= TY_INT && tag <= TY_PARAM);
4204 Type* pType = (Type*) arena.alloc(sizeof(Type));
4205 memset(pType, 0, sizeof(*pType));
4206 pType->tag = tag;
4207 pType->pHead = pHead;
4208 pType->pTail = pTail;
4209 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004210 }
4211
Jack Palevich3f226492009-07-02 14:46:19 -07004212 Type* createPtrType(Type* pType, Arena& arena) {
4213 return createType(TY_POINTER, pType, NULL, arena);
4214 }
4215
4216 /**
4217 * Try to print a type in declaration order
4218 */
Jack Palevich86351982009-06-30 18:09:56 -07004219 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004220 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004221 if (pType == NULL) {
4222 buffer.appendCStr("null");
4223 return;
4224 }
Jack Palevich3f226492009-07-02 14:46:19 -07004225 decodeTypeImp(buffer, pType);
4226 }
4227
4228 void decodeTypeImp(String& buffer, Type* pType) {
4229 decodeTypeImpPrefix(buffer, pType);
4230
Jack Palevich86351982009-06-30 18:09:56 -07004231 String temp;
4232 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004233 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004234 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004235 }
4236
4237 decodeTypeImpPostfix(buffer, pType);
4238 }
4239
4240 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4241 TypeTag tag = pType->tag;
4242
Jack Palevich37c54bd2009-07-14 18:35:36 -07004243 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004244 switch (tag) {
4245 case TY_INT:
4246 buffer.appendCStr("int");
4247 break;
4248 case TY_CHAR:
4249 buffer.appendCStr("char");
4250 break;
4251 case TY_VOID:
4252 buffer.appendCStr("void");
4253 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004254 case TY_FLOAT:
4255 buffer.appendCStr("float");
4256 break;
4257 case TY_DOUBLE:
4258 buffer.appendCStr("double");
4259 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004260 default:
4261 break;
4262 }
Jack Palevich86351982009-06-30 18:09:56 -07004263 buffer.append(' ');
4264 }
Jack Palevich3f226492009-07-02 14:46:19 -07004265
4266 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004267 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004268 break;
4269 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004270 break;
4271 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004272 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004273 case TY_FLOAT:
4274 break;
4275 case TY_DOUBLE:
4276 break;
Jack Palevich86351982009-06-30 18:09:56 -07004277 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004278 decodeTypeImpPrefix(buffer, pType->pHead);
4279 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4280 buffer.append('(');
4281 }
4282 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004283 break;
4284 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004285 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004286 break;
4287 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004288 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004289 break;
4290 default:
4291 String temp;
4292 temp.printf("Unknown tag %d", pType->tag);
4293 buffer.append(temp);
4294 break;
4295 }
Jack Palevich3f226492009-07-02 14:46:19 -07004296 }
4297
4298 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4299 TypeTag tag = pType->tag;
4300
4301 switch(tag) {
4302 case TY_POINTER:
4303 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4304 buffer.append(')');
4305 }
4306 decodeTypeImpPostfix(buffer, pType->pHead);
4307 break;
4308 case TY_FUNC:
4309 buffer.append('(');
4310 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4311 decodeTypeImp(buffer, pArg);
4312 if (pArg->pTail) {
4313 buffer.appendCStr(", ");
4314 }
4315 }
4316 buffer.append(')');
4317 break;
4318 default:
4319 break;
Jack Palevich86351982009-06-30 18:09:56 -07004320 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004321 }
4322
Jack Palevich86351982009-06-30 18:09:56 -07004323 void printType(Type* pType) {
4324 String buffer;
4325 decodeType(buffer, pType);
4326 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004327 }
4328
Jack Palevich86351982009-06-30 18:09:56 -07004329 Type* acceptPrimitiveType(Arena& arena) {
4330 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004331 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004332 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004333 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004334 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004335 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004336 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004337 } else if (tok == TOK_FLOAT) {
4338 pType = mkpFloat;
4339 } else if (tok == TOK_DOUBLE) {
4340 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004341 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004342 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004343 }
4344 next();
Jack Palevich86351982009-06-30 18:09:56 -07004345 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004346 }
4347
Jack Palevich3f226492009-07-02 14:46:19 -07004348 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4349 Arena& arena) {
4350 tokenid_t declName = 0;
Jack Palevich3377bfd2009-07-16 19:05:07 -07004351 bool reportFailure = false;
Jack Palevich3f226492009-07-02 14:46:19 -07004352 pType = acceptDecl2(pType, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004353 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004354 if (declName) {
4355 // Clone the parent type so we can set a unique ID
4356 pType = createType(pType->tag, pType->pHead,
4357 pType->pTail, arena);
4358
Jack Palevich86351982009-06-30 18:09:56 -07004359 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004360 }
Jack Palevich3f226492009-07-02 14:46:19 -07004361 // fprintf(stderr, "Parsed a declaration: ");
4362 // printType(pType);
Jack Palevich3377bfd2009-07-16 19:05:07 -07004363 if (reportFailure) {
4364 return NULL;
4365 }
Jack Palevich86351982009-06-30 18:09:56 -07004366 return pType;
4367 }
4368
Jack Palevich3f226492009-07-02 14:46:19 -07004369 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4370 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004371 if (! pType) {
4372 error("Expected a declaration");
4373 }
4374 return pType;
4375 }
4376
Jack Palevich3f226492009-07-02 14:46:19 -07004377 /* Used for accepting types that appear in casts */
4378 Type* acceptCastTypeDeclaration(Arena& arena) {
4379 Type* pType = acceptPrimitiveType(arena);
4380 if (pType) {
4381 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004382 }
Jack Palevich86351982009-06-30 18:09:56 -07004383 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004384 }
4385
Jack Palevich3f226492009-07-02 14:46:19 -07004386 Type* expectCastTypeDeclaration(Arena& arena) {
4387 Type* pType = acceptCastTypeDeclaration(arena);
4388 if (! pType) {
4389 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004390 }
Jack Palevich3f226492009-07-02 14:46:19 -07004391 return pType;
4392 }
4393
4394 Type* acceptDecl2(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004395 bool nameAllowed, bool nameRequired, Arena& arena,
4396 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004397 int ptrCounter = 0;
4398 while (accept('*')) {
4399 ptrCounter++;
4400 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004401 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena,
4402 reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004403 while (ptrCounter-- > 0) {
4404 pType = createType(TY_POINTER, pType, NULL, arena);
4405 }
4406 return pType;
4407 }
4408
4409 Type* acceptDecl3(Type* pType, tokenid_t& declName,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004410 bool nameAllowed, bool nameRequired, Arena& arena,
4411 bool& reportFailure) {
Jack Palevich3f226492009-07-02 14:46:19 -07004412 // direct-dcl :
4413 // name
4414 // (dcl)
4415 // direct-dcl()
4416 // direct-dcl[]
4417 Type* pNewHead = NULL;
4418 if (accept('(')) {
4419 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
Jack Palevich3377bfd2009-07-16 19:05:07 -07004420 nameRequired, arena, reportFailure);
Jack Palevich3f226492009-07-02 14:46:19 -07004421 skip(')');
4422 } else if ((declName = acceptSymbol()) != 0) {
4423 if (nameAllowed == false && declName) {
4424 error("Symbol %s not allowed here", nameof(declName));
Jack Palevich3377bfd2009-07-16 19:05:07 -07004425 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004426 }
Jack Palevich3377bfd2009-07-16 19:05:07 -07004427 } else if (nameRequired && ! declName) {
4428 String temp;
4429 decodeToken(temp, tok, true);
4430 error("Expected name. Got %s", temp.getUnwrapped());
4431 reportFailure = true;
Jack Palevich3f226492009-07-02 14:46:19 -07004432 }
4433 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004434 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004435 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004436 pType = createType(TY_FUNC, pType, pTail, arena);
4437 skip(')');
4438 }
Jack Palevich3f226492009-07-02 14:46:19 -07004439
4440 if (pNewHead) {
4441 Type* pA = pNewHead;
4442 while (pA->pHead) {
4443 pA = pA->pHead;
4444 }
4445 pA->pHead = pType;
4446 pType = pNewHead;
4447 }
Jack Palevich86351982009-06-30 18:09:56 -07004448 return pType;
4449 }
4450
Jack Palevich3f226492009-07-02 14:46:19 -07004451 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004452 Type* pHead = NULL;
4453 Type* pTail = NULL;
4454 for(;;) {
4455 Type* pBaseArg = acceptPrimitiveType(arena);
4456 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004457 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4458 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004459 if (pArg) {
4460 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4461 if (!pHead) {
4462 pHead = pParam;
4463 pTail = pParam;
4464 } else {
4465 pTail->pTail = pParam;
4466 pTail = pParam;
4467 }
4468 }
4469 }
4470 if (! accept(',')) {
4471 break;
4472 }
4473 }
4474 return pHead;
4475 }
4476
4477 Type* expectPrimitiveType(Arena& arena) {
4478 Type* pType = acceptPrimitiveType(arena);
4479 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004480 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004481 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004482 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004483 }
Jack Palevich86351982009-06-30 18:09:56 -07004484 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004485 }
4486
Jack Palevich86351982009-06-30 18:09:56 -07004487 void addGlobalSymbol(Type* pDecl) {
4488 tokenid_t t = pDecl->id;
4489 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004490 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004491 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004492 }
Jack Palevich86351982009-06-30 18:09:56 -07004493 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004494 }
4495
Jack Palevich86351982009-06-30 18:09:56 -07004496 void reportDuplicate(tokenid_t t) {
4497 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004498 }
4499
Jack Palevich86351982009-06-30 18:09:56 -07004500 void addLocalSymbol(Type* pDecl) {
4501 tokenid_t t = pDecl->id;
4502 if (mLocals.isDefinedAtCurrentLevel(t)) {
4503 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004504 }
Jack Palevich86351982009-06-30 18:09:56 -07004505 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004506 }
4507
Jack Palevich95727a02009-07-06 12:07:15 -07004508 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004509 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004510
Jack Palevich95727a02009-07-06 12:07:15 -07004511 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004512 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004513 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4514 if (!pDecl) {
4515 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004516 }
Jack Palevich86351982009-06-30 18:09:56 -07004517 int variableAddress = 0;
4518 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004519 size_t alignment = pGen->alignmentOf(pDecl);
4520 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004521 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004522 variableAddress = -loc;
4523 VI(pDecl->id)->pAddress = (void*) variableAddress;
4524 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004525 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004526 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004527 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004528 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004529 if (tok == ',')
4530 next();
4531 }
4532 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004533 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004534 }
4535 }
4536
Jack Palevichf1728be2009-06-12 13:53:51 -07004537 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004538 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004539 }
4540
Jack Palevich37c54bd2009-07-14 18:35:36 -07004541 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004542 if (token == EOF ) {
4543 buffer.printf("EOF");
4544 } else if (token == TOK_NUM) {
4545 buffer.printf("numeric constant");
4546 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004547 if (token < 32) {
4548 buffer.printf("'\\x%02x'", token);
4549 } else {
4550 buffer.printf("'%c'", token);
4551 }
Jack Palevich569f1352009-06-29 14:29:08 -07004552 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004553 if (quote) {
4554 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4555 buffer.printf("keyword \"%s\"", nameof(token));
4556 } else {
4557 buffer.printf("symbol \"%s\"", nameof(token));
4558 }
4559 } else {
4560 buffer.printf("%s", nameof(token));
4561 }
Jack Palevich569f1352009-06-29 14:29:08 -07004562 }
4563 }
4564
Jack Palevich40600de2009-07-01 15:32:35 -07004565 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004566 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004567 if (!result) {
4568 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004569 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004570 error("Expected symbol. Got %s", temp.getUnwrapped());
4571 }
4572 return result;
4573 }
4574
Jack Palevich86351982009-06-30 18:09:56 -07004575 tokenid_t acceptSymbol() {
4576 tokenid_t result = 0;
4577 if (tok >= TOK_SYMBOL) {
4578 result = tok;
4579 next();
Jack Palevich86351982009-06-30 18:09:56 -07004580 }
4581 return result;
4582 }
4583
Jack Palevichb7c81e92009-06-04 19:56:13 -07004584 void globalDeclarations() {
4585 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004586 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4587 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004588 break;
4589 }
Jack Palevich86351982009-06-30 18:09:56 -07004590 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4591 if (!pDecl) {
4592 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004593 }
Jack Palevich86351982009-06-30 18:09:56 -07004594 if (! isDefined(pDecl->id)) {
4595 addGlobalSymbol(pDecl);
4596 }
4597 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004598 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004599 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004600 }
Jack Palevich86351982009-06-30 18:09:56 -07004601 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004602 // it's a variable declaration
4603 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004604 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004605 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004606 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004607 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004608 }
Jack Palevich86351982009-06-30 18:09:56 -07004609 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004610 if (tok == TOK_NUM) {
4611 if (name) {
4612 * (int*) name->pAddress = tokc;
4613 }
4614 next();
4615 } else {
4616 error("Expected an integer constant");
4617 }
4618 }
Jack Palevich86351982009-06-30 18:09:56 -07004619 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004620 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004621 }
Jack Palevich86351982009-06-30 18:09:56 -07004622 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4623 if (!pDecl) {
4624 break;
4625 }
4626 if (! isDefined(pDecl->id)) {
4627 addGlobalSymbol(pDecl);
4628 }
4629 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004630 }
4631 skip(';');
4632 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004633 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004634 if (accept(';')) {
4635 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004636 } else if (tok != '{') {
4637 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004638 } else {
4639 if (name) {
4640 /* patch forward references (XXX: does not work for function
4641 pointers) */
4642 pGen->gsym((int) name->pForward);
4643 /* put function address */
4644 name->pAddress = (void*) codeBuf.getPC();
4645 }
4646 // Calculate stack offsets for parameters
4647 mLocals.pushLevel();
4648 intptr_t a = 8;
4649 int argCount = 0;
4650 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4651 Type* pArg = pP->pHead;
4652 addLocalSymbol(pArg);
4653 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004654 size_t alignment = pGen->alignmentOf(pArg);
4655 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004656 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004657 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004658 argCount++;
4659 }
4660 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004661 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004662 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004663 block(0, true);
4664 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004665 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004666 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004667 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004668 }
4669 }
4670 }
4671
Jack Palevich9cbd2262009-07-08 16:48:41 -07004672 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4673 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4674 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004675 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004676 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004677 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004678 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004679 char* result = (char*) base;
4680 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004681 return result;
4682 }
4683
Jack Palevich21a15a22009-05-11 14:49:29 -07004684 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004685 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004686 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004687 pGlobalBase = 0;
4688 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004689 if (pGen) {
4690 delete pGen;
4691 pGen = 0;
4692 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004693 if (file) {
4694 delete file;
4695 file = 0;
4696 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004697 }
4698
Jack Palevich8c246a92009-07-14 21:14:10 -07004699 // One-time initialization, when class is constructed.
4700 void init() {
4701 mpSymbolLookupFn = 0;
4702 mpSymbolLookupContext = 0;
4703 }
4704
Jack Palevich21a15a22009-05-11 14:49:29 -07004705 void clear() {
4706 tok = 0;
4707 tokc = 0;
4708 tokl = 0;
4709 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004710 rsym = 0;
4711 loc = 0;
4712 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004713 dptr = 0;
4714 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004715 file = 0;
4716 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004717 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004718 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004719 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004720 mLineNumber = 1;
4721 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004722 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004723
Jack Palevich22305132009-05-13 10:58:45 -07004724 void setArchitecture(const char* architecture) {
4725 delete pGen;
4726 pGen = 0;
4727
4728 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004729#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004730 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004731 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004732 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004733#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004734#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004735 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004736 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004737 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004738#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004739 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004740 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004741 }
4742 }
4743
4744 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004745#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004746 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004747#elif defined(DEFAULT_X86_CODEGEN)
4748 pGen = new X86CodeGenerator();
4749#endif
4750 }
4751 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004752 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004753 } else {
4754 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004755 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004756 }
4757 }
4758
Jack Palevich77ae76e2009-05-10 19:59:24 -07004759public:
Jack Palevich22305132009-05-13 10:58:45 -07004760 struct args {
4761 args() {
4762 architecture = 0;
4763 }
4764 const char* architecture;
4765 };
4766
Jack Paleviche7b59062009-05-19 17:12:17 -07004767 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004768 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004769 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004770 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004771
Jack Paleviche7b59062009-05-19 17:12:17 -07004772 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004773 cleanup();
4774 }
4775
Jack Palevich8c246a92009-07-14 21:14:10 -07004776 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4777 mpSymbolLookupFn = pFn;
4778 mpSymbolLookupContext = pContext;
4779 }
4780
Jack Palevich1cdef202009-05-22 12:06:27 -07004781 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004782 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004783
Jack Palevicha8f427f2009-07-13 18:40:08 -07004784 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004785 cleanup();
4786 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004787 mTokenTable.setArena(&mGlobalArena);
4788 mGlobals.setArena(&mGlobalArena);
4789 mGlobals.setTokenTable(&mTokenTable);
4790 mLocals.setArena(&mLocalArena);
4791 mLocals.setTokenTable(&mTokenTable);
4792
4793 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004794 codeBuf.init(ALLOC_SIZE);
4795 setArchitecture(NULL);
4796 if (!pGen) {
4797 return -1;
4798 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004799#ifdef PROVIDE_TRACE_CODEGEN
4800 pGen = new TraceCodeGenerator(pGen);
4801#endif
4802 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004803 pGen->init(&codeBuf);
4804 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004805 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4806 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004807 inp();
4808 next();
4809 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004810 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004811 result = pGen->finishCompile();
4812 if (result == 0) {
4813 if (mErrorBuf.len()) {
4814 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004815 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004816 }
Jack Palevichce105a92009-07-16 14:30:33 -07004817 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004818 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004819 }
4820
Jack Palevich86351982009-06-30 18:09:56 -07004821 void createPrimitiveTypes() {
4822 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4823 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4824 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004825 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4826 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004827 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004828 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4829 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004830 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4831 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004832 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004833 }
4834
Jack Palevicha6baa232009-06-12 11:25:59 -07004835 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004836 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004837 }
4838
Jack Palevich569f1352009-06-29 14:29:08 -07004839 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004840 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004841 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004842 }
4843
Jack Palevich569f1352009-06-29 14:29:08 -07004844 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004845 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004846 error("Undefined forward reference: %s",
4847 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004848 }
4849 return true;
4850 }
4851
Jack Palevich21a15a22009-05-11 14:49:29 -07004852 int dump(FILE* out) {
4853 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4854 return 0;
4855 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004856
Jack Palevicha6535612009-05-13 16:24:17 -07004857 int disassemble(FILE* out) {
4858 return pGen->disassemble(out);
4859 }
4860
Jack Palevich1cdef202009-05-22 12:06:27 -07004861 /* Look through the symbol table to find a symbol.
4862 * If found, return its value.
4863 */
4864 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004865 if (mCompileResult == 0) {
4866 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4867 VariableInfo* pVariableInfo = VI(tok);
4868 if (pVariableInfo) {
4869 return pVariableInfo->pAddress;
4870 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004871 }
4872 return NULL;
4873 }
4874
Jack Palevicheedf9d22009-06-04 16:23:40 -07004875 void getPragmas(ACCsizei* actualStringCount,
4876 ACCsizei maxStringCount, ACCchar** strings) {
4877 int stringCount = mPragmaStringCount;
4878 if (actualStringCount) {
4879 *actualStringCount = stringCount;
4880 }
4881 if (stringCount > maxStringCount) {
4882 stringCount = maxStringCount;
4883 }
4884 if (strings) {
4885 char* pPragmas = mPragmas.getUnwrapped();
4886 while (stringCount-- > 0) {
4887 *strings++ = pPragmas;
4888 pPragmas += strlen(pPragmas) + 1;
4889 }
4890 }
4891 }
4892
Jack Palevichac0e95e2009-05-29 13:53:44 -07004893 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004894 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004895 }
4896
Jack Palevich77ae76e2009-05-10 19:59:24 -07004897};
4898
Jack Paleviche7b59062009-05-19 17:12:17 -07004899const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004900 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4901
Jack Paleviche7b59062009-05-19 17:12:17 -07004902const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004903 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4904 5, 5, /* ==, != */
4905 9, 10, /* &&, || */
4906 6, 7, 8, /* & ^ | */
4907 2, 2 /* ~ ! */
4908 };
4909
Jack Palevich8b0624c2009-05-20 12:12:06 -07004910#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004911FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004912#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004913
Jack Palevich8b0624c2009-05-20 12:12:06 -07004914#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004915const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004916 0x1, // ++
4917 0xff, // --
4918 0xc1af0f, // *
4919 0xf9f79991, // /
4920 0xf9f79991, // % (With manual assist to swap results)
4921 0xc801, // +
4922 0xd8f7c829, // -
4923 0xe0d391, // <<
4924 0xf8d391, // >>
4925 0xe, // <=
4926 0xd, // >=
4927 0xc, // <
4928 0xf, // >
4929 0x4, // ==
4930 0x5, // !=
4931 0x0, // &&
4932 0x1, // ||
4933 0xc821, // &
4934 0xc831, // ^
4935 0xc809, // |
4936 0xd0f7, // ~
4937 0x4 // !
4938};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004939#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004940
Jack Palevich1cdef202009-05-22 12:06:27 -07004941struct ACCscript {
4942 ACCscript() {
4943 text = 0;
4944 textLength = 0;
4945 accError = ACC_NO_ERROR;
4946 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004947
Jack Palevich1cdef202009-05-22 12:06:27 -07004948 ~ACCscript() {
4949 delete text;
4950 }
Jack Palevich546b2242009-05-13 15:10:04 -07004951
Jack Palevich8c246a92009-07-14 21:14:10 -07004952 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4953 compiler.registerSymbolCallback(pFn, pContext);
4954 }
4955
Jack Palevich1cdef202009-05-22 12:06:27 -07004956 void setError(ACCenum error) {
4957 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4958 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004959 }
4960 }
4961
Jack Palevich1cdef202009-05-22 12:06:27 -07004962 ACCenum getError() {
4963 ACCenum result = accError;
4964 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004965 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004966 }
4967
Jack Palevich1cdef202009-05-22 12:06:27 -07004968 Compiler compiler;
4969 char* text;
4970 int textLength;
4971 ACCenum accError;
4972};
4973
4974
4975extern "C"
4976ACCscript* accCreateScript() {
4977 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004978}
Jack Palevich1cdef202009-05-22 12:06:27 -07004979
4980extern "C"
4981ACCenum accGetError( ACCscript* script ) {
4982 return script->getError();
4983}
4984
4985extern "C"
4986void accDeleteScript(ACCscript* script) {
4987 delete script;
4988}
4989
4990extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004991void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4992 ACCvoid* pContext) {
4993 script->registerSymbolCallback(pFn, pContext);
4994}
4995
4996extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004997void accScriptSource(ACCscript* script,
4998 ACCsizei count,
4999 const ACCchar ** string,
5000 const ACCint * length) {
5001 int totalLength = 0;
5002 for(int i = 0; i < count; i++) {
5003 int len = -1;
5004 const ACCchar* s = string[i];
5005 if (length) {
5006 len = length[i];
5007 }
5008 if (len < 0) {
5009 len = strlen(s);
5010 }
5011 totalLength += len;
5012 }
5013 delete script->text;
5014 char* text = new char[totalLength + 1];
5015 script->text = text;
5016 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005017 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005018 for(int i = 0; i < count; i++) {
5019 int len = -1;
5020 const ACCchar* s = string[i];
5021 if (length) {
5022 len = length[i];
5023 }
5024 if (len < 0) {
5025 len = strlen(s);
5026 }
Jack Palevich09555c72009-05-27 12:25:55 -07005027 memcpy(dest, s, len);
5028 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005029 }
5030 text[totalLength] = '\0';
5031}
5032
5033extern "C"
5034void accCompileScript(ACCscript* script) {
5035 int result = script->compiler.compile(script->text, script->textLength);
5036 if (result) {
5037 script->setError(ACC_INVALID_OPERATION);
5038 }
5039}
5040
5041extern "C"
5042void accGetScriptiv(ACCscript* script,
5043 ACCenum pname,
5044 ACCint * params) {
5045 switch (pname) {
5046 case ACC_INFO_LOG_LENGTH:
5047 *params = 0;
5048 break;
5049 }
5050}
5051
5052extern "C"
5053void accGetScriptInfoLog(ACCscript* script,
5054 ACCsizei maxLength,
5055 ACCsizei * length,
5056 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005057 char* message = script->compiler.getErrorMessage();
5058 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005059 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005060 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005061 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005062 if (infoLog && maxLength > 0) {
5063 int trimmedLength = maxLength < messageLength ?
5064 maxLength : messageLength;
5065 memcpy(infoLog, message, trimmedLength);
5066 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005067 }
5068}
5069
5070extern "C"
5071void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5072 ACCvoid ** address) {
5073 void* value = script->compiler.lookup(name);
5074 if (value) {
5075 *address = value;
5076 } else {
5077 script->setError(ACC_INVALID_VALUE);
5078 }
5079}
5080
Jack Palevicheedf9d22009-06-04 16:23:40 -07005081extern "C"
5082void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5083 ACCsizei maxStringCount, ACCchar** strings){
5084 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5085}
5086
-b master422972c2009-06-17 19:13:52 -07005087extern "C"
5088void accDisassemble(ACCscript* script) {
5089 script->compiler.disassemble(stderr);
5090}
5091
Jack Palevicheedf9d22009-06-04 16:23:40 -07005092
Jack Palevich1cdef202009-05-22 12:06:27 -07005093} // namespace acc
5094