blob: db208ccc40329f52192a59018c6804a4775b0c97 [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>
12#include <dlfcn.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 Palevichae54f1f2009-05-08 14:54:15 -070018
Jack Palevich546b2242009-05-13 15:10:04 -070019#if defined(__arm__)
20#include <unistd.h>
21#endif
22
Jack Paleviche7b59062009-05-19 17:12:17 -070023#if defined(__arm__)
24#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070025#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070026#elif defined(__i386__)
27#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070028#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070029#elif defined(__x86_64__)
30#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070031#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070032#endif
33
Jack Paleviche7b59062009-05-19 17:12:17 -070034
35#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070036#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070037#endif
Jack Palevicha6535612009-05-13 16:24:17 -070038
Jack Palevich1cdef202009-05-22 12:06:27 -070039#include <acc/acc.h>
40
Jack Palevichbbf8ab52009-05-11 11:54:30 -070041namespace acc {
42
Jack Paleviche7b59062009-05-19 17:12:17 -070043class Compiler {
Jack Palevich21a15a22009-05-11 14:49:29 -070044 class CodeBuf {
45 char* ind;
46 char* pProgramBase;
Jack Palevichf0cbc922009-05-08 16:35:13 -070047
Jack Palevich21a15a22009-05-11 14:49:29 -070048 void release() {
49 if (pProgramBase != 0) {
50 free(pProgramBase);
51 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070052 }
Jack Palevich21a15a22009-05-11 14:49:29 -070053 }
54
55 public:
56 CodeBuf() {
57 pProgramBase = 0;
58 ind = 0;
59 }
60
61 ~CodeBuf() {
62 release();
63 }
64
65 void init(int size) {
66 release();
67 pProgramBase = (char*) calloc(1, size);
68 ind = pProgramBase;
69 }
70
Jack Palevich546b2242009-05-13 15:10:04 -070071 int o4(int n) {
Jack Palevich8b0624c2009-05-20 12:12:06 -070072 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -070073 * (int*) ind = n;
74 ind += 4;
75 return result;
76 }
77
Jack Palevich21a15a22009-05-11 14:49:29 -070078 /*
79 * Output a byte. Handles all values, 0..ff.
80 */
81 void ob(int n) {
82 *ind++ = n;
83 }
84
Jack Palevich21a15a22009-05-11 14:49:29 -070085 inline void* getBase() {
86 return (void*) pProgramBase;
87 }
88
Jack Palevich8b0624c2009-05-20 12:12:06 -070089 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -070090 return ind - pProgramBase;
91 }
92
Jack Palevich8b0624c2009-05-20 12:12:06 -070093 intptr_t getPC() {
94 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -070095 }
96 };
97
Jack Palevich1cdef202009-05-22 12:06:27 -070098 /**
99 * A code generator creates an in-memory program, generating the code on
100 * the fly. There is one code generator implementation for each supported
101 * architecture.
102 *
103 * The code generator implements the following abstract machine:
104 * R0 - the main accumulator.
105 * R1 - the secondary accumulator.
106 * FP - a frame pointer for accessing function arguments and local
107 * variables.
108 * SP - a stack pointer for storing intermediate results while evaluating
109 * expressions. The stack pointer grows downwards.
110 *
111 * The function calling convention is that all arguments are placed on the
112 * stack such that the first argument has the lowest address.
113 * After the call, the result is in R0. The caller is responsible for
114 * removing the arguments from the stack.
115 * The R0 and R1 registers are not saved across function calls. The
116 * FP and SP registers are saved.
117 */
118
Jack Palevich21a15a22009-05-11 14:49:29 -0700119 class CodeGenerator {
120 public:
121 CodeGenerator() {}
122 virtual ~CodeGenerator() {}
123
Jack Palevich22305132009-05-13 10:58:45 -0700124 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700125 this->pCodeBuf = pCodeBuf;
126 }
127
Jack Palevich1cdef202009-05-22 12:06:27 -0700128 /* Emit a function prolog.
129 * argCount is the number of arguments.
130 * Save the old value of the FP.
131 * Set the new value of the FP.
132 * Convert from the native platform calling convention to
133 * our stack-based calling convention. This may require
134 * pushing arguments from registers to the stack.
135 * Allocate "N" bytes of stack space. N isn't known yet, so
136 * just emit the instructions for adjusting the stack, and return
137 * the address to patch up. The patching will be done in
138 * functionExit().
139 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700140 */
Jack Palevich546b2242009-05-13 15:10:04 -0700141 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700142
Jack Palevich1cdef202009-05-22 12:06:27 -0700143 /* Emit a function epilog.
144 * Restore the old SP and FP register values.
145 * Return to the calling function.
146 * argCount - the number of arguments to the function.
147 * localVariableAddress - returned from functionEntry()
148 * localVariableSize - the size in bytes of the local variables.
149 */
150 virtual void functionExit(int argCount, int localVariableAddress,
151 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700152
Jack Palevich1cdef202009-05-22 12:06:27 -0700153 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700154 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700155
Jack Palevich1cdef202009-05-22 12:06:27 -0700156 /* Jump to a target, and return the address of the word that
157 * holds the target data, in case it needs to be fixed up later.
158 */
Jack Palevich22305132009-05-13 10:58:45 -0700159 virtual int gjmp(int t) = 0;
160
Jack Palevich1cdef202009-05-22 12:06:27 -0700161 /* Test R0 and jump to a target if the test succeeds.
162 * l = 0: je, l == 1: jne
163 * Return the address of the word that holds the targed data, in
164 * case it needs to be fixed up later.
165 */
Jack Palevich22305132009-05-13 10:58:45 -0700166 virtual int gtst(bool l, int t) = 0;
167
Jack Palevich1cdef202009-05-22 12:06:27 -0700168 /* Compare R1 against R0, and store the boolean result in R0.
169 * op specifies the comparison.
170 */
Jack Palevich22305132009-05-13 10:58:45 -0700171 virtual void gcmp(int op) = 0;
172
Jack Palevich1cdef202009-05-22 12:06:27 -0700173 /* Perform the arithmetic op specified by op. R1 is the
174 * left argument, R0 is the right argument.
175 */
Jack Palevich546b2242009-05-13 15:10:04 -0700176 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700177
Jack Palevich1cdef202009-05-22 12:06:27 -0700178 /* Set R1 to 0.
179 */
180 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700181
Jack Palevich1cdef202009-05-22 12:06:27 -0700182 /* Push R0 onto the stack.
183 */
184 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700185
Jack Palevich1cdef202009-05-22 12:06:27 -0700186 /* Pop R1 off of the stack.
187 */
188 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700189
Jack Palevich1cdef202009-05-22 12:06:27 -0700190 /* Store R0 to the address stored in R1.
191 * isInt is true if a whole 4-byte integer value
192 * should be stored, otherwise a 1-byte character
193 * value should be stored.
194 */
195 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700196
Jack Palevich1cdef202009-05-22 12:06:27 -0700197 /* Load R0 from the address stored in R0.
198 * isInt is true if a whole 4-byte integer value
199 * should be loaded, otherwise a 1-byte character
200 * value should be loaded.
201 */
202 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700203
Jack Palevich1cdef202009-05-22 12:06:27 -0700204 /* Load the absolute address of a variable to R0.
205 * If ea <= LOCAL, then this is a local variable, or an
206 * argument, addressed relative to FP.
207 * else it is an absolute global address.
208 */
209 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700210
Jack Palevich1cdef202009-05-22 12:06:27 -0700211 /* Store R0 to a variable.
212 * If ea <= LOCAL, then this is a local variable, or an
213 * argument, addressed relative to FP.
214 * else it is an absolute global address.
215 */
216 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700217
Jack Palevich1cdef202009-05-22 12:06:27 -0700218 /* load R0 from a variable.
219 * If ea <= LOCAL, then this is a local variable, or an
220 * argument, addressed relative to FP.
221 * else it is an absolute global address.
222 * If isIncDec is true, then the stored variable's value
223 * should be post-incremented or post-decremented, based
224 * on the value of op.
225 */
226 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700227
Jack Palevich1cdef202009-05-22 12:06:27 -0700228 /* Emit code to adjust the stack for a function call. Return the
229 * label for the address of the instruction that adjusts the
230 * stack size. This will be passed as argument "a" to
231 * endFunctionCallArguments.
232 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700233 virtual int beginFunctionCallArguments() = 0;
234
Jack Palevich1cdef202009-05-22 12:06:27 -0700235 /* Emit code to store R0 to the stack at byte offset l.
236 */
237 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700238
Jack Palevich1cdef202009-05-22 12:06:27 -0700239 /* Patch the function call preamble.
240 * a is the address returned from beginFunctionCallArguments
241 * l is the number of bytes the arguments took on the stack.
242 * Typically you would also emit code to convert the argument
243 * list into whatever the native function calling convention is.
244 * On ARM for example you would pop the first 5 arguments into
245 * R0..R4
246 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700247 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700248
Jack Palevich1cdef202009-05-22 12:06:27 -0700249 /* Emit a call to an unknown function. The argument "symbol" needs to
250 * be stored in the location where the address should go. It forms
251 * a chain. The address will be patched later.
252 * Return the address of the word that has to be patched.
253 */
Jack Palevich22305132009-05-13 10:58:45 -0700254 virtual int callForward(int symbol) = 0;
255
Jack Palevich1cdef202009-05-22 12:06:27 -0700256 /* Call a function using PC-relative addressing. t is the PC-relative
257 * address of the function. It has already been adjusted for the
258 * architectural jump offset, so just store it as-is.
259 */
Jack Palevich22305132009-05-13 10:58:45 -0700260 virtual void callRelative(int t) = 0;
261
Jack Palevich1cdef202009-05-22 12:06:27 -0700262 /* Call a function pointer. L is the number of bytes the arguments
263 * take on the stack. The address of the function is stored at
264 * location SP + l.
265 */
Jack Palevich22305132009-05-13 10:58:45 -0700266 virtual void callIndirect(int l) = 0;
267
Jack Palevich1cdef202009-05-22 12:06:27 -0700268 /* Adjust SP after returning from a function call. l is the
269 * number of bytes of arguments stored on the stack. isIndirect
270 * is true if this was an indirect call. (In which case the
271 * address of the function is stored at location SP + l.)
272 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700273 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700274
Jack Palevich1cdef202009-05-22 12:06:27 -0700275 /* Print a disassembly of the assembled code to out. Return
276 * non-zero if there is an error.
277 */
Jack Palevicha6535612009-05-13 16:24:17 -0700278 virtual int disassemble(FILE* out) = 0;
279
Jack Palevich1cdef202009-05-22 12:06:27 -0700280 /* Generate a symbol at the current PC. t is the head of a
281 * linked list of addresses to patch.
282 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700283 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700284
Jack Palevich1cdef202009-05-22 12:06:27 -0700285 /*
286 * Do any cleanup work required at the end of a compile.
287 * For example, an instruction cache might need to be
288 * invalidated.
289 * Return non-zero if there is an error.
290 */
291 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700292
Jack Palevicha6535612009-05-13 16:24:17 -0700293 /**
294 * Adjust relative branches by this amount.
295 */
296 virtual int jumpOffset() = 0;
297
Jack Palevich21a15a22009-05-11 14:49:29 -0700298 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700299 /*
300 * Output a byte. Handles all values, 0..ff.
301 */
302 void ob(int n) {
303 pCodeBuf->ob(n);
304 }
305
Jack Palevich8b0624c2009-05-20 12:12:06 -0700306 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700307 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700308 }
309
Jack Palevich8b0624c2009-05-20 12:12:06 -0700310 intptr_t getBase() {
311 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700312 }
313
Jack Palevich8b0624c2009-05-20 12:12:06 -0700314 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700315 return pCodeBuf->getPC();
316 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700317
318 intptr_t getSize() {
319 return pCodeBuf->getSize();
320 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700321 private:
322 CodeBuf* pCodeBuf;
323 };
324
Jack Paleviche7b59062009-05-19 17:12:17 -0700325#ifdef PROVIDE_ARM_CODEGEN
326
Jack Palevich22305132009-05-13 10:58:45 -0700327 class ARMCodeGenerator : public CodeGenerator {
328 public:
329 ARMCodeGenerator() {}
330 virtual ~ARMCodeGenerator() {}
331
332 /* returns address to patch with local variable size
333 */
Jack Palevich546b2242009-05-13 15:10:04 -0700334 virtual int functionEntry(int argCount) {
335 fprintf(stderr, "functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700336 // sp -> arg4 arg5 ...
337 // Push our register-based arguments back on the stack
338 if (argCount > 0) {
339 int regArgCount = argCount <= 4 ? argCount : 4;
340 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
341 }
342 // sp -> arg0 arg1 ...
343 o4(0xE92D4800); // stmfd sp!, {fp, lr}
344 // sp, fp -> oldfp, retadr, arg0 arg1 ....
345 o4(0xE1A0B00D); // mov fp, sp
346 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700347 }
348
Jack Palevich546b2242009-05-13 15:10:04 -0700349 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
350 fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700351 // Patch local variable allocation code:
352 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700353 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700354 }
Jack Palevich69796b62009-05-14 15:42:26 -0700355 *(char*) (localVariableAddress) = localVariableSize;
356
357 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
358 o4(0xE1A0E00B); // mov lr, fp
359 o4(0xE59BB000); // ldr fp, [fp]
360 o4(0xE28ED004); // add sp, lr, #4
361 // sp -> retadr, arg0, ...
362 o4(0xE8BD4000); // ldmfd sp!, {lr}
363 // sp -> arg0 ....
364 if (argCount > 0) {
365 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700366 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700367 // earlier. We don't need to actually store them anywhere,
368 // just adjust the stack.
369 int regArgCount = argCount <= 4 ? argCount : 4;
370 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
371 }
372 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700373 }
374
375 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700376 virtual void li(int t) {
Jack Palevich22305132009-05-13 10:58:45 -0700377 fprintf(stderr, "li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700378 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700379 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700380 } else if (t >= -256 && t < 0) {
381 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700382 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700383 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700384 o4(0xE51F0000); // ldr r0, .L3
385 o4(0xEA000000); // b .L99
386 o4(t); // .L3: .word 0
387 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700388 }
Jack Palevich22305132009-05-13 10:58:45 -0700389 }
390
391 virtual int gjmp(int t) {
392 fprintf(stderr, "gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700393 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700394 }
395
396 /* l = 0: je, l == 1: jne */
397 virtual int gtst(bool l, int t) {
398 fprintf(stderr, "gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700399 o4(0xE3500000); // cmp r0,#0
400 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
401 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700402 }
403
404 virtual void gcmp(int op) {
405 fprintf(stderr, "gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700406 o4(0xE1510000); // cmp r1, r1
407 switch(op) {
408 case OP_EQUALS:
409 o4(0x03A00001); // moveq r0,#1
410 o4(0x13A00000); // movne r0,#0
411 break;
412 case OP_NOT_EQUALS:
413 o4(0x03A00000); // moveq r0,#0
414 o4(0x13A00001); // movne r0,#1
415 break;
416 case OP_LESS_EQUAL:
417 o4(0xD3A00001); // movle r0,#1
418 o4(0xC3A00000); // movgt r0,#0
419 break;
420 case OP_GREATER:
421 o4(0xD3A00000); // movle r0,#0
422 o4(0xC3A00001); // movgt r0,#1
423 break;
424 case OP_GREATER_EQUAL:
425 o4(0xA3A00001); // movge r0,#1
426 o4(0xB3A00000); // movlt r0,#0
427 break;
428 case OP_LESS:
429 o4(0xA3A00000); // movge r0,#0
430 o4(0xB3A00001); // movlt r0,#1
431 break;
432 default:
433 error("Unknown comparison op %d", op);
434 break;
435 }
Jack Palevich22305132009-05-13 10:58:45 -0700436 }
437
Jack Palevich546b2242009-05-13 15:10:04 -0700438 virtual void genOp(int op) {
Jack Palevich22305132009-05-13 10:58:45 -0700439 fprintf(stderr, "genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700440 switch(op) {
441 case OP_MUL:
442 o4(0x0E0000091); // mul r0,r1,r0
443 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700444 case OP_DIV:
445 callRuntime(runtime_DIV);
446 break;
447 case OP_MOD:
448 callRuntime(runtime_MOD);
449 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700450 case OP_PLUS:
451 o4(0xE0810000); // add r0,r1,r0
452 break;
453 case OP_MINUS:
454 o4(0xE0410000); // sub r0,r1,r0
455 break;
456 case OP_SHIFT_LEFT:
457 o4(0xE1A00011); // lsl r0,r1,r0
458 break;
459 case OP_SHIFT_RIGHT:
460 o4(0xE1A00051); // asr r0,r1,r0
461 break;
462 case OP_BIT_AND:
463 o4(0xE0010000); // and r0,r1,r0
464 break;
465 case OP_BIT_XOR:
466 o4(0xE0210000); // eor r0,r1,r0
467 break;
468 case OP_BIT_OR:
469 o4(0xE1810000); // orr r0,r1,r0
470 break;
471 case OP_BIT_NOT:
472 o4(0xE1E00000); // mvn r0, r0
473 break;
474 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700475 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700476 break;
477 }
Jack Palevich22305132009-05-13 10:58:45 -0700478#if 0
479 o(decodeOp(op));
480 if (op == OP_MOD)
481 o(0x92); /* xchg %edx, %eax */
482#endif
483 }
484
Jack Palevich1cdef202009-05-22 12:06:27 -0700485 virtual void clearR1() {
486 fprintf(stderr, "clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700487 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700488 }
489
Jack Palevich1cdef202009-05-22 12:06:27 -0700490 virtual void pushR0() {
491 fprintf(stderr, "pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700492 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700493 }
494
Jack Palevich1cdef202009-05-22 12:06:27 -0700495 virtual void popR1() {
496 fprintf(stderr, "popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700497 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700498 }
499
Jack Palevich1cdef202009-05-22 12:06:27 -0700500 virtual void storeR0ToR1(bool isInt) {
501 fprintf(stderr, "storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700502 if (isInt) {
503 o4(0xE5810000); // str r0, [r1]
504 } else {
505 o4(0xE5C10000); // strb r0, [r1]
506 }
Jack Palevich22305132009-05-13 10:58:45 -0700507 }
508
Jack Palevich1cdef202009-05-22 12:06:27 -0700509 virtual void loadR0FromR0(bool isInt) {
510 fprintf(stderr, "loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700511 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700512 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700513 else
Jack Palevich69796b62009-05-14 15:42:26 -0700514 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700515 }
516
Jack Palevich1cdef202009-05-22 12:06:27 -0700517 virtual void leaR0(int ea) {
518 fprintf(stderr, "leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700519 if (ea < LOCAL) {
520 // Local, fp relative
521 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
522 error("Offset out of range: %08x", ea);
523 }
524 if (ea < 0) {
525 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
526 } else {
527 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
528 }
Jack Palevichbd894902009-05-14 19:35:31 -0700529 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700530 // Global, absolute.
531 o4(0xE59F0000); // ldr r0, .L1
532 o4(0xEA000000); // b .L99
533 o4(ea); // .L1: .word 0
534 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700535 }
Jack Palevich22305132009-05-13 10:58:45 -0700536 }
537
Jack Palevich1cdef202009-05-22 12:06:27 -0700538 virtual void storeR0(int ea) {
539 fprintf(stderr, "storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700540 if (ea < LOCAL) {
541 // Local, fp relative
542 if (ea < -4095 || ea > 4095) {
543 error("Offset out of range: %08x", ea);
544 }
545 if (ea < 0) {
546 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
547 } else {
548 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
549 }
550 } else{
551 // Global, absolute
552 o4(0xE59F1000); // ldr r1, .L1
553 o4(0xEA000000); // b .L99
554 o4(ea); // .L1: .word 0
555 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700556 }
Jack Palevich22305132009-05-13 10:58:45 -0700557 }
558
Jack Palevich1cdef202009-05-22 12:06:27 -0700559 virtual void loadR0(int ea, bool isIncDec, int op) {
560 fprintf(stderr, "loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700561 if (ea < LOCAL) {
562 // Local, fp relative
563 if (ea < -4095 || ea > 4095) {
564 error("Offset out of range: %08x", ea);
565 }
566 if (ea < 0) {
567 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
568 } else {
569 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
570 }
Jack Palevich69796b62009-05-14 15:42:26 -0700571 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700572 // Global, absolute
573 o4(0xE59F2000); // ldr r2, .L1
574 o4(0xEA000000); // b .L99
575 o4(ea); // .L1: .word ea
576 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700577 }
Jack Palevich22305132009-05-13 10:58:45 -0700578
Jack Palevich4d93f302009-05-15 13:30:00 -0700579 if (isIncDec) {
580 switch (op) {
581 case OP_INCREMENT:
582 o4(0xE2801001); // add r1, r0, #1
583 break;
584 case OP_DECREMENT:
585 o4(0xE2401001); // sub r1, r0, #1
586 break;
587 default:
588 error("unknown opcode: %d", op);
589 }
590 if (ea < LOCAL) {
591 // Local, fp relative
592 // Don't need range check, was already checked above
593 if (ea < 0) {
594 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
595 } else {
596 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
597 }
598 } else{
599 // Global, absolute
600 // r2 is already set up from before.
601 o4(0xE5821000); // str r1, [r2]
602 }
Jack Palevichbd894902009-05-14 19:35:31 -0700603 }
Jack Palevich22305132009-05-13 10:58:45 -0700604 }
605
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700606 virtual int beginFunctionCallArguments() {
607 fprintf(stderr, "beginFunctionCallArguments();\n");
608 return o4(0xE24DDF00); // Placeholder
609 }
610
Jack Palevich1cdef202009-05-22 12:06:27 -0700611 virtual void storeR0ToArg(int l) {
612 fprintf(stderr, "storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700613 if (l < 0 || l > 4096-4) {
614 error("l out of range for stack offset: 0x%08x", l);
615 }
616 o4(0xE58D0000 + l); // str r0, [sp, #4]
617 }
618
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700619 virtual void endFunctionCallArguments(int a, int l) {
620 fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l);
621 if (l < 0 || l > 0x3FC) {
622 error("L out of range for stack adjustment: 0x%08x", l);
623 }
624 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
625 int argCount = l >> 2;
626 if (argCount > 0) {
627 int regArgCount = argCount > 4 ? 4 : argCount;
628 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
629 }
Jack Palevich22305132009-05-13 10:58:45 -0700630 }
631
Jack Palevich22305132009-05-13 10:58:45 -0700632 virtual int callForward(int symbol) {
633 fprintf(stderr, "callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700634 // Forward calls are always short (local)
635 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700636 }
637
638 virtual void callRelative(int t) {
639 fprintf(stderr, "callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700640 int abs = t + getPC() + jumpOffset();
Jack Palevichbd894902009-05-14 19:35:31 -0700641 fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700642 if (t >= - (1 << 25) && t < (1 << 25)) {
643 o4(0xEB000000 | encodeAddress(t));
644 } else {
645 // Long call.
646 o4(0xE59FC000); // ldr r12, .L1
647 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700648 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700649 o4(0xE08CC00F); // .L99: add r12,pc
650 o4(0xE12FFF3C); // blx r12
651 }
Jack Palevich22305132009-05-13 10:58:45 -0700652 }
653
654 virtual void callIndirect(int l) {
655 fprintf(stderr, "callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700656 int argCount = l >> 2;
657 int poppedArgs = argCount > 4 ? 4 : argCount;
658 int adjustedL = l - (poppedArgs << 2);
659 if (adjustedL < 0 || adjustedL > 4096-4) {
660 error("l out of range for stack offset: 0x%08x", l);
661 }
662 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
663 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700664 }
665
Jack Palevich7810bc92009-05-15 14:31:47 -0700666 virtual void adjustStackAfterCall(int l, bool isIndirect) {
667 fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700668 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700669 int stackArgs = argCount > 4 ? argCount - 4 : 0;
670 int stackUse = stackArgs + (isIndirect ? 1 : 0);
671 if (stackUse) {
672 if (stackUse < 0 || stackUse > 255) {
673 error("L out of range for stack adjustment: 0x%08x", l);
674 }
675 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700676 }
Jack Palevich22305132009-05-13 10:58:45 -0700677 }
678
Jack Palevicha6535612009-05-13 16:24:17 -0700679 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700680 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700681 }
682
683 /* output a symbol and patch all calls to it */
684 virtual void gsym(int t) {
685 fprintf(stderr, "gsym(0x%x)\n", t);
686 int n;
687 int base = getBase();
688 int pc = getPC();
689 fprintf(stderr, "pc = 0x%x\n", pc);
690 while (t) {
691 int data = * (int*) t;
692 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
693 if (decodedOffset == 0) {
694 n = 0;
695 } else {
696 n = base + decodedOffset; /* next value */
697 }
698 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
699 | encodeRelAddress(pc - t - 8);
700 t = n;
701 }
702 }
703
Jack Palevich1cdef202009-05-22 12:06:27 -0700704 virtual int finishCompile() {
705#if defined(__arm__)
706 const long base = long(getBase());
707 const long curr = long(getPC());
708 int err = cacheflush(base, curr, 0);
709 return err;
710#else
711 return 0;
712#endif
713 }
714
Jack Palevicha6535612009-05-13 16:24:17 -0700715 virtual int disassemble(FILE* out) {
716 disasmOut = out;
717 disasm_interface_t di;
718 di.di_readword = disassemble_readword;
719 di.di_printaddr = disassemble_printaddr;
720 di.di_printf = disassemble_printf;
721
722 int base = getBase();
723 int pc = getPC();
724 for(int i = base; i < pc; i += 4) {
725 fprintf(out, "%08x: %08x ", i, *(int*) i);
726 ::disasm(&di, i, 0);
727 }
728 return 0;
729 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700730
Jack Palevich22305132009-05-13 10:58:45 -0700731 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700732 static FILE* disasmOut;
733
734 static u_int
735 disassemble_readword(u_int address)
736 {
737 return(*((u_int *)address));
738 }
739
740 static void
741 disassemble_printaddr(u_int address)
742 {
743 fprintf(disasmOut, "0x%08x", address);
744 }
745
746 static void
747 disassemble_printf(const char *fmt, ...) {
748 va_list ap;
749 va_start(ap, fmt);
750 vfprintf(disasmOut, fmt, ap);
751 va_end(ap);
752 }
753
754 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
755
756 /** Encode a relative address that might also be
757 * a label.
758 */
759 int encodeAddress(int value) {
760 int base = getBase();
761 if (value >= base && value <= getPC() ) {
762 // This is a label, encode it relative to the base.
763 value = value - base;
764 }
765 return encodeRelAddress(value);
766 }
767
768 int encodeRelAddress(int value) {
769 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
770 }
Jack Palevich22305132009-05-13 10:58:45 -0700771
Jack Palevich3d474a72009-05-15 15:12:38 -0700772 typedef int (*int2FnPtr)(int a, int b);
773 void callRuntime(int2FnPtr fn) {
774 o4(0xE59F2000); // ldr r2, .L1
775 o4(0xEA000000); // b .L99
776 o4((int) fn); //.L1: .word fn
777 o4(0xE12FFF32); //.L99: blx r2
778 }
779
780 static int runtime_DIV(int a, int b) {
781 return b / a;
782 }
783
784 static int runtime_MOD(int a, int b) {
785 return b % a;
786 }
787
Jack Palevich546b2242009-05-13 15:10:04 -0700788 void error(const char* fmt,...) {
789 va_list ap;
790 va_start(ap, fmt);
791 vfprintf(stderr, fmt, ap);
792 va_end(ap);
793 exit(12);
794 }
Jack Palevich22305132009-05-13 10:58:45 -0700795 };
796
Jack Paleviche7b59062009-05-19 17:12:17 -0700797#endif // PROVIDE_X86_CODEGEN
798
799#ifdef PROVIDE_X86_CODEGEN
800
Jack Palevich21a15a22009-05-11 14:49:29 -0700801 class X86CodeGenerator : public CodeGenerator {
802 public:
803 X86CodeGenerator() {}
804 virtual ~X86CodeGenerator() {}
805
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700806 /* returns address to patch with local variable size
807 */
Jack Palevich546b2242009-05-13 15:10:04 -0700808 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700809 o(0xe58955); /* push %ebp, mov %esp, %ebp */
810 return oad(0xec81, 0); /* sub $xxx, %esp */
811 }
812
Jack Palevich546b2242009-05-13 15:10:04 -0700813 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700814 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700815 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700816 }
817
Jack Palevich21a15a22009-05-11 14:49:29 -0700818 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700819 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700820 oad(0xb8, t); /* mov $xx, %eax */
821 }
822
Jack Palevich22305132009-05-13 10:58:45 -0700823 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700824 return psym(0xe9, t);
825 }
826
827 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700828 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700829 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
830 return psym(0x84 + l, t);
831 }
832
Jack Palevich22305132009-05-13 10:58:45 -0700833 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700834 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700835 o(0xc139); /* cmp %eax,%ecx */
836 li(0);
837 o(0x0f); /* setxx %al */
838 o(t + 0x90);
839 o(0xc0);
840 }
841
Jack Palevich546b2242009-05-13 15:10:04 -0700842 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700843 o(decodeOp(op));
844 if (op == OP_MOD)
845 o(0x92); /* xchg %edx, %eax */
846 }
847
Jack Palevich1cdef202009-05-22 12:06:27 -0700848 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700849 oad(0xb9, 0); /* movl $0, %ecx */
850 }
851
Jack Palevich1cdef202009-05-22 12:06:27 -0700852 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700853 o(0x50); /* push %eax */
854 }
855
Jack Palevich1cdef202009-05-22 12:06:27 -0700856 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700857 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700858 }
859
Jack Palevich1cdef202009-05-22 12:06:27 -0700860 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700861 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
862 }
863
Jack Palevich1cdef202009-05-22 12:06:27 -0700864 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700865 if (isInt)
866 o(0x8b); /* mov (%eax), %eax */
867 else
868 o(0xbe0f); /* movsbl (%eax), %eax */
869 ob(0); /* add zero in code */
870 }
871
Jack Palevich1cdef202009-05-22 12:06:27 -0700872 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700873 gmov(10, ea); /* leal EA, %eax */
874 }
875
Jack Palevich1cdef202009-05-22 12:06:27 -0700876 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700877 gmov(6, ea); /* mov %eax, EA */
878 }
879
Jack Palevich1cdef202009-05-22 12:06:27 -0700880 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700881 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700882 if (isIncDec) {
883 /* Implement post-increment or post decrement.
884 */
885 gmov(0, ea); /* 83 ADD */
886 o(decodeOp(op));
887 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700888 }
889
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700890 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700891 return oad(0xec81, 0); /* sub $xxx, %esp */
892 }
893
Jack Palevich1cdef202009-05-22 12:06:27 -0700894 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700895 oad(0x248489, l); /* movl %eax, xxx(%esp) */
896 }
897
Jack Palevich7810bc92009-05-15 14:31:47 -0700898 virtual void endFunctionCallArguments(int a, int l) {
899 * (int*) a = l;
900 }
901
Jack Palevich22305132009-05-13 10:58:45 -0700902 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700903 return psym(0xe8, symbol); /* call xxx */
904 }
905
Jack Palevich22305132009-05-13 10:58:45 -0700906 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700907 psym(0xe8, t); /* call xxx */
908 }
909
Jack Palevich22305132009-05-13 10:58:45 -0700910 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700911 oad(0x2494ff, l); /* call *xxx(%esp) */
912 }
913
Jack Palevich7810bc92009-05-15 14:31:47 -0700914 virtual void adjustStackAfterCall(int l, bool isIndirect) {
915 if (isIndirect) {
916 l += 4;
917 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700918 oad(0xc481, l); /* add $xxx, %esp */
919 }
920
Jack Palevicha6535612009-05-13 16:24:17 -0700921 virtual int jumpOffset() {
922 return 5;
923 }
924
925 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -0700926 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -0700927 }
928
Jack Paleviche7b59062009-05-19 17:12:17 -0700929 /* output a symbol and patch all calls to it */
930 virtual void gsym(int t) {
931 int n;
932 int pc = getPC();
933 while (t) {
934 n = *(int *) t; /* next value */
935 *(int *) t = pc - t - 4;
936 t = n;
937 }
938 }
939
Jack Palevich1cdef202009-05-22 12:06:27 -0700940 virtual int finishCompile() {
941 return 0;
942 }
943
Jack Palevich21a15a22009-05-11 14:49:29 -0700944 private:
Jack Paleviche7b59062009-05-19 17:12:17 -0700945
946 /** Output 1 to 4 bytes.
947 *
948 */
949 void o(int n) {
950 /* cannot use unsigned, so we must do a hack */
951 while (n && n != -1) {
952 ob(n & 0xff);
953 n = n >> 8;
954 }
955 }
956
957 /* psym is used to put an instruction with a data field which is a
958 reference to a symbol. It is in fact the same as oad ! */
959 int psym(int n, int t) {
960 return oad(n, t);
961 }
962
963 /* instruction + address */
964 int oad(int n, int t) {
965 o(n);
966 int result = getPC();
967 o4(t);
968 return result;
969 }
970
971
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700972 static const int operatorHelper[];
973
974 int decodeOp(int op) {
975 if (op < 0 || op > OP_COUNT) {
976 fprintf(stderr, "Out-of-range operator: %d\n", op);
977 exit(1);
978 }
979 return operatorHelper[op];
980 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700981
Jack Palevich546b2242009-05-13 15:10:04 -0700982 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700983 o(l + 0x83);
984 oad((t < LOCAL) << 7 | 5, t);
985 }
986 };
987
Jack Paleviche7b59062009-05-19 17:12:17 -0700988#endif // PROVIDE_X86_CODEGEN
989
Jack Palevich1cdef202009-05-22 12:06:27 -0700990 class InputStream {
991 public:
992 virtual int get() = 0;
993 virtual long tell() = 0;
994 };
995
996 class FileInputStream : public InputStream {
997 public:
998 FileInputStream(FILE* in) : f(in) {}
999 virtual int get() { return fgetc(f); }
1000 virtual long tell() { return ftell(f); }
1001 private:
1002 FILE* f;
1003 };
1004
1005 class TextInputStream : public InputStream {
1006 public:
1007 TextInputStream(const char* text, size_t textLength)
1008 : pText(text), mTextLength(textLength), mPosition(0) {
1009 }
1010 virtual int get() {
1011 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1012 }
1013 virtual long tell() {
1014 return mPosition;
1015 }
1016
1017 private:
1018 const char* pText;
1019 size_t mTextLength;
1020 size_t mPosition;
1021 };
1022
Jack Palevich21a15a22009-05-11 14:49:29 -07001023 /* vars: value of variables
1024 loc : local variable index
1025 glo : global variable index
1026 ind : output code ptr
1027 rsym: return symbol
1028 prog: output code
1029 dstk: define stack
1030 dptr, dch: macro state
1031 */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001032 intptr_t tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk,
Jack Palevich21a15a22009-05-11 14:49:29 -07001033 dptr, dch, last_id;
1034 void* pSymbolBase;
1035 void* pGlobalBase;
1036 void* pVarsBase;
Jack Palevich1cdef202009-05-22 12:06:27 -07001037
1038 InputStream* file;
Jack Palevich21a15a22009-05-11 14:49:29 -07001039
1040 CodeBuf codeBuf;
Jack Palevich22305132009-05-13 10:58:45 -07001041 CodeGenerator* pGen;
Jack Palevich21a15a22009-05-11 14:49:29 -07001042
1043 static const int ALLOC_SIZE = 99999;
1044
1045 /* depends on the init string */
1046 static const int TOK_STR_SIZE = 48;
1047 static const int TOK_IDENT = 0x100;
1048 static const int TOK_INT = 0x100;
1049 static const int TOK_IF = 0x120;
1050 static const int TOK_ELSE = 0x138;
1051 static const int TOK_WHILE = 0x160;
1052 static const int TOK_BREAK = 0x190;
1053 static const int TOK_RETURN = 0x1c0;
1054 static const int TOK_FOR = 0x1f8;
1055 static const int TOK_DEFINE = 0x218;
1056 static const int TOK_MAIN = 0x250;
1057
1058 static const int TOK_DUMMY = 1;
1059 static const int TOK_NUM = 2;
1060
1061 static const int LOCAL = 0x200;
1062
1063 static const int SYM_FORWARD = 0;
1064 static const int SYM_DEFINE = 1;
1065
1066 /* tokens in string heap */
1067 static const int TAG_TOK = ' ';
1068 static const int TAG_MACRO = 2;
1069
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001070 static const int OP_INCREMENT = 0;
1071 static const int OP_DECREMENT = 1;
1072 static const int OP_MUL = 2;
1073 static const int OP_DIV = 3;
1074 static const int OP_MOD = 4;
1075 static const int OP_PLUS = 5;
1076 static const int OP_MINUS = 6;
1077 static const int OP_SHIFT_LEFT = 7;
1078 static const int OP_SHIFT_RIGHT = 8;
1079 static const int OP_LESS_EQUAL = 9;
1080 static const int OP_GREATER_EQUAL = 10;
1081 static const int OP_LESS = 11;
1082 static const int OP_GREATER = 12;
1083 static const int OP_EQUALS = 13;
1084 static const int OP_NOT_EQUALS = 14;
1085 static const int OP_LOGICAL_AND = 15;
1086 static const int OP_LOGICAL_OR = 16;
1087 static const int OP_BIT_AND = 17;
1088 static const int OP_BIT_XOR = 18;
1089 static const int OP_BIT_OR = 19;
1090 static const int OP_BIT_NOT = 20;
1091 static const int OP_LOGICAL_NOT = 21;
1092 static const int OP_COUNT = 22;
1093
1094 /* Operators are searched from front, the two-character operators appear
1095 * before the single-character operators with the same first character.
1096 * @ is used to pad out single-character operators.
1097 */
1098 static const char* operatorChars;
1099 static const char operatorLevel[];
1100
Jack Palevich21a15a22009-05-11 14:49:29 -07001101 void pdef(int t) {
1102 *(char *) dstk++ = t;
1103 }
1104
1105 void inp() {
1106 if (dptr) {
1107 ch = *(char *) dptr++;
1108 if (ch == TAG_MACRO) {
1109 dptr = 0;
1110 ch = dch;
1111 }
1112 } else
Jack Palevich1cdef202009-05-22 12:06:27 -07001113 ch = file->get();
Jack Palevich21a15a22009-05-11 14:49:29 -07001114 /* printf("ch=%c 0x%x\n", ch, ch); */
1115 }
1116
1117 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001118 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001119 }
1120
1121 /* read a character constant */
1122 void getq() {
1123 if (ch == '\\') {
1124 inp();
1125 if (ch == 'n')
1126 ch = '\n';
1127 }
1128 }
1129
1130 void next() {
1131 int l, a;
1132
Jack Palevich546b2242009-05-13 15:10:04 -07001133 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001134 if (ch == '#') {
1135 inp();
1136 next();
1137 if (tok == TOK_DEFINE) {
1138 next();
1139 pdef(TAG_TOK); /* fill last ident tag */
1140 *(int *) tok = SYM_DEFINE;
1141 *(int *) (tok + 4) = dstk; /* define stack */
1142 }
1143 /* well we always save the values ! */
1144 while (ch != '\n') {
1145 pdef(ch);
1146 inp();
1147 }
1148 pdef(ch);
1149 pdef(TAG_MACRO);
1150 }
1151 inp();
1152 }
1153 tokl = 0;
1154 tok = ch;
1155 /* encode identifiers & numbers */
1156 if (isid()) {
1157 pdef(TAG_TOK);
1158 last_id = dstk;
1159 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001160 pdef(ch);
1161 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001162 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001163 if (isdigit(tok)) {
1164 tokc = strtol((char*) last_id, 0, 0);
1165 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001166 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001167 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we
1168 suppose data is initialized to zero by calloc) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001169 tok = (intptr_t) (strstr((char*) sym_stk, (char*) (last_id - 1))
Jack Palevich21a15a22009-05-11 14:49:29 -07001170 - sym_stk);
1171 *(char *) dstk = 0; /* mark real end of ident for dlsym() */
1172 tok = tok * 8 + TOK_IDENT;
1173 if (tok > TOK_DEFINE) {
1174 tok = vars + tok;
1175 /* printf("tok=%s %x\n", last_id, tok); */
1176 /* define handling */
1177 if (*(int *) tok == SYM_DEFINE) {
1178 dptr = *(int *) (tok + 4);
1179 dch = ch;
1180 inp();
1181 next();
1182 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001183 }
1184 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001185 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001186 inp();
1187 if (tok == '\'') {
1188 tok = TOK_NUM;
1189 getq();
1190 tokc = ch;
1191 inp();
1192 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001193 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001194 inp();
1195 while (ch) {
1196 while (ch != '*')
1197 inp();
1198 inp();
1199 if (ch == '/')
1200 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001201 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001202 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001203 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001204 } else if ((tok == '/') & (ch == '/')) {
1205 inp();
1206 while (ch && (ch != '\n')) {
1207 inp();
1208 }
1209 inp();
1210 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001211 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001212 const char* t = operatorChars;
1213 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001214 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001215 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001216 tokl = operatorLevel[opIndex];
1217 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001218 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001219#if 0
1220 printf("%c%c -> tokl=%d tokc=0x%x\n",
1221 l, a, tokl, tokc);
1222#endif
1223 if (a == ch) {
1224 inp();
1225 tok = TOK_DUMMY; /* dummy token for double tokens */
1226 }
1227 break;
1228 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001229 opIndex++;
1230 }
1231 if (l == 0) {
1232 tokl = 0;
1233 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001234 }
1235 }
1236 }
1237#if 0
1238 {
1239 int p;
1240
1241 printf("tok=0x%x ", tok);
1242 if (tok >= TOK_IDENT) {
1243 printf("'");
1244 if (tok> TOK_DEFINE)
1245 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8;
1246 else
1247 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
1248 while (*(char *)p != TAG_TOK && *(char *)p)
1249 printf("%c", *(char *)p++);
1250 printf("'\n");
1251 } else if (tok == TOK_NUM) {
1252 printf("%d\n", tokc);
1253 } else {
1254 printf("'%c'\n", tok);
1255 }
1256 }
1257#endif
1258 }
1259
1260 void error(const char *fmt, ...) {
1261 va_list ap;
1262
1263 va_start(ap, fmt);
Jack Palevich1cdef202009-05-22 12:06:27 -07001264 fprintf(stderr, "%ld: ", file->tell());
Jack Palevich21a15a22009-05-11 14:49:29 -07001265 vfprintf(stderr, fmt, ap);
1266 fprintf(stderr, "\n");
1267 va_end(ap);
1268 exit(1);
1269 }
1270
Jack Palevich8b0624c2009-05-20 12:12:06 -07001271 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001272 if (tok != c) {
1273 error("'%c' expected", c);
1274 }
1275 next();
1276 }
1277
Jack Palevich21a15a22009-05-11 14:49:29 -07001278 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001279 void unary(intptr_t l) {
1280 intptr_t n, t, a, c;
Jack Palevich546b2242009-05-13 15:10:04 -07001281 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001282 n = 1; /* type of expression 0 = forward, 1 = value, other =
1283 lvalue */
1284 if (tok == '\"') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001285 pGen->li(glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001286 while (ch != '\"') {
1287 getq();
1288 *(char *) glo++ = ch;
1289 inp();
1290 }
1291 *(char *) glo = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001292 glo = (glo + 4) & -4; /* align heap */
Jack Palevich21a15a22009-05-11 14:49:29 -07001293 inp();
1294 next();
1295 } else {
1296 c = tokl;
1297 a = tokc;
1298 t = tok;
1299 next();
1300 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001301 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001302 } else if (c == 2) {
1303 /* -, +, !, ~ */
1304 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07001305 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001306 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001307 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001308 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001309 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001310 } else if (t == '(') {
1311 expr();
1312 skip(')');
1313 } else if (t == '*') {
1314 /* parse cast */
1315 skip('(');
1316 t = tok; /* get type */
1317 next(); /* skip int/char/void */
1318 next(); /* skip '*' or '(' */
1319 if (tok == '*') {
1320 /* function type */
1321 skip('*');
1322 skip(')');
1323 skip('(');
1324 skip(')');
1325 t = 0;
1326 }
1327 skip(')');
1328 unary(0);
1329 if (tok == '=') {
1330 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07001331 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001332 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001333 pGen->popR1();
1334 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001335 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001336 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001337 }
1338 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07001339 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001340 next();
1341 } else {
1342 n = *(int *) t;
1343 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001344 if (!n) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07001345 n = (intptr_t) dlsym(RTLD_DEFAULT, (char*) last_id);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001346 }
Jack Palevich546b2242009-05-13 15:10:04 -07001347 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001348 /* assignment */
1349 next();
1350 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001351 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07001352 } else if (tok != '(') {
1353 /* variable */
Jack Palevich1cdef202009-05-22 12:06:27 -07001354 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001355 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001356 next();
1357 }
1358 }
1359 }
1360 }
1361
1362 /* function call */
1363 if (tok == '(') {
1364 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07001365 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001366
1367 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001368 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001369 next();
1370 l = 0;
1371 while (tok != ')') {
1372 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001373 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001374 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001375 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001376 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001377 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001378 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001379 next();
1380 if (!n) {
1381 /* forward reference */
1382 t = t + 4;
1383 *(int *) t = pGen->callForward(*(int *) t);
1384 } else if (n == 1) {
1385 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001386 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001387 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001388 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001389 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07001390 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001391 }
1392 }
1393
Jack Palevich8b0624c2009-05-20 12:12:06 -07001394 void sum(intptr_t l) {
1395 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07001396 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001397 if (l-- == 1)
1398 unary(1);
1399 else {
1400 sum(l);
1401 a = 0;
1402 while (l == tokl) {
1403 n = tok;
1404 t = tokc;
1405 next();
1406
1407 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001408 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07001409 sum(l);
1410 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07001411 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001412 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07001413 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001414
Jack Palevich546b2242009-05-13 15:10:04 -07001415 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001416 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001417 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001418 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001419 }
1420 }
1421 }
1422 /* && and || output code generation */
1423 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001424 a = pGen->gtst(t == OP_LOGICAL_OR, a);
1425 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07001426 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001427 pGen->gsym(a);
1428 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07001429 }
1430 }
1431 }
1432
1433 void expr() {
1434 sum(11);
1435 }
1436
1437 int test_expr() {
1438 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001439 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001440 }
1441
Jack Palevich8b0624c2009-05-20 12:12:06 -07001442 void block(intptr_t l) {
1443 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001444
1445 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001446 next();
1447 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07001448 a = test_expr();
1449 skip(')');
1450 block(l);
1451 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001452 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001453 n = pGen->gjmp(0); /* jmp */
1454 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001455 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001456 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001457 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001458 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001459 }
Jack Palevich546b2242009-05-13 15:10:04 -07001460 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001461 t = tok;
1462 next();
1463 skip('(');
1464 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07001465 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07001466 a = test_expr();
1467 } else {
1468 if (tok != ';')
1469 expr();
1470 skip(';');
1471 n = codeBuf.getPC();
1472 a = 0;
1473 if (tok != ';')
1474 a = test_expr();
1475 skip(';');
1476 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001477 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001478 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07001479 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001480 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001481 n = t + 4;
1482 }
1483 }
1484 skip(')');
Jack Palevich8b0624c2009-05-20 12:12:06 -07001485 block((intptr_t) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07001486 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001487 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001488 } else if (tok == '{') {
1489 next();
1490 /* declarations */
1491 decl(1);
1492 while (tok != '}')
1493 block(l);
1494 next();
1495 } else {
1496 if (tok == TOK_RETURN) {
1497 next();
1498 if (tok != ';')
1499 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001500 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001501 } else if (tok == TOK_BREAK) {
1502 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001503 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001504 } else if (tok != ';')
1505 expr();
1506 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001507 }
1508 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001509
1510 /* 'l' is true if local declarations */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001511 void decl(bool l) {
1512 intptr_t a;
Jack Palevich21a15a22009-05-11 14:49:29 -07001513
Jack Palevich546b2242009-05-13 15:10:04 -07001514 while ((tok == TOK_INT) | ((tok != -1) & (!l))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001515 if (tok == TOK_INT) {
1516 next();
1517 while (tok != ';') {
1518 if (l) {
1519 loc = loc + 4;
1520 *(int *) tok = -loc;
1521 } else {
1522 *(int *) tok = glo;
1523 glo = glo + 4;
1524 }
1525 next();
1526 if (tok == ',')
1527 next();
1528 }
1529 skip(';');
1530 } else {
1531 /* patch forward references (XXX: do not work for function
1532 pointers) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001533 pGen->gsym(*(int *) (tok + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07001534 /* put function address */
1535 *(int *) tok = codeBuf.getPC();
1536 next();
1537 skip('(');
1538 a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07001539 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001540 while (tok != ')') {
1541 /* read param name and compute offset */
1542 *(int *) tok = a;
1543 a = a + 4;
1544 next();
1545 if (tok == ',')
1546 next();
Jack Palevich546b2242009-05-13 15:10:04 -07001547 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07001548 }
1549 next(); /* skip ')' */
1550 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001551 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07001552 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001553 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07001554 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001555 }
1556 }
1557 }
1558
1559 void cleanup() {
1560 if (sym_stk != 0) {
1561 free((void*) sym_stk);
1562 sym_stk = 0;
1563 }
1564 if (pGlobalBase != 0) {
1565 free((void*) pGlobalBase);
1566 pGlobalBase = 0;
1567 }
1568 if (pVarsBase != 0) {
1569 free(pVarsBase);
1570 pVarsBase = 0;
1571 }
1572 if (pGen) {
1573 delete pGen;
1574 pGen = 0;
1575 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001576 if (file) {
1577 delete file;
1578 file = 0;
1579 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001580 }
1581
1582 void clear() {
1583 tok = 0;
1584 tokc = 0;
1585 tokl = 0;
1586 ch = 0;
1587 vars = 0;
1588 rsym = 0;
1589 loc = 0;
1590 glo = 0;
1591 sym_stk = 0;
1592 dstk = 0;
1593 dptr = 0;
1594 dch = 0;
1595 last_id = 0;
1596 file = 0;
1597 pGlobalBase = 0;
1598 pVarsBase = 0;
1599 pGen = 0;
1600 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001601
Jack Palevich22305132009-05-13 10:58:45 -07001602 void setArchitecture(const char* architecture) {
1603 delete pGen;
1604 pGen = 0;
1605
1606 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001607#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07001608 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07001609 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001610 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001611#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07001612#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07001613 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07001614 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001615 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001616#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07001617 if (!pGen ) {
1618 fprintf(stderr, "Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07001619 }
1620 }
1621
1622 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001623#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07001624 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07001625#elif defined(DEFAULT_X86_CODEGEN)
1626 pGen = new X86CodeGenerator();
1627#endif
1628 }
1629 if (pGen == NULL) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001630 fprintf(stderr, "No code generator defined.\n");
Jack Palevich22305132009-05-13 10:58:45 -07001631 }
1632 }
1633
Jack Palevich77ae76e2009-05-10 19:59:24 -07001634public:
Jack Palevich22305132009-05-13 10:58:45 -07001635 struct args {
1636 args() {
1637 architecture = 0;
1638 }
1639 const char* architecture;
1640 };
1641
Jack Paleviche7b59062009-05-19 17:12:17 -07001642 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001643 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001644 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001645
Jack Paleviche7b59062009-05-19 17:12:17 -07001646 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001647 cleanup();
1648 }
1649
Jack Palevich1cdef202009-05-22 12:06:27 -07001650 int compile(const char* text, size_t textLength) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001651 cleanup();
1652 clear();
1653 codeBuf.init(ALLOC_SIZE);
Jack Palevich1cdef202009-05-22 12:06:27 -07001654 setArchitecture(NULL);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001655 if (!pGen) {
1656 return -1;
1657 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001658 pGen->init(&codeBuf);
Jack Palevich1cdef202009-05-22 12:06:27 -07001659 file = new TextInputStream(text, textLength);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001660 sym_stk = (intptr_t) calloc(1, ALLOC_SIZE);
1661 dstk = (intptr_t) strcpy((char*) sym_stk,
Jack Palevich21a15a22009-05-11 14:49:29 -07001662 " int if else while break return for define main ")
1663 + TOK_STR_SIZE;
1664 pGlobalBase = calloc(1, ALLOC_SIZE);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001665 glo = (intptr_t) pGlobalBase;
Jack Palevich21a15a22009-05-11 14:49:29 -07001666 pVarsBase = calloc(1, ALLOC_SIZE);
Jack Palevich8b0624c2009-05-20 12:12:06 -07001667 vars = (intptr_t) pVarsBase;
Jack Palevich21a15a22009-05-11 14:49:29 -07001668 inp();
1669 next();
1670 decl(0);
Jack Palevich546b2242009-05-13 15:10:04 -07001671 pGen->finishCompile();
Jack Palevich21a15a22009-05-11 14:49:29 -07001672 return 0;
1673 }
1674
1675 int run(int argc, char** argv) {
1676 typedef int (*mainPtr)(int argc, char** argv);
1677 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN);
1678 if (!aMain) {
1679 fprintf(stderr, "Could not find function \"main\".\n");
1680 return -1;
1681 }
1682 return aMain(argc, argv);
1683 }
1684
1685 int dump(FILE* out) {
1686 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
1687 return 0;
1688 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07001689
Jack Palevicha6535612009-05-13 16:24:17 -07001690 int disassemble(FILE* out) {
1691 return pGen->disassemble(out);
1692 }
1693
Jack Palevich1cdef202009-05-22 12:06:27 -07001694 /* Look through the symbol table to find a symbol.
1695 * If found, return its value.
1696 */
1697 void* lookup(const char* name) {
1698 if (!sym_stk) {
1699 return NULL;
1700 }
1701 size_t nameLen = strlen(name);
1702 char* pSym = (char*) sym_stk;
1703 char c;
1704 for(;;) {
1705 c = *pSym++;
1706 if (c == 0) {
1707 break;
1708 }
1709 if (c == TAG_TOK) {
1710 if (memcmp(pSym, name, nameLen) == 0
1711 && pSym[nameLen] == TAG_TOK) {
1712 int tok = pSym - 1 - (char*) sym_stk;
1713 tok = tok * 8 + TOK_IDENT;
1714 if (tok <= TOK_DEFINE) {
1715 return 0;
1716 } else {
1717 tok = vars + tok;
1718 return * (void**) tok;
1719 }
1720 }
1721 }
1722 }
1723 return NULL;
1724 }
1725
Jack Palevich77ae76e2009-05-10 19:59:24 -07001726};
1727
Jack Paleviche7b59062009-05-19 17:12:17 -07001728const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001729 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
1730
Jack Paleviche7b59062009-05-19 17:12:17 -07001731const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001732 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
1733 5, 5, /* ==, != */
1734 9, 10, /* &&, || */
1735 6, 7, 8, /* & ^ | */
1736 2, 2 /* ~ ! */
1737 };
1738
Jack Palevich8b0624c2009-05-20 12:12:06 -07001739#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001740FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07001741#endif
Jack Palevicha6535612009-05-13 16:24:17 -07001742
Jack Palevich8b0624c2009-05-20 12:12:06 -07001743#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07001744const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001745 0x1, // ++
1746 0xff, // --
1747 0xc1af0f, // *
1748 0xf9f79991, // /
1749 0xf9f79991, // % (With manual assist to swap results)
1750 0xc801, // +
1751 0xd8f7c829, // -
1752 0xe0d391, // <<
1753 0xf8d391, // >>
1754 0xe, // <=
1755 0xd, // >=
1756 0xc, // <
1757 0xf, // >
1758 0x4, // ==
1759 0x5, // !=
1760 0x0, // &&
1761 0x1, // ||
1762 0xc821, // &
1763 0xc831, // ^
1764 0xc809, // |
1765 0xd0f7, // ~
1766 0x4 // !
1767};
Jack Palevich8b0624c2009-05-20 12:12:06 -07001768#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001769
Jack Palevich1cdef202009-05-22 12:06:27 -07001770struct ACCscript {
1771 ACCscript() {
1772 text = 0;
1773 textLength = 0;
1774 accError = ACC_NO_ERROR;
1775 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001776
Jack Palevich1cdef202009-05-22 12:06:27 -07001777 ~ACCscript() {
1778 delete text;
1779 }
Jack Palevich546b2242009-05-13 15:10:04 -07001780
Jack Palevich1cdef202009-05-22 12:06:27 -07001781 void setError(ACCenum error) {
1782 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
1783 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001784 }
1785 }
1786
Jack Palevich1cdef202009-05-22 12:06:27 -07001787 ACCenum getError() {
1788 ACCenum result = accError;
1789 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07001790 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001791 }
1792
Jack Palevich1cdef202009-05-22 12:06:27 -07001793 Compiler compiler;
1794 char* text;
1795 int textLength;
1796 ACCenum accError;
1797};
1798
1799
1800extern "C"
1801ACCscript* accCreateScript() {
1802 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001803}
Jack Palevich1cdef202009-05-22 12:06:27 -07001804
1805extern "C"
1806ACCenum accGetError( ACCscript* script ) {
1807 return script->getError();
1808}
1809
1810extern "C"
1811void accDeleteScript(ACCscript* script) {
1812 delete script;
1813}
1814
1815extern "C"
1816void accScriptSource(ACCscript* script,
1817 ACCsizei count,
1818 const ACCchar ** string,
1819 const ACCint * length) {
1820 int totalLength = 0;
1821 for(int i = 0; i < count; i++) {
1822 int len = -1;
1823 const ACCchar* s = string[i];
1824 if (length) {
1825 len = length[i];
1826 }
1827 if (len < 0) {
1828 len = strlen(s);
1829 }
1830 totalLength += len;
1831 }
1832 delete script->text;
1833 char* text = new char[totalLength + 1];
1834 script->text = text;
1835 script->textLength = totalLength;
1836 for(int i = 0; i < count; i++) {
1837 int len = -1;
1838 const ACCchar* s = string[i];
1839 if (length) {
1840 len = length[i];
1841 }
1842 if (len < 0) {
1843 len = strlen(s);
1844 }
1845 memcpy(text, s, len);
1846 text += len;
1847 }
1848 text[totalLength] = '\0';
1849}
1850
1851extern "C"
1852void accCompileScript(ACCscript* script) {
1853 int result = script->compiler.compile(script->text, script->textLength);
1854 if (result) {
1855 script->setError(ACC_INVALID_OPERATION);
1856 }
1857}
1858
1859extern "C"
1860void accGetScriptiv(ACCscript* script,
1861 ACCenum pname,
1862 ACCint * params) {
1863 switch (pname) {
1864 case ACC_INFO_LOG_LENGTH:
1865 *params = 0;
1866 break;
1867 }
1868}
1869
1870extern "C"
1871void accGetScriptInfoLog(ACCscript* script,
1872 ACCsizei maxLength,
1873 ACCsizei * length,
1874 ACCchar * infoLog) {
1875 if (length) {
1876 *length = 0;
1877 }
1878 if (maxLength > 0 && infoLog) {
1879 *infoLog = 0;
1880 }
1881}
1882
1883extern "C"
1884void accGetScriptLabel(ACCscript* script, const ACCchar * name,
1885 ACCvoid ** address) {
1886 void* value = script->compiler.lookup(name);
1887 if (value) {
1888 *address = value;
1889 } else {
1890 script->setError(ACC_INVALID_VALUE);
1891 }
1892}
1893
1894} // namespace acc
1895