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