blob: de36ce55241fd3f5177395c3848304dc82c7655a [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 Palevichac0e95e2009-05-29 13:53:44 -070013#include <setjmp.h>
Jack Paleviche27bf3e2009-05-10 14:09:03 -070014#include <stdarg.h>
Jack Palevich8b0624c2009-05-20 12:12:06 -070015#include <stdint.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070016#include <stdio.h>
Jack Palevichf6b5a532009-05-10 19:16:42 -070017#include <stdlib.h>
18#include <string.h>
Jack Palevichae54f1f2009-05-08 14:54:15 -070019
Jack Palevich546b2242009-05-13 15:10:04 -070020#if defined(__arm__)
21#include <unistd.h>
22#endif
23
Jack Paleviche7b59062009-05-19 17:12:17 -070024#if defined(__arm__)
25#define DEFAULT_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070026#define PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070027#elif defined(__i386__)
28#define DEFAULT_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070029#define PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070030#elif defined(__x86_64__)
31#define DEFAULT_X64_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -070032#define PROVIDE_X64_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -070033#endif
34
Jack Paleviche7b59062009-05-19 17:12:17 -070035
36#ifdef PROVIDE_ARM_CODEGEN
Jack Palevicha6535612009-05-13 16:24:17 -070037#include "disassem.h"
Jack Paleviche7b59062009-05-19 17:12:17 -070038#endif
Jack Palevicha6535612009-05-13 16:24:17 -070039
Jack Palevich1cdef202009-05-22 12:06:27 -070040#include <acc/acc.h>
41
Jack Palevich09555c72009-05-27 12:25:55 -070042#define LOG_API(...) do {} while(0)
43// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
Jack Palevich09555c72009-05-27 12:25:55 -070044// #define ENABLE_ARM_DISASSEMBLY
45
Jack Palevichbbf8ab52009-05-11 11:54:30 -070046namespace acc {
47
Jack Palevichac0e95e2009-05-29 13:53:44 -070048class ErrorSink {
49public:
50 void error(const char *fmt, ...) {
51 va_list ap;
52 va_start(ap, fmt);
53 verror(fmt, ap);
54 va_end(ap);
55 }
56
57 virtual void verror(const char* fmt, va_list ap) = 0;
58};
59
60class Compiler : public ErrorSink {
Jack Palevich21a15a22009-05-11 14:49:29 -070061 class CodeBuf {
Jack Palevich653f42d2009-05-28 17:15:32 -070062 char* ind; // Output code pointer
Jack Palevich21a15a22009-05-11 14:49:29 -070063 char* pProgramBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -070064 ErrorSink* mErrorSink;
65 int mSize;
Jack Palevichf0cbc922009-05-08 16:35:13 -070066
Jack Palevich21a15a22009-05-11 14:49:29 -070067 void release() {
68 if (pProgramBase != 0) {
69 free(pProgramBase);
70 pProgramBase = 0;
Jack Palevichae54f1f2009-05-08 14:54:15 -070071 }
Jack Palevich21a15a22009-05-11 14:49:29 -070072 }
73
Jack Palevichac0e95e2009-05-29 13:53:44 -070074 void check(int n) {
75 int newSize = ind - pProgramBase + n;
76 if (newSize > mSize) {
77 if (mErrorSink) {
78 mErrorSink->error("Code too large: %d bytes", newSize);
79 }
80 }
81 }
82
Jack Palevich21a15a22009-05-11 14:49:29 -070083 public:
84 CodeBuf() {
85 pProgramBase = 0;
86 ind = 0;
Jack Palevichac0e95e2009-05-29 13:53:44 -070087 mErrorSink = 0;
88 mSize = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -070089 }
90
91 ~CodeBuf() {
92 release();
93 }
94
95 void init(int size) {
96 release();
Jack Palevichac0e95e2009-05-29 13:53:44 -070097 mSize = size;
Jack Palevich21a15a22009-05-11 14:49:29 -070098 pProgramBase = (char*) calloc(1, size);
99 ind = pProgramBase;
100 }
101
Jack Palevichac0e95e2009-05-29 13:53:44 -0700102 void setErrorSink(ErrorSink* pErrorSink) {
103 mErrorSink = pErrorSink;
104 }
105
Jack Palevich546b2242009-05-13 15:10:04 -0700106 int o4(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700107 check(4);
Jack Palevich8b0624c2009-05-20 12:12:06 -0700108 intptr_t result = (intptr_t) ind;
Jack Palevich546b2242009-05-13 15:10:04 -0700109 * (int*) ind = n;
110 ind += 4;
111 return result;
112 }
113
Jack Palevich21a15a22009-05-11 14:49:29 -0700114 /*
115 * Output a byte. Handles all values, 0..ff.
116 */
117 void ob(int n) {
Jack Palevichac0e95e2009-05-29 13:53:44 -0700118 check(1);
Jack Palevich21a15a22009-05-11 14:49:29 -0700119 *ind++ = n;
120 }
121
Jack Palevich21a15a22009-05-11 14:49:29 -0700122 inline void* getBase() {
123 return (void*) pProgramBase;
124 }
125
Jack Palevich8b0624c2009-05-20 12:12:06 -0700126 intptr_t getSize() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700127 return ind - pProgramBase;
128 }
129
Jack Palevich8b0624c2009-05-20 12:12:06 -0700130 intptr_t getPC() {
131 return (intptr_t) ind;
Jack Palevich21a15a22009-05-11 14:49:29 -0700132 }
133 };
134
Jack Palevich1cdef202009-05-22 12:06:27 -0700135 /**
136 * A code generator creates an in-memory program, generating the code on
137 * the fly. There is one code generator implementation for each supported
138 * architecture.
139 *
140 * The code generator implements the following abstract machine:
141 * R0 - the main accumulator.
142 * R1 - the secondary accumulator.
143 * FP - a frame pointer for accessing function arguments and local
144 * variables.
145 * SP - a stack pointer for storing intermediate results while evaluating
146 * expressions. The stack pointer grows downwards.
147 *
148 * The function calling convention is that all arguments are placed on the
149 * stack such that the first argument has the lowest address.
150 * After the call, the result is in R0. The caller is responsible for
151 * removing the arguments from the stack.
152 * The R0 and R1 registers are not saved across function calls. The
153 * FP and SP registers are saved.
154 */
155
Jack Palevich21a15a22009-05-11 14:49:29 -0700156 class CodeGenerator {
157 public:
Jack Palevichac0e95e2009-05-29 13:53:44 -0700158 CodeGenerator() {
159 mErrorSink = 0;
160 pCodeBuf = 0;
161 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700162 virtual ~CodeGenerator() {}
163
Jack Palevich22305132009-05-13 10:58:45 -0700164 virtual void init(CodeBuf* pCodeBuf) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700165 this->pCodeBuf = pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700166 pCodeBuf->setErrorSink(mErrorSink);
167 }
168
169 void setErrorSink(ErrorSink* pErrorSink) {
170 mErrorSink = pErrorSink;
171 if (pCodeBuf) {
172 pCodeBuf->setErrorSink(mErrorSink);
173 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700174 }
175
Jack Palevich1cdef202009-05-22 12:06:27 -0700176 /* Emit a function prolog.
177 * argCount is the number of arguments.
178 * Save the old value of the FP.
179 * Set the new value of the FP.
180 * Convert from the native platform calling convention to
181 * our stack-based calling convention. This may require
182 * pushing arguments from registers to the stack.
183 * Allocate "N" bytes of stack space. N isn't known yet, so
184 * just emit the instructions for adjusting the stack, and return
185 * the address to patch up. The patching will be done in
186 * functionExit().
187 * returns address to patch with local variable size.
Jack Palevich22305132009-05-13 10:58:45 -0700188 */
Jack Palevich546b2242009-05-13 15:10:04 -0700189 virtual int functionEntry(int argCount) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700190
Jack Palevich1cdef202009-05-22 12:06:27 -0700191 /* Emit a function epilog.
192 * Restore the old SP and FP register values.
193 * Return to the calling function.
194 * argCount - the number of arguments to the function.
195 * localVariableAddress - returned from functionEntry()
196 * localVariableSize - the size in bytes of the local variables.
197 */
198 virtual void functionExit(int argCount, int localVariableAddress,
199 int localVariableSize) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700200
Jack Palevich1cdef202009-05-22 12:06:27 -0700201 /* load immediate value to R0 */
Jack Palevich546b2242009-05-13 15:10:04 -0700202 virtual void li(int t) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700203
Jack Palevich1cdef202009-05-22 12:06:27 -0700204 /* Jump to a target, and return the address of the word that
205 * holds the target data, in case it needs to be fixed up later.
206 */
Jack Palevich22305132009-05-13 10:58:45 -0700207 virtual int gjmp(int t) = 0;
208
Jack Palevich1cdef202009-05-22 12:06:27 -0700209 /* Test R0 and jump to a target if the test succeeds.
210 * l = 0: je, l == 1: jne
211 * Return the address of the word that holds the targed data, in
212 * case it needs to be fixed up later.
213 */
Jack Palevich22305132009-05-13 10:58:45 -0700214 virtual int gtst(bool l, int t) = 0;
215
Jack Palevich1cdef202009-05-22 12:06:27 -0700216 /* Compare R1 against R0, and store the boolean result in R0.
217 * op specifies the comparison.
218 */
Jack Palevich22305132009-05-13 10:58:45 -0700219 virtual void gcmp(int op) = 0;
220
Jack Palevich1cdef202009-05-22 12:06:27 -0700221 /* Perform the arithmetic op specified by op. R1 is the
222 * left argument, R0 is the right argument.
223 */
Jack Palevich546b2242009-05-13 15:10:04 -0700224 virtual void genOp(int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700225
Jack Palevich1cdef202009-05-22 12:06:27 -0700226 /* Set R1 to 0.
227 */
228 virtual void clearR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700229
Jack Palevich1cdef202009-05-22 12:06:27 -0700230 /* Push R0 onto the stack.
231 */
232 virtual void pushR0() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700233
Jack Palevich1cdef202009-05-22 12:06:27 -0700234 /* Pop R1 off of the stack.
235 */
236 virtual void popR1() = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700237
Jack Palevich1cdef202009-05-22 12:06:27 -0700238 /* Store R0 to the address stored in R1.
239 * isInt is true if a whole 4-byte integer value
240 * should be stored, otherwise a 1-byte character
241 * value should be stored.
242 */
243 virtual void storeR0ToR1(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700244
Jack Palevich1cdef202009-05-22 12:06:27 -0700245 /* Load R0 from the address stored in R0.
246 * isInt is true if a whole 4-byte integer value
247 * should be loaded, otherwise a 1-byte character
248 * value should be loaded.
249 */
250 virtual void loadR0FromR0(bool isInt) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700251
Jack Palevich1cdef202009-05-22 12:06:27 -0700252 /* Load the absolute address of a variable to R0.
253 * If ea <= LOCAL, then this is a local variable, or an
254 * argument, addressed relative to FP.
255 * else it is an absolute global address.
256 */
257 virtual void leaR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700258
Jack Palevich1cdef202009-05-22 12:06:27 -0700259 /* Store R0 to a variable.
260 * If ea <= LOCAL, then this is a local variable, or an
261 * argument, addressed relative to FP.
262 * else it is an absolute global address.
263 */
264 virtual void storeR0(int ea) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700265
Jack Palevich1cdef202009-05-22 12:06:27 -0700266 /* load R0 from a variable.
267 * If ea <= LOCAL, then this is a local variable, or an
268 * argument, addressed relative to FP.
269 * else it is an absolute global address.
270 * If isIncDec is true, then the stored variable's value
271 * should be post-incremented or post-decremented, based
272 * on the value of op.
273 */
274 virtual void loadR0(int ea, bool isIncDec, int op) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700275
Jack Palevich1cdef202009-05-22 12:06:27 -0700276 /* Emit code to adjust the stack for a function call. Return the
277 * label for the address of the instruction that adjusts the
278 * stack size. This will be passed as argument "a" to
279 * endFunctionCallArguments.
280 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700281 virtual int beginFunctionCallArguments() = 0;
282
Jack Palevich1cdef202009-05-22 12:06:27 -0700283 /* Emit code to store R0 to the stack at byte offset l.
284 */
285 virtual void storeR0ToArg(int l) = 0;
Jack Palevich7810bc92009-05-15 14:31:47 -0700286
Jack Palevich1cdef202009-05-22 12:06:27 -0700287 /* Patch the function call preamble.
288 * a is the address returned from beginFunctionCallArguments
289 * l is the number of bytes the arguments took on the stack.
290 * Typically you would also emit code to convert the argument
291 * list into whatever the native function calling convention is.
292 * On ARM for example you would pop the first 5 arguments into
293 * R0..R4
294 */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700295 virtual void endFunctionCallArguments(int a, int l) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700296
Jack Palevich1cdef202009-05-22 12:06:27 -0700297 /* Emit a call to an unknown function. The argument "symbol" needs to
298 * be stored in the location where the address should go. It forms
299 * a chain. The address will be patched later.
300 * Return the address of the word that has to be patched.
301 */
Jack Palevich22305132009-05-13 10:58:45 -0700302 virtual int callForward(int symbol) = 0;
303
Jack Palevich1cdef202009-05-22 12:06:27 -0700304 /* Call a function using PC-relative addressing. t is the PC-relative
305 * address of the function. It has already been adjusted for the
306 * architectural jump offset, so just store it as-is.
307 */
Jack Palevich22305132009-05-13 10:58:45 -0700308 virtual void callRelative(int t) = 0;
309
Jack Palevich1cdef202009-05-22 12:06:27 -0700310 /* Call a function pointer. L is the number of bytes the arguments
311 * take on the stack. The address of the function is stored at
312 * location SP + l.
313 */
Jack Palevich22305132009-05-13 10:58:45 -0700314 virtual void callIndirect(int l) = 0;
315
Jack Palevich1cdef202009-05-22 12:06:27 -0700316 /* Adjust SP after returning from a function call. l is the
317 * number of bytes of arguments stored on the stack. isIndirect
318 * is true if this was an indirect call. (In which case the
319 * address of the function is stored at location SP + l.)
320 */
Jack Palevich7810bc92009-05-15 14:31:47 -0700321 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
Jack Palevich22305132009-05-13 10:58:45 -0700322
Jack Palevich1cdef202009-05-22 12:06:27 -0700323 /* Print a disassembly of the assembled code to out. Return
324 * non-zero if there is an error.
325 */
Jack Palevicha6535612009-05-13 16:24:17 -0700326 virtual int disassemble(FILE* out) = 0;
327
Jack Palevich1cdef202009-05-22 12:06:27 -0700328 /* Generate a symbol at the current PC. t is the head of a
329 * linked list of addresses to patch.
330 */
Jack Paleviche7b59062009-05-19 17:12:17 -0700331 virtual void gsym(int t) = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -0700332
Jack Palevich1cdef202009-05-22 12:06:27 -0700333 /*
334 * Do any cleanup work required at the end of a compile.
335 * For example, an instruction cache might need to be
336 * invalidated.
337 * Return non-zero if there is an error.
338 */
339 virtual int finishCompile() = 0;
Jack Palevich546b2242009-05-13 15:10:04 -0700340
Jack Palevicha6535612009-05-13 16:24:17 -0700341 /**
342 * Adjust relative branches by this amount.
343 */
344 virtual int jumpOffset() = 0;
345
Jack Palevich21a15a22009-05-11 14:49:29 -0700346 protected:
Jack Palevich21a15a22009-05-11 14:49:29 -0700347 /*
348 * Output a byte. Handles all values, 0..ff.
349 */
350 void ob(int n) {
351 pCodeBuf->ob(n);
352 }
353
Jack Palevich8b0624c2009-05-20 12:12:06 -0700354 intptr_t o4(int data) {
Jack Paleviche7b59062009-05-19 17:12:17 -0700355 return pCodeBuf->o4(data);
Jack Palevich21a15a22009-05-11 14:49:29 -0700356 }
357
Jack Palevich8b0624c2009-05-20 12:12:06 -0700358 intptr_t getBase() {
359 return (intptr_t) pCodeBuf->getBase();
Jack Palevicha6535612009-05-13 16:24:17 -0700360 }
361
Jack Palevich8b0624c2009-05-20 12:12:06 -0700362 intptr_t getPC() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700363 return pCodeBuf->getPC();
364 }
Jack Palevich1cdef202009-05-22 12:06:27 -0700365
366 intptr_t getSize() {
367 return pCodeBuf->getSize();
368 }
Jack Palevichac0e95e2009-05-29 13:53:44 -0700369
370 void error(const char* fmt,...) {
371 va_list ap;
372 va_start(ap, fmt);
373 mErrorSink->verror(fmt, ap);
374 va_end(ap);
375 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700376 private:
377 CodeBuf* pCodeBuf;
Jack Palevichac0e95e2009-05-29 13:53:44 -0700378 ErrorSink* mErrorSink;
Jack Palevich21a15a22009-05-11 14:49:29 -0700379 };
380
Jack Paleviche7b59062009-05-19 17:12:17 -0700381#ifdef PROVIDE_ARM_CODEGEN
382
Jack Palevich22305132009-05-13 10:58:45 -0700383 class ARMCodeGenerator : public CodeGenerator {
384 public:
385 ARMCodeGenerator() {}
386 virtual ~ARMCodeGenerator() {}
387
388 /* returns address to patch with local variable size
389 */
Jack Palevich546b2242009-05-13 15:10:04 -0700390 virtual int functionEntry(int argCount) {
Jack Palevichb7c81e92009-06-04 19:56:13 -0700391 LOG_API("functionEntry(%d);\n", argCount);
Jack Palevich69796b62009-05-14 15:42:26 -0700392 // sp -> arg4 arg5 ...
393 // Push our register-based arguments back on the stack
394 if (argCount > 0) {
395 int regArgCount = argCount <= 4 ? argCount : 4;
396 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {}
397 }
398 // sp -> arg0 arg1 ...
399 o4(0xE92D4800); // stmfd sp!, {fp, lr}
400 // sp, fp -> oldfp, retadr, arg0 arg1 ....
401 o4(0xE1A0B00D); // mov fp, sp
402 return o4(0xE24DD000); // sub sp, sp, # <local variables>
Jack Palevich22305132009-05-13 10:58:45 -0700403 }
404
Jack Palevich546b2242009-05-13 15:10:04 -0700405 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevich09555c72009-05-27 12:25:55 -0700406 LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize);
Jack Palevich69796b62009-05-14 15:42:26 -0700407 // Patch local variable allocation code:
408 if (localVariableSize < 0 || localVariableSize > 255) {
Jack Palevich8de461d2009-05-14 17:21:45 -0700409 error("localVariables out of range: %d", localVariableSize);
Jack Palevich546b2242009-05-13 15:10:04 -0700410 }
Jack Palevich69796b62009-05-14 15:42:26 -0700411 *(char*) (localVariableAddress) = localVariableSize;
412
413 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
414 o4(0xE1A0E00B); // mov lr, fp
415 o4(0xE59BB000); // ldr fp, [fp]
416 o4(0xE28ED004); // add sp, lr, #4
417 // sp -> retadr, arg0, ...
418 o4(0xE8BD4000); // ldmfd sp!, {lr}
419 // sp -> arg0 ....
420 if (argCount > 0) {
421 // We store the PC into the lr so we can adjust the sp before
Jack Palevich8de461d2009-05-14 17:21:45 -0700422 // returning. We need to pull off the registers we pushed
Jack Palevich69796b62009-05-14 15:42:26 -0700423 // earlier. We don't need to actually store them anywhere,
424 // just adjust the stack.
425 int regArgCount = argCount <= 4 ? argCount : 4;
426 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
427 }
428 o4(0xE12FFF1E); // bx lr
Jack Palevich22305132009-05-13 10:58:45 -0700429 }
430
431 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700432 virtual void li(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700433 LOG_API("li(%d);\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700434 if (t >= 0 && t < 255) {
Jack Palevich69796b62009-05-14 15:42:26 -0700435 o4(0xE3A00000 + t); // mov r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700436 } else if (t >= -256 && t < 0) {
437 // mvn means move constant ^ ~0
Jack Palevich69796b62009-05-14 15:42:26 -0700438 o4(0xE3E00001 - t); // mvn r0, #0
Jack Palevicha6535612009-05-13 16:24:17 -0700439 } else {
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700440 o4(0xE51F0000); // ldr r0, .L3
441 o4(0xEA000000); // b .L99
442 o4(t); // .L3: .word 0
443 // .L99:
Jack Palevicha6535612009-05-13 16:24:17 -0700444 }
Jack Palevich22305132009-05-13 10:58:45 -0700445 }
446
447 virtual int gjmp(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700448 LOG_API("gjmp(%d);\n", t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700449 return o4(0xEA000000 | encodeAddress(t)); // b .L33
Jack Palevich22305132009-05-13 10:58:45 -0700450 }
451
452 /* l = 0: je, l == 1: jne */
453 virtual int gtst(bool l, int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700454 LOG_API("gtst(%d, %d);\n", l, t);
Jack Palevich8de461d2009-05-14 17:21:45 -0700455 o4(0xE3500000); // cmp r0,#0
456 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
457 return o4(branch | encodeAddress(t));
Jack Palevich22305132009-05-13 10:58:45 -0700458 }
459
460 virtual void gcmp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700461 LOG_API("gcmp(%d);\n", op);
Jack Palevich8de461d2009-05-14 17:21:45 -0700462 o4(0xE1510000); // cmp r1, r1
463 switch(op) {
464 case OP_EQUALS:
465 o4(0x03A00001); // moveq r0,#1
466 o4(0x13A00000); // movne r0,#0
467 break;
468 case OP_NOT_EQUALS:
469 o4(0x03A00000); // moveq r0,#0
470 o4(0x13A00001); // movne r0,#1
471 break;
472 case OP_LESS_EQUAL:
473 o4(0xD3A00001); // movle r0,#1
474 o4(0xC3A00000); // movgt r0,#0
475 break;
476 case OP_GREATER:
477 o4(0xD3A00000); // movle r0,#0
478 o4(0xC3A00001); // movgt r0,#1
479 break;
480 case OP_GREATER_EQUAL:
481 o4(0xA3A00001); // movge r0,#1
482 o4(0xB3A00000); // movlt r0,#0
483 break;
484 case OP_LESS:
485 o4(0xA3A00000); // movge r0,#0
486 o4(0xB3A00001); // movlt r0,#1
487 break;
488 default:
489 error("Unknown comparison op %d", op);
490 break;
491 }
Jack Palevich22305132009-05-13 10:58:45 -0700492 }
493
Jack Palevich546b2242009-05-13 15:10:04 -0700494 virtual void genOp(int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700495 LOG_API("genOp(%d);\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700496 switch(op) {
497 case OP_MUL:
498 o4(0x0E0000091); // mul r0,r1,r0
499 break;
Jack Palevich3d474a72009-05-15 15:12:38 -0700500 case OP_DIV:
501 callRuntime(runtime_DIV);
502 break;
503 case OP_MOD:
504 callRuntime(runtime_MOD);
505 break;
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700506 case OP_PLUS:
507 o4(0xE0810000); // add r0,r1,r0
508 break;
509 case OP_MINUS:
510 o4(0xE0410000); // sub r0,r1,r0
511 break;
512 case OP_SHIFT_LEFT:
513 o4(0xE1A00011); // lsl r0,r1,r0
514 break;
515 case OP_SHIFT_RIGHT:
516 o4(0xE1A00051); // asr r0,r1,r0
517 break;
518 case OP_BIT_AND:
519 o4(0xE0010000); // and r0,r1,r0
520 break;
521 case OP_BIT_XOR:
522 o4(0xE0210000); // eor r0,r1,r0
523 break;
524 case OP_BIT_OR:
525 o4(0xE1810000); // orr r0,r1,r0
526 break;
527 case OP_BIT_NOT:
528 o4(0xE1E00000); // mvn r0, r0
529 break;
530 default:
Jack Palevich69796b62009-05-14 15:42:26 -0700531 error("Unimplemented op %d\n", op);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700532 break;
533 }
Jack Palevich22305132009-05-13 10:58:45 -0700534#if 0
535 o(decodeOp(op));
536 if (op == OP_MOD)
537 o(0x92); /* xchg %edx, %eax */
538#endif
539 }
540
Jack Palevich1cdef202009-05-22 12:06:27 -0700541 virtual void clearR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700542 LOG_API("clearR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700543 o4(0xE3A01000); // mov r1, #0
Jack Palevich22305132009-05-13 10:58:45 -0700544 }
545
Jack Palevich1cdef202009-05-22 12:06:27 -0700546 virtual void pushR0() {
Jack Palevich09555c72009-05-27 12:25:55 -0700547 LOG_API("pushR0();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700548 o4(0xE92D0001); // stmfd sp!,{r0}
Jack Palevich22305132009-05-13 10:58:45 -0700549 }
550
Jack Palevich1cdef202009-05-22 12:06:27 -0700551 virtual void popR1() {
Jack Palevich09555c72009-05-27 12:25:55 -0700552 LOG_API("popR1();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700553 o4(0xE8BD0002); // ldmfd sp!,{r1}
Jack Palevich22305132009-05-13 10:58:45 -0700554 }
555
Jack Palevich1cdef202009-05-22 12:06:27 -0700556 virtual void storeR0ToR1(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700557 LOG_API("storeR0ToR1(%d);\n", isInt);
Jack Palevichbd894902009-05-14 19:35:31 -0700558 if (isInt) {
559 o4(0xE5810000); // str r0, [r1]
560 } else {
561 o4(0xE5C10000); // strb r0, [r1]
562 }
Jack Palevich22305132009-05-13 10:58:45 -0700563 }
564
Jack Palevich1cdef202009-05-22 12:06:27 -0700565 virtual void loadR0FromR0(bool isInt) {
Jack Palevich09555c72009-05-27 12:25:55 -0700566 LOG_API("loadR0FromR0(%d);\n", isInt);
Jack Palevich22305132009-05-13 10:58:45 -0700567 if (isInt)
Jack Palevich69796b62009-05-14 15:42:26 -0700568 o4(0xE5900000); // ldr r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700569 else
Jack Palevich69796b62009-05-14 15:42:26 -0700570 o4(0xE5D00000); // ldrb r0, [r0]
Jack Palevich22305132009-05-13 10:58:45 -0700571 }
572
Jack Palevich1cdef202009-05-22 12:06:27 -0700573 virtual void leaR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700574 LOG_API("leaR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700575 if (ea < LOCAL) {
576 // Local, fp relative
577 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
578 error("Offset out of range: %08x", ea);
579 }
580 if (ea < 0) {
581 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
582 } else {
583 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
584 }
Jack Palevichbd894902009-05-14 19:35:31 -0700585 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700586 // Global, absolute.
587 o4(0xE59F0000); // ldr r0, .L1
588 o4(0xEA000000); // b .L99
589 o4(ea); // .L1: .word 0
590 // .L99:
Jack Palevichbd894902009-05-14 19:35:31 -0700591 }
Jack Palevich22305132009-05-13 10:58:45 -0700592 }
593
Jack Palevich1cdef202009-05-22 12:06:27 -0700594 virtual void storeR0(int ea) {
Jack Palevich09555c72009-05-27 12:25:55 -0700595 LOG_API("storeR0(%d);\n", ea);
Jack Palevich4d93f302009-05-15 13:30:00 -0700596 if (ea < LOCAL) {
597 // Local, fp relative
598 if (ea < -4095 || ea > 4095) {
599 error("Offset out of range: %08x", ea);
600 }
601 if (ea < 0) {
602 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
603 } else {
604 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
605 }
606 } else{
607 // Global, absolute
608 o4(0xE59F1000); // ldr r1, .L1
609 o4(0xEA000000); // b .L99
610 o4(ea); // .L1: .word 0
611 o4(0xE5810000); // .L99: str r0, [r1]
Jack Palevich69796b62009-05-14 15:42:26 -0700612 }
Jack Palevich22305132009-05-13 10:58:45 -0700613 }
614
Jack Palevich1cdef202009-05-22 12:06:27 -0700615 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich09555c72009-05-27 12:25:55 -0700616 LOG_API("loadR0(%d, %d, %d);\n", ea, isIncDec, op);
Jack Palevich4d93f302009-05-15 13:30:00 -0700617 if (ea < LOCAL) {
618 // Local, fp relative
619 if (ea < -4095 || ea > 4095) {
620 error("Offset out of range: %08x", ea);
621 }
622 if (ea < 0) {
623 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
624 } else {
625 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea]
626 }
Jack Palevich69796b62009-05-14 15:42:26 -0700627 } else {
Jack Palevich4d93f302009-05-15 13:30:00 -0700628 // Global, absolute
629 o4(0xE59F2000); // ldr r2, .L1
630 o4(0xEA000000); // b .L99
631 o4(ea); // .L1: .word ea
632 o4(0xE5920000); // .L99: ldr r0, [r2]
Jack Palevich69796b62009-05-14 15:42:26 -0700633 }
Jack Palevich22305132009-05-13 10:58:45 -0700634
Jack Palevich4d93f302009-05-15 13:30:00 -0700635 if (isIncDec) {
636 switch (op) {
637 case OP_INCREMENT:
638 o4(0xE2801001); // add r1, r0, #1
639 break;
640 case OP_DECREMENT:
641 o4(0xE2401001); // sub r1, r0, #1
642 break;
643 default:
644 error("unknown opcode: %d", op);
645 }
646 if (ea < LOCAL) {
647 // Local, fp relative
648 // Don't need range check, was already checked above
649 if (ea < 0) {
650 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
651 } else {
652 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea]
653 }
654 } else{
655 // Global, absolute
656 // r2 is already set up from before.
657 o4(0xE5821000); // str r1, [r2]
658 }
Jack Palevichbd894902009-05-14 19:35:31 -0700659 }
Jack Palevich22305132009-05-13 10:58:45 -0700660 }
661
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700662 virtual int beginFunctionCallArguments() {
Jack Palevich09555c72009-05-27 12:25:55 -0700663 LOG_API("beginFunctionCallArguments();\n");
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700664 return o4(0xE24DDF00); // Placeholder
665 }
666
Jack Palevich1cdef202009-05-22 12:06:27 -0700667 virtual void storeR0ToArg(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700668 LOG_API("storeR0ToArg(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700669 if (l < 0 || l > 4096-4) {
670 error("l out of range for stack offset: 0x%08x", l);
671 }
672 o4(0xE58D0000 + l); // str r0, [sp, #4]
673 }
674
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700675 virtual void endFunctionCallArguments(int a, int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700676 LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700677 if (l < 0 || l > 0x3FC) {
678 error("L out of range for stack adjustment: 0x%08x", l);
679 }
680 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2
681 int argCount = l >> 2;
682 if (argCount > 0) {
683 int regArgCount = argCount > 4 ? 4 : argCount;
684 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{}
685 }
Jack Palevich22305132009-05-13 10:58:45 -0700686 }
687
Jack Palevich22305132009-05-13 10:58:45 -0700688 virtual int callForward(int symbol) {
Jack Palevich09555c72009-05-27 12:25:55 -0700689 LOG_API("callForward(%d);\n", symbol);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700690 // Forward calls are always short (local)
691 return o4(0xEB000000 | encodeAddress(symbol));
Jack Palevich22305132009-05-13 10:58:45 -0700692 }
693
694 virtual void callRelative(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700695 LOG_API("callRelative(%d);\n", t);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700696 int abs = t + getPC() + jumpOffset();
Jack Palevichac0e95e2009-05-29 13:53:44 -0700697 LOG_API("abs=%d (0x%08x)\n", abs, abs);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700698 if (t >= - (1 << 25) && t < (1 << 25)) {
699 o4(0xEB000000 | encodeAddress(t));
700 } else {
701 // Long call.
702 o4(0xE59FC000); // ldr r12, .L1
703 o4(0xEA000000); // b .L99
Jack Palevichbd894902009-05-14 19:35:31 -0700704 o4(t - 12); // .L1: .word 0
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700705 o4(0xE08CC00F); // .L99: add r12,pc
706 o4(0xE12FFF3C); // blx r12
707 }
Jack Palevich22305132009-05-13 10:58:45 -0700708 }
709
710 virtual void callIndirect(int l) {
Jack Palevich09555c72009-05-27 12:25:55 -0700711 LOG_API("callIndirect(%d);\n", l);
Jack Palevich7810bc92009-05-15 14:31:47 -0700712 int argCount = l >> 2;
713 int poppedArgs = argCount > 4 ? 4 : argCount;
714 int adjustedL = l - (poppedArgs << 2);
715 if (adjustedL < 0 || adjustedL > 4096-4) {
716 error("l out of range for stack offset: 0x%08x", l);
717 }
718 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL]
719 o4(0xE12FFF3C); // blx r12
Jack Palevich22305132009-05-13 10:58:45 -0700720 }
721
Jack Palevich7810bc92009-05-15 14:31:47 -0700722 virtual void adjustStackAfterCall(int l, bool isIndirect) {
Jack Palevich09555c72009-05-27 12:25:55 -0700723 LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700724 int argCount = l >> 2;
Jack Palevich7810bc92009-05-15 14:31:47 -0700725 int stackArgs = argCount > 4 ? argCount - 4 : 0;
726 int stackUse = stackArgs + (isIndirect ? 1 : 0);
727 if (stackUse) {
728 if (stackUse < 0 || stackUse > 255) {
729 error("L out of range for stack adjustment: 0x%08x", l);
730 }
731 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700732 }
Jack Palevich22305132009-05-13 10:58:45 -0700733 }
734
Jack Palevicha6535612009-05-13 16:24:17 -0700735 virtual int jumpOffset() {
Jack Palevichbd894902009-05-14 19:35:31 -0700736 return 8;
Jack Palevicha6535612009-05-13 16:24:17 -0700737 }
738
739 /* output a symbol and patch all calls to it */
740 virtual void gsym(int t) {
Jack Palevich09555c72009-05-27 12:25:55 -0700741 LOG_API("gsym(0x%x)\n", t);
Jack Palevicha6535612009-05-13 16:24:17 -0700742 int n;
743 int base = getBase();
744 int pc = getPC();
Jack Palevich09555c72009-05-27 12:25:55 -0700745 LOG_API("pc = 0x%x\n", pc);
Jack Palevicha6535612009-05-13 16:24:17 -0700746 while (t) {
747 int data = * (int*) t;
748 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
749 if (decodedOffset == 0) {
750 n = 0;
751 } else {
752 n = base + decodedOffset; /* next value */
753 }
754 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
755 | encodeRelAddress(pc - t - 8);
756 t = n;
757 }
758 }
759
Jack Palevich1cdef202009-05-22 12:06:27 -0700760 virtual int finishCompile() {
761#if defined(__arm__)
762 const long base = long(getBase());
763 const long curr = long(getPC());
764 int err = cacheflush(base, curr, 0);
765 return err;
766#else
767 return 0;
768#endif
769 }
770
Jack Palevicha6535612009-05-13 16:24:17 -0700771 virtual int disassemble(FILE* out) {
Jack Palevich09555c72009-05-27 12:25:55 -0700772#ifdef ENABLE_ARM_DISASSEMBLY
773 disasmOut = out;
Jack Palevicha6535612009-05-13 16:24:17 -0700774 disasm_interface_t di;
775 di.di_readword = disassemble_readword;
776 di.di_printaddr = disassemble_printaddr;
777 di.di_printf = disassemble_printf;
778
779 int base = getBase();
780 int pc = getPC();
781 for(int i = base; i < pc; i += 4) {
782 fprintf(out, "%08x: %08x ", i, *(int*) i);
783 ::disasm(&di, i, 0);
784 }
Jack Palevich09555c72009-05-27 12:25:55 -0700785#endif
Jack Palevicha6535612009-05-13 16:24:17 -0700786 return 0;
787 }
Jack Palevich7810bc92009-05-15 14:31:47 -0700788
Jack Palevich22305132009-05-13 10:58:45 -0700789 private:
Jack Palevicha6535612009-05-13 16:24:17 -0700790 static FILE* disasmOut;
791
792 static u_int
793 disassemble_readword(u_int address)
794 {
795 return(*((u_int *)address));
796 }
797
798 static void
799 disassemble_printaddr(u_int address)
800 {
801 fprintf(disasmOut, "0x%08x", address);
802 }
803
804 static void
805 disassemble_printf(const char *fmt, ...) {
806 va_list ap;
807 va_start(ap, fmt);
808 vfprintf(disasmOut, fmt, ap);
809 va_end(ap);
810 }
811
812 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
813
814 /** Encode a relative address that might also be
815 * a label.
816 */
817 int encodeAddress(int value) {
818 int base = getBase();
819 if (value >= base && value <= getPC() ) {
820 // This is a label, encode it relative to the base.
821 value = value - base;
822 }
823 return encodeRelAddress(value);
824 }
825
826 int encodeRelAddress(int value) {
827 return BRANCH_REL_ADDRESS_MASK & (value >> 2);
828 }
Jack Palevich22305132009-05-13 10:58:45 -0700829
Jack Palevich3d474a72009-05-15 15:12:38 -0700830 typedef int (*int2FnPtr)(int a, int b);
831 void callRuntime(int2FnPtr fn) {
832 o4(0xE59F2000); // ldr r2, .L1
833 o4(0xEA000000); // b .L99
834 o4((int) fn); //.L1: .word fn
835 o4(0xE12FFF32); //.L99: blx r2
836 }
837
838 static int runtime_DIV(int a, int b) {
839 return b / a;
840 }
841
842 static int runtime_MOD(int a, int b) {
843 return b % a;
844 }
Jack Palevich22305132009-05-13 10:58:45 -0700845 };
846
Jack Palevich09555c72009-05-27 12:25:55 -0700847#endif // PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -0700848
849#ifdef PROVIDE_X86_CODEGEN
850
Jack Palevich21a15a22009-05-11 14:49:29 -0700851 class X86CodeGenerator : public CodeGenerator {
852 public:
853 X86CodeGenerator() {}
854 virtual ~X86CodeGenerator() {}
855
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700856 /* returns address to patch with local variable size
857 */
Jack Palevich546b2242009-05-13 15:10:04 -0700858 virtual int functionEntry(int argCount) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700859 o(0xe58955); /* push %ebp, mov %esp, %ebp */
860 return oad(0xec81, 0); /* sub $xxx, %esp */
861 }
862
Jack Palevich546b2242009-05-13 15:10:04 -0700863 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700864 o(0xc3c9); /* leave, ret */
Jack Palevich546b2242009-05-13 15:10:04 -0700865 *(int *) localVariableAddress = localVariableSize; /* save local variables */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700866 }
867
Jack Palevich21a15a22009-05-11 14:49:29 -0700868 /* load immediate value */
Jack Palevich546b2242009-05-13 15:10:04 -0700869 virtual void li(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700870 oad(0xb8, t); /* mov $xx, %eax */
871 }
872
Jack Palevich22305132009-05-13 10:58:45 -0700873 virtual int gjmp(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700874 return psym(0xe9, t);
875 }
876
877 /* l = 0: je, l == 1: jne */
Jack Palevich22305132009-05-13 10:58:45 -0700878 virtual int gtst(bool l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700879 o(0x0fc085); /* test %eax, %eax, je/jne xxx */
880 return psym(0x84 + l, t);
881 }
882
Jack Palevich22305132009-05-13 10:58:45 -0700883 virtual void gcmp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700884 int t = decodeOp(op);
Jack Palevich21a15a22009-05-11 14:49:29 -0700885 o(0xc139); /* cmp %eax,%ecx */
886 li(0);
887 o(0x0f); /* setxx %al */
888 o(t + 0x90);
889 o(0xc0);
890 }
891
Jack Palevich546b2242009-05-13 15:10:04 -0700892 virtual void genOp(int op) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700893 o(decodeOp(op));
894 if (op == OP_MOD)
895 o(0x92); /* xchg %edx, %eax */
896 }
897
Jack Palevich1cdef202009-05-22 12:06:27 -0700898 virtual void clearR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700899 oad(0xb9, 0); /* movl $0, %ecx */
900 }
901
Jack Palevich1cdef202009-05-22 12:06:27 -0700902 virtual void pushR0() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700903 o(0x50); /* push %eax */
904 }
905
Jack Palevich1cdef202009-05-22 12:06:27 -0700906 virtual void popR1() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700907 o(0x59); /* pop %ecx */
Jack Palevichbf42c9c2009-05-12 12:48:35 -0700908 }
909
Jack Palevich1cdef202009-05-22 12:06:27 -0700910 virtual void storeR0ToR1(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700911 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
912 }
913
Jack Palevich1cdef202009-05-22 12:06:27 -0700914 virtual void loadR0FromR0(bool isInt) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700915 if (isInt)
916 o(0x8b); /* mov (%eax), %eax */
917 else
918 o(0xbe0f); /* movsbl (%eax), %eax */
919 ob(0); /* add zero in code */
920 }
921
Jack Palevich1cdef202009-05-22 12:06:27 -0700922 virtual void leaR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700923 gmov(10, ea); /* leal EA, %eax */
924 }
925
Jack Palevich1cdef202009-05-22 12:06:27 -0700926 virtual void storeR0(int ea) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700927 gmov(6, ea); /* mov %eax, EA */
928 }
929
Jack Palevich1cdef202009-05-22 12:06:27 -0700930 virtual void loadR0(int ea, bool isIncDec, int op) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700931 gmov(8, ea); /* mov EA, %eax */
Jack Palevich4d93f302009-05-15 13:30:00 -0700932 if (isIncDec) {
933 /* Implement post-increment or post decrement.
934 */
935 gmov(0, ea); /* 83 ADD */
936 o(decodeOp(op));
937 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700938 }
939
Jack Palevichcb1c9ef2009-05-14 11:38:49 -0700940 virtual int beginFunctionCallArguments() {
Jack Palevich21a15a22009-05-11 14:49:29 -0700941 return oad(0xec81, 0); /* sub $xxx, %esp */
942 }
943
Jack Palevich1cdef202009-05-22 12:06:27 -0700944 virtual void storeR0ToArg(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700945 oad(0x248489, l); /* movl %eax, xxx(%esp) */
946 }
947
Jack Palevich7810bc92009-05-15 14:31:47 -0700948 virtual void endFunctionCallArguments(int a, int l) {
949 * (int*) a = l;
950 }
951
Jack Palevich22305132009-05-13 10:58:45 -0700952 virtual int callForward(int symbol) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700953 return psym(0xe8, symbol); /* call xxx */
954 }
955
Jack Palevich22305132009-05-13 10:58:45 -0700956 virtual void callRelative(int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700957 psym(0xe8, t); /* call xxx */
958 }
959
Jack Palevich22305132009-05-13 10:58:45 -0700960 virtual void callIndirect(int l) {
Jack Palevich21a15a22009-05-11 14:49:29 -0700961 oad(0x2494ff, l); /* call *xxx(%esp) */
962 }
963
Jack Palevich7810bc92009-05-15 14:31:47 -0700964 virtual void adjustStackAfterCall(int l, bool isIndirect) {
965 if (isIndirect) {
966 l += 4;
967 }
Jack Palevich21a15a22009-05-11 14:49:29 -0700968 oad(0xc481, l); /* add $xxx, %esp */
969 }
970
Jack Palevicha6535612009-05-13 16:24:17 -0700971 virtual int jumpOffset() {
972 return 5;
973 }
974
975 virtual int disassemble(FILE* out) {
Jack Palevich1cdef202009-05-22 12:06:27 -0700976 return 0;
Jack Palevicha6535612009-05-13 16:24:17 -0700977 }
978
Jack Paleviche7b59062009-05-19 17:12:17 -0700979 /* output a symbol and patch all calls to it */
980 virtual void gsym(int t) {
981 int n;
982 int pc = getPC();
983 while (t) {
984 n = *(int *) t; /* next value */
985 *(int *) t = pc - t - 4;
986 t = n;
987 }
988 }
989
Jack Palevich1cdef202009-05-22 12:06:27 -0700990 virtual int finishCompile() {
991 return 0;
992 }
993
Jack Palevich21a15a22009-05-11 14:49:29 -0700994 private:
Jack Paleviche7b59062009-05-19 17:12:17 -0700995
996 /** Output 1 to 4 bytes.
997 *
998 */
999 void o(int n) {
1000 /* cannot use unsigned, so we must do a hack */
1001 while (n && n != -1) {
1002 ob(n & 0xff);
1003 n = n >> 8;
1004 }
1005 }
1006
1007 /* psym is used to put an instruction with a data field which is a
1008 reference to a symbol. It is in fact the same as oad ! */
1009 int psym(int n, int t) {
1010 return oad(n, t);
1011 }
1012
1013 /* instruction + address */
1014 int oad(int n, int t) {
1015 o(n);
1016 int result = getPC();
1017 o4(t);
1018 return result;
1019 }
1020
1021
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001022 static const int operatorHelper[];
1023
1024 int decodeOp(int op) {
1025 if (op < 0 || op > OP_COUNT) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001026 error("Out-of-range operator: %d\n", op);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001027 }
1028 return operatorHelper[op];
1029 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001030
Jack Palevich546b2242009-05-13 15:10:04 -07001031 void gmov(int l, int t) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001032 o(l + 0x83);
1033 oad((t < LOCAL) << 7 | 5, t);
1034 }
1035 };
1036
Jack Paleviche7b59062009-05-19 17:12:17 -07001037#endif // PROVIDE_X86_CODEGEN
1038
Jack Palevich1cdef202009-05-22 12:06:27 -07001039 class InputStream {
1040 public:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001041 int getChar() {
1042 if (bumpLine) {
1043 line++;
1044 bumpLine = false;
1045 }
1046 int ch = get();
1047 if (ch == '\n') {
1048 bumpLine = true;
1049 }
1050 return ch;
1051 }
1052 int getLine() {
1053 return line;
1054 }
1055 protected:
1056 InputStream() :
1057 line(1), bumpLine(false) {
1058 }
1059 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001060 virtual int get() = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001061 int line;
1062 bool bumpLine;
Jack Palevich1cdef202009-05-22 12:06:27 -07001063 };
1064
1065 class FileInputStream : public InputStream {
1066 public:
1067 FileInputStream(FILE* in) : f(in) {}
Jack Palevich1cdef202009-05-22 12:06:27 -07001068 private:
Jack Palevicheedf9d22009-06-04 16:23:40 -07001069 virtual int get() { return fgetc(f); }
Jack Palevich1cdef202009-05-22 12:06:27 -07001070 FILE* f;
1071 };
1072
1073 class TextInputStream : public InputStream {
1074 public:
1075 TextInputStream(const char* text, size_t textLength)
1076 : pText(text), mTextLength(textLength), mPosition(0) {
1077 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001078
1079 private:
Jack Palevich1cdef202009-05-22 12:06:27 -07001080 virtual int get() {
1081 return mPosition < mTextLength ? pText[mPosition++] : EOF;
1082 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001083
Jack Palevich1cdef202009-05-22 12:06:27 -07001084 const char* pText;
1085 size_t mTextLength;
1086 size_t mPosition;
1087 };
1088
Jack Palevich653f42d2009-05-28 17:15:32 -07001089 int ch; // Current input character, or EOF
1090 intptr_t tok; // token
1091 intptr_t tokc; // token extra info
1092 int tokl; // token operator level
1093 intptr_t rsym; // return symbol
1094 intptr_t loc; // local variable index
1095 char* glo; // global variable index
1096 char* sym_stk;
1097 char* dstk; // Define stack
1098 char* dptr; // Macro state: Points to macro text during macro playback.
1099 int dch; // Macro state: Saves old value of ch during a macro playback.
1100 char* last_id;
Jack Palevich21a15a22009-05-11 14:49:29 -07001101 void* pSymbolBase;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001102 char* pGlobalBase;
Jack Palevich653f42d2009-05-28 17:15:32 -07001103 char* pVarsBase; // Value of variables
Jack Palevich1cdef202009-05-22 12:06:27 -07001104
1105 InputStream* file;
Jack Palevich21a15a22009-05-11 14:49:29 -07001106
1107 CodeBuf codeBuf;
Jack Palevich22305132009-05-13 10:58:45 -07001108 CodeGenerator* pGen;
Jack Palevich21a15a22009-05-11 14:49:29 -07001109
Jack Palevicheedf9d22009-06-04 16:23:40 -07001110 class String {
1111 public:
1112 String() {
1113 mpBase = 0;
1114 mUsed = 0;
1115 mSize = 0;
1116 }
1117
1118 ~String() {
1119 if (mpBase) {
1120 free(mpBase);
1121 }
1122 }
1123
1124 char* getUnwrapped() {
1125 return mpBase;
1126 }
1127
1128 void appendCStr(const char* s) {
1129 int n = strlen(s);
1130 memcpy(ensure(n), s, n + 1);
1131 }
1132
1133 void append(char c) {
1134 * ensure(1) = c;
1135 }
1136
1137 void printf(const char* fmt,...) {
1138 va_list ap;
1139 va_start(ap, fmt);
1140 vprintf(fmt, ap);
1141 va_end(ap);
1142 }
1143
1144 void vprintf(const char* fmt, va_list ap) {
1145 char* temp;
1146 int numChars = vasprintf(&temp, fmt, ap);
1147 memcpy(ensure(numChars), temp, numChars+1);
1148 free(temp);
1149 }
1150
1151 size_t len() {
1152 return mUsed;
1153 }
1154
1155 private:
1156 char* ensure(int n) {
1157 size_t newUsed = mUsed + n;
1158 if (newUsed > mSize) {
1159 size_t newSize = mSize * 2 + 10;
1160 if (newSize < newUsed) {
1161 newSize = newUsed;
1162 }
1163 mpBase = (char*) realloc(mpBase, newSize + 1);
1164 mSize = newSize;
1165 }
1166 mpBase[newUsed] = '\0';
1167 char* result = mpBase + mUsed;
1168 mUsed = newUsed;
1169 return result;
1170 }
1171
1172 char* mpBase;
1173 size_t mUsed;
1174 size_t mSize;
1175 };
1176
1177 String mErrorBuf;
1178
Jack Palevichac0e95e2009-05-29 13:53:44 -07001179 jmp_buf mErrorRecoveryJumpBuf;
1180
Jack Palevicheedf9d22009-06-04 16:23:40 -07001181 String mPragmas;
1182 int mPragmaStringCount;
1183
Jack Palevich21a15a22009-05-11 14:49:29 -07001184 static const int ALLOC_SIZE = 99999;
1185
Jack Palevicheedf9d22009-06-04 16:23:40 -07001186 // Indentifiers start at 0x100 and increase by # (chars + 1) * 8
Jack Palevich21a15a22009-05-11 14:49:29 -07001187 static const int TOK_IDENT = 0x100;
1188 static const int TOK_INT = 0x100;
Jack Palevichb7c81e92009-06-04 19:56:13 -07001189 static const int TOK_CHAR = TOK_INT + 4*8;
1190 static const int TOK_VOID = TOK_CHAR + 5*8;
1191 static const int TOK_IF = TOK_VOID + 5*8;
1192 static const int TOK_ELSE = TOK_IF + 3*8;
1193 static const int TOK_WHILE = TOK_ELSE + 5*8;
1194 static const int TOK_BREAK = TOK_WHILE + 6*8;
1195 static const int TOK_RETURN = TOK_BREAK + 6*8;
1196 static const int TOK_FOR = TOK_RETURN + 7*8;
1197 static const int TOK_PRAGMA = TOK_FOR + 4*8;
1198 static const int TOK_DEFINE = TOK_PRAGMA + 7*8;
1199 static const int TOK_MAIN = TOK_DEFINE + 7*8;
Jack Palevich21a15a22009-05-11 14:49:29 -07001200
1201 static const int TOK_DUMMY = 1;
1202 static const int TOK_NUM = 2;
1203
1204 static const int LOCAL = 0x200;
1205
1206 static const int SYM_FORWARD = 0;
1207 static const int SYM_DEFINE = 1;
1208
1209 /* tokens in string heap */
1210 static const int TAG_TOK = ' ';
1211 static const int TAG_MACRO = 2;
1212
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001213 static const int OP_INCREMENT = 0;
1214 static const int OP_DECREMENT = 1;
1215 static const int OP_MUL = 2;
1216 static const int OP_DIV = 3;
1217 static const int OP_MOD = 4;
1218 static const int OP_PLUS = 5;
1219 static const int OP_MINUS = 6;
1220 static const int OP_SHIFT_LEFT = 7;
1221 static const int OP_SHIFT_RIGHT = 8;
1222 static const int OP_LESS_EQUAL = 9;
1223 static const int OP_GREATER_EQUAL = 10;
1224 static const int OP_LESS = 11;
1225 static const int OP_GREATER = 12;
1226 static const int OP_EQUALS = 13;
1227 static const int OP_NOT_EQUALS = 14;
1228 static const int OP_LOGICAL_AND = 15;
1229 static const int OP_LOGICAL_OR = 16;
1230 static const int OP_BIT_AND = 17;
1231 static const int OP_BIT_XOR = 18;
1232 static const int OP_BIT_OR = 19;
1233 static const int OP_BIT_NOT = 20;
1234 static const int OP_LOGICAL_NOT = 21;
1235 static const int OP_COUNT = 22;
1236
1237 /* Operators are searched from front, the two-character operators appear
1238 * before the single-character operators with the same first character.
1239 * @ is used to pad out single-character operators.
1240 */
1241 static const char* operatorChars;
1242 static const char operatorLevel[];
1243
Jack Palevich21a15a22009-05-11 14:49:29 -07001244 void pdef(int t) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001245 if (dstk - sym_stk >= ALLOC_SIZE) {
1246 error("Symbol table exhausted");
1247 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001248 *dstk++ = t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001249 }
1250
1251 void inp() {
1252 if (dptr) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001253 ch = *dptr++;
Jack Palevich21a15a22009-05-11 14:49:29 -07001254 if (ch == TAG_MACRO) {
1255 dptr = 0;
1256 ch = dch;
1257 }
1258 } else
Jack Palevicheedf9d22009-06-04 16:23:40 -07001259 ch = file->getChar();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001260#if 0
1261 printf("ch='%c' 0x%x\n", ch, ch);
1262#endif
Jack Palevich21a15a22009-05-11 14:49:29 -07001263 }
1264
1265 int isid() {
Jack Palevich546b2242009-05-13 15:10:04 -07001266 return isalnum(ch) | (ch == '_');
Jack Palevich21a15a22009-05-11 14:49:29 -07001267 }
1268
1269 /* read a character constant */
1270 void getq() {
1271 if (ch == '\\') {
1272 inp();
1273 if (ch == 'n')
1274 ch = '\n';
1275 }
1276 }
1277
1278 void next() {
1279 int l, a;
1280
Jack Palevich546b2242009-05-13 15:10:04 -07001281 while (isspace(ch) | (ch == '#')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001282 if (ch == '#') {
1283 inp();
1284 next();
1285 if (tok == TOK_DEFINE) {
1286 next();
1287 pdef(TAG_TOK); /* fill last ident tag */
1288 *(int *) tok = SYM_DEFINE;
Jack Palevich653f42d2009-05-28 17:15:32 -07001289 *(char* *) (tok + 4) = dstk; /* define stack */
Jack Palevicheedf9d22009-06-04 16:23:40 -07001290 while (ch != '\n') {
1291 pdef(ch);
1292 inp();
1293 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001294 pdef(ch);
Jack Palevicheedf9d22009-06-04 16:23:40 -07001295 pdef(TAG_MACRO);
1296 } else if (tok == TOK_PRAGMA) {
1297 doPragma();
1298 } else {
1299 error("Unsupported preprocessor directive \"%s\"", last_id);
Jack Palevich21a15a22009-05-11 14:49:29 -07001300 }
Jack Palevicheedf9d22009-06-04 16:23:40 -07001301
Jack Palevich21a15a22009-05-11 14:49:29 -07001302 }
1303 inp();
1304 }
1305 tokl = 0;
1306 tok = ch;
1307 /* encode identifiers & numbers */
1308 if (isid()) {
1309 pdef(TAG_TOK);
1310 last_id = dstk;
1311 while (isid()) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001312 pdef(ch);
1313 inp();
Jack Palevichae54f1f2009-05-08 14:54:15 -07001314 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001315 if (isdigit(tok)) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001316 tokc = strtol(last_id, 0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001317 tok = TOK_NUM;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001318 } else {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001319 if (dstk - sym_stk + 1 > ALLOC_SIZE) {
1320 error("symbol stack overflow");
1321 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001322 * dstk = TAG_TOK; /* no need to mark end of string (we
Jack Palevich21a15a22009-05-11 14:49:29 -07001323 suppose data is initialized to zero by calloc) */
Jack Palevich653f42d2009-05-28 17:15:32 -07001324 tok = (intptr_t) (strstr(sym_stk, (last_id - 1))
Jack Palevich21a15a22009-05-11 14:49:29 -07001325 - sym_stk);
Jack Palevich653f42d2009-05-28 17:15:32 -07001326 * dstk = 0; /* mark real end of ident for dlsym() */
Jack Palevich21a15a22009-05-11 14:49:29 -07001327 tok = tok * 8 + TOK_IDENT;
1328 if (tok > TOK_DEFINE) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001329 if (tok + 8 > ALLOC_SIZE) {
1330 error("Variable Table overflow.");
1331 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001332 tok = (intptr_t) (pVarsBase + tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001333 /* printf("tok=%s %x\n", last_id, tok); */
1334 /* define handling */
1335 if (*(int *) tok == SYM_DEFINE) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001336 dptr = *(char* *) (tok + 4);
Jack Palevich21a15a22009-05-11 14:49:29 -07001337 dch = ch;
1338 inp();
1339 next();
1340 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001341 }
1342 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001343 } else {
Jack Palevich21a15a22009-05-11 14:49:29 -07001344 inp();
1345 if (tok == '\'') {
1346 tok = TOK_NUM;
1347 getq();
1348 tokc = ch;
1349 inp();
1350 inp();
Jack Palevich546b2242009-05-13 15:10:04 -07001351 } else if ((tok == '/') & (ch == '*')) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001352 inp();
1353 while (ch) {
1354 while (ch != '*')
1355 inp();
1356 inp();
1357 if (ch == '/')
1358 ch = 0;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001359 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001360 inp();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001361 next();
Jack Palevichbd894902009-05-14 19:35:31 -07001362 } else if ((tok == '/') & (ch == '/')) {
1363 inp();
1364 while (ch && (ch != '\n')) {
1365 inp();
1366 }
1367 inp();
1368 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001369 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001370 const char* t = operatorChars;
1371 int opIndex = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001372 while ((l = *t++) != 0) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001373 a = *t++;
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001374 tokl = operatorLevel[opIndex];
1375 tokc = opIndex;
Jack Palevich546b2242009-05-13 15:10:04 -07001376 if ((l == tok) & ((a == ch) | (a == '@'))) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001377#if 0
1378 printf("%c%c -> tokl=%d tokc=0x%x\n",
1379 l, a, tokl, tokc);
1380#endif
1381 if (a == ch) {
1382 inp();
1383 tok = TOK_DUMMY; /* dummy token for double tokens */
1384 }
1385 break;
1386 }
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001387 opIndex++;
1388 }
1389 if (l == 0) {
1390 tokl = 0;
1391 tokc = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001392 }
1393 }
1394 }
1395#if 0
1396 {
Jack Palevich653f42d2009-05-28 17:15:32 -07001397 char* p;
Jack Palevich21a15a22009-05-11 14:49:29 -07001398
1399 printf("tok=0x%x ", tok);
1400 if (tok >= TOK_IDENT) {
1401 printf("'");
1402 if (tok> TOK_DEFINE)
Jack Palevich653f42d2009-05-28 17:15:32 -07001403 p = sym_stk + 1 + ((char*) tok - pVarsBase - TOK_IDENT) / 8;
Jack Palevich21a15a22009-05-11 14:49:29 -07001404 else
1405 p = sym_stk + 1 + (tok - TOK_IDENT) / 8;
Jack Palevich653f42d2009-05-28 17:15:32 -07001406 while (*p != TAG_TOK && *p)
1407 printf("%c", *p++);
Jack Palevich21a15a22009-05-11 14:49:29 -07001408 printf("'\n");
1409 } else if (tok == TOK_NUM) {
1410 printf("%d\n", tokc);
1411 } else {
1412 printf("'%c'\n", tok);
1413 }
1414 }
1415#endif
1416 }
1417
Jack Palevicheedf9d22009-06-04 16:23:40 -07001418 void doPragma() {
1419 // # pragma name(val)
1420 int state = 0;
1421 while(ch != EOF && ch != '\n' && state < 10) {
1422 switch(state) {
1423 case 0:
1424 if (isspace(ch)) {
1425 inp();
1426 } else {
1427 state++;
1428 }
1429 break;
1430 case 1:
1431 if (isalnum(ch)) {
1432 mPragmas.append(ch);
1433 inp();
1434 } else if (ch == '(') {
1435 mPragmas.append(0);
1436 inp();
1437 state++;
1438 } else {
1439 state = 11;
1440 }
1441 break;
1442 case 2:
1443 if (isalnum(ch)) {
1444 mPragmas.append(ch);
1445 inp();
1446 } else if (ch == ')') {
1447 mPragmas.append(0);
1448 inp();
1449 state = 10;
1450 } else {
1451 state = 11;
1452 }
1453 break;
1454 }
1455 }
1456 if(state != 10) {
1457 error("Unexpected pragma syntax");
1458 }
1459 mPragmaStringCount += 2;
1460 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001461
Jack Palevichac0e95e2009-05-29 13:53:44 -07001462 virtual void verror(const char* fmt, va_list ap) {
Jack Palevicheedf9d22009-06-04 16:23:40 -07001463 mErrorBuf.printf("%ld: ", file->getLine());
1464 mErrorBuf.vprintf(fmt, ap);
1465 mErrorBuf.printf("\n");
Jack Palevichac0e95e2009-05-29 13:53:44 -07001466 longjmp(mErrorRecoveryJumpBuf, 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001467 }
1468
Jack Palevich8b0624c2009-05-20 12:12:06 -07001469 void skip(intptr_t c) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001470 if (tok != c) {
1471 error("'%c' expected", c);
1472 }
1473 next();
1474 }
1475
Jack Palevich21a15a22009-05-11 14:49:29 -07001476 /* l is one if '=' parsing wanted (quick hack) */
Jack Palevich8b0624c2009-05-20 12:12:06 -07001477 void unary(intptr_t l) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001478 intptr_t n, t, a;
1479 int c;
Jack Palevich546b2242009-05-13 15:10:04 -07001480 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001481 n = 1; /* type of expression 0 = forward, 1 = value, other =
1482 lvalue */
1483 if (tok == '\"') {
Jack Palevich653f42d2009-05-28 17:15:32 -07001484 pGen->li((int) glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001485 while (ch != '\"') {
1486 getq();
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001487 *allocGlobalSpace(1) = ch;
Jack Palevich21a15a22009-05-11 14:49:29 -07001488 inp();
1489 }
Jack Palevich653f42d2009-05-28 17:15:32 -07001490 *glo = 0;
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001491 /* align heap */
1492 allocGlobalSpace((char*) (((intptr_t) glo + 4) & -4) - glo);
Jack Palevich21a15a22009-05-11 14:49:29 -07001493 inp();
1494 next();
1495 } else {
1496 c = tokl;
1497 a = tokc;
1498 t = tok;
1499 next();
1500 if (t == TOK_NUM) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001501 pGen->li(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001502 } else if (c == 2) {
1503 /* -, +, !, ~ */
1504 unary(0);
Jack Palevich1cdef202009-05-22 12:06:27 -07001505 pGen->clearR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001506 if (t == '!')
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001507 pGen->gcmp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001508 else
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001509 pGen->genOp(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001510 } else if (t == '(') {
1511 expr();
1512 skip(')');
1513 } else if (t == '*') {
1514 /* parse cast */
1515 skip('(');
1516 t = tok; /* get type */
1517 next(); /* skip int/char/void */
1518 next(); /* skip '*' or '(' */
1519 if (tok == '*') {
1520 /* function type */
1521 skip('*');
1522 skip(')');
1523 skip('(');
1524 skip(')');
1525 t = 0;
1526 }
1527 skip(')');
1528 unary(0);
1529 if (tok == '=') {
1530 next();
Jack Palevich1cdef202009-05-22 12:06:27 -07001531 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001532 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001533 pGen->popR1();
1534 pGen->storeR0ToR1(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001535 } else if (t) {
Jack Palevich1cdef202009-05-22 12:06:27 -07001536 pGen->loadR0FromR0(t == TOK_INT);
Jack Palevich21a15a22009-05-11 14:49:29 -07001537 }
1538 } else if (t == '&') {
Jack Palevich1cdef202009-05-22 12:06:27 -07001539 pGen->leaR0(*(int *) tok);
Jack Palevich21a15a22009-05-11 14:49:29 -07001540 next();
1541 } else {
1542 n = *(int *) t;
1543 /* forward reference: try dlsym */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001544 if (!n) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001545 n = (intptr_t) dlsym(RTLD_DEFAULT, last_id);
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001546 }
Jack Palevich546b2242009-05-13 15:10:04 -07001547 if ((tok == '=') & l) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001548 /* assignment */
1549 next();
1550 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001551 pGen->storeR0(n);
Jack Palevich21a15a22009-05-11 14:49:29 -07001552 } else if (tok != '(') {
1553 /* variable */
Jack Palevich1cdef202009-05-22 12:06:27 -07001554 pGen->loadR0(n, tokl == 11, tokc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001555 if (tokl == 11) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001556 next();
1557 }
1558 }
1559 }
1560 }
1561
1562 /* function call */
1563 if (tok == '(') {
1564 if (n == 1)
Jack Palevich1cdef202009-05-22 12:06:27 -07001565 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001566
1567 /* push args and invert order */
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001568 a = pGen->beginFunctionCallArguments();
Jack Palevich21a15a22009-05-11 14:49:29 -07001569 next();
1570 l = 0;
1571 while (tok != ')') {
1572 expr();
Jack Palevich1cdef202009-05-22 12:06:27 -07001573 pGen->storeR0ToArg(l);
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001574 if (tok == ',')
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001575 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001576 l = l + 4;
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001577 }
Jack Palevichcb1c9ef2009-05-14 11:38:49 -07001578 pGen->endFunctionCallArguments(a, l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001579 next();
1580 if (!n) {
1581 /* forward reference */
1582 t = t + 4;
1583 *(int *) t = pGen->callForward(*(int *) t);
1584 } else if (n == 1) {
1585 pGen->callIndirect(l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001586 } else {
Jack Palevich7810bc92009-05-15 14:31:47 -07001587 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevich21a15a22009-05-11 14:49:29 -07001588 }
Jack Palevich3d474a72009-05-15 15:12:38 -07001589 if (l | (n == 1))
Jack Palevich7810bc92009-05-15 14:31:47 -07001590 pGen->adjustStackAfterCall(l, n == 1);
Jack Palevich21a15a22009-05-11 14:49:29 -07001591 }
1592 }
1593
Jack Palevich653f42d2009-05-28 17:15:32 -07001594 void sum(int l) {
Jack Palevich8b0624c2009-05-20 12:12:06 -07001595 intptr_t t, n, a;
Jack Palevich546b2242009-05-13 15:10:04 -07001596 t = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001597 if (l-- == 1)
1598 unary(1);
1599 else {
1600 sum(l);
1601 a = 0;
1602 while (l == tokl) {
1603 n = tok;
1604 t = tokc;
1605 next();
1606
1607 if (l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001608 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
Jack Palevich21a15a22009-05-11 14:49:29 -07001609 sum(l);
1610 } else {
Jack Palevich1cdef202009-05-22 12:06:27 -07001611 pGen->pushR0();
Jack Palevich21a15a22009-05-11 14:49:29 -07001612 sum(l);
Jack Palevich1cdef202009-05-22 12:06:27 -07001613 pGen->popR1();
Jack Palevich21a15a22009-05-11 14:49:29 -07001614
Jack Palevich546b2242009-05-13 15:10:04 -07001615 if ((l == 4) | (l == 5)) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001616 pGen->gcmp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001617 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001618 pGen->genOp(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001619 }
1620 }
1621 }
1622 /* && and || output code generation */
1623 if (a && l > 8) {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001624 a = pGen->gtst(t == OP_LOGICAL_OR, a);
1625 pGen->li(t != OP_LOGICAL_OR);
Jack Palevicha6535612009-05-13 16:24:17 -07001626 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001627 pGen->gsym(a);
1628 pGen->li(t == OP_LOGICAL_OR);
Jack Palevich21a15a22009-05-11 14:49:29 -07001629 }
1630 }
1631 }
1632
1633 void expr() {
1634 sum(11);
1635 }
1636
1637 int test_expr() {
1638 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001639 return pGen->gtst(0, 0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001640 }
1641
Jack Palevich8b0624c2009-05-20 12:12:06 -07001642 void block(intptr_t l) {
1643 intptr_t a, n, t;
Jack Palevich21a15a22009-05-11 14:49:29 -07001644
1645 if (tok == TOK_IF) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001646 next();
1647 skip('(');
Jack Palevich21a15a22009-05-11 14:49:29 -07001648 a = test_expr();
1649 skip(')');
1650 block(l);
1651 if (tok == TOK_ELSE) {
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001652 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001653 n = pGen->gjmp(0); /* jmp */
1654 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001655 block(l);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001656 pGen->gsym(n); /* patch else jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001657 } else {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001658 pGen->gsym(a); /* patch if test */
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001659 }
Jack Palevich546b2242009-05-13 15:10:04 -07001660 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
Jack Palevich21a15a22009-05-11 14:49:29 -07001661 t = tok;
1662 next();
1663 skip('(');
1664 if (t == TOK_WHILE) {
Jack Palevicha6535612009-05-13 16:24:17 -07001665 n = codeBuf.getPC(); // top of loop, target of "next" iteration
Jack Palevich21a15a22009-05-11 14:49:29 -07001666 a = test_expr();
1667 } else {
1668 if (tok != ';')
1669 expr();
1670 skip(';');
1671 n = codeBuf.getPC();
1672 a = 0;
1673 if (tok != ';')
1674 a = test_expr();
1675 skip(';');
1676 if (tok != ')') {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001677 t = pGen->gjmp(0);
Jack Palevich21a15a22009-05-11 14:49:29 -07001678 expr();
Jack Palevicha6535612009-05-13 16:24:17 -07001679 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001680 pGen->gsym(t);
Jack Palevich21a15a22009-05-11 14:49:29 -07001681 n = t + 4;
1682 }
1683 }
1684 skip(')');
Jack Palevich8b0624c2009-05-20 12:12:06 -07001685 block((intptr_t) &a);
Jack Palevicha6535612009-05-13 16:24:17 -07001686 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001687 pGen->gsym(a);
Jack Palevich21a15a22009-05-11 14:49:29 -07001688 } else if (tok == '{') {
1689 next();
1690 /* declarations */
Jack Palevichb7c81e92009-06-04 19:56:13 -07001691 localDeclarations();
Jack Palevich21a15a22009-05-11 14:49:29 -07001692 while (tok != '}')
1693 block(l);
1694 next();
1695 } else {
1696 if (tok == TOK_RETURN) {
1697 next();
1698 if (tok != ';')
1699 expr();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001700 rsym = pGen->gjmp(rsym); /* jmp */
Jack Palevich21a15a22009-05-11 14:49:29 -07001701 } else if (tok == TOK_BREAK) {
1702 next();
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001703 *(int *) l = pGen->gjmp(*(int *) l);
Jack Palevich21a15a22009-05-11 14:49:29 -07001704 } else if (tok != ';')
1705 expr();
1706 skip(';');
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001707 }
1708 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001709
Jack Palevichb7c81e92009-06-04 19:56:13 -07001710 typedef int Type;
1711 static const Type TY_UNKNOWN = 0;
1712 static const Type TY_INT = 1;
1713 static const Type TY_CHAR = 2;
1714 static const Type TY_VOID = 3;
1715 static const int TY_BASE_TYPE_MASK = 0xf;
1716 static const int TY_INDIRECTION_MASK = 0xf0;
1717 static const int TY_INDIRECTION_SHIFT = 4;
1718 static const int MAX_INDIRECTION_COUNT = 15;
Jack Palevich21a15a22009-05-11 14:49:29 -07001719
Jack Palevichb7c81e92009-06-04 19:56:13 -07001720 Type getBaseType(Type t) {
1721 return t & TY_BASE_TYPE_MASK;
1722 }
1723
1724 int getIndirectionCount(Type t) {
1725 return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
1726 }
1727
1728 void setIndirectionCount(Type& t, int count) {
1729 t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
1730 | (t & ~TY_INDIRECTION_MASK));
1731 }
1732
1733 bool acceptType(Type& t) {
1734 t = TY_UNKNOWN;
1735 if (tok == TOK_INT) {
1736 t = TY_INT;
1737 } else if (tok == TOK_CHAR) {
1738 t = TY_CHAR;
1739 } else if (tok == TOK_VOID) {
1740 t = TY_VOID;
1741 } else {
1742 return false;
1743 }
1744 next();
1745 return true;
1746 }
1747
1748 Type acceptPointerDeclaration(Type& base) {
1749 Type t = base;
1750 int indirectionCount = 0;
1751 while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
1752 next();
1753 indirectionCount++;
1754 }
1755 if (indirectionCount > MAX_INDIRECTION_COUNT) {
1756 error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
1757 }
1758 setIndirectionCount(t, indirectionCount);
1759 return t;
1760 }
1761
1762 void expectType(Type& t) {
1763 if (!acceptType(t)) {
1764 error("Expected a type.");
1765 }
1766 }
1767
1768 void checkSymbol() {
1769 if (tok <= TOK_DEFINE) {
1770 error("Expected a symbol");
1771 }
1772 }
1773
1774 void localDeclarations() {
1775 intptr_t a;
1776 Type base;
1777
1778 while (acceptType(base)) {
1779 while (tok != ';') {
1780 Type t = acceptPointerDeclaration(t);
1781 checkSymbol();
1782 loc = loc + 4;
1783 *(int *) tok = -loc;
1784
Jack Palevich21a15a22009-05-11 14:49:29 -07001785 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001786 if (tok == ',')
1787 next();
1788 }
1789 skip(';');
1790 }
1791 }
1792
1793 void globalDeclarations() {
1794 while (tok != EOF) {
1795 Type base;
1796 expectType(base);
1797 Type t = acceptPointerDeclaration(t);
1798 checkSymbol();
1799 int name = tok;
1800 next();
1801 if (tok == ',' || tok == ';') {
1802 // it's a variable declaration
1803 for(;;) {
1804 *(int* *) name = (int*) allocGlobalSpace(4);
1805 if (tok != ',') {
1806 break;
Jack Palevich21a15a22009-05-11 14:49:29 -07001807 }
1808 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001809 t = acceptPointerDeclaration(t);
1810 checkSymbol();
1811 name = tok;
1812 next();
Jack Palevich21a15a22009-05-11 14:49:29 -07001813 }
1814 skip(';');
1815 } else {
Jack Palevichb7c81e92009-06-04 19:56:13 -07001816 /* patch forward references (XXX: does not work for function
Jack Palevich21a15a22009-05-11 14:49:29 -07001817 pointers) */
Jack Palevichb7c81e92009-06-04 19:56:13 -07001818 pGen->gsym(*(int *) (name + 4));
Jack Palevich21a15a22009-05-11 14:49:29 -07001819 /* put function address */
Jack Palevichb7c81e92009-06-04 19:56:13 -07001820 *(int *) name = codeBuf.getPC();
Jack Palevich21a15a22009-05-11 14:49:29 -07001821 skip('(');
Jack Palevichb7c81e92009-06-04 19:56:13 -07001822 intptr_t a = 8;
Jack Palevich546b2242009-05-13 15:10:04 -07001823 int argCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001824 while (tok != ')') {
Jack Palevichb7c81e92009-06-04 19:56:13 -07001825 Type aType;
1826 expectType(aType);
1827 aType = acceptPointerDeclaration(aType);
1828 checkSymbol();
Jack Palevich21a15a22009-05-11 14:49:29 -07001829 /* read param name and compute offset */
1830 *(int *) tok = a;
1831 a = a + 4;
1832 next();
1833 if (tok == ',')
1834 next();
Jack Palevich546b2242009-05-13 15:10:04 -07001835 argCount++;
Jack Palevich21a15a22009-05-11 14:49:29 -07001836 }
Jack Palevichb7c81e92009-06-04 19:56:13 -07001837 skip(')'); /* skip ')' */
Jack Palevich21a15a22009-05-11 14:49:29 -07001838 rsym = loc = 0;
Jack Palevich546b2242009-05-13 15:10:04 -07001839 a = pGen->functionEntry(argCount);
Jack Palevich21a15a22009-05-11 14:49:29 -07001840 block(0);
Jack Palevichbf42c9c2009-05-12 12:48:35 -07001841 pGen->gsym(rsym);
Jack Palevich546b2242009-05-13 15:10:04 -07001842 pGen->functionExit(argCount, a, loc);
Jack Palevich21a15a22009-05-11 14:49:29 -07001843 }
1844 }
1845 }
1846
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001847 char* allocGlobalSpace(int bytes) {
1848 if (glo - pGlobalBase + bytes > ALLOC_SIZE) {
1849 error("Global space exhausted");
1850 }
1851 char* result = glo;
1852 glo += bytes;
1853 return result;
1854 }
1855
Jack Palevich21a15a22009-05-11 14:49:29 -07001856 void cleanup() {
1857 if (sym_stk != 0) {
Jack Palevich653f42d2009-05-28 17:15:32 -07001858 free(sym_stk);
Jack Palevich21a15a22009-05-11 14:49:29 -07001859 sym_stk = 0;
1860 }
1861 if (pGlobalBase != 0) {
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001862 free(pGlobalBase);
Jack Palevich21a15a22009-05-11 14:49:29 -07001863 pGlobalBase = 0;
1864 }
1865 if (pVarsBase != 0) {
1866 free(pVarsBase);
1867 pVarsBase = 0;
1868 }
1869 if (pGen) {
1870 delete pGen;
1871 pGen = 0;
1872 }
Jack Palevich1cdef202009-05-22 12:06:27 -07001873 if (file) {
1874 delete file;
1875 file = 0;
1876 }
Jack Palevich21a15a22009-05-11 14:49:29 -07001877 }
1878
1879 void clear() {
1880 tok = 0;
1881 tokc = 0;
1882 tokl = 0;
1883 ch = 0;
Jack Palevich653f42d2009-05-28 17:15:32 -07001884 pVarsBase = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001885 rsym = 0;
1886 loc = 0;
1887 glo = 0;
1888 sym_stk = 0;
1889 dstk = 0;
1890 dptr = 0;
1891 dch = 0;
1892 last_id = 0;
1893 file = 0;
1894 pGlobalBase = 0;
1895 pVarsBase = 0;
1896 pGen = 0;
Jack Palevicheedf9d22009-06-04 16:23:40 -07001897 mPragmaStringCount = 0;
Jack Palevich21a15a22009-05-11 14:49:29 -07001898 }
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001899
Jack Palevich22305132009-05-13 10:58:45 -07001900 void setArchitecture(const char* architecture) {
1901 delete pGen;
1902 pGen = 0;
1903
1904 if (architecture != NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001905#ifdef PROVIDE_ARM_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07001906 if (! pGen && strcmp(architecture, "arm") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07001907 pGen = new ARMCodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001908 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001909#endif
Jack Paleviche7b59062009-05-19 17:12:17 -07001910#ifdef PROVIDE_X86_CODEGEN
Jack Palevich8b0624c2009-05-20 12:12:06 -07001911 if (! pGen && strcmp(architecture, "x86") == 0) {
Jack Palevich22305132009-05-13 10:58:45 -07001912 pGen = new X86CodeGenerator();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001913 }
Jack Paleviche7b59062009-05-19 17:12:17 -07001914#endif
Jack Palevich8b0624c2009-05-20 12:12:06 -07001915 if (!pGen ) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001916 error("Unknown architecture %s\n", architecture);
Jack Palevich22305132009-05-13 10:58:45 -07001917 }
1918 }
1919
1920 if (pGen == NULL) {
Jack Paleviche7b59062009-05-19 17:12:17 -07001921#if defined(DEFAULT_ARM_CODEGEN)
Jack Palevich22305132009-05-13 10:58:45 -07001922 pGen = new ARMCodeGenerator();
Jack Paleviche7b59062009-05-19 17:12:17 -07001923#elif defined(DEFAULT_X86_CODEGEN)
1924 pGen = new X86CodeGenerator();
1925#endif
1926 }
1927 if (pGen == NULL) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001928 error("No code generator defined.");
Jack Palevich22305132009-05-13 10:58:45 -07001929 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07001930 pGen->setErrorSink(this);
Jack Palevich22305132009-05-13 10:58:45 -07001931 }
1932
Jack Palevich77ae76e2009-05-10 19:59:24 -07001933public:
Jack Palevich22305132009-05-13 10:58:45 -07001934 struct args {
1935 args() {
1936 architecture = 0;
1937 }
1938 const char* architecture;
1939 };
1940
Jack Paleviche7b59062009-05-19 17:12:17 -07001941 Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001942 clear();
Jack Paleviche27bf3e2009-05-10 14:09:03 -07001943 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07001944
Jack Paleviche7b59062009-05-19 17:12:17 -07001945 ~Compiler() {
Jack Palevich21a15a22009-05-11 14:49:29 -07001946 cleanup();
1947 }
1948
Jack Palevich1cdef202009-05-22 12:06:27 -07001949 int compile(const char* text, size_t textLength) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07001950 int result;
1951 if (! (result = setjmp(mErrorRecoveryJumpBuf))) {
1952 cleanup();
1953 clear();
1954 codeBuf.init(ALLOC_SIZE);
1955 setArchitecture(NULL);
1956 if (!pGen) {
1957 return -1;
1958 }
1959 pGen->init(&codeBuf);
1960 file = new TextInputStream(text, textLength);
1961 sym_stk = (char*) calloc(1, ALLOC_SIZE);
Jack Palevicheedf9d22009-06-04 16:23:40 -07001962 static const char* predefinedSymbols =
Jack Palevichb7c81e92009-06-04 19:56:13 -07001963 " int char void"
1964 " if else while break return for"
1965 " pragma define main ";
Jack Palevicheedf9d22009-06-04 16:23:40 -07001966 dstk = strcpy(sym_stk, predefinedSymbols)
1967 + strlen(predefinedSymbols);
Jack Palevichf1f39cc2009-05-29 18:03:15 -07001968 pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
1969 glo = pGlobalBase;
Jack Palevichac0e95e2009-05-29 13:53:44 -07001970 pVarsBase = (char*) calloc(1, ALLOC_SIZE);
1971 inp();
1972 next();
Jack Palevichb7c81e92009-06-04 19:56:13 -07001973 globalDeclarations();
Jack Palevichac0e95e2009-05-29 13:53:44 -07001974 pGen->finishCompile();
Jack Palevich8b0624c2009-05-20 12:12:06 -07001975 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07001976 return result;
Jack Palevich21a15a22009-05-11 14:49:29 -07001977 }
1978
1979 int run(int argc, char** argv) {
1980 typedef int (*mainPtr)(int argc, char** argv);
Jack Palevich653f42d2009-05-28 17:15:32 -07001981 mainPtr aMain = (mainPtr) *(int*) (pVarsBase + TOK_MAIN);
Jack Palevich21a15a22009-05-11 14:49:29 -07001982 if (!aMain) {
1983 fprintf(stderr, "Could not find function \"main\".\n");
1984 return -1;
1985 }
1986 return aMain(argc, argv);
1987 }
1988
1989 int dump(FILE* out) {
1990 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
1991 return 0;
1992 }
Jack Palevich77ae76e2009-05-10 19:59:24 -07001993
Jack Palevicha6535612009-05-13 16:24:17 -07001994 int disassemble(FILE* out) {
1995 return pGen->disassemble(out);
1996 }
1997
Jack Palevich1cdef202009-05-22 12:06:27 -07001998 /* Look through the symbol table to find a symbol.
1999 * If found, return its value.
2000 */
2001 void* lookup(const char* name) {
2002 if (!sym_stk) {
2003 return NULL;
2004 }
2005 size_t nameLen = strlen(name);
Jack Palevich653f42d2009-05-28 17:15:32 -07002006 char* pSym = sym_stk;
Jack Palevich1cdef202009-05-22 12:06:27 -07002007 char c;
2008 for(;;) {
2009 c = *pSym++;
2010 if (c == 0) {
2011 break;
2012 }
2013 if (c == TAG_TOK) {
2014 if (memcmp(pSym, name, nameLen) == 0
2015 && pSym[nameLen] == TAG_TOK) {
Jack Palevich653f42d2009-05-28 17:15:32 -07002016 int tok = pSym - 1 - sym_stk;
Jack Palevich1cdef202009-05-22 12:06:27 -07002017 tok = tok * 8 + TOK_IDENT;
2018 if (tok <= TOK_DEFINE) {
2019 return 0;
2020 } else {
Jack Palevich653f42d2009-05-28 17:15:32 -07002021 tok = (intptr_t) (pVarsBase + tok);
Jack Palevich1cdef202009-05-22 12:06:27 -07002022 return * (void**) tok;
2023 }
2024 }
2025 }
2026 }
2027 return NULL;
2028 }
2029
Jack Palevicheedf9d22009-06-04 16:23:40 -07002030 void getPragmas(ACCsizei* actualStringCount,
2031 ACCsizei maxStringCount, ACCchar** strings) {
2032 int stringCount = mPragmaStringCount;
2033 if (actualStringCount) {
2034 *actualStringCount = stringCount;
2035 }
2036 if (stringCount > maxStringCount) {
2037 stringCount = maxStringCount;
2038 }
2039 if (strings) {
2040 char* pPragmas = mPragmas.getUnwrapped();
2041 while (stringCount-- > 0) {
2042 *strings++ = pPragmas;
2043 pPragmas += strlen(pPragmas) + 1;
2044 }
2045 }
2046 }
2047
Jack Palevichac0e95e2009-05-29 13:53:44 -07002048 char* getErrorMessage() {
Jack Palevicheedf9d22009-06-04 16:23:40 -07002049 return mErrorBuf.getUnwrapped();
Jack Palevichac0e95e2009-05-29 13:53:44 -07002050 }
2051
Jack Palevich77ae76e2009-05-10 19:59:24 -07002052};
2053
Jack Paleviche7b59062009-05-19 17:12:17 -07002054const char* Compiler::operatorChars =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002055 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
2056
Jack Paleviche7b59062009-05-19 17:12:17 -07002057const char Compiler::operatorLevel[] =
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002058 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
2059 5, 5, /* ==, != */
2060 9, 10, /* &&, || */
2061 6, 7, 8, /* & ^ | */
2062 2, 2 /* ~ ! */
2063 };
2064
Jack Palevich8b0624c2009-05-20 12:12:06 -07002065#ifdef PROVIDE_ARM_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002066FILE* Compiler::ARMCodeGenerator::disasmOut;
Jack Palevich8b0624c2009-05-20 12:12:06 -07002067#endif
Jack Palevicha6535612009-05-13 16:24:17 -07002068
Jack Palevich8b0624c2009-05-20 12:12:06 -07002069#ifdef PROVIDE_X86_CODEGEN
Jack Paleviche7b59062009-05-19 17:12:17 -07002070const int Compiler::X86CodeGenerator::operatorHelper[] = {
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002071 0x1, // ++
2072 0xff, // --
2073 0xc1af0f, // *
2074 0xf9f79991, // /
2075 0xf9f79991, // % (With manual assist to swap results)
2076 0xc801, // +
2077 0xd8f7c829, // -
2078 0xe0d391, // <<
2079 0xf8d391, // >>
2080 0xe, // <=
2081 0xd, // >=
2082 0xc, // <
2083 0xf, // >
2084 0x4, // ==
2085 0x5, // !=
2086 0x0, // &&
2087 0x1, // ||
2088 0xc821, // &
2089 0xc831, // ^
2090 0xc809, // |
2091 0xd0f7, // ~
2092 0x4 // !
2093};
Jack Palevich8b0624c2009-05-20 12:12:06 -07002094#endif
Jack Palevichbf42c9c2009-05-12 12:48:35 -07002095
Jack Palevich1cdef202009-05-22 12:06:27 -07002096struct ACCscript {
2097 ACCscript() {
2098 text = 0;
2099 textLength = 0;
2100 accError = ACC_NO_ERROR;
2101 }
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002102
Jack Palevich1cdef202009-05-22 12:06:27 -07002103 ~ACCscript() {
2104 delete text;
2105 }
Jack Palevich546b2242009-05-13 15:10:04 -07002106
Jack Palevich1cdef202009-05-22 12:06:27 -07002107 void setError(ACCenum error) {
2108 if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
2109 accError = error;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002110 }
2111 }
2112
Jack Palevich1cdef202009-05-22 12:06:27 -07002113 ACCenum getError() {
2114 ACCenum result = accError;
2115 accError = ACC_NO_ERROR;
Jack Palevich22305132009-05-13 10:58:45 -07002116 return result;
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002117 }
2118
Jack Palevich1cdef202009-05-22 12:06:27 -07002119 Compiler compiler;
2120 char* text;
2121 int textLength;
2122 ACCenum accError;
2123};
2124
2125
2126extern "C"
2127ACCscript* accCreateScript() {
2128 return new ACCscript();
Jack Palevichbbf8ab52009-05-11 11:54:30 -07002129}
Jack Palevich1cdef202009-05-22 12:06:27 -07002130
2131extern "C"
2132ACCenum accGetError( ACCscript* script ) {
2133 return script->getError();
2134}
2135
2136extern "C"
2137void accDeleteScript(ACCscript* script) {
2138 delete script;
2139}
2140
2141extern "C"
2142void accScriptSource(ACCscript* script,
2143 ACCsizei count,
2144 const ACCchar ** string,
2145 const ACCint * length) {
2146 int totalLength = 0;
2147 for(int i = 0; i < count; i++) {
2148 int len = -1;
2149 const ACCchar* s = string[i];
2150 if (length) {
2151 len = length[i];
2152 }
2153 if (len < 0) {
2154 len = strlen(s);
2155 }
2156 totalLength += len;
2157 }
2158 delete script->text;
2159 char* text = new char[totalLength + 1];
2160 script->text = text;
2161 script->textLength = totalLength;
Jack Palevich09555c72009-05-27 12:25:55 -07002162 char* dest = text;
Jack Palevich1cdef202009-05-22 12:06:27 -07002163 for(int i = 0; i < count; i++) {
2164 int len = -1;
2165 const ACCchar* s = string[i];
2166 if (length) {
2167 len = length[i];
2168 }
2169 if (len < 0) {
2170 len = strlen(s);
2171 }
Jack Palevich09555c72009-05-27 12:25:55 -07002172 memcpy(dest, s, len);
2173 dest += len;
Jack Palevich1cdef202009-05-22 12:06:27 -07002174 }
2175 text[totalLength] = '\0';
2176}
2177
2178extern "C"
2179void accCompileScript(ACCscript* script) {
2180 int result = script->compiler.compile(script->text, script->textLength);
2181 if (result) {
2182 script->setError(ACC_INVALID_OPERATION);
2183 }
2184}
2185
2186extern "C"
2187void accGetScriptiv(ACCscript* script,
2188 ACCenum pname,
2189 ACCint * params) {
2190 switch (pname) {
2191 case ACC_INFO_LOG_LENGTH:
2192 *params = 0;
2193 break;
2194 }
2195}
2196
2197extern "C"
2198void accGetScriptInfoLog(ACCscript* script,
2199 ACCsizei maxLength,
2200 ACCsizei * length,
2201 ACCchar * infoLog) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002202 char* message = script->compiler.getErrorMessage();
2203 int messageLength = strlen(message) + 1;
Jack Palevich1cdef202009-05-22 12:06:27 -07002204 if (length) {
Jack Palevichac0e95e2009-05-29 13:53:44 -07002205 *length = messageLength;
Jack Palevich1cdef202009-05-22 12:06:27 -07002206 }
Jack Palevichac0e95e2009-05-29 13:53:44 -07002207 if (infoLog && maxLength > 0) {
2208 int trimmedLength = maxLength < messageLength ?
2209 maxLength : messageLength;
2210 memcpy(infoLog, message, trimmedLength);
2211 infoLog[trimmedLength] = 0;
Jack Palevich1cdef202009-05-22 12:06:27 -07002212 }
2213}
2214
2215extern "C"
2216void accGetScriptLabel(ACCscript* script, const ACCchar * name,
2217 ACCvoid ** address) {
2218 void* value = script->compiler.lookup(name);
2219 if (value) {
2220 *address = value;
2221 } else {
2222 script->setError(ACC_INVALID_VALUE);
2223 }
2224}
2225
Jack Palevicheedf9d22009-06-04 16:23:40 -07002226extern "C"
2227void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
2228 ACCsizei maxStringCount, ACCchar** strings){
2229 script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
2230}
2231
2232
Jack Palevich1cdef202009-05-22 12:06:27 -07002233} // namespace acc
2234