blob: b4b989fc66061ee20037d3f822a08a3c6805f9ea [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 Palevichdc456462009-07-16 16:50:56 -07002909 virtual int getChar() = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002910 };
2911
2912 class TextInputStream : public InputStream {
2913 public:
2914 TextInputStream(const char* text, size_t textLength)
2915 : pText(text), mTextLength(textLength), mPosition(0) {
2916 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07002917
Jack Palevichdc456462009-07-16 16:50:56 -07002918 virtual int getChar() {
Jack Palevich1cdef202009-05-22 12:06:27 -07002919 return mPosition < mTextLength ? pText[mPosition++] : EOF;
2920 }
Jack Palevich1cdef202009-05-22 12:06:27 -07002921
Jack Palevichdc456462009-07-16 16:50:56 -07002922 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07002923 const char* pText;
2924 size_t mTextLength;
2925 size_t mPosition;
2926 };
2927
Jack Palevicheedf9d22009-06-04 16:23:40 -07002928 class String {
2929 public:
2930 String() {
2931 mpBase = 0;
2932 mUsed = 0;
2933 mSize = 0;
2934 }
2935
Jack Palevich303d8ff2009-06-11 19:06:24 -07002936 String(const char* item, int len, bool adopt) {
2937 if (len < 0) {
2938 len = strlen(item);
2939 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002940 if (adopt) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07002941 mpBase = (char*) item;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002942 mUsed = len;
2943 mSize = len + 1;
2944 } else {
2945 mpBase = 0;
2946 mUsed = 0;
2947 mSize = 0;
2948 appendBytes(item, len);
2949 }
2950 }
2951
Jack Palevich303d8ff2009-06-11 19:06:24 -07002952 String(const String& other) {
2953 mpBase = 0;
2954 mUsed = 0;
2955 mSize = 0;
2956 appendBytes(other.getUnwrapped(), other.len());
2957 }
2958
Jack Palevicheedf9d22009-06-04 16:23:40 -07002959 ~String() {
2960 if (mpBase) {
2961 free(mpBase);
2962 }
2963 }
2964
Jack Palevicha6baa232009-06-12 11:25:59 -07002965 String& operator=(const String& other) {
2966 clear();
2967 appendBytes(other.getUnwrapped(), other.len());
2968 return *this;
2969 }
2970
Jack Palevich303d8ff2009-06-11 19:06:24 -07002971 inline char* getUnwrapped() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002972 return mpBase;
2973 }
2974
Jack Palevich303d8ff2009-06-11 19:06:24 -07002975 void clear() {
2976 mUsed = 0;
2977 if (mSize > 0) {
2978 mpBase[0] = 0;
2979 }
2980 }
2981
Jack Palevicheedf9d22009-06-04 16:23:40 -07002982 void appendCStr(const char* s) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002983 appendBytes(s, strlen(s));
2984 }
2985
2986 void appendBytes(const char* s, int n) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002987 memcpy(ensure(n), s, n + 1);
2988 }
2989
2990 void append(char c) {
2991 * ensure(1) = c;
2992 }
2993
Jack Palevich86351982009-06-30 18:09:56 -07002994 void append(String& other) {
2995 appendBytes(other.getUnwrapped(), other.len());
2996 }
2997
Jack Palevich2d11dfb2009-06-08 14:34:26 -07002998 char* orphan() {
2999 char* result = mpBase;
3000 mpBase = 0;
3001 mUsed = 0;
3002 mSize = 0;
3003 return result;
3004 }
3005
Jack Palevicheedf9d22009-06-04 16:23:40 -07003006 void printf(const char* fmt,...) {
3007 va_list ap;
3008 va_start(ap, fmt);
3009 vprintf(fmt, ap);
3010 va_end(ap);
3011 }
3012
3013 void vprintf(const char* fmt, va_list ap) {
3014 char* temp;
3015 int numChars = vasprintf(&temp, fmt, ap);
3016 memcpy(ensure(numChars), temp, numChars+1);
3017 free(temp);
3018 }
3019
Jack Palevich303d8ff2009-06-11 19:06:24 -07003020 inline size_t len() const {
Jack Palevicheedf9d22009-06-04 16:23:40 -07003021 return mUsed;
3022 }
3023
3024 private:
3025 char* ensure(int n) {
3026 size_t newUsed = mUsed + n;
3027 if (newUsed > mSize) {
3028 size_t newSize = mSize * 2 + 10;
3029 if (newSize < newUsed) {
3030 newSize = newUsed;
3031 }
3032 mpBase = (char*) realloc(mpBase, newSize + 1);
3033 mSize = newSize;
3034 }
3035 mpBase[newUsed] = '\0';
3036 char* result = mpBase + mUsed;
3037 mUsed = newUsed;
3038 return result;
3039 }
3040
3041 char* mpBase;
3042 size_t mUsed;
3043 size_t mSize;
3044 };
3045
Jack Palevich569f1352009-06-29 14:29:08 -07003046 void internKeywords() {
3047 // Note: order has to match TOK_ constants
3048 static const char* keywords[] = {
3049 "int",
3050 "char",
3051 "void",
3052 "if",
3053 "else",
3054 "while",
3055 "break",
3056 "return",
3057 "for",
Jack Palevich569f1352009-06-29 14:29:08 -07003058 "auto",
3059 "case",
3060 "const",
3061 "continue",
3062 "default",
3063 "do",
3064 "double",
3065 "enum",
3066 "extern",
3067 "float",
3068 "goto",
3069 "long",
3070 "register",
3071 "short",
3072 "signed",
3073 "sizeof",
3074 "static",
3075 "struct",
3076 "switch",
3077 "typedef",
3078 "union",
3079 "unsigned",
3080 "volatile",
3081 "_Bool",
3082 "_Complex",
3083 "_Imaginary",
3084 "inline",
3085 "restrict",
Jack Palevichdc456462009-07-16 16:50:56 -07003086
3087 // predefined tokens that can also be symbols start here:
3088 "pragma",
3089 "define",
3090 "line",
Jack Palevich569f1352009-06-29 14:29:08 -07003091 0};
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003092
Jack Palevich569f1352009-06-29 14:29:08 -07003093 for(int i = 0; keywords[i]; i++) {
3094 mTokenTable.intern(keywords[i], strlen(keywords[i]));
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003095 }
Jack Palevich569f1352009-06-29 14:29:08 -07003096 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003097
Jack Palevich36d94142009-06-08 15:55:32 -07003098 struct InputState {
3099 InputStream* pStream;
3100 int oldCh;
3101 };
3102
Jack Palevich2db168f2009-06-11 14:29:47 -07003103 struct VariableInfo {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003104 void* pAddress;
3105 void* pForward; // For a forward direction, linked list of data to fix up
Jack Palevich569f1352009-06-29 14:29:08 -07003106 tokenid_t tok;
3107 size_t level;
3108 VariableInfo* pOldDefinition;
Jack Palevich86351982009-06-30 18:09:56 -07003109 Type* pType;
Jack Palevich2db168f2009-06-11 14:29:47 -07003110 };
3111
Jack Palevich303d8ff2009-06-11 19:06:24 -07003112 class SymbolStack {
3113 public:
3114 SymbolStack() {
Jack Palevich569f1352009-06-29 14:29:08 -07003115 mpArena = 0;
3116 mpTokenTable = 0;
3117 }
3118
3119 void setArena(Arena* pArena) {
3120 mpArena = pArena;
3121 }
3122
3123 void setTokenTable(TokenTable* pTokenTable) {
3124 mpTokenTable = pTokenTable;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003125 }
3126
3127 void pushLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003128 Mark mark;
3129 mark.mArenaMark = mpArena->mark();
3130 mark.mSymbolHead = mStack.size();
3131 mLevelStack.push_back(mark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003132 }
3133
3134 void popLevel() {
Jack Palevich569f1352009-06-29 14:29:08 -07003135 // Undo any shadowing that was done:
3136 Mark mark = mLevelStack.back();
3137 mLevelStack.pop_back();
3138 while (mStack.size() > mark.mSymbolHead) {
3139 VariableInfo* pV = mStack.back();
3140 mStack.pop_back();
3141 (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003142 }
Jack Palevich569f1352009-06-29 14:29:08 -07003143 mpArena->freeToMark(mark.mArenaMark);
Jack Palevich303d8ff2009-06-11 19:06:24 -07003144 }
3145
Jack Palevich569f1352009-06-29 14:29:08 -07003146 bool isDefinedAtCurrentLevel(tokenid_t tok) {
3147 VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3148 return pV && pV->level == level();
3149 }
3150
3151 VariableInfo* add(tokenid_t tok) {
3152 Token& token = (*mpTokenTable)[tok];
3153 VariableInfo* pOldV = token.mpVariableInfo;
3154 VariableInfo* pNewV =
3155 (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3156 memset(pNewV, 0, sizeof(VariableInfo));
3157 pNewV->tok = tok;
3158 pNewV->level = level();
3159 pNewV->pOldDefinition = pOldV;
3160 token.mpVariableInfo = pNewV;
3161 mStack.push_back(pNewV);
3162 return pNewV;
3163 }
3164
Jack Palevich86351982009-06-30 18:09:56 -07003165 VariableInfo* add(Type* pType) {
3166 VariableInfo* pVI = add(pType->id);
3167 pVI->pType = pType;
3168 return pVI;
3169 }
3170
Jack Palevich569f1352009-06-29 14:29:08 -07003171 void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3172 for (size_t i = 0; i < mStack.size(); i++) {
3173 if (! fn(mStack[i], context)) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003174 break;
3175 }
3176 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003177 }
3178
Jack Palevich303d8ff2009-06-11 19:06:24 -07003179 private:
Jack Palevich569f1352009-06-29 14:29:08 -07003180 inline size_t level() {
3181 return mLevelStack.size();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003182 }
3183
Jack Palevich569f1352009-06-29 14:29:08 -07003184 struct Mark {
3185 Arena::Mark mArenaMark;
3186 size_t mSymbolHead;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003187 };
3188
Jack Palevich569f1352009-06-29 14:29:08 -07003189 Arena* mpArena;
3190 TokenTable* mpTokenTable;
3191 Vector<VariableInfo*> mStack;
3192 Vector<Mark> mLevelStack;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003193 };
Jack Palevich36d94142009-06-08 15:55:32 -07003194
3195 int ch; // Current input character, or EOF
Jack Palevich569f1352009-06-29 14:29:08 -07003196 tokenid_t tok; // token
Jack Palevich36d94142009-06-08 15:55:32 -07003197 intptr_t tokc; // token extra info
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003198 double tokd; // floating point constant value
Jack Palevich36d94142009-06-08 15:55:32 -07003199 int tokl; // token operator level
3200 intptr_t rsym; // return symbol
Jack Palevich8df46192009-07-07 14:48:51 -07003201 Type* pReturnType; // type of the current function's return.
Jack Palevich36d94142009-06-08 15:55:32 -07003202 intptr_t loc; // local variable index
3203 char* glo; // global variable index
Jack Palevich303d8ff2009-06-11 19:06:24 -07003204 String mTokenString;
Jack Palevich36d94142009-06-08 15:55:32 -07003205 char* dptr; // Macro state: Points to macro text during macro playback.
3206 int dch; // Macro state: Saves old value of ch during a macro playback.
Jack Palevich36d94142009-06-08 15:55:32 -07003207 char* pGlobalBase;
Jack Palevich8c246a92009-07-14 21:14:10 -07003208 ACCSymbolLookupFn mpSymbolLookupFn;
3209 void* mpSymbolLookupContext;
Jack Palevich569f1352009-06-29 14:29:08 -07003210
3211 // Arena for the duration of the compile
3212 Arena mGlobalArena;
3213 // Arena for data that's only needed when compiling a single function
3214 Arena mLocalArena;
3215
3216 TokenTable mTokenTable;
3217 SymbolStack mGlobals;
3218 SymbolStack mLocals;
3219
Jack Palevich40600de2009-07-01 15:32:35 -07003220 // Prebuilt types, makes things slightly faster.
Jack Palevich9eed7a22009-07-06 17:24:34 -07003221 Type* mkpInt; // int
3222 Type* mkpChar; // char
3223 Type* mkpVoid; // void
Jack Palevich95727a02009-07-06 12:07:15 -07003224 Type* mkpFloat;
3225 Type* mkpDouble;
Jack Palevich8df46192009-07-07 14:48:51 -07003226 Type* mkpIntFn;
Jack Palevich3f226492009-07-02 14:46:19 -07003227 Type* mkpIntPtr;
3228 Type* mkpCharPtr;
Jack Palevich1a539db2009-07-08 13:04:41 -07003229 Type* mkpFloatPtr;
3230 Type* mkpDoublePtr;
Jack Palevich3f226492009-07-02 14:46:19 -07003231 Type* mkpPtrIntFn;
Jack Palevich86351982009-06-30 18:09:56 -07003232
Jack Palevich36d94142009-06-08 15:55:32 -07003233 InputStream* file;
Jack Palevichdc456462009-07-16 16:50:56 -07003234 int mLineNumber;
3235 bool mbBumpLine;
Jack Palevich36d94142009-06-08 15:55:32 -07003236
3237 CodeBuf codeBuf;
3238 CodeGenerator* pGen;
3239
Jack Palevicheedf9d22009-06-04 16:23:40 -07003240 String mErrorBuf;
3241
Jack Palevicheedf9d22009-06-04 16:23:40 -07003242 String mPragmas;
3243 int mPragmaStringCount;
Jack Palevichce105a92009-07-16 14:30:33 -07003244 int mCompileResult;
Jack Palevicheedf9d22009-06-04 16:23:40 -07003245
Jack Palevich21a15a22009-05-11 14:49:29 -07003246 static const int ALLOC_SIZE = 99999;
3247
Jack Palevich303d8ff2009-06-11 19:06:24 -07003248 static const int TOK_DUMMY = 1;
3249 static const int TOK_NUM = 2;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003250 static const int TOK_NUM_FLOAT = 3;
3251 static const int TOK_NUM_DOUBLE = 4;
Jack Palevich303d8ff2009-06-11 19:06:24 -07003252
3253 // 3..255 are character and/or operators
3254
Jack Palevich2db168f2009-06-11 14:29:47 -07003255 // Keywords start at 0x100 and increase by 1
Jack Palevich569f1352009-06-29 14:29:08 -07003256 // Order has to match string list in "internKeywords".
3257 enum {
3258 TOK_KEYWORD = TokenTable::TOKEN_BASE,
3259 TOK_INT = TOK_KEYWORD,
3260 TOK_CHAR,
3261 TOK_VOID,
3262 TOK_IF,
3263 TOK_ELSE,
3264 TOK_WHILE,
3265 TOK_BREAK,
3266 TOK_RETURN,
3267 TOK_FOR,
Jack Palevich569f1352009-06-29 14:29:08 -07003268 TOK_AUTO,
3269 TOK_CASE,
3270 TOK_CONST,
3271 TOK_CONTINUE,
3272 TOK_DEFAULT,
3273 TOK_DO,
3274 TOK_DOUBLE,
3275 TOK_ENUM,
3276 TOK_EXTERN,
3277 TOK_FLOAT,
3278 TOK_GOTO,
3279 TOK_LONG,
3280 TOK_REGISTER,
3281 TOK_SHORT,
3282 TOK_SIGNED,
3283 TOK_SIZEOF,
3284 TOK_STATIC,
3285 TOK_STRUCT,
3286 TOK_SWITCH,
3287 TOK_TYPEDEF,
3288 TOK_UNION,
3289 TOK_UNSIGNED,
3290 TOK_VOLATILE,
3291 TOK__BOOL,
3292 TOK__COMPLEX,
3293 TOK__IMAGINARY,
3294 TOK_INLINE,
3295 TOK_RESTRICT,
Jack Palevichdc456462009-07-16 16:50:56 -07003296
3297 // Symbols start after keywords
3298
3299 TOK_SYMBOL,
3300 TOK_PRAGMA = TOK_SYMBOL,
3301 TOK_DEFINE,
3302 TOK_LINE
Jack Palevich569f1352009-06-29 14:29:08 -07003303 };
Jack Palevich21a15a22009-05-11 14:49:29 -07003304
3305 static const int LOCAL = 0x200;
3306
3307 static const int SYM_FORWARD = 0;
3308 static const int SYM_DEFINE = 1;
3309
3310 /* tokens in string heap */
3311 static const int TAG_TOK = ' ';
Jack Palevich21a15a22009-05-11 14:49:29 -07003312
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003313 static const int OP_INCREMENT = 0;
3314 static const int OP_DECREMENT = 1;
3315 static const int OP_MUL = 2;
3316 static const int OP_DIV = 3;
3317 static const int OP_MOD = 4;
3318 static const int OP_PLUS = 5;
3319 static const int OP_MINUS = 6;
3320 static const int OP_SHIFT_LEFT = 7;
3321 static const int OP_SHIFT_RIGHT = 8;
3322 static const int OP_LESS_EQUAL = 9;
3323 static const int OP_GREATER_EQUAL = 10;
3324 static const int OP_LESS = 11;
3325 static const int OP_GREATER = 12;
3326 static const int OP_EQUALS = 13;
3327 static const int OP_NOT_EQUALS = 14;
3328 static const int OP_LOGICAL_AND = 15;
3329 static const int OP_LOGICAL_OR = 16;
3330 static const int OP_BIT_AND = 17;
3331 static const int OP_BIT_XOR = 18;
3332 static const int OP_BIT_OR = 19;
3333 static const int OP_BIT_NOT = 20;
3334 static const int OP_LOGICAL_NOT = 21;
3335 static const int OP_COUNT = 22;
3336
3337 /* Operators are searched from front, the two-character operators appear
3338 * before the single-character operators with the same first character.
3339 * @ is used to pad out single-character operators.
3340 */
3341 static const char* operatorChars;
3342 static const char operatorLevel[];
3343
Jack Palevich569f1352009-06-29 14:29:08 -07003344 /* Called when we detect an internal problem. Does nothing in production.
3345 *
3346 */
3347 void internalError() {
3348 * (char*) 0 = 0;
3349 }
3350
Jack Palevich86351982009-06-30 18:09:56 -07003351 void assert(bool isTrue) {
3352 if (!isTrue) {
Jack Palevich569f1352009-06-29 14:29:08 -07003353 internalError();
3354 }
Jack Palevich86351982009-06-30 18:09:56 -07003355 }
3356
Jack Palevich40600de2009-07-01 15:32:35 -07003357 bool isSymbol(tokenid_t t) {
3358 return t >= TOK_SYMBOL &&
3359 ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3360 }
3361
3362 bool isSymbolOrKeyword(tokenid_t t) {
3363 return t >= TOK_KEYWORD &&
Jack Palevich95727a02009-07-06 12:07:15 -07003364 ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
Jack Palevich40600de2009-07-01 15:32:35 -07003365 }
3366
Jack Palevich86351982009-06-30 18:09:56 -07003367 VariableInfo* VI(tokenid_t t) {
Jack Palevich40600de2009-07-01 15:32:35 -07003368 assert(isSymbol(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003369 VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3370 if (pV && pV->tok != t) {
3371 internalError();
3372 }
3373 return pV;
3374 }
3375
3376 inline bool isDefined(tokenid_t t) {
3377 return t >= TOK_SYMBOL && VI(t) != 0;
3378 }
3379
Jack Palevich40600de2009-07-01 15:32:35 -07003380 const char* nameof(tokenid_t t) {
3381 assert(isSymbolOrKeyword(t));
Jack Palevich569f1352009-06-29 14:29:08 -07003382 return mTokenTable[t].pText;
3383 }
3384
Jack Palevich21a15a22009-05-11 14:49:29 -07003385 void pdef(int t) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003386 mTokenString.append(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07003387 }
3388
3389 void inp() {
3390 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07003391 ch = *dptr++;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003392 if (ch == 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003393 dptr = 0;
3394 ch = dch;
3395 }
Jack Palevichdc456462009-07-16 16:50:56 -07003396 } else {
3397 if (mbBumpLine) {
3398 mLineNumber++;
3399 mbBumpLine = false;
3400 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07003401 ch = file->getChar();
Jack Palevichdc456462009-07-16 16:50:56 -07003402 if (ch == '\n') {
3403 mbBumpLine = true;
3404 }
3405 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07003406#if 0
3407 printf("ch='%c' 0x%x\n", ch, ch);
3408#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07003409 }
3410
3411 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07003412 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07003413 }
3414
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003415 int decodeHex(int c) {
3416 if (isdigit(c)) {
3417 c -= '0';
3418 } else if (c <= 'F') {
3419 c = c - 'A' + 10;
3420 } else {
3421 c =c - 'a' + 10;
3422 }
3423 return c;
3424 }
3425
Jack Palevichb4758ff2009-06-12 12:49:14 -07003426 /* read a character constant, advances ch to after end of constant */
3427 int getq() {
3428 int val = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07003429 if (ch == '\\') {
3430 inp();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003431 if (isoctal(ch)) {
3432 // 1 to 3 octal characters.
3433 val = 0;
3434 for(int i = 0; i < 3; i++) {
3435 if (isoctal(ch)) {
3436 val = (val << 3) + ch - '0';
3437 inp();
3438 }
3439 }
3440 return val;
3441 } else if (ch == 'x' || ch == 'X') {
3442 // N hex chars
3443 inp();
3444 if (! isxdigit(ch)) {
3445 error("'x' character escape requires at least one digit.");
3446 } else {
3447 val = 0;
3448 while (isxdigit(ch)) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003449 val = (val << 4) + decodeHex(ch);
Jack Palevichb4758ff2009-06-12 12:49:14 -07003450 inp();
3451 }
3452 }
3453 } else {
3454 int val = ch;
3455 switch (ch) {
3456 case 'a':
3457 val = '\a';
3458 break;
3459 case 'b':
3460 val = '\b';
3461 break;
3462 case 'f':
3463 val = '\f';
3464 break;
3465 case 'n':
3466 val = '\n';
3467 break;
3468 case 'r':
3469 val = '\r';
3470 break;
3471 case 't':
3472 val = '\t';
3473 break;
3474 case 'v':
3475 val = '\v';
3476 break;
3477 case '\\':
3478 val = '\\';
3479 break;
3480 case '\'':
3481 val = '\'';
3482 break;
3483 case '"':
3484 val = '"';
3485 break;
3486 case '?':
3487 val = '?';
3488 break;
3489 default:
3490 error("Undefined character escape %c", ch);
3491 break;
3492 }
3493 inp();
3494 return val;
3495 }
3496 } else {
3497 inp();
Jack Palevich21a15a22009-05-11 14:49:29 -07003498 }
Jack Palevichb4758ff2009-06-12 12:49:14 -07003499 return val;
3500 }
3501
3502 static bool isoctal(int ch) {
3503 return ch >= '0' && ch <= '7';
Jack Palevich21a15a22009-05-11 14:49:29 -07003504 }
3505
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003506 bool acceptCh(int c) {
3507 bool result = c == ch;
3508 if (result) {
3509 pdef(ch);
3510 inp();
3511 }
3512 return result;
3513 }
3514
3515 bool acceptDigitsCh() {
3516 bool result = false;
3517 while (isdigit(ch)) {
3518 result = true;
3519 pdef(ch);
3520 inp();
3521 }
3522 return result;
3523 }
3524
3525 void parseFloat() {
3526 tok = TOK_NUM_DOUBLE;
3527 // mTokenString already has the integral part of the number.
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003528 if(mTokenString.len() == 0) {
3529 mTokenString.append('0');
3530 }
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003531 acceptCh('.');
3532 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003533 if (acceptCh('e') || acceptCh('E')) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003534 acceptCh('-') || acceptCh('+');
3535 acceptDigitsCh();
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003536 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003537 if (ch == 'f' || ch == 'F') {
3538 tok = TOK_NUM_FLOAT;
3539 inp();
3540 } else if (ch == 'l' || ch == 'L') {
3541 inp();
3542 error("Long floating point constants not supported.");
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003543 }
3544 char* pText = mTokenString.getUnwrapped();
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003545 char* pEnd = pText + strlen(pText);
3546 char* pEndPtr = 0;
3547 errno = 0;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003548 if (tok == TOK_NUM_FLOAT) {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003549 tokd = strtof(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003550 } else {
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003551 tokd = strtod(pText, &pEndPtr);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003552 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003553 if (errno || pEndPtr != pEnd) {
3554 error("Can't parse constant: %s", pText);
3555 }
3556 // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003557 }
3558
Jack Palevich21a15a22009-05-11 14:49:29 -07003559 void next() {
3560 int l, a;
3561
Jack Palevich546b2242009-05-13 15:10:04 -07003562 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003563 if (ch == '#') {
3564 inp();
3565 next();
3566 if (tok == TOK_DEFINE) {
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003567 doDefine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003568 } else if (tok == TOK_PRAGMA) {
3569 doPragma();
Jack Palevichdc456462009-07-16 16:50:56 -07003570 } else if (tok == TOK_LINE) {
3571 doLine();
Jack Palevicheedf9d22009-06-04 16:23:40 -07003572 } else {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003573 error("Unsupported preprocessor directive \"%s\"",
3574 mTokenString.getUnwrapped());
Jack Palevich21a15a22009-05-11 14:49:29 -07003575 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003576 }
3577 inp();
3578 }
3579 tokl = 0;
3580 tok = ch;
3581 /* encode identifiers & numbers */
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003582 if (isdigit(ch) || ch == '.') {
3583 // Start of a numeric constant. Could be integer, float, or
3584 // double, won't know until we look further.
3585 mTokenString.clear();
3586 pdef(ch);
3587 inp();
3588 int base = 10;
3589 if (tok == '0') {
3590 if (ch == 'x' || ch == 'X') {
3591 base = 16;
3592 tok = TOK_NUM;
3593 tokc = 0;
3594 inp();
3595 while ( isxdigit(ch) ) {
3596 tokc = (tokc << 4) + decodeHex(ch);
3597 inp();
3598 }
3599 } else if (isoctal(ch)){
3600 base = 8;
3601 tok = TOK_NUM;
3602 tokc = 0;
3603 while ( isoctal(ch) ) {
3604 tokc = (tokc << 3) + (ch - '0');
3605 inp();
3606 }
3607 }
3608 } else if (isdigit(tok)){
3609 acceptDigitsCh();
3610 }
3611 if (base == 10) {
3612 if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
3613 parseFloat();
3614 } else {
3615 // It's an integer constant
3616 char* pText = mTokenString.getUnwrapped();
3617 char* pEnd = pText + strlen(pText);
3618 char* pEndPtr = 0;
3619 errno = 0;
3620 tokc = strtol(pText, &pEndPtr, base);
3621 if (errno || pEndPtr != pEnd) {
3622 error("Can't parse constant: %s %d %d", pText, base, errno);
3623 }
3624 tok = TOK_NUM;
3625 }
3626 }
3627 } else if (isid()) {
Jack Palevich303d8ff2009-06-11 19:06:24 -07003628 mTokenString.clear();
Jack Palevich21a15a22009-05-11 14:49:29 -07003629 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003630 pdef(ch);
3631 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07003632 }
Jack Palevich2aaf21f2009-07-15 16:16:37 -07003633 tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
3634 // Is this a macro?
3635 char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
3636 if (pMacroDefinition) {
3637 // Yes, it is a macro
3638 dptr = pMacroDefinition;
3639 dch = ch;
3640 inp();
3641 next();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003642 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003643 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003644 inp();
3645 if (tok == '\'') {
3646 tok = TOK_NUM;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003647 tokc = getq();
3648 if (ch != '\'') {
3649 error("Expected a ' character, got %c", ch);
3650 } else {
3651 inp();
3652 }
Jack Palevich546b2242009-05-13 15:10:04 -07003653 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003654 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003655 while (ch && ch != EOF) {
3656 while (ch != '*' && ch != EOF)
Jack Palevich21a15a22009-05-11 14:49:29 -07003657 inp();
3658 inp();
3659 if (ch == '/')
3660 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003661 }
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003662 if (ch == EOF) {
3663 error("End of file inside comment.");
3664 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003665 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07003666 next();
Jack Palevichbd894902009-05-14 19:35:31 -07003667 } else if ((tok == '/') & (ch == '/')) {
3668 inp();
Jack Palevich22e3e8e2009-06-12 13:12:55 -07003669 while (ch && (ch != '\n') && (ch != EOF)) {
Jack Palevichbd894902009-05-14 19:35:31 -07003670 inp();
3671 }
3672 inp();
3673 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07003674 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003675 const char* t = operatorChars;
3676 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07003677 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003678 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003679 tokl = operatorLevel[opIndex];
3680 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07003681 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003682#if 0
3683 printf("%c%c -> tokl=%d tokc=0x%x\n",
3684 l, a, tokl, tokc);
3685#endif
3686 if (a == ch) {
3687 inp();
3688 tok = TOK_DUMMY; /* dummy token for double tokens */
3689 }
3690 break;
3691 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07003692 opIndex++;
3693 }
3694 if (l == 0) {
3695 tokl = 0;
3696 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07003697 }
3698 }
3699 }
3700#if 0
3701 {
Jack Palevich569f1352009-06-29 14:29:08 -07003702 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07003703 decodeToken(buf, tok, true);
Jack Palevich86351982009-06-30 18:09:56 -07003704 fprintf(stderr, "%s\n", buf.getUnwrapped());
3705 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003706#endif
3707 }
3708
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003709 void doDefine() {
Jack Palevich569f1352009-06-29 14:29:08 -07003710 next();
3711 tokenid_t name = tok;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003712 String* pName = new String();
3713 while (isspace(ch)) {
3714 inp();
3715 }
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003716 if (ch == '(') {
3717 delete pName;
3718 error("Defines with arguments not supported");
Jack Palevich0a280a02009-06-11 10:53:51 -07003719 return;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003720 }
3721 while (isspace(ch)) {
3722 inp();
3723 }
Jack Palevich569f1352009-06-29 14:29:08 -07003724 String value;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003725 while (ch != '\n' && ch != EOF) {
Jack Palevich569f1352009-06-29 14:29:08 -07003726 value.append(ch);
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003727 inp();
3728 }
Jack Palevich569f1352009-06-29 14:29:08 -07003729 char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
3730 memcpy(pDefn, value.getUnwrapped(), value.len());
3731 pDefn[value.len()] = 0;
3732 mTokenTable[name].mpMacroDefinition = pDefn;
Jack Palevich2d11dfb2009-06-08 14:34:26 -07003733 }
3734
Jack Palevicheedf9d22009-06-04 16:23:40 -07003735 void doPragma() {
3736 // # pragma name(val)
3737 int state = 0;
3738 while(ch != EOF && ch != '\n' && state < 10) {
3739 switch(state) {
3740 case 0:
3741 if (isspace(ch)) {
3742 inp();
3743 } else {
3744 state++;
3745 }
3746 break;
3747 case 1:
3748 if (isalnum(ch)) {
3749 mPragmas.append(ch);
3750 inp();
3751 } else if (ch == '(') {
3752 mPragmas.append(0);
3753 inp();
3754 state++;
3755 } else {
3756 state = 11;
3757 }
3758 break;
3759 case 2:
3760 if (isalnum(ch)) {
3761 mPragmas.append(ch);
3762 inp();
3763 } else if (ch == ')') {
3764 mPragmas.append(0);
3765 inp();
3766 state = 10;
3767 } else {
3768 state = 11;
3769 }
3770 break;
3771 }
3772 }
3773 if(state != 10) {
3774 error("Unexpected pragma syntax");
3775 }
3776 mPragmaStringCount += 2;
3777 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003778
Jack Palevichdc456462009-07-16 16:50:56 -07003779 void doLine() {
3780 // # line number { "filename "}
3781 next();
3782 if (tok != TOK_NUM) {
3783 error("Expected a line-number");
3784 } else {
3785 mLineNumber = tokc-1; // The end-of-line will increment it.
3786 }
3787 while(ch != EOF && ch != '\n') {
3788 inp();
3789 }
3790 }
3791
Jack Palevichac0e95e2009-05-29 13:53:44 -07003792 virtual void verror(const char* fmt, va_list ap) {
Jack Palevichdc456462009-07-16 16:50:56 -07003793 mErrorBuf.printf("%ld: ", mLineNumber);
Jack Palevicheedf9d22009-06-04 16:23:40 -07003794 mErrorBuf.vprintf(fmt, ap);
3795 mErrorBuf.printf("\n");
Jack Palevich21a15a22009-05-11 14:49:29 -07003796 }
3797
Jack Palevich8b0624c2009-05-20 12:12:06 -07003798 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003799 if (tok != c) {
3800 error("'%c' expected", c);
3801 }
3802 next();
3803 }
3804
Jack Palevich86351982009-06-30 18:09:56 -07003805 bool accept(intptr_t c) {
3806 if (tok == c) {
3807 next();
3808 return true;
3809 }
3810 return false;
3811 }
3812
Jack Palevich40600de2009-07-01 15:32:35 -07003813 bool acceptStringLiteral() {
3814 if (tok == '"') {
Jack Palevich8df46192009-07-07 14:48:51 -07003815 pGen->li((int) glo, mkpCharPtr);
Jack Palevich40600de2009-07-01 15:32:35 -07003816 // This while loop merges multiple adjacent string constants.
3817 while (tok == '"') {
3818 while (ch != '"' && ch != EOF) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07003819 *allocGlobalSpace(1,1) = getq();
Jack Palevich40600de2009-07-01 15:32:35 -07003820 }
3821 if (ch != '"') {
3822 error("Unterminated string constant.");
3823 }
3824 inp();
3825 next();
Jack Palevichb4758ff2009-06-12 12:49:14 -07003826 }
Jack Palevich40600de2009-07-01 15:32:35 -07003827 /* Null terminate */
Jack Palevich653f42d2009-05-28 17:15:32 -07003828 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07003829 /* align heap */
Jack Palevich9cbd2262009-07-08 16:48:41 -07003830 allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich40600de2009-07-01 15:32:35 -07003831
3832 return true;
3833 }
3834 return false;
3835 }
Jack Palevich8c246a92009-07-14 21:14:10 -07003836
Jack Palevichb1544ca2009-07-16 15:09:20 -07003837 void linkGlobal(tokenid_t t, bool isFunction) {
3838 VariableInfo* pVI = VI(t);
3839 void* n = NULL;
3840 if (mpSymbolLookupFn) {
3841 n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
3842 }
3843 if (pVI->pType == NULL) {
3844 if (isFunction) {
3845 pVI->pType = mkpIntFn;
3846 } else {
3847 pVI->pType = mkpInt;
3848 }
3849 }
3850 pVI->pAddress = n;
3851 }
3852
Jack Palevich40600de2009-07-01 15:32:35 -07003853 /* Parse and evaluate a unary expression.
3854 * allowAssignment is true if '=' parsing wanted (quick hack)
3855 */
3856 void unary(bool allowAssignment) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003857 tokenid_t t;
3858 intptr_t n, a;
Jack Palevich40600de2009-07-01 15:32:35 -07003859 t = 0;
3860 n = 1; /* type of expression 0 = forward, 1 = value, other = lvalue */
3861 if (acceptStringLiteral()) {
3862 // Nothing else to do.
Jack Palevich21a15a22009-05-11 14:49:29 -07003863 } else {
Jack Palevich40600de2009-07-01 15:32:35 -07003864 int c = tokl;
Jack Palevich21a15a22009-05-11 14:49:29 -07003865 a = tokc;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003866 double ad = tokd;
Jack Palevich21a15a22009-05-11 14:49:29 -07003867 t = tok;
3868 next();
3869 if (t == TOK_NUM) {
Jack Palevich8df46192009-07-07 14:48:51 -07003870 pGen->li(a, mkpInt);
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003871 } else if (t == TOK_NUM_FLOAT) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003872 // Align to 4-byte boundary
3873 glo = (char*) (((intptr_t) glo + 3) & -4);
3874 * (float*) glo = (float) ad;
3875 pGen->loadFloat((int) glo, mkpFloat);
3876 glo += 4;
Jack Palevich1aeb87b2009-07-06 18:33:20 -07003877 } else if (t == TOK_NUM_DOUBLE) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003878 // Align to 8-byte boundary
3879 glo = (char*) (((intptr_t) glo + 7) & -8);
3880 * (double*) glo = ad;
3881 pGen->loadFloat((int) glo, mkpDouble);
3882 glo += 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07003883 } else if (c == 2) {
3884 /* -, +, !, ~ */
Jack Palevich40600de2009-07-01 15:32:35 -07003885 unary(false);
Jack Palevich21a15a22009-05-11 14:49:29 -07003886 if (t == '!')
Jack Palevicha39749f2009-07-08 20:40:31 -07003887 pGen->gUnaryCmp(a, mkpInt);
3888 else if (t == '+') {
3889 // ignore unary plus.
3890 } else {
Jack Palevich9eed7a22009-07-06 17:24:34 -07003891 pGen->genUnaryOp(a);
Jack Palevicha39749f2009-07-08 20:40:31 -07003892 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003893 } else if (t == '(') {
Jack Palevich45431bc2009-07-13 15:57:26 -07003894 // It's either a cast or an expression
3895 Type* pCast = acceptCastTypeDeclaration(mLocalArena);
3896 if (pCast) {
3897 skip(')');
3898 unary(false);
3899 pGen->convertR0(pCast);
Jack Palevich3f226492009-07-02 14:46:19 -07003900 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07003901 expr();
Jack Palevich45431bc2009-07-13 15:57:26 -07003902 skip(')');
3903 }
3904 } else if (t == '*') {
3905 /* This is a pointer dereference.
3906 */
3907 unary(false);
3908 Type* pR0Type = pGen->getR0Type();
3909 if (pR0Type->tag != TY_POINTER) {
3910 error("Expected a pointer type.");
3911 } else {
3912 if (pR0Type->pHead->tag == TY_FUNC) {
3913 t = 0;
3914 }
3915 if (accept('=')) {
3916 pGen->pushR0();
3917 expr();
3918 pGen->storeR0ToTOS(pR0Type);
3919 } else if (t) {
3920 pGen->loadR0FromR0(pR0Type);
3921 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003922 }
Jack Palevich3f226492009-07-02 14:46:19 -07003923 // Else we fall through to the function call below, with
3924 // t == 0 to trigger an indirect function call. Hack!
Jack Palevich21a15a22009-05-11 14:49:29 -07003925 } else if (t == '&') {
Jack Palevich8df46192009-07-07 14:48:51 -07003926 VariableInfo* pVI = VI(tok);
3927 pGen->leaR0((int) pVI->pAddress,
3928 createPtrType(pVI->pType, mLocalArena));
Jack Palevich21a15a22009-05-11 14:49:29 -07003929 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07003930 } else if (t == EOF ) {
3931 error("Unexpected EOF.");
Jack Palevichd1f57e62009-07-15 18:23:22 -07003932 } else if (t == ';') {
3933 error("Unexpected ';'");
Jack Palevich40600de2009-07-01 15:32:35 -07003934 } else if (!checkSymbol(t)) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07003935 // Don't have to do anything special here, the error
3936 // message was printed by checkSymbol() above.
Jack Palevich21a15a22009-05-11 14:49:29 -07003937 } else {
Jack Palevich569f1352009-06-29 14:29:08 -07003938 if (!isDefined(t)) {
3939 mGlobals.add(t);
3940 // printf("Adding new global function %s\n", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07003941 }
Jack Palevich8df46192009-07-07 14:48:51 -07003942 VariableInfo* pVI = VI(t);
3943 n = (intptr_t) pVI->pAddress;
Jack Palevich8c246a92009-07-14 21:14:10 -07003944 /* forward reference: try our lookup function */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003945 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003946 linkGlobal(t, tok == '(');
3947 n = (intptr_t) pVI->pAddress;
3948 if (!n && tok != '(') {
3949 error("Undeclared variable %s\n", nameof(t));
Jack Palevich8c246a92009-07-14 21:14:10 -07003950 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003951 }
Jack Palevich40600de2009-07-01 15:32:35 -07003952 if ((tok == '=') & allowAssignment) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003953 /* assignment */
3954 next();
3955 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07003956 pGen->storeR0(n, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003957 } else if (tok != '(') {
3958 /* variable */
Jack Palevicha6baa232009-06-12 11:25:59 -07003959 if (!n) {
Jack Palevichb1544ca2009-07-16 15:09:20 -07003960 linkGlobal(t, false);
3961 n = (intptr_t) pVI->pAddress;
3962 if (!n) {
3963 error("Undeclared variable %s\n", nameof(t));
3964 }
Jack Palevicha6baa232009-06-12 11:25:59 -07003965 }
Jack Palevich8df46192009-07-07 14:48:51 -07003966 pGen->loadR0(n, tokl == 11, tokc, pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07003967 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07003968 next();
3969 }
3970 }
3971 }
3972 }
3973
3974 /* function call */
Jack Palevich8df46192009-07-07 14:48:51 -07003975 if (accept('(')) {
Jack Palevichb7718b92009-07-09 22:00:24 -07003976 Type* pDecl = NULL;
Jack Palevich1a539db2009-07-08 13:04:41 -07003977 VariableInfo* pVI = NULL;
3978 if (n == 1) { // Indirect function call, push address of fn.
Jack Palevichb7718b92009-07-09 22:00:24 -07003979 pDecl = pGen->getR0Type();
Jack Palevich1cdef202009-05-22 12:06:27 -07003980 pGen->pushR0();
Jack Palevich1a539db2009-07-08 13:04:41 -07003981 } else {
3982 pVI = VI(t);
Jack Palevichb7718b92009-07-09 22:00:24 -07003983 pDecl = pVI->pType;
Jack Palevich1a539db2009-07-08 13:04:41 -07003984 }
Jack Palevichb7718b92009-07-09 22:00:24 -07003985 Type* pArgList = pDecl->pTail;
Jack Palevich1a539db2009-07-08 13:04:41 -07003986 bool varArgs = pArgList == NULL;
Jack Palevich21a15a22009-05-11 14:49:29 -07003987 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07003988 a = pGen->beginFunctionCallArguments();
Jack Palevich40600de2009-07-01 15:32:35 -07003989 int l = 0;
Jack Palevich2a4e1a92009-07-09 13:34:25 -07003990 int argCount = 0;
Jack Palevichb4758ff2009-06-12 12:49:14 -07003991 while (tok != ')' && tok != EOF) {
Jack Palevich1a539db2009-07-08 13:04:41 -07003992 if (! varArgs && !pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07003993 error("Unexpected argument.");
Jack Palevich1a539db2009-07-08 13:04:41 -07003994 }
Jack Palevich21a15a22009-05-11 14:49:29 -07003995 expr();
Jack Palevich1a539db2009-07-08 13:04:41 -07003996 Type* pTargetType;
3997 if (pArgList) {
3998 pTargetType = pArgList->pHead;
3999 pArgList = pArgList->pTail;
4000 } else {
4001 pTargetType = pGen->getR0Type();
4002 if (pTargetType->tag == TY_FLOAT) {
4003 pTargetType = mkpDouble;
4004 }
4005 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004006 if (pTargetType->tag == TY_VOID) {
4007 error("Can't pass void value for argument %d",
4008 argCount + 1);
4009 } else {
4010 pGen->convertR0(pTargetType);
4011 l += pGen->storeR0ToArg(l);
4012 }
Jack Palevich95727a02009-07-06 12:07:15 -07004013 if (accept(',')) {
4014 // fine
4015 } else if ( tok != ')') {
4016 error("Expected ',' or ')'");
4017 }
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004018 argCount += 1;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004019 }
Jack Palevich1a539db2009-07-08 13:04:41 -07004020 if (! varArgs && pArgList) {
Jack Palevichce105a92009-07-16 14:30:33 -07004021 error("Expected more argument(s). Saw %d", argCount);
Jack Palevich1a539db2009-07-08 13:04:41 -07004022 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004023 pGen->endFunctionCallArguments(pDecl, a, l);
Jack Palevichb4758ff2009-06-12 12:49:14 -07004024 skip(')');
Jack Palevich21a15a22009-05-11 14:49:29 -07004025 if (!n) {
4026 /* forward reference */
Jack Palevich8df46192009-07-07 14:48:51 -07004027 pVI->pForward = (void*) pGen->callForward((int) pVI->pForward,
4028 pVI->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004029 } else if (n == 1) {
Jack Palevich8df46192009-07-07 14:48:51 -07004030 pGen->callIndirect(l, mkpPtrIntFn->pHead);
Jack Palevich21a15a22009-05-11 14:49:29 -07004031 } else {
Jack Palevich8df46192009-07-07 14:48:51 -07004032 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(),
4033 VI(t)->pType);
Jack Palevich21a15a22009-05-11 14:49:29 -07004034 }
Jack Palevichb7718b92009-07-09 22:00:24 -07004035 pGen->adjustStackAfterCall(pDecl, l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07004036 }
4037 }
4038
Jack Palevich40600de2009-07-01 15:32:35 -07004039 /* Recursive descent parser for binary operations.
4040 */
4041 void binaryOp(int level) {
Jack Palevich7ecc5552009-07-14 16:24:55 -07004042 intptr_t t, a;
Jack Palevich546b2242009-05-13 15:10:04 -07004043 t = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004044 if (level-- == 1)
4045 unary(true);
Jack Palevich21a15a22009-05-11 14:49:29 -07004046 else {
Jack Palevich40600de2009-07-01 15:32:35 -07004047 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004048 a = 0;
Jack Palevich40600de2009-07-01 15:32:35 -07004049 while (level == tokl) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004050 t = tokc;
4051 next();
4052
Jack Palevich40600de2009-07-01 15:32:35 -07004053 if (level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004054 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004055 binaryOp(level);
Jack Palevich21a15a22009-05-11 14:49:29 -07004056 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07004057 pGen->pushR0();
Jack Palevich40600de2009-07-01 15:32:35 -07004058 binaryOp(level);
Jack Palevichd1f57e62009-07-15 18:23:22 -07004059 // Check for syntax error.
4060 if (pGen->getR0Type() == NULL) {
4061 // We failed to parse a right-hand argument.
4062 // Push a dummy value so we don't fail
4063 pGen->li(0, mkpInt);
4064 }
Jack Palevich40600de2009-07-01 15:32:35 -07004065 if ((level == 4) | (level == 5)) {
Jack Palevicha39749f2009-07-08 20:40:31 -07004066 pGen->gcmp(t, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004067 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004068 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004069 }
4070 }
4071 }
4072 /* && and || output code generation */
Jack Palevich40600de2009-07-01 15:32:35 -07004073 if (a && level > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004074 a = pGen->gtst(t == OP_LOGICAL_OR, a);
Jack Palevich8df46192009-07-07 14:48:51 -07004075 pGen->li(t != OP_LOGICAL_OR, mkpInt);
Jack Palevicha6535612009-05-13 16:24:17 -07004076 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004077 pGen->gsym(a);
Jack Palevich8df46192009-07-07 14:48:51 -07004078 pGen->li(t == OP_LOGICAL_OR, mkpInt);
Jack Palevich21a15a22009-05-11 14:49:29 -07004079 }
4080 }
4081 }
4082
4083 void expr() {
Jack Palevich40600de2009-07-01 15:32:35 -07004084 binaryOp(11);
Jack Palevich21a15a22009-05-11 14:49:29 -07004085 }
4086
4087 int test_expr() {
4088 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004089 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004090 }
4091
Jack Palevicha6baa232009-06-12 11:25:59 -07004092 void block(intptr_t l, bool outermostFunctionBlock) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07004093 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07004094
Jack Palevich95727a02009-07-06 12:07:15 -07004095 Type* pBaseType;
4096 if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
Jack Palevicha1804dd2009-06-12 14:40:04 -07004097 /* declarations */
Jack Palevich95727a02009-07-06 12:07:15 -07004098 localDeclarations(pBaseType);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004099 } else if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004100 next();
4101 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07004102 a = test_expr();
4103 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004104 block(l, false);
Jack Palevich21a15a22009-05-11 14:49:29 -07004105 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004106 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004107 n = pGen->gjmp(0); /* jmp */
4108 pGen->gsym(a);
Jack Palevicha6baa232009-06-12 11:25:59 -07004109 block(l, false);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004110 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07004111 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004112 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004113 }
Jack Palevich546b2242009-05-13 15:10:04 -07004114 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07004115 t = tok;
4116 next();
4117 skip('(');
4118 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07004119 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07004120 a = test_expr();
4121 } else {
4122 if (tok != ';')
4123 expr();
4124 skip(';');
4125 n = codeBuf.getPC();
4126 a = 0;
4127 if (tok != ';')
4128 a = test_expr();
4129 skip(';');
4130 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004131 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07004132 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07004133 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004134 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07004135 n = t + 4;
4136 }
4137 }
4138 skip(')');
Jack Palevicha6baa232009-06-12 11:25:59 -07004139 block((intptr_t) &a, false);
Jack Palevicha6535612009-05-13 16:24:17 -07004140 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004141 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07004142 } else if (tok == '{') {
Jack Palevicha6baa232009-06-12 11:25:59 -07004143 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004144 mLocals.pushLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004145 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004146 next();
Jack Palevich303d8ff2009-06-11 19:06:24 -07004147 while (tok != '}' && tok != EOF)
Jack Palevicha6baa232009-06-12 11:25:59 -07004148 block(l, false);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004149 skip('}');
Jack Palevicha6baa232009-06-12 11:25:59 -07004150 if (! outermostFunctionBlock) {
Jack Palevich569f1352009-06-29 14:29:08 -07004151 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004152 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004153 } else {
Jack Palevich95727a02009-07-06 12:07:15 -07004154 if (accept(TOK_RETURN)) {
Jack Palevich8df46192009-07-07 14:48:51 -07004155 if (tok != ';') {
Jack Palevich21a15a22009-05-11 14:49:29 -07004156 expr();
Jack Palevich2a4e1a92009-07-09 13:34:25 -07004157 if (pReturnType->tag == TY_VOID) {
4158 error("Must not return a value from a void function");
4159 } else {
4160 pGen->convertR0(pReturnType);
4161 }
4162 } else {
4163 if (pReturnType->tag != TY_VOID) {
4164 error("Must specify a value here");
4165 }
Jack Palevich8df46192009-07-07 14:48:51 -07004166 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004167 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich95727a02009-07-06 12:07:15 -07004168 } else if (accept(TOK_BREAK)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004169 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07004170 } else if (tok != ';')
4171 expr();
4172 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004173 }
4174 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004175
Jack Palevicha8f427f2009-07-13 18:40:08 -07004176 static bool typeEqual(Type* a, Type* b) {
Jack Palevich3f226492009-07-02 14:46:19 -07004177 if (a == b) {
4178 return true;
4179 }
4180 if (a == NULL || b == NULL) {
4181 return false;
4182 }
4183 TypeTag at = a->tag;
4184 if (at != b->tag) {
4185 return false;
4186 }
4187 if (at == TY_POINTER) {
4188 return typeEqual(a->pHead, b->pHead);
4189 } else if (at == TY_FUNC || at == TY_PARAM) {
4190 return typeEqual(a->pHead, b->pHead)
4191 && typeEqual(a->pTail, b->pTail);
4192 }
4193 return true;
4194 }
4195
Jack Palevich86351982009-06-30 18:09:56 -07004196 Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
4197 assert(tag >= TY_INT && tag <= TY_PARAM);
4198 Type* pType = (Type*) arena.alloc(sizeof(Type));
4199 memset(pType, 0, sizeof(*pType));
4200 pType->tag = tag;
4201 pType->pHead = pHead;
4202 pType->pTail = pTail;
4203 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004204 }
4205
Jack Palevich3f226492009-07-02 14:46:19 -07004206 Type* createPtrType(Type* pType, Arena& arena) {
4207 return createType(TY_POINTER, pType, NULL, arena);
4208 }
4209
4210 /**
4211 * Try to print a type in declaration order
4212 */
Jack Palevich86351982009-06-30 18:09:56 -07004213 void decodeType(String& buffer, Type* pType) {
Jack Palevich3f226492009-07-02 14:46:19 -07004214 buffer.clear();
Jack Palevich86351982009-06-30 18:09:56 -07004215 if (pType == NULL) {
4216 buffer.appendCStr("null");
4217 return;
4218 }
Jack Palevich3f226492009-07-02 14:46:19 -07004219 decodeTypeImp(buffer, pType);
4220 }
4221
4222 void decodeTypeImp(String& buffer, Type* pType) {
4223 decodeTypeImpPrefix(buffer, pType);
4224
Jack Palevich86351982009-06-30 18:09:56 -07004225 String temp;
4226 if (pType->id != 0) {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004227 decodeToken(temp, pType->id, false);
Jack Palevich86351982009-06-30 18:09:56 -07004228 buffer.append(temp);
Jack Palevich3f226492009-07-02 14:46:19 -07004229 }
4230
4231 decodeTypeImpPostfix(buffer, pType);
4232 }
4233
4234 void decodeTypeImpPrefix(String& buffer, Type* pType) {
4235 TypeTag tag = pType->tag;
4236
Jack Palevich37c54bd2009-07-14 18:35:36 -07004237 if (tag >= TY_INT && tag <= TY_DOUBLE) {
Jack Palevich3f226492009-07-02 14:46:19 -07004238 switch (tag) {
4239 case TY_INT:
4240 buffer.appendCStr("int");
4241 break;
4242 case TY_CHAR:
4243 buffer.appendCStr("char");
4244 break;
4245 case TY_VOID:
4246 buffer.appendCStr("void");
4247 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004248 case TY_FLOAT:
4249 buffer.appendCStr("float");
4250 break;
4251 case TY_DOUBLE:
4252 buffer.appendCStr("double");
4253 break;
Jack Palevich3f226492009-07-02 14:46:19 -07004254 default:
4255 break;
4256 }
Jack Palevich86351982009-06-30 18:09:56 -07004257 buffer.append(' ');
4258 }
Jack Palevich3f226492009-07-02 14:46:19 -07004259
4260 switch (tag) {
Jack Palevich86351982009-06-30 18:09:56 -07004261 case TY_INT:
Jack Palevich86351982009-06-30 18:09:56 -07004262 break;
4263 case TY_CHAR:
Jack Palevich86351982009-06-30 18:09:56 -07004264 break;
4265 case TY_VOID:
Jack Palevich3f226492009-07-02 14:46:19 -07004266 break;
Jack Palevich95727a02009-07-06 12:07:15 -07004267 case TY_FLOAT:
4268 break;
4269 case TY_DOUBLE:
4270 break;
Jack Palevich86351982009-06-30 18:09:56 -07004271 case TY_POINTER:
Jack Palevich3f226492009-07-02 14:46:19 -07004272 decodeTypeImpPrefix(buffer, pType->pHead);
4273 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4274 buffer.append('(');
4275 }
4276 buffer.append('*');
Jack Palevich86351982009-06-30 18:09:56 -07004277 break;
4278 case TY_FUNC:
Jack Palevich3f226492009-07-02 14:46:19 -07004279 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004280 break;
4281 case TY_PARAM:
Jack Palevich3f226492009-07-02 14:46:19 -07004282 decodeTypeImp(buffer, pType->pHead);
Jack Palevich86351982009-06-30 18:09:56 -07004283 break;
4284 default:
4285 String temp;
4286 temp.printf("Unknown tag %d", pType->tag);
4287 buffer.append(temp);
4288 break;
4289 }
Jack Palevich3f226492009-07-02 14:46:19 -07004290 }
4291
4292 void decodeTypeImpPostfix(String& buffer, Type* pType) {
4293 TypeTag tag = pType->tag;
4294
4295 switch(tag) {
4296 case TY_POINTER:
4297 if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4298 buffer.append(')');
4299 }
4300 decodeTypeImpPostfix(buffer, pType->pHead);
4301 break;
4302 case TY_FUNC:
4303 buffer.append('(');
4304 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4305 decodeTypeImp(buffer, pArg);
4306 if (pArg->pTail) {
4307 buffer.appendCStr(", ");
4308 }
4309 }
4310 buffer.append(')');
4311 break;
4312 default:
4313 break;
Jack Palevich86351982009-06-30 18:09:56 -07004314 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004315 }
4316
Jack Palevich86351982009-06-30 18:09:56 -07004317 void printType(Type* pType) {
4318 String buffer;
4319 decodeType(buffer, pType);
4320 fprintf(stderr, "%s\n", buffer.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004321 }
4322
Jack Palevich86351982009-06-30 18:09:56 -07004323 Type* acceptPrimitiveType(Arena& arena) {
4324 Type* pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004325 if (tok == TOK_INT) {
Jack Palevich86351982009-06-30 18:09:56 -07004326 pType = mkpInt;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004327 } else if (tok == TOK_CHAR) {
Jack Palevich86351982009-06-30 18:09:56 -07004328 pType = mkpChar;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004329 } else if (tok == TOK_VOID) {
Jack Palevich86351982009-06-30 18:09:56 -07004330 pType = mkpVoid;
Jack Palevich95727a02009-07-06 12:07:15 -07004331 } else if (tok == TOK_FLOAT) {
4332 pType = mkpFloat;
4333 } else if (tok == TOK_DOUBLE) {
4334 pType = mkpDouble;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004335 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004336 return NULL;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004337 }
4338 next();
Jack Palevich86351982009-06-30 18:09:56 -07004339 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004340 }
4341
Jack Palevich3f226492009-07-02 14:46:19 -07004342 Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
4343 Arena& arena) {
4344 tokenid_t declName = 0;
4345 pType = acceptDecl2(pType, declName, nameAllowed,
4346 nameRequired, arena);
4347 if (declName) {
4348 // Clone the parent type so we can set a unique ID
4349 pType = createType(pType->tag, pType->pHead,
4350 pType->pTail, arena);
4351
Jack Palevich86351982009-06-30 18:09:56 -07004352 pType->id = declName;
Jack Palevich86351982009-06-30 18:09:56 -07004353 }
Jack Palevich3f226492009-07-02 14:46:19 -07004354 // fprintf(stderr, "Parsed a declaration: ");
4355 // printType(pType);
Jack Palevich86351982009-06-30 18:09:56 -07004356 return pType;
4357 }
4358
Jack Palevich3f226492009-07-02 14:46:19 -07004359 Type* expectDeclaration(Type* pBaseType, Arena& arena) {
4360 Type* pType = acceptDeclaration(pBaseType, true, true, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004361 if (! pType) {
4362 error("Expected a declaration");
4363 }
4364 return pType;
4365 }
4366
Jack Palevich3f226492009-07-02 14:46:19 -07004367 /* Used for accepting types that appear in casts */
4368 Type* acceptCastTypeDeclaration(Arena& arena) {
4369 Type* pType = acceptPrimitiveType(arena);
4370 if (pType) {
4371 pType = acceptDeclaration(pType, false, false, arena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004372 }
Jack Palevich86351982009-06-30 18:09:56 -07004373 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004374 }
4375
Jack Palevich3f226492009-07-02 14:46:19 -07004376 Type* expectCastTypeDeclaration(Arena& arena) {
4377 Type* pType = acceptCastTypeDeclaration(arena);
4378 if (! pType) {
4379 error("Expected a declaration");
Jack Palevich86351982009-06-30 18:09:56 -07004380 }
Jack Palevich3f226492009-07-02 14:46:19 -07004381 return pType;
4382 }
4383
4384 Type* acceptDecl2(Type* pType, tokenid_t& declName,
4385 bool nameAllowed, bool nameRequired, Arena& arena) {
4386 int ptrCounter = 0;
4387 while (accept('*')) {
4388 ptrCounter++;
4389 }
4390 pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
4391 while (ptrCounter-- > 0) {
4392 pType = createType(TY_POINTER, pType, NULL, arena);
4393 }
4394 return pType;
4395 }
4396
4397 Type* acceptDecl3(Type* pType, tokenid_t& declName,
4398 bool nameAllowed, bool nameRequired, Arena& arena) {
4399 // direct-dcl :
4400 // name
4401 // (dcl)
4402 // direct-dcl()
4403 // direct-dcl[]
4404 Type* pNewHead = NULL;
4405 if (accept('(')) {
4406 pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
4407 nameRequired, arena);
4408 skip(')');
4409 } else if ((declName = acceptSymbol()) != 0) {
4410 if (nameAllowed == false && declName) {
4411 error("Symbol %s not allowed here", nameof(declName));
4412 } else if (nameRequired && ! declName) {
4413 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004414 decodeToken(temp, tok, true);
Jack Palevich3f226492009-07-02 14:46:19 -07004415 error("Expected symbol. Got %s", temp.getUnwrapped());
4416 }
4417 }
4418 while (accept('(')) {
Jack Palevich86351982009-06-30 18:09:56 -07004419 // Function declaration
Jack Palevich3f226492009-07-02 14:46:19 -07004420 Type* pTail = acceptArgs(nameAllowed, arena);
Jack Palevich86351982009-06-30 18:09:56 -07004421 pType = createType(TY_FUNC, pType, pTail, arena);
4422 skip(')');
4423 }
Jack Palevich3f226492009-07-02 14:46:19 -07004424
4425 if (pNewHead) {
4426 Type* pA = pNewHead;
4427 while (pA->pHead) {
4428 pA = pA->pHead;
4429 }
4430 pA->pHead = pType;
4431 pType = pNewHead;
4432 }
Jack Palevich86351982009-06-30 18:09:56 -07004433 return pType;
4434 }
4435
Jack Palevich3f226492009-07-02 14:46:19 -07004436 Type* acceptArgs(bool nameAllowed, Arena& arena) {
Jack Palevich86351982009-06-30 18:09:56 -07004437 Type* pHead = NULL;
4438 Type* pTail = NULL;
4439 for(;;) {
4440 Type* pBaseArg = acceptPrimitiveType(arena);
4441 if (pBaseArg) {
Jack Palevich3f226492009-07-02 14:46:19 -07004442 Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
4443 arena);
Jack Palevich86351982009-06-30 18:09:56 -07004444 if (pArg) {
4445 Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
4446 if (!pHead) {
4447 pHead = pParam;
4448 pTail = pParam;
4449 } else {
4450 pTail->pTail = pParam;
4451 pTail = pParam;
4452 }
4453 }
4454 }
4455 if (! accept(',')) {
4456 break;
4457 }
4458 }
4459 return pHead;
4460 }
4461
4462 Type* expectPrimitiveType(Arena& arena) {
4463 Type* pType = acceptPrimitiveType(arena);
4464 if (!pType) {
Jack Palevich569f1352009-06-29 14:29:08 -07004465 String buf;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004466 decodeToken(buf, tok, true);
Jack Palevich569f1352009-06-29 14:29:08 -07004467 error("Expected a type, got %s", buf.getUnwrapped());
Jack Palevichb7c81e92009-06-04 19:56:13 -07004468 }
Jack Palevich86351982009-06-30 18:09:56 -07004469 return pType;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004470 }
4471
Jack Palevich86351982009-06-30 18:09:56 -07004472 void addGlobalSymbol(Type* pDecl) {
4473 tokenid_t t = pDecl->id;
4474 VariableInfo* pVI = VI(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004475 if(pVI && pVI->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004476 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004477 }
Jack Palevich86351982009-06-30 18:09:56 -07004478 mGlobals.add(pDecl);
Jack Palevicha6baa232009-06-12 11:25:59 -07004479 }
4480
Jack Palevich86351982009-06-30 18:09:56 -07004481 void reportDuplicate(tokenid_t t) {
4482 error("Duplicate definition of %s", nameof(t));
Jack Palevich303d8ff2009-06-11 19:06:24 -07004483 }
4484
Jack Palevich86351982009-06-30 18:09:56 -07004485 void addLocalSymbol(Type* pDecl) {
4486 tokenid_t t = pDecl->id;
4487 if (mLocals.isDefinedAtCurrentLevel(t)) {
4488 reportDuplicate(t);
Jack Palevich569f1352009-06-29 14:29:08 -07004489 }
Jack Palevich86351982009-06-30 18:09:56 -07004490 mLocals.add(pDecl);
Jack Palevich303d8ff2009-06-11 19:06:24 -07004491 }
4492
Jack Palevich95727a02009-07-06 12:07:15 -07004493 void localDeclarations(Type* pBaseType) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004494 intptr_t a;
Jack Palevichb7c81e92009-06-04 19:56:13 -07004495
Jack Palevich95727a02009-07-06 12:07:15 -07004496 while (pBaseType) {
Jack Palevich22e3e8e2009-06-12 13:12:55 -07004497 while (tok != ';' && tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004498 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
4499 if (!pDecl) {
4500 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004501 }
Jack Palevich86351982009-06-30 18:09:56 -07004502 int variableAddress = 0;
4503 addLocalSymbol(pDecl);
Jack Palevichb7718b92009-07-09 22:00:24 -07004504 size_t alignment = pGen->alignmentOf(pDecl);
4505 loc = (loc + alignment - 1) & ~ (alignment-1);
Jack Palevich9eed7a22009-07-06 17:24:34 -07004506 loc = loc + pGen->sizeOf(pDecl);
Jack Palevich86351982009-06-30 18:09:56 -07004507 variableAddress = -loc;
4508 VI(pDecl->id)->pAddress = (void*) variableAddress;
4509 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004510 /* assignment */
Jack Palevichd7461a72009-06-12 14:26:58 -07004511 expr();
Jack Palevich9cbd2262009-07-08 16:48:41 -07004512 pGen->storeR0(variableAddress, pDecl);
Jack Palevichd7461a72009-06-12 14:26:58 -07004513 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07004514 if (tok == ',')
4515 next();
4516 }
4517 skip(';');
Jack Palevich95727a02009-07-06 12:07:15 -07004518 pBaseType = acceptPrimitiveType(mLocalArena);
Jack Palevichb7c81e92009-06-04 19:56:13 -07004519 }
4520 }
4521
Jack Palevichf1728be2009-06-12 13:53:51 -07004522 bool checkSymbol() {
Jack Palevich40600de2009-07-01 15:32:35 -07004523 return checkSymbol(tok);
Jack Palevicha1804dd2009-06-12 14:40:04 -07004524 }
4525
Jack Palevich37c54bd2009-07-14 18:35:36 -07004526 void decodeToken(String& buffer, tokenid_t token, bool quote) {
Jack Palevich569f1352009-06-29 14:29:08 -07004527 if (token == EOF ) {
4528 buffer.printf("EOF");
4529 } else if (token == TOK_NUM) {
4530 buffer.printf("numeric constant");
4531 } else if (token >= 0 && token < 256) {
Jack Palevich86351982009-06-30 18:09:56 -07004532 if (token < 32) {
4533 buffer.printf("'\\x%02x'", token);
4534 } else {
4535 buffer.printf("'%c'", token);
4536 }
Jack Palevich569f1352009-06-29 14:29:08 -07004537 } else {
Jack Palevich37c54bd2009-07-14 18:35:36 -07004538 if (quote) {
4539 if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
4540 buffer.printf("keyword \"%s\"", nameof(token));
4541 } else {
4542 buffer.printf("symbol \"%s\"", nameof(token));
4543 }
4544 } else {
4545 buffer.printf("%s", nameof(token));
4546 }
Jack Palevich569f1352009-06-29 14:29:08 -07004547 }
4548 }
4549
Jack Palevich40600de2009-07-01 15:32:35 -07004550 bool checkSymbol(tokenid_t token) {
Jack Palevich569f1352009-06-29 14:29:08 -07004551 bool result = token >= TOK_SYMBOL;
Jack Palevichf1728be2009-06-12 13:53:51 -07004552 if (!result) {
4553 String temp;
Jack Palevich37c54bd2009-07-14 18:35:36 -07004554 decodeToken(temp, token, true);
Jack Palevichf1728be2009-06-12 13:53:51 -07004555 error("Expected symbol. Got %s", temp.getUnwrapped());
4556 }
4557 return result;
4558 }
4559
Jack Palevich86351982009-06-30 18:09:56 -07004560 tokenid_t acceptSymbol() {
4561 tokenid_t result = 0;
4562 if (tok >= TOK_SYMBOL) {
4563 result = tok;
4564 next();
Jack Palevich86351982009-06-30 18:09:56 -07004565 }
4566 return result;
4567 }
4568
Jack Palevichb7c81e92009-06-04 19:56:13 -07004569 void globalDeclarations() {
4570 while (tok != EOF) {
Jack Palevich86351982009-06-30 18:09:56 -07004571 Type* pBaseType = expectPrimitiveType(mGlobalArena);
4572 if (!pBaseType) {
Jack Palevichf1728be2009-06-12 13:53:51 -07004573 break;
4574 }
Jack Palevich86351982009-06-30 18:09:56 -07004575 Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
4576 if (!pDecl) {
4577 break;
Jack Palevicha6baa232009-06-12 11:25:59 -07004578 }
Jack Palevich86351982009-06-30 18:09:56 -07004579 if (! isDefined(pDecl->id)) {
4580 addGlobalSymbol(pDecl);
4581 }
4582 VariableInfo* name = VI(pDecl->id);
Jack Palevicha6baa232009-06-12 11:25:59 -07004583 if (name && name->pAddress) {
Jack Palevich86351982009-06-30 18:09:56 -07004584 error("Already defined global %s", nameof(pDecl->id));
Jack Palevicha6baa232009-06-12 11:25:59 -07004585 }
Jack Palevich86351982009-06-30 18:09:56 -07004586 if (pDecl->tag < TY_FUNC) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004587 // it's a variable declaration
4588 for(;;) {
Jack Palevich86351982009-06-30 18:09:56 -07004589 if (name && !name->pAddress) {
Jack Palevich9cbd2262009-07-08 16:48:41 -07004590 name->pAddress = (int*) allocGlobalSpace(
Jack Palevichb7718b92009-07-09 22:00:24 -07004591 pGen->alignmentOf(name->pType),
Jack Palevich9cbd2262009-07-08 16:48:41 -07004592 pGen->sizeOf(name->pType));
Jack Palevicha6baa232009-06-12 11:25:59 -07004593 }
Jack Palevich86351982009-06-30 18:09:56 -07004594 if (accept('=')) {
Jack Palevichd7461a72009-06-12 14:26:58 -07004595 if (tok == TOK_NUM) {
4596 if (name) {
4597 * (int*) name->pAddress = tokc;
4598 }
4599 next();
4600 } else {
4601 error("Expected an integer constant");
4602 }
4603 }
Jack Palevich86351982009-06-30 18:09:56 -07004604 if (!accept(',')) {
Jack Palevichb7c81e92009-06-04 19:56:13 -07004605 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07004606 }
Jack Palevich86351982009-06-30 18:09:56 -07004607 pDecl = expectDeclaration(pBaseType, mGlobalArena);
4608 if (!pDecl) {
4609 break;
4610 }
4611 if (! isDefined(pDecl->id)) {
4612 addGlobalSymbol(pDecl);
4613 }
4614 name = VI(pDecl->id);
Jack Palevich21a15a22009-05-11 14:49:29 -07004615 }
4616 skip(';');
4617 } else {
Jack Palevich86351982009-06-30 18:09:56 -07004618 // Function declaration
Jack Palevich95727a02009-07-06 12:07:15 -07004619 if (accept(';')) {
4620 // forward declaration.
Jack Palevichd1f57e62009-07-15 18:23:22 -07004621 } else if (tok != '{') {
4622 error("expected '{'");
Jack Palevich95727a02009-07-06 12:07:15 -07004623 } else {
4624 if (name) {
4625 /* patch forward references (XXX: does not work for function
4626 pointers) */
4627 pGen->gsym((int) name->pForward);
4628 /* put function address */
4629 name->pAddress = (void*) codeBuf.getPC();
4630 }
4631 // Calculate stack offsets for parameters
4632 mLocals.pushLevel();
4633 intptr_t a = 8;
4634 int argCount = 0;
4635 for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
4636 Type* pArg = pP->pHead;
4637 addLocalSymbol(pArg);
4638 /* read param name and compute offset */
Jack Palevichb7718b92009-07-09 22:00:24 -07004639 size_t alignment = pGen->alignmentOf(pArg);
4640 a = (a + alignment - 1) & ~ (alignment-1);
Jack Palevich95727a02009-07-06 12:07:15 -07004641 VI(pArg->id)->pAddress = (void*) a;
Jack Palevich9cbd2262009-07-08 16:48:41 -07004642 a = a + pGen->stackSizeOf(pArg);
Jack Palevich95727a02009-07-06 12:07:15 -07004643 argCount++;
4644 }
4645 rsym = loc = 0;
Jack Palevich8df46192009-07-07 14:48:51 -07004646 pReturnType = pDecl->pHead;
Jack Palevichb7718b92009-07-09 22:00:24 -07004647 a = pGen->functionEntry(pDecl);
Jack Palevich95727a02009-07-06 12:07:15 -07004648 block(0, true);
4649 pGen->gsym(rsym);
Jack Palevichb7718b92009-07-09 22:00:24 -07004650 pGen->functionExit(pDecl, a, loc);
Jack Palevich95727a02009-07-06 12:07:15 -07004651 mLocals.popLevel();
Jack Palevicha6baa232009-06-12 11:25:59 -07004652 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004653 }
4654 }
4655 }
4656
Jack Palevich9cbd2262009-07-08 16:48:41 -07004657 char* allocGlobalSpace(size_t alignment, size_t bytes) {
4658 size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
4659 size_t end = base + bytes;
Jack Palevicha39749f2009-07-08 20:40:31 -07004660 if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004661 error("Global space exhausted");
Jack Palevich0a280a02009-06-11 10:53:51 -07004662 return NULL;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004663 }
Jack Palevich9cbd2262009-07-08 16:48:41 -07004664 char* result = (char*) base;
4665 glo = (char*) end;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004666 return result;
4667 }
4668
Jack Palevich21a15a22009-05-11 14:49:29 -07004669 void cleanup() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004670 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07004671 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07004672 pGlobalBase = 0;
4673 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004674 if (pGen) {
4675 delete pGen;
4676 pGen = 0;
4677 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004678 if (file) {
4679 delete file;
4680 file = 0;
4681 }
Jack Palevich21a15a22009-05-11 14:49:29 -07004682 }
4683
Jack Palevich8c246a92009-07-14 21:14:10 -07004684 // One-time initialization, when class is constructed.
4685 void init() {
4686 mpSymbolLookupFn = 0;
4687 mpSymbolLookupContext = 0;
4688 }
4689
Jack Palevich21a15a22009-05-11 14:49:29 -07004690 void clear() {
4691 tok = 0;
4692 tokc = 0;
4693 tokl = 0;
4694 ch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004695 rsym = 0;
4696 loc = 0;
4697 glo = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004698 dptr = 0;
4699 dch = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004700 file = 0;
4701 pGlobalBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07004702 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07004703 mPragmaStringCount = 0;
Jack Palevichce105a92009-07-16 14:30:33 -07004704 mCompileResult = 0;
Jack Palevichdc456462009-07-16 16:50:56 -07004705 mLineNumber = 1;
4706 mbBumpLine = false;
Jack Palevich21a15a22009-05-11 14:49:29 -07004707 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004708
Jack Palevich22305132009-05-13 10:58:45 -07004709 void setArchitecture(const char* architecture) {
4710 delete pGen;
4711 pGen = 0;
4712
4713 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004714#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004715 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004716 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004717 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004718#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07004719#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07004720 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07004721 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07004722 }
Jack Paleviche7b59062009-05-19 17:12:17 -07004723#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07004724 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004725 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07004726 }
4727 }
4728
4729 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07004730#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07004731 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07004732#elif defined(DEFAULT_X86_CODEGEN)
4733 pGen = new X86CodeGenerator();
4734#endif
4735 }
4736 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004737 error("No code generator defined.");
Jack Palevich0a280a02009-06-11 10:53:51 -07004738 } else {
4739 pGen->setErrorSink(this);
Jack Palevicha8f427f2009-07-13 18:40:08 -07004740 pGen->setTypes(mkpInt);
Jack Palevich22305132009-05-13 10:58:45 -07004741 }
4742 }
4743
Jack Palevich77ae76e2009-05-10 19:59:24 -07004744public:
Jack Palevich22305132009-05-13 10:58:45 -07004745 struct args {
4746 args() {
4747 architecture = 0;
4748 }
4749 const char* architecture;
4750 };
4751
Jack Paleviche7b59062009-05-19 17:12:17 -07004752 Compiler() {
Jack Palevich8c246a92009-07-14 21:14:10 -07004753 init();
Jack Palevich21a15a22009-05-11 14:49:29 -07004754 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07004755 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004756
Jack Paleviche7b59062009-05-19 17:12:17 -07004757 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07004758 cleanup();
4759 }
4760
Jack Palevich8c246a92009-07-14 21:14:10 -07004761 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4762 mpSymbolLookupFn = pFn;
4763 mpSymbolLookupContext = pContext;
4764 }
4765
Jack Palevich1cdef202009-05-22 12:06:27 -07004766 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07004767 int result;
Jack Palevich0a280a02009-06-11 10:53:51 -07004768
Jack Palevicha8f427f2009-07-13 18:40:08 -07004769 createPrimitiveTypes();
Jack Palevich0a280a02009-06-11 10:53:51 -07004770 cleanup();
4771 clear();
Jack Palevich569f1352009-06-29 14:29:08 -07004772 mTokenTable.setArena(&mGlobalArena);
4773 mGlobals.setArena(&mGlobalArena);
4774 mGlobals.setTokenTable(&mTokenTable);
4775 mLocals.setArena(&mLocalArena);
4776 mLocals.setTokenTable(&mTokenTable);
4777
4778 internKeywords();
Jack Palevich0a280a02009-06-11 10:53:51 -07004779 codeBuf.init(ALLOC_SIZE);
4780 setArchitecture(NULL);
4781 if (!pGen) {
4782 return -1;
4783 }
Jack Palevichb67b18f2009-06-11 21:12:23 -07004784#ifdef PROVIDE_TRACE_CODEGEN
4785 pGen = new TraceCodeGenerator(pGen);
4786#endif
4787 pGen->setErrorSink(this);
Jack Palevich0a280a02009-06-11 10:53:51 -07004788 pGen->init(&codeBuf);
4789 file = new TextInputStream(text, textLength);
Jack Palevich0a280a02009-06-11 10:53:51 -07004790 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
4791 glo = pGlobalBase;
Jack Palevich0a280a02009-06-11 10:53:51 -07004792 inp();
4793 next();
4794 globalDeclarations();
Jack Palevicha6baa232009-06-12 11:25:59 -07004795 checkForUndefinedForwardReferences();
Jack Palevich0a280a02009-06-11 10:53:51 -07004796 result = pGen->finishCompile();
4797 if (result == 0) {
4798 if (mErrorBuf.len()) {
4799 result = -2;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004800 }
Jack Palevich8b0624c2009-05-20 12:12:06 -07004801 }
Jack Palevichce105a92009-07-16 14:30:33 -07004802 mCompileResult = result;
Jack Palevichac0e95e2009-05-29 13:53:44 -07004803 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07004804 }
4805
Jack Palevich86351982009-06-30 18:09:56 -07004806 void createPrimitiveTypes() {
4807 mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
4808 mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
4809 mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
Jack Palevich95727a02009-07-06 12:07:15 -07004810 mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
4811 mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004812 mkpIntFn = createType(TY_FUNC, mkpInt, NULL, mGlobalArena);
Jack Palevich3f226492009-07-02 14:46:19 -07004813 mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
4814 mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
Jack Palevich1a539db2009-07-08 13:04:41 -07004815 mkpFloatPtr = createPtrType(mkpFloat, mGlobalArena);
4816 mkpDoublePtr = createPtrType(mkpDouble, mGlobalArena);
Jack Palevich8df46192009-07-07 14:48:51 -07004817 mkpPtrIntFn = createPtrType(mkpIntFn, mGlobalArena);
Jack Palevich86351982009-06-30 18:09:56 -07004818 }
4819
Jack Palevicha6baa232009-06-12 11:25:59 -07004820 void checkForUndefinedForwardReferences() {
Jack Palevich569f1352009-06-29 14:29:08 -07004821 mGlobals.forEach(static_ufrcFn, this);
Jack Palevicha6baa232009-06-12 11:25:59 -07004822 }
4823
Jack Palevich569f1352009-06-29 14:29:08 -07004824 static bool static_ufrcFn(VariableInfo* value, void* context) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004825 Compiler* pCompiler = (Compiler*) context;
Jack Palevich569f1352009-06-29 14:29:08 -07004826 return pCompiler->undefinedForwardReferenceCheck(value);
Jack Palevicha6baa232009-06-12 11:25:59 -07004827 }
4828
Jack Palevich569f1352009-06-29 14:29:08 -07004829 bool undefinedForwardReferenceCheck(VariableInfo* value) {
Jack Palevicha6baa232009-06-12 11:25:59 -07004830 if (!value->pAddress && value->pForward) {
Jack Palevich569f1352009-06-29 14:29:08 -07004831 error("Undefined forward reference: %s",
4832 mTokenTable[value->tok].pText);
Jack Palevicha6baa232009-06-12 11:25:59 -07004833 }
4834 return true;
4835 }
4836
Jack Palevich21a15a22009-05-11 14:49:29 -07004837 int dump(FILE* out) {
4838 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
4839 return 0;
4840 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07004841
Jack Palevicha6535612009-05-13 16:24:17 -07004842 int disassemble(FILE* out) {
4843 return pGen->disassemble(out);
4844 }
4845
Jack Palevich1cdef202009-05-22 12:06:27 -07004846 /* Look through the symbol table to find a symbol.
4847 * If found, return its value.
4848 */
4849 void* lookup(const char* name) {
Jack Palevichce105a92009-07-16 14:30:33 -07004850 if (mCompileResult == 0) {
4851 tokenid_t tok = mTokenTable.intern(name, strlen(name));
4852 VariableInfo* pVariableInfo = VI(tok);
4853 if (pVariableInfo) {
4854 return pVariableInfo->pAddress;
4855 }
Jack Palevich1cdef202009-05-22 12:06:27 -07004856 }
4857 return NULL;
4858 }
4859
Jack Palevicheedf9d22009-06-04 16:23:40 -07004860 void getPragmas(ACCsizei* actualStringCount,
4861 ACCsizei maxStringCount, ACCchar** strings) {
4862 int stringCount = mPragmaStringCount;
4863 if (actualStringCount) {
4864 *actualStringCount = stringCount;
4865 }
4866 if (stringCount > maxStringCount) {
4867 stringCount = maxStringCount;
4868 }
4869 if (strings) {
4870 char* pPragmas = mPragmas.getUnwrapped();
4871 while (stringCount-- > 0) {
4872 *strings++ = pPragmas;
4873 pPragmas += strlen(pPragmas) + 1;
4874 }
4875 }
4876 }
4877
Jack Palevichac0e95e2009-05-29 13:53:44 -07004878 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07004879 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07004880 }
4881
Jack Palevich77ae76e2009-05-10 19:59:24 -07004882};
4883
Jack Paleviche7b59062009-05-19 17:12:17 -07004884const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004885 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
4886
Jack Paleviche7b59062009-05-19 17:12:17 -07004887const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004888 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
4889 5, 5, /* ==, != */
4890 9, 10, /* &&, || */
4891 6, 7, 8, /* & ^ | */
4892 2, 2 /* ~ ! */
4893 };
4894
Jack Palevich8b0624c2009-05-20 12:12:06 -07004895#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004896FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07004897#endif
Jack Palevicha6535612009-05-13 16:24:17 -07004898
Jack Palevich8b0624c2009-05-20 12:12:06 -07004899#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07004900const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004901 0x1, // ++
4902 0xff, // --
4903 0xc1af0f, // *
4904 0xf9f79991, // /
4905 0xf9f79991, // % (With manual assist to swap results)
4906 0xc801, // +
4907 0xd8f7c829, // -
4908 0xe0d391, // <<
4909 0xf8d391, // >>
4910 0xe, // <=
4911 0xd, // >=
4912 0xc, // <
4913 0xf, // >
4914 0x4, // ==
4915 0x5, // !=
4916 0x0, // &&
4917 0x1, // ||
4918 0xc821, // &
4919 0xc831, // ^
4920 0xc809, // |
4921 0xd0f7, // ~
4922 0x4 // !
4923};
Jack Palevich8b0624c2009-05-20 12:12:06 -07004924#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07004925
Jack Palevich1cdef202009-05-22 12:06:27 -07004926struct ACCscript {
4927 ACCscript() {
4928 text = 0;
4929 textLength = 0;
4930 accError = ACC_NO_ERROR;
4931 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004932
Jack Palevich1cdef202009-05-22 12:06:27 -07004933 ~ACCscript() {
4934 delete text;
4935 }
Jack Palevich546b2242009-05-13 15:10:04 -07004936
Jack Palevich8c246a92009-07-14 21:14:10 -07004937 void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
4938 compiler.registerSymbolCallback(pFn, pContext);
4939 }
4940
Jack Palevich1cdef202009-05-22 12:06:27 -07004941 void setError(ACCenum error) {
4942 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
4943 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004944 }
4945 }
4946
Jack Palevich1cdef202009-05-22 12:06:27 -07004947 ACCenum getError() {
4948 ACCenum result = accError;
4949 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07004950 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004951 }
4952
Jack Palevich1cdef202009-05-22 12:06:27 -07004953 Compiler compiler;
4954 char* text;
4955 int textLength;
4956 ACCenum accError;
4957};
4958
4959
4960extern "C"
4961ACCscript* accCreateScript() {
4962 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07004963}
Jack Palevich1cdef202009-05-22 12:06:27 -07004964
4965extern "C"
4966ACCenum accGetError( ACCscript* script ) {
4967 return script->getError();
4968}
4969
4970extern "C"
4971void accDeleteScript(ACCscript* script) {
4972 delete script;
4973}
4974
4975extern "C"
Jack Palevich8c246a92009-07-14 21:14:10 -07004976void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
4977 ACCvoid* pContext) {
4978 script->registerSymbolCallback(pFn, pContext);
4979}
4980
4981extern "C"
Jack Palevich1cdef202009-05-22 12:06:27 -07004982void accScriptSource(ACCscript* script,
4983 ACCsizei count,
4984 const ACCchar ** string,
4985 const ACCint * length) {
4986 int totalLength = 0;
4987 for(int i = 0; i < count; i++) {
4988 int len = -1;
4989 const ACCchar* s = string[i];
4990 if (length) {
4991 len = length[i];
4992 }
4993 if (len < 0) {
4994 len = strlen(s);
4995 }
4996 totalLength += len;
4997 }
4998 delete script->text;
4999 char* text = new char[totalLength + 1];
5000 script->text = text;
5001 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07005002 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07005003 for(int i = 0; i < count; i++) {
5004 int len = -1;
5005 const ACCchar* s = string[i];
5006 if (length) {
5007 len = length[i];
5008 }
5009 if (len < 0) {
5010 len = strlen(s);
5011 }
Jack Palevich09555c72009-05-27 12:25:55 -07005012 memcpy(dest, s, len);
5013 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07005014 }
5015 text[totalLength] = '\0';
5016}
5017
5018extern "C"
5019void accCompileScript(ACCscript* script) {
5020 int result = script->compiler.compile(script->text, script->textLength);
5021 if (result) {
5022 script->setError(ACC_INVALID_OPERATION);
5023 }
5024}
5025
5026extern "C"
5027void accGetScriptiv(ACCscript* script,
5028 ACCenum pname,
5029 ACCint * params) {
5030 switch (pname) {
5031 case ACC_INFO_LOG_LENGTH:
5032 *params = 0;
5033 break;
5034 }
5035}
5036
5037extern "C"
5038void accGetScriptInfoLog(ACCscript* script,
5039 ACCsizei maxLength,
5040 ACCsizei * length,
5041 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005042 char* message = script->compiler.getErrorMessage();
5043 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07005044 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07005045 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07005046 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07005047 if (infoLog && maxLength > 0) {
5048 int trimmedLength = maxLength < messageLength ?
5049 maxLength : messageLength;
5050 memcpy(infoLog, message, trimmedLength);
5051 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07005052 }
5053}
5054
5055extern "C"
5056void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5057 ACCvoid ** address) {
5058 void* value = script->compiler.lookup(name);
5059 if (value) {
5060 *address = value;
5061 } else {
5062 script->setError(ACC_INVALID_VALUE);
5063 }
5064}
5065
Jack Palevicheedf9d22009-06-04 16:23:40 -07005066extern "C"
5067void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5068 ACCsizei maxStringCount, ACCchar** strings){
5069 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5070}
5071
-b master422972c2009-06-17 19:13:52 -07005072extern "C"
5073void accDisassemble(ACCscript* script) {
5074 script->compiler.disassemble(stderr);
5075}
5076
Jack Palevicheedf9d22009-06-04 16:23:40 -07005077
Jack Palevich1cdef202009-05-22 12:06:27 -07005078} // namespace acc
5079