diff options
Diffstat (limited to 'libacc/acc.cpp')
-rw-r--r-- | libacc/acc.cpp | 6407 |
1 files changed, 0 insertions, 6407 deletions
diff --git a/libacc/acc.cpp b/libacc/acc.cpp deleted file mode 100644 index 6e13f9a..0000000 --- a/libacc/acc.cpp +++ /dev/null @@ -1,6407 +0,0 @@ -/* - * Android "Almost" C Compiler. - * This is a compiler for a small subset of the C language, intended for use - * in scripting environments where speed and memory footprint are important. - * - * This code is based upon the "unobfuscated" version of the - * Obfuscated Tiny C compiler, see the file LICENSE for details. - * - */ - -#define LOG_TAG "acc" -#include <cutils/log.h> - -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <cutils/hashmap.h> - -#include <sys/mman.h> - -#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) -#define MAP_ANONYMOUS MAP_ANON -#endif - -#if defined(__arm__) -#define DEFAULT_ARM_CODEGEN -#define PROVIDE_ARM_CODEGEN -#elif defined(__i386__) -#define DEFAULT_X86_CODEGEN -#define PROVIDE_X86_CODEGEN -#elif defined(__x86_64__) -#define DEFAULT_X64_CODEGEN -#define PROVIDE_X64_CODEGEN -#endif - -#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) -#define ARM_USE_VFP -#endif - -#include <acc/acc.h> - -#define LOG_API(...) do {} while(0) -// #define LOG_API(...) fprintf (stderr, __VA_ARGS__) - -#define LOG_STACK(...) do {} while(0) -// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__) - -// #define PROVIDE_TRACE_CODEGEN - -// Uncomment to disable ARM peephole optimizations -// #define DISABLE_ARM_PEEPHOLE - -// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN -// #define DEBUG_SAVE_INPUT_TO_FILE - -#ifdef DEBUG_SAVE_INPUT_TO_FILE -#ifdef ARM_USE_VFP -#define DEBUG_DUMP_PATTERN "/data/misc/acc_dump/%d.c" -#else -#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c" -#endif -#endif - -#define assert(b) assertImpl(b, __LINE__) - -namespace acc { - -// Subset of STL vector. -template<class E> class Vector { - public: - Vector() { - mpBase = 0; - mUsed = 0; - mSize = 0; - } - - ~Vector() { - if (mpBase) { - clear(); - free(mpBase); - } - } - - inline E& operator[](size_t i) { - return mpBase[i]; - } - - inline E& front() { - return mpBase[0]; - } - - inline E& back() { - return mpBase[mUsed - 1]; - } - - void pop_back() { - mUsed -= 1; - mpBase[mUsed].~E(); - } - - void push_back(const E& item) { - * ensure(1) = item; - } - - inline size_t size() { - return mUsed; - } - - void clear() { - if (mpBase) { - size_t used = mUsed; - for(size_t i = 0; i < used; i++) { - mpBase[i].~E(); - } - } - mUsed = 0; - } - -private: - E* ensure(int n) { - size_t newUsed = mUsed + n; - if (newUsed > mSize) { - size_t newSize = mSize * 2 + 10; - if (newSize < newUsed) { - newSize = newUsed; - } - mpBase = (E*) realloc(mpBase, sizeof(E) * newSize); - mSize = newSize; - } - E* result = mpBase + mUsed; - mUsed = newUsed; - return result; - } - - E* mpBase; - size_t mUsed; - size_t mSize; -}; - -class ErrorSink { -public: - void error(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - verror(fmt, ap); - va_end(ap); - } - - virtual ~ErrorSink() {} - virtual void verror(const char* fmt, va_list ap) = 0; -}; - -class Compiler : public ErrorSink { - typedef int tokenid_t; - enum TypeTag { - TY_UNKNOWN = -1, - TY_INT, // 0 - TY_CHAR, // 1 - TY_SHORT, // 2 - TY_VOID, // 3 - TY_FLOAT, // 4 - TY_DOUBLE, // 5 - TY_POINTER, // 6 - TY_ARRAY, // 7 - TY_STRUCT, // 8 - TY_FUNC, // 9 - TY_PARAM // 10 - }; - - enum StorageClass { - SC_DEFAULT, // 0 - SC_AUTO, // 1 - SC_REGISTER, // 2 - SC_STATIC, // 3 - SC_EXTERN, // 4 - SC_TYPEDEF // 5 - }; - - struct Type { - TypeTag tag; - StorageClass storageClass; - tokenid_t id; // For function arguments, global vars, local vars, struct elements - tokenid_t structTag; // For structs the name of the struct - int length; // length of array, offset of struct element. -1 means struct is forward defined - int alignment; // for structs only - Type* pHead; // For a struct this is the prototype struct. - Type* pTail; - }; - - enum ExpressionType { - ET_RVALUE, - ET_LVALUE - }; - - struct ExpressionValue { - ExpressionValue() { - et = ET_RVALUE; - pType = NULL; - } - ExpressionType et; - Type* pType; - }; - - class ICodeBuf { - public: - virtual ~ICodeBuf() {} - virtual void init(int size) = 0; - virtual void setErrorSink(ErrorSink* pErrorSink) = 0; - virtual void o4(int n) = 0; - virtual void ob(int n) = 0; - virtual void* getBase() = 0; - virtual intptr_t getSize() = 0; - virtual intptr_t getPC() = 0; - // Call this before trying to modify code in the buffer. - virtual void flush() = 0; - }; - - class CodeBuf : public ICodeBuf { - char* ind; // Output code pointer - char* pProgramBase; - ErrorSink* mErrorSink; - int mSize; - bool mOverflowed; - - void release() { - if (pProgramBase != 0) { - munmap(pProgramBase, mSize); - pProgramBase = 0; - } - } - - bool check(int n) { - int newSize = ind - pProgramBase + n; - bool overflow = newSize > mSize; - if (overflow && !mOverflowed) { - mOverflowed = true; - if (mErrorSink) { - mErrorSink->error("Code too large: %d bytes", newSize); - } - } - return overflow; - } - - public: - CodeBuf() { - pProgramBase = 0; - ind = 0; - mErrorSink = 0; - mSize = 0; - mOverflowed = false; - } - - virtual ~CodeBuf() { - release(); - } - - virtual void init(int size) { - release(); - mSize = size; - pProgramBase = (char*) mmap(NULL, size, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - ind = pProgramBase; - } - - virtual void setErrorSink(ErrorSink* pErrorSink) { - mErrorSink = pErrorSink; - } - - virtual void o4(int n) { - if(check(4)) { - return; - } - * (int*) ind = n; - ind += 4; - } - - /* - * Output a byte. Handles all values, 0..ff. - */ - virtual void ob(int n) { - if(check(1)) { - return; - } - *ind++ = n; - } - - virtual void* getBase() { - return (void*) pProgramBase; - } - - virtual intptr_t getSize() { - return ind - pProgramBase; - } - - virtual intptr_t getPC() { - return (intptr_t) ind; - } - - virtual void flush() {} - }; - - /** - * A code generator creates an in-memory program, generating the code on - * the fly. There is one code generator implementation for each supported - * architecture. - * - * The code generator implements the following abstract machine: - * R0 - the accumulator. - * FP - a frame pointer for accessing function arguments and local - * variables. - * SP - a stack pointer for storing intermediate results while evaluating - * expressions. The stack pointer grows downwards. - * - * The function calling convention is that all arguments are placed on the - * stack such that the first argument has the lowest address. - * After the call, the result is in R0. The caller is responsible for - * removing the arguments from the stack. - * The R0 register is not saved across function calls. The - * FP and SP registers are saved. - */ - - class CodeGenerator { - public: - CodeGenerator() { - mErrorSink = 0; - pCodeBuf = 0; - pushType(); - } - virtual ~CodeGenerator() {} - - virtual void init(ICodeBuf* pCodeBuf) { - this->pCodeBuf = pCodeBuf; - pCodeBuf->setErrorSink(mErrorSink); - } - - virtual void setErrorSink(ErrorSink* pErrorSink) { - mErrorSink = pErrorSink; - if (pCodeBuf) { - pCodeBuf->setErrorSink(mErrorSink); - } - } - - /* Give the code generator some utility types so it can - * use its own types as needed for the results of some - * operations like gcmp. - */ - - void setTypes(Type* pInt) { - mkpInt = pInt; - } - - /* Emit a function prolog. - * pDecl is the function declaration, which gives the arguments. - * Save the old value of the FP. - * Set the new value of the FP. - * Convert from the native platform calling convention to - * our stack-based calling convention. This may require - * pushing arguments from registers to the stack. - * Allocate "N" bytes of stack space. N isn't known yet, so - * just emit the instructions for adjusting the stack, and return - * the address to patch up. The patching will be done in - * functionExit(). - * returns address to patch with local variable size. - */ - virtual int functionEntry(Type* pDecl) = 0; - - /* Emit a function epilog. - * Restore the old SP and FP register values. - * Return to the calling function. - * argCount - the number of arguments to the function. - * localVariableAddress - returned from functionEntry() - * localVariableSize - the size in bytes of the local variables. - */ - virtual void functionExit(Type* pDecl, int localVariableAddress, - int localVariableSize) = 0; - - /* load immediate value to R0 */ - virtual void li(int i) = 0; - - /* Load floating point value from global address. */ - virtual void loadFloat(int address, Type* pType) = 0; - - /* Add the struct offset in bytes to R0, change the type to pType */ - virtual void addStructOffsetR0(int offset, Type* pType) = 0; - - /* Jump to a target, and return the address of the word that - * holds the target data, in case it needs to be fixed up later. - */ - virtual int gjmp(int t) = 0; - - /* Test R0 and jump to a target if the test succeeds. - * l = 0: je, l == 1: jne - * Return the address of the word that holds the targed data, in - * case it needs to be fixed up later. - */ - virtual int gtst(bool l, int t) = 0; - - /* Compare TOS against R0, and store the boolean result in R0. - * Pops TOS. - * op specifies the comparison. - */ - virtual void gcmp(int op) = 0; - - /* Perform the arithmetic op specified by op. TOS is the - * left argument, R0 is the right argument. - * Pops TOS. - */ - virtual void genOp(int op) = 0; - - /* Compare 0 against R0, and store the boolean result in R0. - * op specifies the comparison. - */ - virtual void gUnaryCmp(int op) = 0; - - /* Perform the arithmetic op specified by op. 0 is the - * left argument, R0 is the right argument. - */ - virtual void genUnaryOp(int op) = 0; - - /* Push R0 onto the stack. (Also known as "dup" for duplicate.) - */ - virtual void pushR0() = 0; - - /* Turn R0, TOS into R0 TOS R0 */ - - virtual void over() = 0; - - /* Pop R0 from the stack. (Also known as "drop") - */ - virtual void popR0() = 0; - - /* Store R0 to the address stored in TOS. - * The TOS is popped. - */ - virtual void storeR0ToTOS() = 0; - - /* Load R0 from the address stored in R0. - */ - virtual void loadR0FromR0() = 0; - - /* Load the absolute address of a variable to R0. - * If ea <= LOCAL, then this is a local variable, or an - * argument, addressed relative to FP. - * else it is an absolute global address. - * - * et is ET_RVALUE for things like string constants, ET_LVALUE for - * variables. - */ - virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0; - - /* Load the pc-relative address of a forward-referenced variable to R0. - * Return the address of the 4-byte constant so that it can be filled - * in later. - */ - virtual int leaForward(int ea, Type* pPointerType) = 0; - - /** - * Convert R0 to the given type. - */ - - void convertR0(Type* pType) { - convertR0Imp(pType, false); - } - - void castR0(Type* pType) { - convertR0Imp(pType, true); - } - - virtual void convertR0Imp(Type* pType, bool isCast) = 0; - - /* Emit code to adjust the stack for a function call. Return the - * label for the address of the instruction that adjusts the - * stack size. This will be passed as argument "a" to - * endFunctionCallArguments. - */ - virtual int beginFunctionCallArguments() = 0; - - /* Emit code to store R0 to the stack at byte offset l. - * Returns stack size of object (typically 4 or 8 bytes) - */ - virtual size_t storeR0ToArg(int l, Type* pArgType) = 0; - - /* Patch the function call preamble. - * a is the address returned from beginFunctionCallArguments - * l is the number of bytes the arguments took on the stack. - * Typically you would also emit code to convert the argument - * list into whatever the native function calling convention is. - * On ARM for example you would pop the first 5 arguments into - * R0..R4 - */ - virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0; - - /* Emit a call to an unknown function. The argument "symbol" needs to - * be stored in the location where the address should go. It forms - * a chain. The address will be patched later. - * Return the address of the word that has to be patched. - */ - virtual int callForward(int symbol, Type* pFunc) = 0; - - /* Call a function pointer. L is the number of bytes the arguments - * take on the stack. The address of the function is stored at - * location SP + l. - */ - virtual void callIndirect(int l, Type* pFunc) = 0; - - /* Adjust SP after returning from a function call. l is the - * number of bytes of arguments stored on the stack. isIndirect - * is true if this was an indirect call. (In which case the - * address of the function is stored at location SP + l.) - */ - virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0; - - /* Generate a symbol at the current PC. t is the head of a - * linked list of addresses to patch. - */ - virtual void gsym(int t) = 0; - - /* Resolve a forward reference function at the current PC. - * t is the head of a - * linked list of addresses to patch. - * (Like gsym, but using absolute address, not PC relative address.) - */ - virtual void resolveForward(int t) = 0; - - /* - * Do any cleanup work required at the end of a compile. - * For example, an instruction cache might need to be - * invalidated. - * Return non-zero if there is an error. - */ - virtual int finishCompile() = 0; - - /** - * Adjust relative branches by this amount. - */ - virtual int jumpOffset() = 0; - - /** - * Memory alignment (in bytes) for this type of data - */ - virtual size_t alignmentOf(Type* type) = 0; - - /** - * Array element alignment (in bytes) for this type of data. - */ - virtual size_t sizeOf(Type* type) = 0; - - virtual Type* getR0Type() { - return mExpressionStack.back().pType; - } - - virtual ExpressionType getR0ExpressionType() { - return mExpressionStack.back().et; - } - - virtual void setR0ExpressionType(ExpressionType et) { - mExpressionStack.back().et = et; - } - - virtual size_t getExpressionStackDepth() { - return mExpressionStack.size(); - } - - virtual void forceR0RVal() { - if (getR0ExpressionType() == ET_LVALUE) { - loadR0FromR0(); - } - } - - protected: - /* - * Output a byte. Handles all values, 0..ff. - */ - void ob(int n) { - pCodeBuf->ob(n); - } - - void o4(int data) { - pCodeBuf->o4(data); - } - - intptr_t getBase() { - return (intptr_t) pCodeBuf->getBase(); - } - - intptr_t getPC() { - return pCodeBuf->getPC(); - } - - intptr_t getSize() { - return pCodeBuf->getSize(); - } - - void flush() { - pCodeBuf->flush(); - } - - void error(const char* fmt,...) { - va_list ap; - va_start(ap, fmt); - mErrorSink->verror(fmt, ap); - va_end(ap); - } - - void assertImpl(bool test, int line) { - if (!test) { - error("code generator assertion failed at line %s:%d.", __FILE__, line); - LOGD("code generator assertion failed at line %s:%d.", __FILE__, line); - * (char*) 0 = 0; - } - } - - void setR0Type(Type* pType) { - assert(pType != NULL); - mExpressionStack.back().pType = pType; - mExpressionStack.back().et = ET_RVALUE; - } - - void setR0Type(Type* pType, ExpressionType et) { - assert(pType != NULL); - mExpressionStack.back().pType = pType; - mExpressionStack.back().et = et; - } - - Type* getTOSType() { - return mExpressionStack[mExpressionStack.size()-2].pType; - } - - void pushType() { - if (mExpressionStack.size()) { - mExpressionStack.push_back(mExpressionStack.back()); - } else { - mExpressionStack.push_back(ExpressionValue()); - } - - } - - void overType() { - size_t size = mExpressionStack.size(); - if (size >= 2) { - mExpressionStack.push_back(mExpressionStack.back()); - mExpressionStack[size-1] = mExpressionStack[size-2]; - mExpressionStack[size-2] = mExpressionStack[size]; - } - } - - void popType() { - mExpressionStack.pop_back(); - } - - bool bitsSame(Type* pA, Type* pB) { - return collapseType(pA->tag) == collapseType(pB->tag); - } - - TypeTag collapseType(TypeTag tag) { - static const TypeTag collapsedTag[] = { - TY_INT, - TY_INT, - TY_INT, - TY_VOID, - TY_FLOAT, - TY_DOUBLE, - TY_INT, - TY_INT, - TY_VOID, - TY_VOID, - TY_VOID - }; - return collapsedTag[tag]; - } - - TypeTag collapseTypeR0() { - return collapseType(getR0Type()->tag); - } - - static bool isFloatType(Type* pType) { - return isFloatTag(pType->tag); - } - - static bool isFloatTag(TypeTag tag) { - return tag == TY_FLOAT || tag == TY_DOUBLE; - } - - static bool isPointerType(Type* pType) { - return isPointerTag(pType->tag); - } - - static bool isPointerTag(TypeTag tag) { - return tag == TY_POINTER || tag == TY_ARRAY; - } - - Type* getPointerArithmeticResultType(Type* a, Type* b) { - TypeTag aTag = a->tag; - TypeTag bTag = b->tag; - if (aTag == TY_POINTER) { - return a; - } - if (bTag == TY_POINTER) { - return b; - } - if (aTag == TY_ARRAY) { - return a->pTail; - } - if (bTag == TY_ARRAY) { - return b->pTail; - } - return NULL; - } - Type* mkpInt; - - private: - Vector<ExpressionValue> mExpressionStack; - ICodeBuf* pCodeBuf; - ErrorSink* mErrorSink; - }; - -#ifdef PROVIDE_ARM_CODEGEN - - static size_t rotateRight(size_t n, size_t rotate) { - return (n >> rotate) | (n << (32 - rotate)); - } - - static size_t rotateLeft(size_t n, size_t rotate) { - return (n << rotate) | (n >> (32 - rotate)); - } - - static bool encode12BitImmediate(size_t immediate, size_t* pResult) { - for(size_t i = 0; i < 16; i++) { - size_t rotate = i * 2; - size_t mask = rotateRight(0xff, rotate); - if ((immediate | mask) == mask) { - size_t bits8 = rotateLeft(immediate, rotate); - // assert(bits8 <= 0xff); - *pResult = (i << 8) | bits8; - return true; - } - } - return false; - } - - static size_t decode12BitImmediate(size_t immediate) { - size_t data = immediate & 0xff; - size_t rotate = 2 * ((immediate >> 8) & 0xf); - return rotateRight(data, rotate); - } - - static bool isPowerOfTwo(size_t n) { - return (n != 0) & ((n & (n-1)) == 0); - } - - static size_t log2(size_t n) { - int result = 0; - while (n >>= 1) { - result++; - } - return result; - } - - class ARMCodeBuf : public ICodeBuf { - ICodeBuf* mpBase; - ErrorSink* mErrorSink; - - class CircularQueue { - static const int SIZE = 16; // Must be power of 2 - static const int MASK = SIZE-1; - unsigned int mBuf[SIZE]; - int mHead; - int mCount; - - public: - CircularQueue() { - mHead = 0; - mCount = 0; - } - - void pushBack(unsigned int data) { - mBuf[(mHead + mCount) & MASK] = data; - mCount += 1; - } - - unsigned int popFront() { - unsigned int result = mBuf[mHead]; - mHead = (mHead + 1) & MASK; - mCount -= 1; - return result; - } - - void popBack(int n) { - mCount -= n; - } - - inline int count() { - return mCount; - } - - bool empty() { - return mCount == 0; - } - - bool full() { - return mCount == SIZE; - } - - // The valid indexes are 1 - count() to 0 - unsigned int operator[](int i) { - return mBuf[(mHead + mCount + i) & MASK]; - } - }; - - CircularQueue mQ; - - void error(const char* fmt,...) { - va_list ap; - va_start(ap, fmt); - mErrorSink->verror(fmt, ap); - va_end(ap); - } - - void flush() { - while (!mQ.empty()) { - mpBase->o4(mQ.popFront()); - } - mpBase->flush(); - } - - public: - ARMCodeBuf(ICodeBuf* pBase) { - mpBase = pBase; - } - - virtual ~ARMCodeBuf() { - delete mpBase; - } - - void init(int size) { - mpBase->init(size); - } - - void setErrorSink(ErrorSink* pErrorSink) { - mErrorSink = pErrorSink; - mpBase->setErrorSink(pErrorSink); - } - - void o4(int n) { - if (mQ.full()) { - mpBase->o4(mQ.popFront()); - } - mQ.pushBack(n); - -#ifndef DISABLE_ARM_PEEPHOLE - // Peephole check - bool didPeep; - do { - static const unsigned int opMask = 0x01e00000; - static const unsigned int immediateMask = 0x00000fff; - static const unsigned int BMask = 0x00400000; - didPeep = false; - if (mQ.count() >= 4) { - - // Operand by a small constant - // push;mov #imm;pop;op ==> op #imm - - if (mQ[-4] == 0xe92d0001 && // stmfd r13!, {r0} - (mQ[-3] & ~immediateMask) == 0xe3a00000 && // mov r0, #X - mQ[-2] == 0xe8bd0002 && // ldmea r13!, {r1} - (mQ[-1] & ~opMask) == (0xe0810000 & ~opMask)) { // OP r0, r1, r0 - unsigned int movConst = mQ[-3]; - unsigned int op = mQ[-1]; - unsigned int combined = 0xe2000000 | (op & opMask) | (movConst & immediateMask); - // fprintf(stderr, "op %x movConst %x combined %x\n", op, movConst, combined); - if (! (combined == 0xe2800000 || combined == 0xe2400000)) { // add/sub #0 - mQ.popBack(4); - mQ.pushBack(combined); - didPeep = true; - } else { - mQ.popBack(4); - didPeep = true; - } - } - } - - // Load local variable - // sub r0,r11,#imm;ldr/ldrb r0,[r0] ==> ldr/ldrb r0, [r11,#-imm] - if (mQ.count() >= 2) { - if ((mQ[-2] & ~immediateMask) == 0xe24b0000) { // sub r0,r11,#imm - const unsigned int encodedImmediate = mQ[-2] & immediateMask; - const unsigned int ld = mQ[-1]; - if ((ld & ~BMask) == 0xe5900000) { // ldr{b} r0, [r0] - unsigned int combined = encodedImmediate | (0xE51B0000 | (ld & BMask)); // ldr r0, [r11, #-0] - mQ.popBack(2); - mQ.pushBack(combined); - didPeep = true; - } else if (ld == 0xedd07a00) { // ldcl p10, c7, [r0, #0x000] - unsigned int decodedImmediate = decode12BitImmediate(encodedImmediate); - if (decodedImmediate <= 1020 && ((decodedImmediate & 3) == 0)) { - unsigned int combined = (decodedImmediate >> 2) | 0xed5b7a00; // ldcl p10, c7, [r11, #-0] - mQ.popBack(2); - mQ.pushBack(combined); - didPeep = true; - } - } - } - } - - // Constant array lookup - - if (mQ.count() >= 6 && - mQ[-6] == 0xe92d0001 && // stmfd r13!, {r0} - (mQ[-5] & ~immediateMask)== 0xe3a00000 && // mov r0, #0x00000001 - mQ[-4] == 0xe8bd0002 && // ldmea r13!, {r1} - (mQ[-3] & ~immediateMask)== 0xe3a02000 && // mov r2, #0x00000004 - mQ[-2] == 0xe0000092 && // mul r0, r2, r0 - mQ[-1] == 0xe0810000) { // add r0, r1, r0 - unsigned int mov1 = mQ[-5]; - unsigned int mov2 = mQ[-3]; - unsigned int const1 = decode12BitImmediate(mov1); - unsigned int const2 = decode12BitImmediate(mov2); - unsigned int comboConst = const1 * const2; - size_t immediate = 0; - if (encode12BitImmediate(comboConst, &immediate)) { - mQ.popBack(6); - unsigned int add = immediate | 0xE2800000; // add r0, r0, #n - if (comboConst) { - mQ.pushBack(add); - } - didPeep = true; - } - } - - // Pointer arithmetic with a stride that is a power of two - - if (mQ.count() >= 3 && - (mQ[-3] & ~ immediateMask) == 0xe3a02000 && // mov r2, #stride - mQ[-2] == 0xe0000092 && // mul r0, r2, r0 - mQ[-1] == 0xe0810000) { // add r0, r1, r0 - int stride = decode12BitImmediate(mQ[-3]); - if (isPowerOfTwo(stride)) { - mQ.popBack(3); - unsigned int add = 0xe0810000 | (log2(stride) << 7); // add r0, r1, r0, LSL #log2(stride) - mQ.pushBack(add); - didPeep = true; - } - } - - } while (didPeep); -#endif - } - - void ob(int n) { - error("ob() not supported."); - } - - void* getBase() { - flush(); - return mpBase->getBase(); - } - - intptr_t getSize() { - flush(); - return mpBase->getSize(); - } - - intptr_t getPC() { - flush(); - return mpBase->getPC(); - } - }; - - class ARMCodeGenerator : public CodeGenerator { - public: - ARMCodeGenerator() { -#ifdef ARM_USE_VFP - // LOGD("Using ARM VFP hardware floating point."); -#else - // LOGD("Using ARM soft floating point."); -#endif - } - - virtual ~ARMCodeGenerator() {} - - /* returns address to patch with local variable size - */ - virtual int functionEntry(Type* pDecl) { - mStackUse = 0; - // sp -> arg4 arg5 ... - // Push our register-based arguments back on the stack - int regArgCount = calcRegArgCount(pDecl); - if (regArgCount > 0) { - mStackUse += regArgCount * 4; - o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {} - } - // sp -> arg0 arg1 ... - o4(0xE92D4800); // stmfd sp!, {fp, lr} - mStackUse += 2 * 4; - // sp, fp -> oldfp, retadr, arg0 arg1 .... - o4(0xE1A0B00D); // mov fp, sp - LOG_STACK("functionEntry: %d\n", mStackUse); - int pc = getPC(); - o4(0xE24DD000); // sub sp, sp, # <local variables> - // We don't know how many local variables we are going to use, - // but we will round the allocation up to a multiple of - // STACK_ALIGNMENT, so it won't affect the stack alignment. - return pc; - } - - virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { - // Round local variable size up to a multiple of stack alignment - localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) / - STACK_ALIGNMENT) * STACK_ALIGNMENT; - // Patch local variable allocation code: - if (localVariableSize < 0 || localVariableSize > 255) { - error("localVariables out of range: %d", localVariableSize); - } - *(char*) (localVariableAddress) = localVariableSize; - -#ifdef ARM_USE_VFP - { - Type* pReturnType = pDecl->pHead; - switch(pReturnType->tag) { - case TY_FLOAT: - o4(0xEE170A90); // fmrs r0, s15 - break; - case TY_DOUBLE: - o4(0xEC510B17); // fmrrd r0, r1, d7 - break; - default: - break; - } - } -#endif - - // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ... - o4(0xE1A0E00B); // mov lr, fp - o4(0xE59BB000); // ldr fp, [fp] - o4(0xE28ED004); // add sp, lr, #4 - // sp -> retadr, arg0, ... - o4(0xE8BD4000); // ldmfd sp!, {lr} - // sp -> arg0 .... - - // We store the PC into the lr so we can adjust the sp before - // returning. We need to pull off the registers we pushed - // earlier. We don't need to actually store them anywhere, - // just adjust the stack. - int regArgCount = calcRegArgCount(pDecl); - if (regArgCount) { - o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2 - } - o4(0xE12FFF1E); // bx lr - } - - /* load immediate value */ - virtual void li(int t) { - liReg(t, 0); - setR0Type(mkpInt); - } - - virtual void loadFloat(int address, Type* pType) { - setR0Type(pType); - // Global, absolute address - o4(0xE59F0000); // ldr r0, .L1 - o4(0xEA000000); // b .L99 - o4(address); // .L1: .word ea - // .L99: - - switch (pType->tag) { - case TY_FLOAT: -#ifdef ARM_USE_VFP - o4(0xEDD07A00); // flds s15, [r0] -#else - o4(0xE5900000); // ldr r0, [r0] -#endif - break; - case TY_DOUBLE: -#ifdef ARM_USE_VFP - o4(0xED907B00); // fldd d7, [r0] -#else - o4(0xE1C000D0); // ldrd r0, [r0] -#endif - break; - default: - assert(false); - break; - } - } - - - virtual void addStructOffsetR0(int offset, Type* pType) { - if (offset) { - size_t immediate = 0; - if (encode12BitImmediate(offset, &immediate)) { - o4(0xE2800000 | immediate); // add r0, r0, #offset - } else { - error("structure offset out of range: %d", offset); - } - } - setR0Type(pType, ET_LVALUE); - } - - virtual int gjmp(int t) { - int pc = getPC(); - o4(0xEA000000 | encodeAddress(t)); // b .L33 - return pc; - } - - /* l = 0: je, l == 1: jne */ - virtual int gtst(bool l, int t) { - Type* pR0Type = getR0Type(); - TypeTag tagR0 = pR0Type->tag; - switch(tagR0) { - case TY_FLOAT: -#ifdef ARM_USE_VFP - o4(0xEEF57A40); // fcmpzs s15 - o4(0xEEF1FA10); // fmstat -#else - callRuntime((void*) runtime_is_non_zero_f); - o4(0xE3500000); // cmp r0,#0 -#endif - break; - case TY_DOUBLE: -#ifdef ARM_USE_VFP - o4(0xEEB57B40); // fcmpzd d7 - o4(0xEEF1FA10); // fmstat -#else - callRuntime((void*) runtime_is_non_zero_d); - o4(0xE3500000); // cmp r0,#0 -#endif - break; - default: - o4(0xE3500000); // cmp r0,#0 - break; - } - int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq - int pc = getPC(); - o4(branch | encodeAddress(t)); - return pc; - } - - virtual void gcmp(int op) { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = collapseType(pR0Type->tag); - TypeTag tagTOS = collapseType(pTOSType->tag); - if (tagR0 == TY_INT && tagTOS == TY_INT) { - setupIntPtrArgs(); - o4(0xE1510000); // cmp r1, r1 - switch(op) { - case OP_EQUALS: - o4(0x03A00001); // moveq r0,#1 - o4(0x13A00000); // movne r0,#0 - break; - case OP_NOT_EQUALS: - o4(0x03A00000); // moveq r0,#0 - o4(0x13A00001); // movne r0,#1 - break; - case OP_LESS_EQUAL: - o4(0xD3A00001); // movle r0,#1 - o4(0xC3A00000); // movgt r0,#0 - break; - case OP_GREATER: - o4(0xD3A00000); // movle r0,#0 - o4(0xC3A00001); // movgt r0,#1 - break; - case OP_GREATER_EQUAL: - o4(0xA3A00001); // movge r0,#1 - o4(0xB3A00000); // movlt r0,#0 - break; - case OP_LESS: - o4(0xA3A00000); // movge r0,#0 - o4(0xB3A00001); // movlt r0,#1 - break; - default: - error("Unknown comparison op %d", op); - break; - } - } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) { - setupDoubleArgs(); -#ifdef ARM_USE_VFP - o4(0xEEB46BC7); // fcmped d6, d7 - o4(0xEEF1FA10); // fmstat - switch(op) { - case OP_EQUALS: - o4(0x03A00001); // moveq r0,#1 - o4(0x13A00000); // movne r0,#0 - break; - case OP_NOT_EQUALS: - o4(0x03A00000); // moveq r0,#0 - o4(0x13A00001); // movne r0,#1 - break; - case OP_LESS_EQUAL: - o4(0xD3A00001); // movle r0,#1 - o4(0xC3A00000); // movgt r0,#0 - break; - case OP_GREATER: - o4(0xD3A00000); // movle r0,#0 - o4(0xC3A00001); // movgt r0,#1 - break; - case OP_GREATER_EQUAL: - o4(0xA3A00001); // movge r0,#1 - o4(0xB3A00000); // movlt r0,#0 - break; - case OP_LESS: - o4(0xA3A00000); // movge r0,#0 - o4(0xB3A00001); // movlt r0,#1 - break; - default: - error("Unknown comparison op %d", op); - break; - } -#else - switch(op) { - case OP_EQUALS: - callRuntime((void*) runtime_cmp_eq_dd); - break; - case OP_NOT_EQUALS: - callRuntime((void*) runtime_cmp_ne_dd); - break; - case OP_LESS_EQUAL: - callRuntime((void*) runtime_cmp_le_dd); - break; - case OP_GREATER: - callRuntime((void*) runtime_cmp_gt_dd); - break; - case OP_GREATER_EQUAL: - callRuntime((void*) runtime_cmp_ge_dd); - break; - case OP_LESS: - callRuntime((void*) runtime_cmp_lt_dd); - break; - default: - error("Unknown comparison op %d", op); - break; - } -#endif - } else { - setupFloatArgs(); -#ifdef ARM_USE_VFP - o4(0xEEB47AE7); // fcmpes s14, s15 - o4(0xEEF1FA10); // fmstat - switch(op) { - case OP_EQUALS: - o4(0x03A00001); // moveq r0,#1 - o4(0x13A00000); // movne r0,#0 - break; - case OP_NOT_EQUALS: - o4(0x03A00000); // moveq r0,#0 - o4(0x13A00001); // movne r0,#1 - break; - case OP_LESS_EQUAL: - o4(0xD3A00001); // movle r0,#1 - o4(0xC3A00000); // movgt r0,#0 - break; - case OP_GREATER: - o4(0xD3A00000); // movle r0,#0 - o4(0xC3A00001); // movgt r0,#1 - break; - case OP_GREATER_EQUAL: - o4(0xA3A00001); // movge r0,#1 - o4(0xB3A00000); // movlt r0,#0 - break; - case OP_LESS: - o4(0xA3A00000); // movge r0,#0 - o4(0xB3A00001); // movlt r0,#1 - break; - default: - error("Unknown comparison op %d", op); - break; - } -#else - switch(op) { - case OP_EQUALS: - callRuntime((void*) runtime_cmp_eq_ff); - break; - case OP_NOT_EQUALS: - callRuntime((void*) runtime_cmp_ne_ff); - break; - case OP_LESS_EQUAL: - callRuntime((void*) runtime_cmp_le_ff); - break; - case OP_GREATER: - callRuntime((void*) runtime_cmp_gt_ff); - break; - case OP_GREATER_EQUAL: - callRuntime((void*) runtime_cmp_ge_ff); - break; - case OP_LESS: - callRuntime((void*) runtime_cmp_lt_ff); - break; - default: - error("Unknown comparison op %d", op); - break; - } -#endif - } - setR0Type(mkpInt); - } - - virtual void genOp(int op) { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = pR0Type->tag; - TypeTag tagTOS = pTOSType->tag; - bool isFloatR0 = isFloatTag(tagR0); - bool isFloatTOS = isFloatTag(tagTOS); - if (!isFloatR0 && !isFloatTOS) { - setupIntPtrArgs(); - bool isPtrR0 = isPointerTag(tagR0); - bool isPtrTOS = isPointerTag(tagTOS); - if (isPtrR0 || isPtrTOS) { - if (isPtrR0 && isPtrTOS) { - if (op != OP_MINUS) { - error("Unsupported pointer-pointer operation %d.", op); - } - if (! typeEqual(pR0Type, pTOSType)) { - error("Incompatible pointer types for subtraction."); - } - o4(0xE0410000); // sub r0,r1,r0 - setR0Type(mkpInt); - int size = sizeOf(pR0Type->pHead); - if (size != 1) { - pushR0(); - li(size); - // TODO: Optimize for power-of-two. - genOp(OP_DIV); - } - } else { - if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) { - error("Unsupported pointer-scalar operation %d", op); - } - Type* pPtrType = getPointerArithmeticResultType( - pR0Type, pTOSType); - int size = sizeOf(pPtrType->pHead); - if (size != 1) { - // TODO: Optimize for power-of-two. - liReg(size, 2); - if (isPtrR0) { - o4(0x0E0010192); // mul r1,r2,r1 - } else { - o4(0x0E0000092); // mul r0,r2,r0 - } - } - switch(op) { - case OP_PLUS: - o4(0xE0810000); // add r0,r1,r0 - break; - case OP_MINUS: - o4(0xE0410000); // sub r0,r1,r0 - break; - } - setR0Type(pPtrType); - } - } else { - switch(op) { - case OP_MUL: - o4(0x0E0000091); // mul r0,r1,r0 - break; - case OP_DIV: - callRuntime((void*) runtime_DIV); - break; - case OP_MOD: - callRuntime((void*) runtime_MOD); - break; - case OP_PLUS: - o4(0xE0810000); // add r0,r1,r0 - break; - case OP_MINUS: - o4(0xE0410000); // sub r0,r1,r0 - break; - case OP_SHIFT_LEFT: - o4(0xE1A00011); // lsl r0,r1,r0 - break; - case OP_SHIFT_RIGHT: - o4(0xE1A00051); // asr r0,r1,r0 - break; - case OP_BIT_AND: - o4(0xE0010000); // and r0,r1,r0 - break; - case OP_BIT_XOR: - o4(0xE0210000); // eor r0,r1,r0 - break; - case OP_BIT_OR: - o4(0xE1810000); // orr r0,r1,r0 - break; - case OP_BIT_NOT: - o4(0xE1E00000); // mvn r0, r0 - break; - default: - error("Unimplemented op %d\n", op); - break; - } - } - } else { - Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType; - if (pResultType->tag == TY_DOUBLE) { - setupDoubleArgs(); - - switch(op) { - case OP_MUL: -#ifdef ARM_USE_VFP - o4(0xEE267B07); // fmuld d7, d6, d7 -#else - callRuntime((void*) runtime_op_mul_dd); -#endif - break; - case OP_DIV: -#ifdef ARM_USE_VFP - o4(0xEE867B07); // fdivd d7, d6, d7 -#else - callRuntime((void*) runtime_op_div_dd); -#endif - break; - case OP_PLUS: -#ifdef ARM_USE_VFP - o4(0xEE367B07); // faddd d7, d6, d7 -#else - callRuntime((void*) runtime_op_add_dd); -#endif - break; - case OP_MINUS: -#ifdef ARM_USE_VFP - o4(0xEE367B47); // fsubd d7, d6, d7 -#else - callRuntime((void*) runtime_op_sub_dd); -#endif - break; - default: - error("Unsupported binary floating operation %d\n", op); - break; - } - } else { - setupFloatArgs(); - switch(op) { - case OP_MUL: -#ifdef ARM_USE_VFP - o4(0xEE677A27); // fmuls s15, s14, s15 -#else - callRuntime((void*) runtime_op_mul_ff); -#endif - break; - case OP_DIV: -#ifdef ARM_USE_VFP - o4(0xEEC77A27); // fdivs s15, s14, s15 -#else - callRuntime((void*) runtime_op_div_ff); -#endif - break; - case OP_PLUS: -#ifdef ARM_USE_VFP - o4(0xEE777A27); // fadds s15, s14, s15 -#else - callRuntime((void*) runtime_op_add_ff); -#endif - break; - case OP_MINUS: -#ifdef ARM_USE_VFP - o4(0xEE777A67); // fsubs s15, s14, s15 -#else - callRuntime((void*) runtime_op_sub_ff); -#endif - break; - default: - error("Unsupported binary floating operation %d\n", op); - break; - } - } - setR0Type(pResultType); - } - } - - virtual void gUnaryCmp(int op) { - if (op != OP_LOGICAL_NOT) { - error("Unknown unary cmp %d", op); - } else { - Type* pR0Type = getR0Type(); - TypeTag tag = collapseType(pR0Type->tag); - switch(tag) { - case TY_INT: - o4(0xE3A01000); // mov r1, #0 - o4(0xE1510000); // cmp r1, r0 - o4(0x03A00001); // moveq r0,#1 - o4(0x13A00000); // movne r0,#0 - break; - case TY_FLOAT: -#ifdef ARM_USE_VFP - o4(0xEEF57A40); // fcmpzs s15 - o4(0xEEF1FA10); // fmstat - o4(0x03A00001); // moveq r0,#1 - o4(0x13A00000); // movne r0,#0 -#else - callRuntime((void*) runtime_is_zero_f); -#endif - break; - case TY_DOUBLE: -#ifdef ARM_USE_VFP - o4(0xEEB57B40); // fcmpzd d7 - o4(0xEEF1FA10); // fmstat - o4(0x03A00001); // moveq r0,#1 - o4(0x13A00000); // movne r0,#0 -#else - callRuntime((void*) runtime_is_zero_d); -#endif - break; - default: - error("gUnaryCmp unsupported type"); - break; - } - } - setR0Type(mkpInt); - } - - virtual void genUnaryOp(int op) { - Type* pR0Type = getR0Type(); - TypeTag tag = collapseType(pR0Type->tag); - switch(tag) { - case TY_INT: - switch(op) { - case OP_MINUS: - o4(0xE3A01000); // mov r1, #0 - o4(0xE0410000); // sub r0,r1,r0 - break; - case OP_BIT_NOT: - o4(0xE1E00000); // mvn r0, r0 - break; - default: - error("Unknown unary op %d\n", op); - break; - } - break; - case TY_FLOAT: - case TY_DOUBLE: - switch (op) { - case OP_MINUS: - if (tag == TY_FLOAT) { -#ifdef ARM_USE_VFP - o4(0xEEF17A67); // fnegs s15, s15 -#else - callRuntime((void*) runtime_op_neg_f); -#endif - } else { -#ifdef ARM_USE_VFP - o4(0xEEB17B47); // fnegd d7, d7 -#else - callRuntime((void*) runtime_op_neg_d); -#endif - } - break; - case OP_BIT_NOT: - error("Can't apply '~' operator to a float or double."); - break; - default: - error("Unknown unary op %d\n", op); - break; - } - break; - default: - error("genUnaryOp unsupported type"); - break; - } - } - - virtual void pushR0() { - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); - -#ifdef ARM_USE_VFP - switch (r0ct ) { - case TY_FLOAT: - o4(0xED6D7A01); // fstmfds sp!,{s15} - mStackUse += 4; - break; - case TY_DOUBLE: - o4(0xED2D7B02); // fstmfdd sp!,{d7} - mStackUse += 8; - break; - default: - o4(0xE92D0001); // stmfd sp!,{r0} - mStackUse += 4; - } -#else - - if (r0ct != TY_DOUBLE) { - o4(0xE92D0001); // stmfd sp!,{r0} - mStackUse += 4; - } else { - o4(0xE92D0003); // stmfd sp!,{r0,r1} - mStackUse += 8; - } -#endif - pushType(); - LOG_STACK("pushR0: %d\n", mStackUse); - } - - virtual void over() { - // We know it's only used for int-ptr ops (++/--) - - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); - - Type* pTOSType = getTOSType(); - TypeTag tosct = collapseType(pTOSType->tag); - - assert (r0ct == TY_INT && tosct == TY_INT); - - o4(0xE8BD0002); // ldmfd sp!,{r1} - o4(0xE92D0001); // stmfd sp!,{r0} - o4(0xE92D0002); // stmfd sp!,{r1} - overType(); - mStackUse += 4; - } - - virtual void popR0() { - Type* pTOSType = getTOSType(); - TypeTag tosct = collapseType(pTOSType->tag); -#ifdef ARM_USE_VFP - if (tosct == TY_FLOAT || tosct == TY_DOUBLE) { - error("Unsupported popR0 float/double"); - } -#endif - switch (tosct){ - case TY_INT: - case TY_FLOAT: - o4(0xE8BD0001); // ldmfd sp!,{r0} - mStackUse -= 4; - break; - case TY_DOUBLE: - o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0 - mStackUse -= 8; - break; - default: - error("Can't pop this type."); - break; - } - popType(); - LOG_STACK("popR0: %d\n", mStackUse); - } - - virtual void storeR0ToTOS() { - Type* pPointerType = getTOSType(); - assert(pPointerType->tag == TY_POINTER); - Type* pDestType = pPointerType->pHead; - convertR0(pDestType); - o4(0xE8BD0004); // ldmfd sp!,{r2} - popType(); - mStackUse -= 4; - switch (pDestType->tag) { - case TY_POINTER: - case TY_INT: - o4(0xE5820000); // str r0, [r2] - break; - case TY_FLOAT: -#ifdef ARM_USE_VFP - o4(0xEDC27A00); // fsts s15, [r2, #0] -#else - o4(0xE5820000); // str r0, [r2] -#endif - break; - case TY_SHORT: - o4(0xE1C200B0); // strh r0, [r2] - break; - case TY_CHAR: - o4(0xE5C20000); // strb r0, [r2] - break; - case TY_DOUBLE: -#ifdef ARM_USE_VFP - o4(0xED827B00); // fstd d7, [r2, #0] -#else - o4(0xE1C200F0); // strd r0, [r2] -#endif - break; - case TY_STRUCT: - { - int size = sizeOf(pDestType); - if (size > 0) { - liReg(size, 1); - callRuntime((void*) runtime_structCopy); - } - } - break; - default: - error("storeR0ToTOS: unimplemented type %d", - pDestType->tag); - break; - } - setR0Type(pDestType); - } - - virtual void loadR0FromR0() { - Type* pPointerType = getR0Type(); - assert(pPointerType->tag == TY_POINTER); - Type* pNewType = pPointerType->pHead; - TypeTag tag = pNewType->tag; - switch (tag) { - case TY_POINTER: - case TY_INT: - o4(0xE5900000); // ldr r0, [r0] - break; - case TY_FLOAT: -#ifdef ARM_USE_VFP - o4(0xEDD07A00); // flds s15, [r0, #0] -#else - o4(0xE5900000); // ldr r0, [r0] -#endif - break; - case TY_SHORT: - o4(0xE1D000F0); // ldrsh r0, [r0] - break; - case TY_CHAR: - o4(0xE5D00000); // ldrb r0, [r0] - break; - case TY_DOUBLE: -#ifdef ARM_USE_VFP - o4(0xED907B00); // fldd d7, [r0, #0] -#else - o4(0xE1C000D0); // ldrd r0, [r0] -#endif - break; - case TY_ARRAY: - pNewType = pNewType->pTail; - break; - case TY_STRUCT: - break; - default: - error("loadR0FromR0: unimplemented type %d", tag); - break; - } - setR0Type(pNewType); - } - - virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { - if (ea > -LOCAL && ea < LOCAL) { - // Local, fp relative - - size_t immediate = 0; - bool inRange = false; - if (ea < 0) { - inRange = encode12BitImmediate(-ea, &immediate); - o4(0xE24B0000 | immediate); // sub r0, fp, #ea - } else { - inRange = encode12BitImmediate(ea, &immediate); - o4(0xE28B0000 | immediate); // add r0, fp, #ea - } - if (! inRange) { - error("Offset out of range: %08x", ea); - } - } else { - // Global, absolute. - o4(0xE59F0000); // ldr r0, .L1 - o4(0xEA000000); // b .L99 - o4(ea); // .L1: .word 0 - // .L99: - } - setR0Type(pPointerType, et); - } - - virtual int leaForward(int ea, Type* pPointerType) { - setR0Type(pPointerType); - int result = ea; - int pc = getPC(); - int offset = 0; - if (ea) { - offset = (pc - ea - 8) >> 2; - if ((offset & 0xffff) != offset) { - error("function forward reference out of bounds"); - } - } else { - offset = 0; - } - o4(0xE59F0000 | offset); // ldr r0, .L1 - - if (ea == 0) { - o4(0xEA000000); // b .L99 - result = getPC(); - o4(ea); // .L1: .word 0 - // .L99: - } - return result; - } - - virtual void convertR0Imp(Type* pType, bool isCast){ - Type* pR0Type = getR0Type(); - if (isPointerType(pType) && isPointerType(pR0Type)) { - Type* pA = pR0Type; - Type* pB = pType; - // Array decays to pointer - if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) { - pA = pA->pTail; - } - if (! (typeEqual(pA, pB) - || pB->pHead->tag == TY_VOID - || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast) - )) { - error("Incompatible pointer or array types"); - } - } else if (bitsSame(pType, pR0Type)) { - // do nothing special - } else { - TypeTag r0Tag = collapseType(pR0Type->tag); - TypeTag destTag = collapseType(pType->tag); - if (r0Tag == TY_INT) { - if (destTag == TY_FLOAT) { -#ifdef ARM_USE_VFP - o4(0xEE070A90); // fmsr s15, r0 - o4(0xEEF87AE7); // fsitos s15, s15 - -#else - callRuntime((void*) runtime_int_to_float); -#endif - } else { - assert(destTag == TY_DOUBLE); -#ifdef ARM_USE_VFP - o4(0xEE070A90); // fmsr s15, r0 - o4(0xEEB87BE7); // fsitod d7, s15 - -#else - callRuntime((void*) runtime_int_to_double); -#endif - } - } else if (r0Tag == TY_FLOAT) { - if (destTag == TY_INT) { -#ifdef ARM_USE_VFP - o4(0xEEFD7AE7); // ftosizs s15, s15 - o4(0xEE170A90); // fmrs r0, s15 -#else - callRuntime((void*) runtime_float_to_int); -#endif - } else { - assert(destTag == TY_DOUBLE); -#ifdef ARM_USE_VFP - o4(0xEEB77AE7); // fcvtds d7, s15 -#else - callRuntime((void*) runtime_float_to_double); -#endif - } - } else { - if (r0Tag == TY_DOUBLE) { - if (destTag == TY_INT) { -#ifdef ARM_USE_VFP - o4(0xEEFD7BC7); // ftosizd s15, d7 - o4(0xEE170A90); // fmrs r0, s15 -#else - callRuntime((void*) runtime_double_to_int); -#endif - } else { - if(destTag == TY_FLOAT) { -#ifdef ARM_USE_VFP - o4(0xEEF77BC7); // fcvtsd s15, d7 -#else - callRuntime((void*) runtime_double_to_float); -#endif - } else { - incompatibleTypes(pR0Type, pType); - } - } - } else { - incompatibleTypes(pR0Type, pType); - } - } - } - setR0Type(pType); - } - - virtual int beginFunctionCallArguments() { - int pc = getPC(); - o4(0xE24DDF00); // Placeholder sub sp, sp, #0 - return pc; - } - - virtual size_t storeR0ToArg(int l, Type* pArgType) { - convertR0(pArgType); - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); -#ifdef ARM_USE_VFP - switch(r0ct) { - case TY_INT: - if (l < 0 || l > 4096-4) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xE58D0000 | l); // str r0, [sp, #l] - return 4; - case TY_FLOAT: - if (l < 0 || l > 1020 || (l & 3)) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xEDCD7A00 | (l >> 2)); // fsts s15, [sp, #l] - return 4; - case TY_DOUBLE: { - // Align to 8 byte boundary - int l2 = (l + 7) & ~7; - if (l2 < 0 || l2 > 1020 || (l2 & 3)) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xED8D7B00 | (l2 >> 2)); // fstd d7, [sp, #l2] - return (l2 - l) + 8; - } - default: - assert(false); - return 0; - } -#else - switch(r0ct) { - case TY_INT: - case TY_FLOAT: - if (l < 0 || l > 4096-4) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xE58D0000 + l); // str r0, [sp, #l] - return 4; - case TY_DOUBLE: { - // Align to 8 byte boundary - int l2 = (l + 7) & ~7; - if (l2 < 0 || l2 > 4096-8) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xE58D0000 + l2); // str r0, [sp, #l] - o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4] - return (l2 - l) + 8; - } - default: - assert(false); - return 0; - } -#endif - } - - virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { - int argumentStackUse = l; - // Have to calculate register arg count from actual stack size, - // in order to properly handle ... functions. - int regArgCount = l >> 2; - if (regArgCount > 4) { - regArgCount = 4; - } - if (regArgCount > 0) { - argumentStackUse -= regArgCount * 4; - o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{} - } - mStackUse += argumentStackUse; - - // Align stack. - int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT) - * STACK_ALIGNMENT); - mStackAlignmentAdjustment = 0; - if (missalignment > 0) { - mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment; - } - l += mStackAlignmentAdjustment; - - if (l < 0 || l > 0x3FC) { - error("L out of range for stack adjustment: 0x%08x", l); - } - flush(); - * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2 - mStackUse += mStackAlignmentAdjustment; - LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n", - mStackUse, mStackAlignmentAdjustment); - } - - virtual int callForward(int symbol, Type* pFunc) { - setR0Type(pFunc->pHead); - // Forward calls are always short (local) - int pc = getPC(); - o4(0xEB000000 | encodeAddress(symbol)); - return pc; - } - - virtual void callIndirect(int l, Type* pFunc) { - assert(pFunc->tag == TY_FUNC); - popType(); // Get rid of indirect fn pointer type - int argCount = l >> 2; - int poppedArgs = argCount > 4 ? 4 : argCount; - int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment; - if (adjustedL < 0 || adjustedL > 4096-4) { - error("l out of range for stack offset: 0x%08x", l); - } - o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL] - o4(0xE12FFF3C); // blx r12 - Type* pReturnType = pFunc->pHead; - setR0Type(pReturnType); -#ifdef ARM_USE_VFP - switch(pReturnType->tag) { - case TY_FLOAT: - o4(0xEE070A90); // fmsr s15, r0 - break; - case TY_DOUBLE: - o4(0xEC410B17); // fmdrr d7, r0, r1 - break; - default: - break; - } -#endif - } - - virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { - int argCount = l >> 2; - // Have to calculate register arg count from actual stack size, - // in order to properly handle ... functions. - int regArgCount = l >> 2; - if (regArgCount > 4) { - regArgCount = 4; - } - int stackArgs = argCount - regArgCount; - int stackUse = stackArgs + (isIndirect ? 1 : 0) - + (mStackAlignmentAdjustment >> 2); - if (stackUse) { - if (stackUse < 0 || stackUse > 255) { - error("L out of range for stack adjustment: 0x%08x", l); - } - o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2 - mStackUse -= stackUse * 4; - LOG_STACK("adjustStackAfterCall: %d\n", mStackUse); - } - } - - virtual int jumpOffset() { - return 8; - } - - /* output a symbol and patch all calls to it */ - virtual void gsym(int t) { - int n; - int base = getBase(); - int pc = getPC(); - while (t) { - int data = * (int*) t; - int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2); - if (decodedOffset == 0) { - n = 0; - } else { - n = base + decodedOffset; /* next value */ - } - *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK) - | encodeRelAddress(pc - t - 8); - t = n; - } - } - - /* output a symbol and patch all calls to it */ - virtual void resolveForward(int t) { - if (t) { - int pc = getPC(); - *(int *) t = pc; - } - } - - virtual int finishCompile() { -#if defined(__arm__) - const long base = long(getBase()); - const long curr = long(getPC()); - int err = cacheflush(base, curr, 0); - return err; -#else - return 0; -#endif - } - - /** - * alignment (in bytes) for this type of data - */ - virtual size_t alignmentOf(Type* pType){ - switch(pType->tag) { - case TY_CHAR: - return 1; - case TY_SHORT: - return 2; - case TY_DOUBLE: - return 8; - case TY_ARRAY: - return alignmentOf(pType->pHead); - case TY_STRUCT: - return pType->pHead->alignment & 0x7fffffff; - case TY_FUNC: - error("alignment of func not supported"); - return 1; - default: - return 4; - } - } - - /** - * Array element alignment (in bytes) for this type of data. - */ - virtual size_t sizeOf(Type* pType){ - switch(pType->tag) { - case TY_INT: - return 4; - case TY_SHORT: - return 2; - case TY_CHAR: - return 1; - case TY_FLOAT: - return 4; - case TY_DOUBLE: - return 8; - case TY_POINTER: - return 4; - case TY_ARRAY: - return pType->length * sizeOf(pType->pHead); - case TY_STRUCT: - return pType->pHead->length; - default: - error("Unsupported type %d", pType->tag); - return 0; - } - } - - private: - - static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff; - - /** Encode a relative address that might also be - * a label. - */ - int encodeAddress(int value) { - int base = getBase(); - if (value >= base && value <= getPC() ) { - // This is a label, encode it relative to the base. - value = value - base; - } - return encodeRelAddress(value); - } - - int encodeRelAddress(int value) { - return BRANCH_REL_ADDRESS_MASK & (value >> 2); - } - - int calcRegArgCount(Type* pDecl) { - int reg = 0; - Type* pArgs = pDecl->pTail; - while (pArgs && reg < 4) { - Type* pArg = pArgs->pHead; - if ( pArg->tag == TY_DOUBLE) { - int evenReg = (reg + 1) & ~1; - if (evenReg >= 4) { - break; - } - reg = evenReg + 2; - } else { - reg++; - } - pArgs = pArgs->pTail; - } - return reg; - } - - void setupIntPtrArgs() { - o4(0xE8BD0002); // ldmfd sp!,{r1} - mStackUse -= 4; - popType(); - } - - /* Pop TOS to R1 (use s14 if VFP) - * Make sure both R0 and TOS are floats. (Could be ints) - * We know that at least one of R0 and TOS is already a float - */ - void setupFloatArgs() { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = collapseType(pR0Type->tag); - TypeTag tagTOS = collapseType(pTOSType->tag); - if (tagR0 != TY_FLOAT) { - assert(tagR0 == TY_INT); -#ifdef ARM_USE_VFP - o4(0xEE070A90); // fmsr s15, r0 - o4(0xEEF87AE7); // fsitos s15, s15 -#else - callRuntime((void*) runtime_int_to_float); -#endif - } - if (tagTOS != TY_FLOAT) { - assert(tagTOS == TY_INT); - assert(tagR0 == TY_FLOAT); -#ifdef ARM_USE_VFP - o4(0xECBD7A01); // fldmfds sp!, {s14} - o4(0xEEB87AC7); // fsitos s14, s14 -#else - o4(0xE92D0001); // stmfd sp!,{r0} // push R0 - o4(0xE59D0004); // ldr r0, [sp, #4] - callRuntime((void*) runtime_int_to_float); - o4(0xE1A01000); // mov r1, r0 - o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0 - o4(0xE28DD004); // add sp, sp, #4 // Pop sp -#endif - } else { - // Pop TOS -#ifdef ARM_USE_VFP - o4(0xECBD7A01); // fldmfds sp!, {s14} - -#else - o4(0xE8BD0002); // ldmfd sp!,{r1} -#endif - } - mStackUse -= 4; - popType(); - } - - /* Pop TOS into R2..R3 (use D6 if VFP) - * Make sure both R0 and TOS are doubles. Could be floats or ints. - * We know that at least one of R0 and TOS are already a double. - */ - - void setupDoubleArgs() { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = collapseType(pR0Type->tag); - TypeTag tagTOS = collapseType(pTOSType->tag); - if (tagR0 != TY_DOUBLE) { - if (tagR0 == TY_INT) { -#ifdef ARM_USE_VFP - o4(0xEE070A90); // fmsr s15, r0 - o4(0xEEB87BE7); // fsitod d7, s15 - -#else - callRuntime((void*) runtime_int_to_double); -#endif - } else { - assert(tagR0 == TY_FLOAT); -#ifdef ARM_USE_VFP - o4(0xEEB77AE7); // fcvtds d7, s15 -#else - callRuntime((void*) runtime_float_to_double); -#endif - } - } - if (tagTOS != TY_DOUBLE) { -#ifdef ARM_USE_VFP - if (tagTOS == TY_INT) { - o4(0xECFD6A01); // fldmfds sp!,{s13} - o4(0xEEB86BE6); // fsitod d6, s13 - } else { - assert(tagTOS == TY_FLOAT); - o4(0xECFD6A01); // fldmfds sp!,{s13} - o4(0xEEB76AE6); // fcvtds d6, s13 - } -#else - o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1 - o4(0xE59D0008); // ldr r0, [sp, #8] - if (tagTOS == TY_INT) { - callRuntime((void*) runtime_int_to_double); - } else { - assert(tagTOS == TY_FLOAT); - callRuntime((void*) runtime_float_to_double); - } - o4(0xE1A02000); // mov r2, r0 - o4(0xE1A03001); // mov r3, r1 - o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0 - o4(0xE28DD004); // add sp, sp, #4 // Pop sp -#endif - mStackUse -= 4; - } else { -#ifdef ARM_USE_VFP - o4(0xECBD6B02); // fldmfdd sp!, {d6} -#else - o4(0xE8BD000C); // ldmfd sp!,{r2,r3} -#endif - mStackUse -= 8; - } - popType(); - } - - void liReg(int t, int reg) { - assert(reg >= 0 && reg < 16); - int rN = (reg & 0xf) << 12; - size_t encodedImmediate; - if (encode12BitImmediate(t, &encodedImmediate)) { - o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0 - } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) { - // mvn means move constant ^ ~0 - o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0 - } else { - o4(0xE51F0000 | rN); // ldr rN, .L3 - o4(0xEA000000); // b .L99 - o4(t); // .L3: .word 0 - // .L99: - } - } - - void incompatibleTypes(Type* pR0Type, Type* pType) { - error("Incompatible types old: %d new: %d", pR0Type->tag, pType->tag); - } - - void callRuntime(void* fn) { - o4(0xE59FC000); // ldr r12, .L1 - o4(0xEA000000); // b .L99 - o4((int) fn); //.L1: .word fn - o4(0xE12FFF3C); //.L99: blx r12 - } - - // Integer math: - - static int runtime_DIV(int b, int a) { - return a / b; - } - - static int runtime_MOD(int b, int a) { - return a % b; - } - - static void runtime_structCopy(void* src, size_t size, void* dest) { - memcpy(dest, src, size); - } - -#ifndef ARM_USE_VFP - - // Comparison to zero - - static int runtime_is_non_zero_f(float a) { - return a != 0; - } - - static int runtime_is_non_zero_d(double a) { - return a != 0; - } - - // Comparison to zero - - static int runtime_is_zero_f(float a) { - return a == 0; - } - - static int runtime_is_zero_d(double a) { - return a == 0; - } - - // Type conversion - - static int runtime_float_to_int(float a) { - return (int) a; - } - - static double runtime_float_to_double(float a) { - return (double) a; - } - - static int runtime_double_to_int(double a) { - return (int) a; - } - - static float runtime_double_to_float(double a) { - return (float) a; - } - - static float runtime_int_to_float(int a) { - return (float) a; - } - - static double runtime_int_to_double(int a) { - return (double) a; - } - - // Comparisons float - - static int runtime_cmp_eq_ff(float b, float a) { - return a == b; - } - - static int runtime_cmp_ne_ff(float b, float a) { - return a != b; - } - - static int runtime_cmp_lt_ff(float b, float a) { - return a < b; - } - - static int runtime_cmp_le_ff(float b, float a) { - return a <= b; - } - - static int runtime_cmp_ge_ff(float b, float a) { - return a >= b; - } - - static int runtime_cmp_gt_ff(float b, float a) { - return a > b; - } - - // Comparisons double - - static int runtime_cmp_eq_dd(double b, double a) { - return a == b; - } - - static int runtime_cmp_ne_dd(double b, double a) { - return a != b; - } - - static int runtime_cmp_lt_dd(double b, double a) { - return a < b; - } - - static int runtime_cmp_le_dd(double b, double a) { - return a <= b; - } - - static int runtime_cmp_ge_dd(double b, double a) { - return a >= b; - } - - static int runtime_cmp_gt_dd(double b, double a) { - return a > b; - } - - // Math float - - static float runtime_op_add_ff(float b, float a) { - return a + b; - } - - static float runtime_op_sub_ff(float b, float a) { - return a - b; - } - - static float runtime_op_mul_ff(float b, float a) { - return a * b; - } - - static float runtime_op_div_ff(float b, float a) { - return a / b; - } - - static float runtime_op_neg_f(float a) { - return -a; - } - - // Math double - - static double runtime_op_add_dd(double b, double a) { - return a + b; - } - - static double runtime_op_sub_dd(double b, double a) { - return a - b; - } - - static double runtime_op_mul_dd(double b, double a) { - return a * b; - } - - static double runtime_op_div_dd(double b, double a) { - return a / b; - } - - static double runtime_op_neg_d(double a) { - return -a; - } - -#endif - - static const int STACK_ALIGNMENT = 8; - int mStackUse; - // This variable holds the amount we adjusted the stack in the most - // recent endFunctionCallArguments call. It's examined by the - // following adjustStackAfterCall call. - int mStackAlignmentAdjustment; - }; - -#endif // PROVIDE_ARM_CODEGEN - -#ifdef PROVIDE_X86_CODEGEN - - class X86CodeGenerator : public CodeGenerator { - public: - X86CodeGenerator() {} - virtual ~X86CodeGenerator() {} - - /* returns address to patch with local variable size - */ - virtual int functionEntry(Type* pDecl) { - o(0xe58955); /* push %ebp, mov %esp, %ebp */ - return oad(0xec81, 0); /* sub $xxx, %esp */ - } - - virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { - o(0xc3c9); /* leave, ret */ - *(int *) localVariableAddress = localVariableSize; /* save local variables */ - } - - /* load immediate value */ - virtual void li(int i) { - oad(0xb8, i); /* mov $xx, %eax */ - setR0Type(mkpInt); - } - - virtual void loadFloat(int address, Type* pType) { - setR0Type(pType); - switch (pType->tag) { - case TY_FLOAT: - oad(0x05D9, address); // flds - break; - case TY_DOUBLE: - oad(0x05DD, address); // fldl - break; - default: - assert(false); - break; - } - } - - virtual void addStructOffsetR0(int offset, Type* pType) { - if (offset) { - oad(0x05, offset); // addl offset, %eax - } - setR0Type(pType, ET_LVALUE); - } - - virtual int gjmp(int t) { - return psym(0xe9, t); - } - - /* l = 0: je, l == 1: jne */ - virtual int gtst(bool l, int t) { - Type* pR0Type = getR0Type(); - TypeTag tagR0 = pR0Type->tag; - bool isFloatR0 = isFloatTag(tagR0); - if (isFloatR0) { - o(0xeed9); // fldz - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x9e); // sahf - } else { - o(0xc085); // test %eax, %eax - } - // Use two output statements to generate one instruction. - o(0x0f); // je/jne xxx - return psym(0x84 + l, t); - } - - virtual void gcmp(int op) { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = pR0Type->tag; - TypeTag tagTOS = pTOSType->tag; - bool isFloatR0 = isFloatTag(tagR0); - bool isFloatTOS = isFloatTag(tagTOS); - if (!isFloatR0 && !isFloatTOS) { - int t = decodeOp(op); - o(0x59); /* pop %ecx */ - o(0xc139); /* cmp %eax,%ecx */ - li(0); - o(0x0f); /* setxx %al */ - o(t + 0x90); - o(0xc0); - popType(); - } else { - setupFloatOperands(); - switch (op) { - case OP_EQUALS: - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x9e); // sahf - o(0xc0940f); // sete %al - o(0xc29b0f); // setnp %dl - o(0xd021); // andl %edx, %eax - break; - case OP_NOT_EQUALS: - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x9e); // sahf - o(0xc0950f); // setne %al - o(0xc29a0f); // setp %dl - o(0xd009); // orl %edx, %eax - break; - case OP_GREATER_EQUAL: - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x05c4f6); // testb $5, %ah - o(0xc0940f); // sete %al - break; - case OP_LESS: - o(0xc9d9); // fxch %st(1) - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x9e); // sahf - o(0xc0970f); // seta %al - break; - case OP_LESS_EQUAL: - o(0xc9d9); // fxch %st(1) - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x9e); // sahf - o(0xc0930f); // setea %al - break; - case OP_GREATER: - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x45c4f6); // testb $69, %ah - o(0xc0940f); // sete %al - break; - default: - error("Unknown comparison op"); - } - o(0xc0b60f); // movzbl %al, %eax - } - setR0Type(mkpInt); - } - - virtual void genOp(int op) { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = pR0Type->tag; - TypeTag tagTOS = pTOSType->tag; - bool isFloatR0 = isFloatTag(tagR0); - bool isFloatTOS = isFloatTag(tagTOS); - if (!isFloatR0 && !isFloatTOS) { - bool isPtrR0 = isPointerTag(tagR0); - bool isPtrTOS = isPointerTag(tagTOS); - if (isPtrR0 || isPtrTOS) { - if (isPtrR0 && isPtrTOS) { - if (op != OP_MINUS) { - error("Unsupported pointer-pointer operation %d.", op); - } - if (! typeEqual(pR0Type, pTOSType)) { - error("Incompatible pointer types for subtraction."); - } - o(0x59); /* pop %ecx */ - o(decodeOp(op)); - popType(); - setR0Type(mkpInt); - int size = sizeOf(pR0Type->pHead); - if (size != 1) { - pushR0(); - li(size); - // TODO: Optimize for power-of-two. - genOp(OP_DIV); - } - } else { - if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) { - error("Unsupported pointer-scalar operation %d", op); - } - Type* pPtrType = getPointerArithmeticResultType( - pR0Type, pTOSType); - o(0x59); /* pop %ecx */ - int size = sizeOf(pPtrType->pHead); - if (size != 1) { - // TODO: Optimize for power-of-two. - if (isPtrR0) { - oad(0xC969, size); // imull $size, %ecx - } else { - oad(0xC069, size); // mul $size, %eax - } - } - o(decodeOp(op)); - popType(); - setR0Type(pPtrType); - } - } else { - o(0x59); /* pop %ecx */ - o(decodeOp(op)); - if (op == OP_MOD) - o(0x92); /* xchg %edx, %eax */ - popType(); - } - } else { - Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType; - setupFloatOperands(); - // Both float. x87 R0 == left hand, x87 R1 == right hand - switch (op) { - case OP_MUL: - o(0xc9de); // fmulp - break; - case OP_DIV: - o(0xf1de); // fdivp - break; - case OP_PLUS: - o(0xc1de); // faddp - break; - case OP_MINUS: - o(0xe1de); // fsubp - break; - default: - error("Unsupported binary floating operation."); - break; - } - setR0Type(pResultType); - } - } - - virtual void gUnaryCmp(int op) { - if (op != OP_LOGICAL_NOT) { - error("Unknown unary cmp %d", op); - } else { - Type* pR0Type = getR0Type(); - TypeTag tag = collapseType(pR0Type->tag); - switch(tag) { - case TY_INT: { - oad(0xb9, 0); /* movl $0, %ecx */ - int t = decodeOp(op); - o(0xc139); /* cmp %eax,%ecx */ - li(0); - o(0x0f); /* setxx %al */ - o(t + 0x90); - o(0xc0); - } - break; - case TY_FLOAT: - case TY_DOUBLE: - o(0xeed9); // fldz - o(0xe9da); // fucompp - o(0xe0df); // fnstsw %ax - o(0x9e); // sahf - o(0xc0950f); // setne %al - o(0xc29a0f); // setp %dl - o(0xd009); // orl %edx, %eax - o(0xc0b60f); // movzbl %al, %eax - o(0x01f083); // xorl $1, %eax - break; - default: - error("gUnaryCmp unsupported type"); - break; - } - } - setR0Type(mkpInt); - } - - virtual void genUnaryOp(int op) { - Type* pR0Type = getR0Type(); - TypeTag tag = collapseType(pR0Type->tag); - switch(tag) { - case TY_INT: - oad(0xb9, 0); /* movl $0, %ecx */ - o(decodeOp(op)); - break; - case TY_FLOAT: - case TY_DOUBLE: - switch (op) { - case OP_MINUS: - o(0xe0d9); // fchs - break; - case OP_BIT_NOT: - error("Can't apply '~' operator to a float or double."); - break; - default: - error("Unknown unary op %d\n", op); - break; - } - break; - default: - error("genUnaryOp unsupported type"); - break; - } - } - - virtual void pushR0() { - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); - switch(r0ct) { - case TY_INT: - o(0x50); /* push %eax */ - break; - case TY_FLOAT: - o(0x50); /* push %eax */ - o(0x241cd9); // fstps 0(%esp) - break; - case TY_DOUBLE: - o(0x50); /* push %eax */ - o(0x50); /* push %eax */ - o(0x241cdd); // fstpl 0(%esp) - break; - default: - error("pushR0 unsupported type %d", r0ct); - break; - } - pushType(); - } - - virtual void over() { - // We know it's only used for int-ptr ops (++/--) - - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); - - Type* pTOSType = getTOSType(); - TypeTag tosct = collapseType(pTOSType->tag); - - assert (r0ct == TY_INT && tosct == TY_INT); - - o(0x59); /* pop %ecx */ - o(0x50); /* push %eax */ - o(0x51); /* push %ecx */ - - overType(); - } - - virtual void popR0() { - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); - switch(r0ct) { - case TY_INT: - o(0x58); /* popl %eax */ - break; - case TY_FLOAT: - o(0x2404d9); // flds (%esp) - o(0x58); /* popl %eax */ - break; - case TY_DOUBLE: - o(0x2404dd); // fldl (%esp) - o(0x58); /* popl %eax */ - o(0x58); /* popl %eax */ - break; - default: - error("popR0 unsupported type %d", r0ct); - break; - } - popType(); - } - - virtual void storeR0ToTOS() { - Type* pPointerType = getTOSType(); - assert(pPointerType->tag == TY_POINTER); - Type* pTargetType = pPointerType->pHead; - convertR0(pTargetType); - o(0x59); /* pop %ecx */ - popType(); - switch (pTargetType->tag) { - case TY_POINTER: - case TY_INT: - o(0x0189); /* movl %eax/%al, (%ecx) */ - break; - case TY_SHORT: - o(0x018966); /* movw %ax, (%ecx) */ - break; - case TY_CHAR: - o(0x0188); /* movl %eax/%al, (%ecx) */ - break; - case TY_FLOAT: - o(0x19d9); /* fstps (%ecx) */ - break; - case TY_DOUBLE: - o(0x19dd); /* fstpl (%ecx) */ - break; - case TY_STRUCT: - { - // TODO: use alignment information to use movsw/movsl instead of movsb - int size = sizeOf(pTargetType); - if (size > 0) { - o(0x9c); // pushf - o(0x57); // pushl %edi - o(0x56); // pushl %esi - o(0xcf89); // movl %ecx, %edi - o(0xc689); // movl %eax, %esi - oad(0xb9, size); // mov #size, %ecx - o(0xfc); // cld - o(0xf3); // rep - o(0xa4); // movsb - o(0x5e); // popl %esi - o(0x5f); // popl %edi - o(0x9d); // popf - } - } - break; - default: - error("storeR0ToTOS: unsupported type %d", - pTargetType->tag); - break; - } - setR0Type(pTargetType); - } - - virtual void loadR0FromR0() { - Type* pPointerType = getR0Type(); - assert(pPointerType->tag == TY_POINTER); - Type* pNewType = pPointerType->pHead; - TypeTag tag = pNewType->tag; - switch (tag) { - case TY_POINTER: - case TY_INT: - o2(0x008b); /* mov (%eax), %eax */ - break; - case TY_SHORT: - o(0xbf0f); /* movswl (%eax), %eax */ - ob(0); - break; - case TY_CHAR: - o(0xbe0f); /* movsbl (%eax), %eax */ - ob(0); /* add zero in code */ - break; - case TY_FLOAT: - o2(0x00d9); // flds (%eax) - break; - case TY_DOUBLE: - o2(0x00dd); // fldl (%eax) - break; - case TY_ARRAY: - pNewType = pNewType->pTail; - break; - case TY_STRUCT: - break; - default: - error("loadR0FromR0: unsupported type %d", tag); - break; - } - setR0Type(pNewType); - } - - virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { - gmov(10, ea); /* leal EA, %eax */ - setR0Type(pPointerType, et); - } - - virtual int leaForward(int ea, Type* pPointerType) { - oad(0xb8, ea); /* mov $xx, %eax */ - setR0Type(pPointerType); - return getPC() - 4; - } - - virtual void convertR0Imp(Type* pType, bool isCast){ - Type* pR0Type = getR0Type(); - if (pR0Type == NULL) { - assert(false); - setR0Type(pType); - return; - } - if (isPointerType(pType) && isPointerType(pR0Type)) { - Type* pA = pR0Type; - Type* pB = pType; - // Array decays to pointer - if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) { - pA = pA->pTail; - } - if (! (typeEqual(pA, pB) - || pB->pHead->tag == TY_VOID - || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast) - )) { - error("Incompatible pointer or array types"); - } - } else if (bitsSame(pType, pR0Type)) { - // do nothing special - } else if (isFloatType(pType) && isFloatType(pR0Type)) { - // do nothing special, both held in same register on x87. - } else { - TypeTag r0Tag = collapseType(pR0Type->tag); - TypeTag destTag = collapseType(pType->tag); - if (r0Tag == TY_INT && isFloatTag(destTag)) { - // Convert R0 from int to float - o(0x50); // push %eax - o(0x2404DB); // fildl 0(%esp) - o(0x58); // pop %eax - } else if (isFloatTag(r0Tag) && destTag == TY_INT) { - // Convert R0 from float to int. Complicated because - // need to save and restore the rounding mode. - o(0x50); // push %eax - o(0x50); // push %eax - o(0x02247cD9); // fnstcw 2(%esp) - o(0x2444b70f); // movzwl 2(%esp), %eax - o(0x02); - o(0x0cb4); // movb $12, %ah - o(0x24048966); // movw %ax, 0(%esp) - o(0x242cd9); // fldcw 0(%esp) - o(0x04245cdb); // fistpl 4(%esp) - o(0x02246cd9); // fldcw 2(%esp) - o(0x58); // pop %eax - o(0x58); // pop %eax - } else { - error("Incompatible types old: %d new: %d", - pR0Type->tag, pType->tag); - } - } - setR0Type(pType); - } - - virtual int beginFunctionCallArguments() { - return oad(0xec81, 0); /* sub $xxx, %esp */ - } - - virtual size_t storeR0ToArg(int l, Type* pArgType) { - convertR0(pArgType); - Type* pR0Type = getR0Type(); - TypeTag r0ct = collapseType(pR0Type->tag); - switch(r0ct) { - case TY_INT: - oad(0x248489, l); /* movl %eax, xxx(%esp) */ - return 4; - case TY_FLOAT: - oad(0x249CD9, l); /* fstps xxx(%esp) */ - return 4; - case TY_DOUBLE: - oad(0x249CDD, l); /* fstpl xxx(%esp) */ - return 8; - default: - assert(false); - return 0; - } - } - - virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { - * (int*) a = l; - } - - virtual int callForward(int symbol, Type* pFunc) { - assert(pFunc->tag == TY_FUNC); - setR0Type(pFunc->pHead); - return psym(0xe8, symbol); /* call xxx */ - } - - virtual void callIndirect(int l, Type* pFunc) { - assert(pFunc->tag == TY_FUNC); - popType(); // Get rid of indirect fn pointer type - setR0Type(pFunc->pHead); - oad(0x2494ff, l); /* call *xxx(%esp) */ - } - - virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { - assert(pDecl->tag == TY_FUNC); - if (isIndirect) { - l += 4; - } - if (l > 0) { - oad(0xc481, l); /* add $xxx, %esp */ - } - } - - virtual int jumpOffset() { - return 5; - } - - /* output a symbol and patch all calls to it */ - virtual void gsym(int t) { - int n; - int pc = getPC(); - while (t) { - n = *(int *) t; /* next value */ - *(int *) t = pc - t - 4; - t = n; - } - } - - /* output a symbol and patch all calls to it, using absolute address */ - virtual void resolveForward(int t) { - int n; - int pc = getPC(); - while (t) { - n = *(int *) t; /* next value */ - *(int *) t = pc; - t = n; - } - } - - virtual int finishCompile() { - size_t pagesize = 4096; - size_t base = (size_t) getBase() & ~ (pagesize - 1); - size_t top = ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1); - int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC); - if (err) { - error("mprotect() failed: %d", errno); - } - return err; - } - - /** - * Alignment (in bytes) for this type of data - */ - virtual size_t alignmentOf(Type* pType){ - switch (pType->tag) { - case TY_CHAR: - return 1; - case TY_SHORT: - return 2; - case TY_ARRAY: - return alignmentOf(pType->pHead); - case TY_STRUCT: - return pType->pHead->alignment & 0x7fffffff; - case TY_FUNC: - error("alignment of func not supported"); - return 1; - default: - return 4; - } - } - - /** - * Array element alignment (in bytes) for this type of data. - */ - virtual size_t sizeOf(Type* pType){ - switch(pType->tag) { - case TY_INT: - return 4; - case TY_SHORT: - return 2; - case TY_CHAR: - return 1; - case TY_FLOAT: - return 4; - case TY_DOUBLE: - return 8; - case TY_POINTER: - return 4; - case TY_ARRAY: - return pType->length * sizeOf(pType->pHead); - case TY_STRUCT: - return pType->pHead->length; - default: - error("Unsupported type %d", pType->tag); - return 0; - } - } - - private: - - /** Output 1 to 4 bytes. - * - */ - void o(int n) { - /* cannot use unsigned, so we must do a hack */ - while (n && n != -1) { - ob(n & 0xff); - n = n >> 8; - } - } - - /* Output exactly 2 bytes - */ - void o2(int n) { - ob(n & 0xff); - ob(0xff & (n >> 8)); - } - - /* psym is used to put an instruction with a data field which is a - reference to a symbol. It is in fact the same as oad ! */ - int psym(int n, int t) { - return oad(n, t); - } - - /* instruction + address */ - int oad(int n, int t) { - o(n); - int result = getPC(); - o4(t); - return result; - } - - static const int operatorHelper[]; - - int decodeOp(int op) { - if (op < 0 || op > OP_COUNT) { - error("Out-of-range operator: %d\n", op); - op = 0; - } - return operatorHelper[op]; - } - - void gmov(int l, int t) { - o(l + 0x83); - oad((t > -LOCAL && t < LOCAL) << 7 | 5, t); - } - - void setupFloatOperands() { - Type* pR0Type = getR0Type(); - Type* pTOSType = getTOSType(); - TypeTag tagR0 = pR0Type->tag; - TypeTag tagTOS = pTOSType->tag; - bool isFloatR0 = isFloatTag(tagR0); - bool isFloatTOS = isFloatTag(tagTOS); - if (! isFloatR0) { - // Convert R0 from int to float - o(0x50); // push %eax - o(0x2404DB); // fildl 0(%esp) - o(0x58); // pop %eax - } - if (! isFloatTOS){ - o(0x2404DB); // fildl 0(%esp); - o(0x58); // pop %eax - } else { - if (tagTOS == TY_FLOAT) { - o(0x2404d9); // flds (%esp) - o(0x58); // pop %eax - } else { - o(0x2404dd); // fldl (%esp) - o(0x58); // pop %eax - o(0x58); // pop %eax - } - } - popType(); - } - }; - -#endif // PROVIDE_X86_CODEGEN - -#ifdef PROVIDE_TRACE_CODEGEN - class TraceCodeGenerator : public CodeGenerator { - private: - CodeGenerator* mpBase; - - public: - TraceCodeGenerator(CodeGenerator* pBase) { - mpBase = pBase; - } - - virtual ~TraceCodeGenerator() { - delete mpBase; - } - - virtual void init(ICodeBuf* pCodeBuf) { - mpBase->init(pCodeBuf); - } - - void setErrorSink(ErrorSink* pErrorSink) { - mpBase->setErrorSink(pErrorSink); - } - - /* returns address to patch with local variable size - */ - virtual int functionEntry(Type* pDecl) { - int result = mpBase->functionEntry(pDecl); - fprintf(stderr, "functionEntry(pDecl) -> %d\n", result); - return result; - } - - virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { - fprintf(stderr, "functionExit(pDecl, %d, %d)\n", - localVariableAddress, localVariableSize); - mpBase->functionExit(pDecl, localVariableAddress, localVariableSize); - } - - /* load immediate value */ - virtual void li(int t) { - fprintf(stderr, "li(%d)\n", t); - mpBase->li(t); - } - - virtual void loadFloat(int address, Type* pType) { - fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag); - mpBase->loadFloat(address, pType); - } - - virtual void addStructOffsetR0(int offset, Type* pType) { - fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag); - mpBase->addStructOffsetR0(offset, pType); - } - - virtual int gjmp(int t) { - int result = mpBase->gjmp(t); - fprintf(stderr, "gjmp(%d) = %d\n", t, result); - return result; - } - - /* l = 0: je, l == 1: jne */ - virtual int gtst(bool l, int t) { - int result = mpBase->gtst(l, t); - fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result); - return result; - } - - virtual void gcmp(int op) { - fprintf(stderr, "gcmp(%d)\n", op); - mpBase->gcmp(op); - } - - virtual void genOp(int op) { - fprintf(stderr, "genOp(%d)\n", op); - mpBase->genOp(op); - } - - - virtual void gUnaryCmp(int op) { - fprintf(stderr, "gUnaryCmp(%d)\n", op); - mpBase->gUnaryCmp(op); - } - - virtual void genUnaryOp(int op) { - fprintf(stderr, "genUnaryOp(%d)\n", op); - mpBase->genUnaryOp(op); - } - - virtual void pushR0() { - fprintf(stderr, "pushR0()\n"); - mpBase->pushR0(); - } - - virtual void over() { - fprintf(stderr, "over()\n"); - mpBase->over(); - } - - virtual void popR0() { - fprintf(stderr, "popR0()\n"); - mpBase->popR0(); - } - - virtual void storeR0ToTOS() { - fprintf(stderr, "storeR0ToTOS()\n"); - mpBase->storeR0ToTOS(); - } - - virtual void loadR0FromR0() { - fprintf(stderr, "loadR0FromR0()\n"); - mpBase->loadR0FromR0(); - } - - virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { - fprintf(stderr, "leaR0(%d, %d, %d)\n", ea, - pPointerType->pHead->tag, et); - mpBase->leaR0(ea, pPointerType, et); - } - - virtual int leaForward(int ea, Type* pPointerType) { - fprintf(stderr, "leaForward(%d)\n", ea); - return mpBase->leaForward(ea, pPointerType); - } - - virtual void convertR0Imp(Type* pType, bool isCast){ - fprintf(stderr, "convertR0(pType tag=%d, %d)\n", pType->tag, isCast); - mpBase->convertR0Imp(pType, isCast); - } - - virtual int beginFunctionCallArguments() { - int result = mpBase->beginFunctionCallArguments(); - fprintf(stderr, "beginFunctionCallArguments() = %d\n", result); - return result; - } - - virtual size_t storeR0ToArg(int l, Type* pArgType) { - fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l, - pArgType->tag); - return mpBase->storeR0ToArg(l, pArgType); - } - - virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { - fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l); - mpBase->endFunctionCallArguments(pDecl, a, l); - } - - virtual int callForward(int symbol, Type* pFunc) { - int result = mpBase->callForward(symbol, pFunc); - fprintf(stderr, "callForward(%d) = %d\n", symbol, result); - return result; - } - - virtual void callIndirect(int l, Type* pFunc) { - fprintf(stderr, "callIndirect(%d returntype = %d)\n", l, - pFunc->pHead->tag); - mpBase->callIndirect(l, pFunc); - } - - virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { - fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect); - mpBase->adjustStackAfterCall(pDecl, l, isIndirect); - } - - virtual int jumpOffset() { - return mpBase->jumpOffset(); - } - - /* output a symbol and patch all calls to it */ - virtual void gsym(int t) { - fprintf(stderr, "gsym(%d)\n", t); - mpBase->gsym(t); - } - - virtual void resolveForward(int t) { - mpBase->resolveForward(t); - } - - virtual int finishCompile() { - int result = mpBase->finishCompile(); - fprintf(stderr, "finishCompile() = %d\n", result); - return result; - } - - /** - * Alignment (in bytes) for this type of data - */ - virtual size_t alignmentOf(Type* pType){ - return mpBase->alignmentOf(pType); - } - - /** - * Array element alignment (in bytes) for this type of data. - */ - virtual size_t sizeOf(Type* pType){ - return mpBase->sizeOf(pType); - } - - virtual Type* getR0Type() { - return mpBase->getR0Type(); - } - - virtual ExpressionType getR0ExpressionType() { - return mpBase->getR0ExpressionType(); - } - - virtual void setR0ExpressionType(ExpressionType et) { - mpBase->setR0ExpressionType(et); - } - - virtual size_t getExpressionStackDepth() { - return mpBase->getExpressionStackDepth(); - } - - virtual void forceR0RVal() { - return mpBase->forceR0RVal(); - } - }; - -#endif // PROVIDE_TRACE_CODEGEN - - class Arena { - public: - // Used to record a given allocation amount. - // Used: - // Mark mark = arena.mark(); - // ... lots of arena.allocate() - // arena.free(mark); - - struct Mark { - size_t chunk; - size_t offset; - }; - - Arena() { - mCurrentChunk = 0; - Chunk start(CHUNK_SIZE); - mData.push_back(start); - } - - ~Arena() { - for(size_t i = 0; i < mData.size(); i++) { - mData[i].free(); - } - } - - // Alloc using the standard alignment size safe for any variable - void* alloc(size_t size) { - return alloc(size, 8); - } - - Mark mark(){ - Mark result; - result.chunk = mCurrentChunk; - result.offset = mData[mCurrentChunk].mOffset; - return result; - } - - void freeToMark(const Mark& mark) { - mCurrentChunk = mark.chunk; - mData[mCurrentChunk].mOffset = mark.offset; - } - - private: - // Allocate memory aligned to a given size - // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...) - // Memory is not zero filled. - - void* alloc(size_t size, size_t alignment) { - while (size > mData[mCurrentChunk].remainingCapacity(alignment)) { - if (mCurrentChunk + 1 < mData.size()) { - mCurrentChunk++; - } else { - size_t allocSize = CHUNK_SIZE; - if (allocSize < size + alignment - 1) { - allocSize = size + alignment - 1; - } - Chunk chunk(allocSize); - mData.push_back(chunk); - mCurrentChunk++; - } - } - return mData[mCurrentChunk].allocate(size, alignment); - } - - static const size_t CHUNK_SIZE = 128*1024; - // Note: this class does not deallocate its - // memory when it's destroyed. It depends upon - // its parent to deallocate the memory. - struct Chunk { - Chunk() { - mpData = 0; - mSize = 0; - mOffset = 0; - } - - Chunk(size_t size) { - mSize = size; - mpData = (char*) malloc(size); - mOffset = 0; - } - - ~Chunk() { - // Doesn't deallocate memory. - } - - void* allocate(size_t size, size_t alignment) { - size_t alignedOffset = aligned(mOffset, alignment); - void* result = mpData + alignedOffset; - mOffset = alignedOffset + size; - return result; - } - - void free() { - if (mpData) { - ::free(mpData); - mpData = 0; - } - } - - size_t remainingCapacity(size_t alignment) { - return aligned(mSize, alignment) - aligned(mOffset, alignment); - } - - // Assume alignment is a power of two - inline size_t aligned(size_t v, size_t alignment) { - size_t mask = alignment-1; - return (v + mask) & ~mask; - } - - char* mpData; - size_t mSize; - size_t mOffset; - }; - - size_t mCurrentChunk; - - Vector<Chunk> mData; - }; - - struct VariableInfo; - - struct Token { - int hash; - size_t length; - char* pText; - tokenid_t id; - - // Current values for the token - char* mpMacroDefinition; - VariableInfo* mpVariableInfo; - VariableInfo* mpStructInfo; - }; - - class TokenTable { - public: - // Don't use 0..0xff, allows characters and operators to be tokens too. - - static const int TOKEN_BASE = 0x100; - TokenTable() { - mpMap = hashmapCreate(128, hashFn, equalsFn); - } - - ~TokenTable() { - hashmapFree(mpMap); - } - - void setArena(Arena* pArena) { - mpArena = pArena; - } - - // Returns a token for a given string of characters. - tokenid_t intern(const char* pText, size_t length) { - Token probe; - int hash = hashmapHash((void*) pText, length); - { - Token probe; - probe.hash = hash; - probe.length = length; - probe.pText = (char*) pText; - Token* pValue = (Token*) hashmapGet(mpMap, &probe); - if (pValue) { - return pValue->id; - } - } - - Token* pToken = (Token*) mpArena->alloc(sizeof(Token)); - memset(pToken, 0, sizeof(*pToken)); - pToken->hash = hash; - pToken->length = length; - pToken->pText = (char*) mpArena->alloc(length + 1); - memcpy(pToken->pText, pText, length); - pToken->pText[length] = 0; - pToken->id = mTokens.size() + TOKEN_BASE; - mTokens.push_back(pToken); - hashmapPut(mpMap, pToken, pToken); - return pToken->id; - } - - // Return the Token for a given tokenid. - Token& operator[](tokenid_t id) { - return *mTokens[id - TOKEN_BASE]; - } - - inline size_t size() { - return mTokens.size(); - } - - private: - - static int hashFn(void* pKey) { - Token* pToken = (Token*) pKey; - return pToken->hash; - } - - static bool equalsFn(void* keyA, void* keyB) { - Token* pTokenA = (Token*) keyA; - Token* pTokenB = (Token*) keyB; - // Don't need to compare hash values, they should always be equal - return pTokenA->length == pTokenB->length - && strcmp(pTokenA->pText, pTokenB->pText) == 0; - } - - Hashmap* mpMap; - Vector<Token*> mTokens; - Arena* mpArena; - }; - - class InputStream { - public: - virtual ~InputStream() {} - virtual int getChar() = 0; - }; - - class TextInputStream : public InputStream { - public: - TextInputStream(const char* text, size_t textLength) - : pText(text), mTextLength(textLength), mPosition(0) { - } - - virtual int getChar() { - return mPosition < mTextLength ? pText[mPosition++] : EOF; - } - - private: - const char* pText; - size_t mTextLength; - size_t mPosition; - }; - - class String { - public: - String() { - mpBase = 0; - mUsed = 0; - mSize = 0; - } - - String(const char* item, int len, bool adopt) { - if (len < 0) { - len = strlen(item); - } - if (adopt) { - mpBase = (char*) item; - mUsed = len; - mSize = len + 1; - } else { - mpBase = 0; - mUsed = 0; - mSize = 0; - appendBytes(item, len); - } - } - - String(const String& other) { - mpBase = 0; - mUsed = 0; - mSize = 0; - appendBytes(other.getUnwrapped(), other.len()); - } - - ~String() { - if (mpBase) { - free(mpBase); - } - } - - String& operator=(const String& other) { - clear(); - appendBytes(other.getUnwrapped(), other.len()); - return *this; - } - - inline char* getUnwrapped() const { - return mpBase; - } - - void clear() { - mUsed = 0; - if (mSize > 0) { - mpBase[0] = 0; - } - } - - void appendCStr(const char* s) { - appendBytes(s, strlen(s)); - } - - void appendBytes(const char* s, int n) { - memcpy(ensure(n), s, n + 1); - } - - void append(char c) { - * ensure(1) = c; - } - - void append(String& other) { - appendBytes(other.getUnwrapped(), other.len()); - } - - char* orphan() { - char* result = mpBase; - mpBase = 0; - mUsed = 0; - mSize = 0; - return result; - } - - void printf(const char* fmt,...) { - va_list ap; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - } - - void vprintf(const char* fmt, va_list ap) { - char* temp; - int numChars = vasprintf(&temp, fmt, ap); - memcpy(ensure(numChars), temp, numChars+1); - free(temp); - } - - inline size_t len() const { - return mUsed; - } - - private: - char* ensure(int n) { - size_t newUsed = mUsed + n; - if (newUsed > mSize) { - size_t newSize = mSize * 2 + 10; - if (newSize < newUsed) { - newSize = newUsed; - } - mpBase = (char*) realloc(mpBase, newSize + 1); - mSize = newSize; - } - mpBase[newUsed] = '\0'; - char* result = mpBase + mUsed; - mUsed = newUsed; - return result; - } - - char* mpBase; - size_t mUsed; - size_t mSize; - }; - - void internKeywords() { - // Note: order has to match TOK_ constants - static const char* keywords[] = { - "int", - "char", - "void", - "if", - "else", - "while", - "break", - "return", - "for", - "auto", - "case", - "const", - "continue", - "default", - "do", - "double", - "enum", - "extern", - "float", - "goto", - "long", - "register", - "short", - "signed", - "sizeof", - "static", - "struct", - "switch", - "typedef", - "union", - "unsigned", - "volatile", - "_Bool", - "_Complex", - "_Imaginary", - "inline", - "restrict", - - // predefined tokens that can also be symbols start here: - "pragma", - "define", - "line", - 0}; - - for(int i = 0; keywords[i]; i++) { - mTokenTable.intern(keywords[i], strlen(keywords[i])); - } - } - - struct InputState { - InputStream* pStream; - int oldCh; - }; - - struct VariableInfo { - void* pAddress; - void* pForward; // For a forward direction, linked list of data to fix up - tokenid_t tok; - size_t level; - VariableInfo* pOldDefinition; - Type* pType; - bool isStructTag; - }; - - class SymbolStack { - public: - SymbolStack() { - mpArena = 0; - mpTokenTable = 0; - } - - void setArena(Arena* pArena) { - mpArena = pArena; - } - - void setTokenTable(TokenTable* pTokenTable) { - mpTokenTable = pTokenTable; - } - - void pushLevel() { - Mark mark; - mark.mArenaMark = mpArena->mark(); - mark.mSymbolHead = mStack.size(); - mLevelStack.push_back(mark); - } - - void popLevel() { - // Undo any shadowing that was done: - Mark mark = mLevelStack.back(); - mLevelStack.pop_back(); - while (mStack.size() > mark.mSymbolHead) { - VariableInfo* pV = mStack.back(); - mStack.pop_back(); - if (pV->isStructTag) { - (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition; - } else { - (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition; - } - } - mpArena->freeToMark(mark.mArenaMark); - } - - bool isDefinedAtCurrentLevel(tokenid_t tok) { - VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo; - return pV && pV->level == level(); - } - - bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) { - VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo; - return pV && pV->level == level(); - } - - VariableInfo* add(tokenid_t tok) { - Token& token = (*mpTokenTable)[tok]; - VariableInfo* pOldV = token.mpVariableInfo; - VariableInfo* pNewV = - (VariableInfo*) mpArena->alloc(sizeof(VariableInfo)); - memset(pNewV, 0, sizeof(VariableInfo)); - pNewV->tok = tok; - pNewV->level = level(); - pNewV->pOldDefinition = pOldV; - token.mpVariableInfo = pNewV; - mStack.push_back(pNewV); - return pNewV; - } - - VariableInfo* addStructTag(tokenid_t tok) { - Token& token = (*mpTokenTable)[tok]; - VariableInfo* pOldS = token.mpStructInfo; - VariableInfo* pNewS = - (VariableInfo*) mpArena->alloc(sizeof(VariableInfo)); - memset(pNewS, 0, sizeof(VariableInfo)); - pNewS->tok = tok; - pNewS->level = level(); - pNewS->isStructTag = true; - pNewS->pOldDefinition = pOldS; - token.mpStructInfo = pNewS; - mStack.push_back(pNewS); - return pNewS; - } - - VariableInfo* add(Type* pType) { - VariableInfo* pVI = add(pType->id); - pVI->pType = pType; - return pVI; - } - - void forEach(bool (*fn)(VariableInfo*, void*), void* context) { - for (size_t i = 0; i < mStack.size(); i++) { - if (! fn(mStack[i], context)) { - break; - } - } - } - - private: - inline size_t level() { - return mLevelStack.size(); - } - - struct Mark { - Arena::Mark mArenaMark; - size_t mSymbolHead; - }; - - Arena* mpArena; - TokenTable* mpTokenTable; - Vector<VariableInfo*> mStack; - Vector<Mark> mLevelStack; - }; - - struct MacroState { - tokenid_t name; // Name of the current macro we are expanding - char* dptr; // point to macro text during macro playback - int dch; // Saves old value of ch during a macro playback - }; - -#define MACRO_NESTING_MAX 32 - MacroState macroState[MACRO_NESTING_MAX]; - int macroLevel; // -1 means not playing any macro. - - int ch; // Current input character, or EOF - tokenid_t tok; // token - intptr_t tokc; // token extra info - double tokd; // floating point constant value - int tokl; // token operator level - intptr_t rsym; // return symbol - Type* pReturnType; // type of the current function's return. - intptr_t loc; // local variable index - char* glo; // global variable index - String mTokenString; - bool mbSuppressMacroExpansion; - char* pGlobalBase; - ACCSymbolLookupFn mpSymbolLookupFn; - void* mpSymbolLookupContext; - - // Arena for the duration of the compile - Arena mGlobalArena; - // Arena for data that's only needed when compiling a single function - Arena mLocalArena; - - Arena* mpCurrentArena; - - TokenTable mTokenTable; - SymbolStack mGlobals; - SymbolStack mLocals; - - SymbolStack* mpCurrentSymbolStack; - - // Prebuilt types, makes things slightly faster. - Type* mkpInt; // int - Type* mkpShort; // short - Type* mkpChar; // char - Type* mkpVoid; // void - Type* mkpFloat; - Type* mkpDouble; - Type* mkpIntFn; - Type* mkpIntPtr; - Type* mkpCharPtr; - Type* mkpFloatPtr; - Type* mkpDoublePtr; - Type* mkpPtrIntFn; - - InputStream* file; - int mLineNumber; - bool mbBumpLine; - - ICodeBuf* pCodeBuf; - CodeGenerator* pGen; - - String mErrorBuf; - - String mPragmas; - int mPragmaStringCount; - int mCompileResult; - - static const int ALLOC_SIZE = 99999; - - static const int TOK_DUMMY = 1; - static const int TOK_NUM = 2; - static const int TOK_NUM_FLOAT = 3; - static const int TOK_NUM_DOUBLE = 4; - static const int TOK_OP_ASSIGNMENT = 5; - static const int TOK_OP_ARROW = 6; - - // 3..255 are character and/or operators - - // Keywords start at 0x100 and increase by 1 - // Order has to match string list in "internKeywords". - enum { - TOK_KEYWORD = TokenTable::TOKEN_BASE, - TOK_INT = TOK_KEYWORD, - TOK_CHAR, - TOK_VOID, - TOK_IF, - TOK_ELSE, - TOK_WHILE, - TOK_BREAK, - TOK_RETURN, - TOK_FOR, - TOK_AUTO, - TOK_CASE, - TOK_CONST, - TOK_CONTINUE, - TOK_DEFAULT, - TOK_DO, - TOK_DOUBLE, - TOK_ENUM, - TOK_EXTERN, - TOK_FLOAT, - TOK_GOTO, - TOK_LONG, - TOK_REGISTER, - TOK_SHORT, - TOK_SIGNED, - TOK_SIZEOF, - TOK_STATIC, - TOK_STRUCT, - TOK_SWITCH, - TOK_TYPEDEF, - TOK_UNION, - TOK_UNSIGNED, - TOK_VOLATILE, - TOK__BOOL, - TOK__COMPLEX, - TOK__IMAGINARY, - TOK_INLINE, - TOK_RESTRICT, - - // Symbols start after keywords - - TOK_SYMBOL, - TOK_PRAGMA = TOK_SYMBOL, - TOK_DEFINE, - TOK_LINE - }; - - static const int LOCAL = 0x200; - - /* tokens in string heap */ - static const int TAG_TOK = ' '; - - static const int OP_INCREMENT = 0; - static const int OP_DECREMENT = 1; - static const int OP_MUL = 2; - static const int OP_DIV = 3; - static const int OP_MOD = 4; - static const int OP_PLUS = 5; - static const int OP_MINUS = 6; - static const int OP_SHIFT_LEFT = 7; - static const int OP_SHIFT_RIGHT = 8; - static const int OP_LESS_EQUAL = 9; - static const int OP_GREATER_EQUAL = 10; - static const int OP_LESS = 11; - static const int OP_GREATER = 12; - static const int OP_EQUALS = 13; - static const int OP_NOT_EQUALS = 14; - static const int OP_LOGICAL_AND = 15; - static const int OP_LOGICAL_OR = 16; - static const int OP_BIT_AND = 17; - static const int OP_BIT_XOR = 18; - static const int OP_BIT_OR = 19; - static const int OP_BIT_NOT = 20; - static const int OP_LOGICAL_NOT = 21; - static const int OP_COUNT = 22; - - /* Operators are searched from front, the two-character operators appear - * before the single-character operators with the same first character. - * @ is used to pad out single-character operators. - */ - static const char* operatorChars; - static const char operatorLevel[]; - - /* Called when we detect an internal problem. Does nothing in production. - * - */ - void internalError() { - * (char*) 0 = 0; - } - - void assertImpl(bool isTrue, int line) { - if (!isTrue) { - LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line); - internalError(); - } - } - - bool isSymbol(tokenid_t t) { - return t >= TOK_SYMBOL && - ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size(); - } - - bool isSymbolOrKeyword(tokenid_t t) { - return t >= TOK_KEYWORD && - ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size(); - } - - VariableInfo* VI(tokenid_t t) { - assert(isSymbol(t)); - VariableInfo* pV = mTokenTable[t].mpVariableInfo; - if (pV && pV->tok != t) { - internalError(); - } - return pV; - } - - inline bool isDefined(tokenid_t t) { - return t >= TOK_SYMBOL && VI(t) != 0; - } - - const char* nameof(tokenid_t t) { - assert(isSymbolOrKeyword(t)); - return mTokenTable[t].pText; - } - - void pdef(int t) { - mTokenString.append(t); - } - - void inp() { - // Close any totally empty macros. We leave them on the stack until now - // so that we know which macros are being expanded when checking if the - // last token in the macro is a macro that's already being expanded. - while (macroLevel >= 0 && macroState[macroLevel].dptr == NULL) { - macroLevel--; - } - if (macroLevel >= 0) { - ch = *macroState[macroLevel].dptr++; - if (ch == 0) { - ch = macroState[macroLevel].dch; - macroState[macroLevel].dptr = NULL; // This macro's done - } - } else { - if (mbBumpLine) { - mLineNumber++; - mbBumpLine = false; - } - ch = file->getChar(); - if (ch == '\n') { - mbBumpLine = true; - } - } -#if 0 - printf("ch='%c' 0x%x\n", ch, ch); -#endif - } - - int isid() { - return isalnum(ch) | (ch == '_'); - } - - int decodeHex(int c) { - if (isdigit(c)) { - c -= '0'; - } else if (c <= 'F') { - c = c - 'A' + 10; - } else { - c =c - 'a' + 10; - } - return c; - } - - /* read a character constant, advances ch to after end of constant */ - int getq() { - int val = ch; - if (ch == '\\') { - inp(); - if (isoctal(ch)) { - // 1 to 3 octal characters. - val = 0; - for(int i = 0; i < 3; i++) { - if (isoctal(ch)) { - val = (val << 3) + ch - '0'; - inp(); - } - } - return val; - } else if (ch == 'x' || ch == 'X') { - // N hex chars - inp(); - if (! isxdigit(ch)) { - error("'x' character escape requires at least one digit."); - } else { - val = 0; - while (isxdigit(ch)) { - val = (val << 4) + decodeHex(ch); - inp(); - } - } - } else { - int val = ch; - switch (ch) { - case 'a': - val = '\a'; - break; - case 'b': - val = '\b'; - break; - case 'f': - val = '\f'; - break; - case 'n': - val = '\n'; - break; - case 'r': - val = '\r'; - break; - case 't': - val = '\t'; - break; - case 'v': - val = '\v'; - break; - case '\\': - val = '\\'; - break; - case '\'': - val = '\''; - break; - case '"': - val = '"'; - break; - case '?': - val = '?'; - break; - default: - error("Undefined character escape %c", ch); - break; - } - inp(); - return val; - } - } else { - inp(); - } - return val; - } - - static bool isoctal(int ch) { - return ch >= '0' && ch <= '7'; - } - - bool acceptCh(int c) { - bool result = c == ch; - if (result) { - pdef(ch); - inp(); - } - return result; - } - - bool acceptDigitsCh() { - bool result = false; - while (isdigit(ch)) { - result = true; - pdef(ch); - inp(); - } - return result; - } - - void parseFloat() { - tok = TOK_NUM_DOUBLE; - // mTokenString already has the integral part of the number. - if(mTokenString.len() == 0) { - mTokenString.append('0'); - } - acceptCh('.'); - acceptDigitsCh(); - if (acceptCh('e') || acceptCh('E')) { - acceptCh('-') || acceptCh('+'); - acceptDigitsCh(); - } - if (ch == 'f' || ch == 'F') { - tok = TOK_NUM_FLOAT; - inp(); - } else if (ch == 'l' || ch == 'L') { - inp(); - error("Long floating point constants not supported."); - } - char* pText = mTokenString.getUnwrapped(); - char* pEnd = pText + strlen(pText); - char* pEndPtr = 0; - errno = 0; - if (tok == TOK_NUM_FLOAT) { - tokd = strtof(pText, &pEndPtr); - } else { - tokd = strtod(pText, &pEndPtr); - } - if (errno || pEndPtr != pEnd) { - error("Can't parse constant: %s", pText); - } - // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd); - } - - bool currentlyBeingExpanded(tokenid_t id) { - for (int i = 0; i <= macroLevel; i++) { - if (macroState[macroLevel].name == id) { - return true; - } - } - return false; - } - - void next() { - int l, a; - - while (isspace(ch) | (ch == '#')) { - if (ch == '#') { - inp(); - next(); - if (tok == TOK_DEFINE) { - doDefine(); - } else if (tok == TOK_PRAGMA) { - doPragma(); - } else if (tok == TOK_LINE) { - doLine(); - } else { - error("Unsupported preprocessor directive \"%s\"", - mTokenString.getUnwrapped()); - } - } - inp(); - } - tokl = 0; - tok = ch; - /* encode identifiers & numbers */ - if (isdigit(ch) || ch == '.') { - // Start of a numeric constant. Could be integer, float, or - // double, won't know until we look further. - mTokenString.clear(); - pdef(ch); - inp(); - if (tok == '.' && !isdigit(ch)) { - goto done; - } - int base = 10; - if (tok == '0') { - if (ch == 'x' || ch == 'X') { - base = 16; - tok = TOK_NUM; - tokc = 0; - inp(); - while ( isxdigit(ch) ) { - tokc = (tokc << 4) + decodeHex(ch); - inp(); - } - } else if (isoctal(ch)){ - base = 8; - tok = TOK_NUM; - tokc = 0; - while ( isoctal(ch) ) { - tokc = (tokc << 3) + (ch - '0'); - inp(); - } - } - } else if (isdigit(tok)){ - acceptDigitsCh(); - } - if (base == 10) { - if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') { - parseFloat(); - } else { - // It's an integer constant - char* pText = mTokenString.getUnwrapped(); - char* pEnd = pText + strlen(pText); - char* pEndPtr = 0; - errno = 0; - tokc = strtol(pText, &pEndPtr, base); - if (errno || pEndPtr != pEnd) { - error("Can't parse constant: %s %d %d", pText, base, errno); - } - tok = TOK_NUM; - } - } - } else if (isid()) { - mTokenString.clear(); - while (isid()) { - pdef(ch); - inp(); - } - tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len()); - if (! mbSuppressMacroExpansion) { - // Is this a macro? - char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition; - if (pMacroDefinition && !currentlyBeingExpanded(tok)) { - // Yes, it is a macro -#if 0 - printf("Expanding macro %s -> %s", - mTokenString.getUnwrapped(), pMacroDefinition); -#endif - if (macroLevel >= MACRO_NESTING_MAX-1) { - error("Too many levels of macro recursion."); - } else { - macroLevel++; - macroState[macroLevel].name = tok; - macroState[macroLevel].dptr = pMacroDefinition; - macroState[macroLevel].dch = ch; - inp(); - next(); - } - } - } - } else { - inp(); - if (tok == '\'') { - tok = TOK_NUM; - tokc = getq(); - if (ch != '\'') { - error("Expected a ' character, got %c", ch); - } else { - inp(); - } - } else if ((tok == '/') & (ch == '*')) { - inp(); - while (ch && ch != EOF) { - while (ch != '*' && ch != EOF) - inp(); - inp(); - if (ch == '/') - ch = 0; - } - if (ch == EOF) { - error("End of file inside comment."); - } - inp(); - next(); - } else if ((tok == '/') & (ch == '/')) { - inp(); - while (ch && (ch != '\n') && (ch != EOF)) { - inp(); - } - inp(); - next(); - } else if ((tok == '-') & (ch == '>')) { - inp(); - tok = TOK_OP_ARROW; - } else { - const char* t = operatorChars; - int opIndex = 0; - while ((l = *t++) != 0) { - a = *t++; - tokl = operatorLevel[opIndex]; - tokc = opIndex; - if ((l == tok) & ((a == ch) | (a == '@'))) { -#if 0 - printf("%c%c -> tokl=%d tokc=0x%x\n", - l, a, tokl, tokc); -#endif - if (a == ch) { - inp(); - tok = TOK_DUMMY; /* dummy token for double tokens */ - } - /* check for op=, valid for * / % + - << >> & ^ | */ - if (ch == '=' && - ((tokl >= 1 && tokl <= 3) - || (tokl >=6 && tokl <= 8)) ) { - inp(); - tok = TOK_OP_ASSIGNMENT; - } - break; - } - opIndex++; - } - if (l == 0) { - tokl = 0; - tokc = 0; - } - } - } - - done: ; -#if 0 - { - String buf; - decodeToken(buf, tok, true); - fprintf(stderr, "%s\n", buf.getUnwrapped()); - } -#endif - } - - void doDefine() { - mbSuppressMacroExpansion = true; - next(); - mbSuppressMacroExpansion = false; - tokenid_t name = tok; - if (ch == '(') { - error("Defines with arguments not supported"); - return; - } - while (isspace(ch)) { - inp(); - } - String value; - bool appendToValue = true; - while (ch != '\n' && ch != EOF) { - // Check for '//' comments. - if (appendToValue && ch == '/') { - inp(); - if (ch == '/') { - appendToValue = false; - } else { - value.append('/'); - } - } - if (appendToValue && ch != EOF) { - value.append(ch); - } - inp(); - } - char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1); - memcpy(pDefn, value.getUnwrapped(), value.len()); - pDefn[value.len()] = 0; - mTokenTable[name].mpMacroDefinition = pDefn; -#if 0 - { - String buf; - decodeToken(buf, name, true); - fprintf(stderr, "define %s = \"%s\"\n", buf.getUnwrapped(), pDefn); - } -#endif - } - - void doPragma() { - // # pragma name(val) - int state = 0; - while(ch != EOF && ch != '\n' && state < 10) { - switch(state) { - case 0: - if (isspace(ch)) { - inp(); - } else { - state++; - } - break; - case 1: - if (isalnum(ch)) { - mPragmas.append(ch); - inp(); - } else if (ch == '(') { - mPragmas.append(0); - inp(); - state++; - } else { - state = 11; - } - break; - case 2: - if (isalnum(ch)) { - mPragmas.append(ch); - inp(); - } else if (ch == ')') { - mPragmas.append(0); - inp(); - state = 10; - } else { - state = 11; - } - break; - } - } - if(state != 10) { - error("Unexpected pragma syntax"); - } - mPragmaStringCount += 2; - } - - void doLine() { - // # line number { "filename "} - next(); - if (tok != TOK_NUM) { - error("Expected a line-number"); - } else { - mLineNumber = tokc-1; // The end-of-line will increment it. - } - while(ch != EOF && ch != '\n') { - inp(); - } - } - - virtual void verror(const char* fmt, va_list ap) { - mErrorBuf.printf("%ld: ", mLineNumber); - mErrorBuf.vprintf(fmt, ap); - mErrorBuf.printf("\n"); - } - - void skip(intptr_t c) { - if (!accept(c)) { - error("'%c' expected", c); - } - } - - bool accept(intptr_t c) { - if (tok == c) { - next(); - return true; - } - return false; - } - - bool acceptStringLiteral() { - if (tok == '"') { - pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE); - // This while loop merges multiple adjacent string constants. - while (tok == '"') { - while (ch != '"' && ch != EOF) { - *allocGlobalSpace(1,1) = getq(); - } - if (ch != '"') { - error("Unterminated string constant."); - } - inp(); - next(); - } - /* Null terminate */ - *glo = 0; - /* align heap */ - allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo); - - return true; - } - return false; - } - - void linkGlobal(tokenid_t t, bool isFunction) { - VariableInfo* pVI = VI(t); - void* n = NULL; - if (mpSymbolLookupFn) { - n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t)); - } - if (pVI->pType == NULL) { - if (isFunction) { - pVI->pType = mkpIntFn; - } else { - pVI->pType = mkpInt; - } - } - pVI->pAddress = n; - } - - void unaryOrAssignment() { - unary(); - if (accept('=')) { - checkLVal(); - pGen->pushR0(); - expr(); - pGen->forceR0RVal(); - pGen->storeR0ToTOS(); - } else if (tok == TOK_OP_ASSIGNMENT) { - int t = tokc; - next(); - checkLVal(); - pGen->pushR0(); - pGen->forceR0RVal(); - pGen->pushR0(); - expr(); - pGen->forceR0RVal(); - pGen->genOp(t); - pGen->storeR0ToTOS(); - } - } - - /* Parse and evaluate a unary expression. - */ - void unary() { - tokenid_t t; - intptr_t a; - t = 0; - if (acceptStringLiteral()) { - // Nothing else to do. - } else { - int c = tokl; - a = tokc; - double ad = tokd; - t = tok; - next(); - if (t == TOK_NUM) { - pGen->li(a); - } else if (t == TOK_NUM_FLOAT) { - // Align to 4-byte boundary - glo = (char*) (((intptr_t) glo + 3) & -4); - * (float*) glo = (float) ad; - pGen->loadFloat((int) glo, mkpFloat); - glo += 4; - } else if (t == TOK_NUM_DOUBLE) { - // Align to 8-byte boundary - glo = (char*) (((intptr_t) glo + 7) & -8); - * (double*) glo = ad; - pGen->loadFloat((int) glo, mkpDouble); - glo += 8; - } else if (c == 2) { - /* -, +, !, ~ */ - unary(); - pGen->forceR0RVal(); - if (t == '!') - pGen->gUnaryCmp(a); - else if (t == '+') { - // ignore unary plus. - } else { - pGen->genUnaryOp(a); - } - } else if (c == 11) { - // pre increment / pre decrement - unary(); - doIncDec(a == OP_INCREMENT, 0); - } - else if (t == '(') { - // It's either a cast or an expression - Type* pCast = acceptCastTypeDeclaration(); - if (pCast) { - skip(')'); - unary(); - pGen->forceR0RVal(); - pGen->castR0(pCast); - } else { - commaExpr(); - skip(')'); - } - } else if (t == '*') { - /* This is a pointer dereference. - */ - unary(); - doPointer(); - } else if (t == '&') { - unary(); - doAddressOf(); - } else if (t == EOF ) { - error("Unexpected EOF."); - } else if (t == ';') { - error("Unexpected ';'"); - } else if (!checkSymbol(t)) { - // Don't have to do anything special here, the error - // message was printed by checkSymbol() above. - } else { - if (!isDefined(t)) { - mGlobals.add(t); - // printf("Adding new global function %s\n", nameof(t)); - } - VariableInfo* pVI = VI(t); - int n = (intptr_t) pVI->pAddress; - /* forward reference: try our lookup function */ - if (!n) { - linkGlobal(t, tok == '('); - n = (intptr_t) pVI->pAddress; - if (!n && tok != '(') { - error("Undeclared variable %s", nameof(t)); - } - } - if (tok != '(') { - /* variable or function name */ - if (!n) { - linkGlobal(t, false); - n = (intptr_t) pVI->pAddress; - if (!n) { - error("Undeclared variable %s", nameof(t)); - } - } - } - // load a variable - Type* pVal; - ExpressionType et; - if (pVI->pType->tag == TY_ARRAY) { - pVal = pVI->pType; - et = ET_RVALUE; - } else { - pVal = createPtrType(pVI->pType); - et = ET_LVALUE; - } - if (n) { - int tag = pVal->pHead->tag; - if (tag == TY_FUNC) { - et = ET_RVALUE; - } - pGen->leaR0(n, pVal, et); - } else { - pVI->pForward = (void*) pGen->leaForward( - (int) pVI->pForward, pVal); - } - } - } - - /* Now handle postfix operators */ - for(;;) { - if (tokl == 11) { - // post inc / post dec - doIncDec(tokc == OP_INCREMENT, true); - next(); - } else if (accept('[')) { - // Array reference - pGen->forceR0RVal(); - pGen->pushR0(); - commaExpr(); - pGen->forceR0RVal(); - pGen->genOp(OP_PLUS); - doPointer(); - skip(']'); - } else if (accept('.')) { - // struct element - pGen->forceR0RVal(); - Type* pStruct = pGen->getR0Type(); - if (pStruct->tag == TY_STRUCT) { - doStructMember(pStruct, true); - } else { - error("expected a struct value to the left of '.'"); - } - } else if (accept(TOK_OP_ARROW)) { - pGen->forceR0RVal(); - Type* pPtr = pGen->getR0Type(); - if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) { - pGen->loadR0FromR0(); - doStructMember(pPtr->pHead, false); - } else { - error("Expected a pointer to a struct to the left of '->'"); - } - } else if (accept('(')) { - /* function call */ - Type* pDecl = NULL; - VariableInfo* pVI = NULL; - Type* pFn = pGen->getR0Type(); - if (pFn->tag == TY_POINTER && pFn->pHead->tag == TY_FUNC) { - pDecl = pFn->pHead; - pGen->pushR0(); - Type* pArgList = pDecl->pTail; - bool varArgs = pArgList == NULL; - /* push args and invert order */ - a = pGen->beginFunctionCallArguments(); - int l = 0; - int argCount = 0; - while (tok != ')' && tok != EOF) { - if (! varArgs && !pArgList) { - error("Unexpected argument."); - } - expr(); - pGen->forceR0RVal(); - Type* pTargetType; - if (pArgList) { - pTargetType = pArgList->pHead; - pArgList = pArgList->pTail; - } else { - // This is a ... function, just pass arguments in their - // natural type. - pTargetType = pGen->getR0Type(); - if (pTargetType->tag == TY_FLOAT) { - pTargetType = mkpDouble; - } else if (pTargetType->tag == TY_ARRAY) { - // Pass arrays by pointer. - pTargetType = pTargetType->pTail; - } - } - if (pTargetType->tag == TY_VOID) { - error("Can't pass void value for argument %d", - argCount + 1); - } else { - l += pGen->storeR0ToArg(l, pTargetType); - } - if (accept(',')) { - // fine - } else if ( tok != ')') { - error("Expected ',' or ')'"); - } - argCount += 1; - } - if (! varArgs && pArgList) { - error("Expected more argument(s). Saw %d", argCount); - } - pGen->endFunctionCallArguments(pDecl, a, l); - skip(')'); - pGen->callIndirect(l, pDecl); - pGen->adjustStackAfterCall(pDecl, l, true); - } else { - error("Expected a function value to left of '('."); - } - } else { - break; - } - } - } - - void doStructMember(Type* pStruct, bool isDot) { - Type* pStructElement = lookupStructMember(pStruct, tok); - if (pStructElement) { - next(); - pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead)); - } else { - String buf; - decodeToken(buf, tok, true); - error("Expected a struct member to the right of '%s', got %s", - isDot ? "." : "->", buf.getUnwrapped()); - } - } - - void doIncDec(int isInc, int isPost) { - // R0 already has the lval - checkLVal(); - int lit = isInc ? 1 : -1; - pGen->pushR0(); - pGen->loadR0FromR0(); - int tag = pGen->getR0Type()->tag; - if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR || - tag == TY_POINTER)) { - error("++/-- illegal for this type. %d", tag); - } - if (isPost) { - pGen->over(); - pGen->pushR0(); - pGen->li(lit); - pGen->genOp(OP_PLUS); - pGen->storeR0ToTOS(); - pGen->popR0(); - } else { - pGen->pushR0(); - pGen->li(lit); - pGen->genOp(OP_PLUS); - pGen->over(); - pGen->storeR0ToTOS(); - pGen->popR0(); - } - } - - void doPointer() { - pGen->forceR0RVal(); - Type* pR0Type = pGen->getR0Type(); - if (pR0Type->tag != TY_POINTER) { - error("Expected a pointer type."); - } else { - if (pR0Type->pHead->tag != TY_FUNC) { - pGen->setR0ExpressionType(ET_LVALUE); - } - } - } - - void doAddressOf() { - Type* pR0 = pGen->getR0Type(); - bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC; - if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) { - error("Expected an lvalue"); - } - Type* pR0Type = pGen->getR0Type(); - pGen->setR0ExpressionType(ET_RVALUE); - } - - /* Recursive descent parser for binary operations. - */ - void binaryOp(int level) { - intptr_t t, a; - t = 0; - if (level-- == 1) - unaryOrAssignment(); - else { - binaryOp(level); - a = 0; - while (level == tokl) { - t = tokc; - next(); - pGen->forceR0RVal(); - if (level > 8) { - a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */ - binaryOp(level); - } else { - pGen->pushR0(); - binaryOp(level); - // Check for syntax error. - if (pGen->getR0Type() == NULL) { - // We failed to parse a right-hand argument. - // Push a dummy value so we don't fail - pGen->li(0); - } - pGen->forceR0RVal(); - if ((level == 4) | (level == 5)) { - pGen->gcmp(t); - } else { - pGen->genOp(t); - } - } - } - /* && and || output code generation */ - if (a && level > 8) { - pGen->forceR0RVal(); - a = pGen->gtst(t == OP_LOGICAL_OR, a); - pGen->li(t != OP_LOGICAL_OR); - int b = pGen->gjmp(0); - pGen->gsym(a); - pGen->li(t == OP_LOGICAL_OR); - pGen->gsym(b); - } - } - } - - void commaExpr() { - for(;;) { - expr(); - if (!accept(',')) { - break; - } - } - } - - void expr() { - binaryOp(11); - } - - int test_expr() { - commaExpr(); - pGen->forceR0RVal(); - return pGen->gtst(0, 0); - } - - void block(intptr_t* breakLabel, intptr_t continueAddress, bool outermostFunctionBlock) { - intptr_t a, n, t; - - Type* pBaseType; - if ((pBaseType = acceptPrimitiveType(true))) { - /* declarations */ - localDeclarations(pBaseType); - } else if (tok == TOK_IF) { - next(); - skip('('); - a = test_expr(); - skip(')'); - block(breakLabel, continueAddress, false); - if (tok == TOK_ELSE) { - next(); - n = pGen->gjmp(0); /* jmp */ - pGen->gsym(a); - block(breakLabel, continueAddress, false); - pGen->gsym(n); /* patch else jmp */ - } else { - pGen->gsym(a); /* patch if test */ - } - } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) { - t = tok; - next(); - skip('('); - if (t == TOK_WHILE) { - n = pCodeBuf->getPC(); // top of loop, target of "next" iteration - a = test_expr(); - } else { - if (tok != ';') - commaExpr(); - skip(';'); - n = pCodeBuf->getPC(); - a = 0; - if (tok != ';') - a = test_expr(); - skip(';'); - if (tok != ')') { - t = pGen->gjmp(0); - commaExpr(); - pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); - pGen->gsym(t); - n = t + 4; - } - } - skip(')'); - block(&a, n, false); - pGen->gjmp(n - pCodeBuf->getPC() - pGen->jumpOffset()); /* jmp */ - pGen->gsym(a); - } else if (tok == '{') { - if (! outermostFunctionBlock) { - mLocals.pushLevel(); - } - next(); - while (tok != '}' && tok != EOF) - block(breakLabel, continueAddress, false); - skip('}'); - if (! outermostFunctionBlock) { - mLocals.popLevel(); - } - } else { - if (accept(TOK_RETURN)) { - if (tok != ';') { - commaExpr(); - pGen->forceR0RVal(); - if (pReturnType->tag == TY_VOID) { - error("Must not return a value from a void function"); - } else { - pGen->convertR0(pReturnType); - } - } else { - if (pReturnType->tag != TY_VOID) { - error("Must specify a value here"); - } - } - rsym = pGen->gjmp(rsym); /* jmp */ - } else if (accept(TOK_BREAK)) { - if (breakLabel) { - *breakLabel = pGen->gjmp(*breakLabel); - } else { - error("break statement must be within a for, do, while, or switch statement"); - } - } else if (accept(TOK_CONTINUE)) { - if (continueAddress) { - pGen->gjmp(continueAddress - pCodeBuf->getPC() - pGen->jumpOffset()); - } else { - error("continue statement must be within a for, do, or while statement"); - } - } else if (tok != ';') - commaExpr(); - skip(';'); - } - } - - static bool typeEqual(Type* a, Type* b) { - if (a == b) { - return true; - } - if (a == NULL || b == NULL) { - return false; - } - TypeTag at = a->tag; - if (at != b->tag) { - return false; - } - if (at == TY_POINTER) { - return typeEqual(a->pHead, b->pHead); - } else if (at == TY_ARRAY) { - return a->length == b->length && typeEqual(a->pHead, b->pHead); - } else if (at == TY_FUNC || at == TY_PARAM) { - return typeEqual(a->pHead, b->pHead) - && typeEqual(a->pTail, b->pTail); - } else if (at == TY_STRUCT) { - return a->pHead == b->pHead; - } - return true; - } - - Type* createType(TypeTag tag, Type* pHead, Type* pTail) { - assert(tag >= TY_UNKNOWN && tag <= TY_PARAM); - Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type)); - memset(pType, 0, sizeof(*pType)); - pType->storageClass = SC_DEFAULT; - pType->tag = tag; - pType->pHead = pHead; - pType->pTail = pTail; - return pType; - } - - Type* createPtrType(Type* pType) { - return createType(TY_POINTER, pType, NULL); - } - - /** - * Try to print a type in declaration order - */ - void decodeType(String& buffer, Type* pType) { - buffer.clear(); - if (pType == NULL) { - buffer.appendCStr("null"); - return; - } - decodeTypeImp(buffer, pType); - } - - void decodeTypeImp(String& buffer, Type* pType) { - decodeTypeImpPrefix(buffer, pType); - decodeId(buffer, pType->id); - decodeTypeImpPostfix(buffer, pType); - } - - void decodeId(String& buffer, tokenid_t id) { - if (id) { - String temp; - decodeToken(temp, id, false); - buffer.append(temp); - } - } - - void decodeTypeImpPrefix(String& buffer, Type* pType) { - TypeTag tag = pType->tag; - - if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) { - switch (tag) { - case TY_INT: - buffer.appendCStr("int"); - break; - case TY_SHORT: - buffer.appendCStr("short"); - break; - case TY_CHAR: - buffer.appendCStr("char"); - break; - case TY_VOID: - buffer.appendCStr("void"); - break; - case TY_FLOAT: - buffer.appendCStr("float"); - break; - case TY_DOUBLE: - buffer.appendCStr("double"); - break; - case TY_STRUCT: - { - bool isStruct = (pType->pHead->alignment & 0x80000000) != 0; - buffer.appendCStr(isStruct ? "struct" : "union"); - if (pType->pHead && pType->pHead->structTag) { - buffer.append(' '); - decodeId(buffer, pType->pHead->structTag); - } - } - break; - default: - break; - } - buffer.append(' '); - } - - switch (tag) { - case TY_INT: - break; - case TY_SHORT: - break; - case TY_CHAR: - break; - case TY_VOID: - break; - case TY_FLOAT: - break; - case TY_DOUBLE: - break; - case TY_POINTER: - decodeTypeImpPrefix(buffer, pType->pHead); - if(pType->pHead && pType->pHead->tag == TY_FUNC) { - buffer.append('('); - } - buffer.append('*'); - break; - case TY_ARRAY: - decodeTypeImpPrefix(buffer, pType->pHead); - break; - case TY_STRUCT: - break; - case TY_FUNC: - decodeTypeImp(buffer, pType->pHead); - break; - case TY_PARAM: - decodeTypeImp(buffer, pType->pHead); - break; - default: - String temp; - temp.printf("Unknown tag %d", pType->tag); - buffer.append(temp); - break; - } - } - - void decodeTypeImpPostfix(String& buffer, Type* pType) { - TypeTag tag = pType->tag; - - switch(tag) { - case TY_POINTER: - if(pType->pHead && pType->pHead->tag == TY_FUNC) { - buffer.append(')'); - } - decodeTypeImpPostfix(buffer, pType->pHead); - break; - case TY_ARRAY: - { - String temp; - temp.printf("[%d]", pType->length); - buffer.append(temp); - } - break; - case TY_STRUCT: - if (pType->pHead->length >= 0) { - buffer.appendCStr(" {"); - for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) { - decodeTypeImp(buffer, pArg->pHead); - buffer.appendCStr(";"); - } - buffer.append('}'); - } - break; - case TY_FUNC: - buffer.append('('); - for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) { - decodeTypeImp(buffer, pArg); - if (pArg->pTail) { - buffer.appendCStr(", "); - } - } - buffer.append(')'); - break; - default: - break; - } - } - - void printType(Type* pType) { - String buffer; - decodeType(buffer, pType); - fprintf(stderr, "%s\n", buffer.getUnwrapped()); - } - - void insertTypeSpecifier(Type** ppType, TypeTag tag) { - if (! *ppType) { - *ppType = createType(tag, NULL, NULL); - } else { - if ((*ppType)->tag != TY_UNKNOWN) { - error("Only one type specifier allowed."); - } else { - (*ppType)->tag = tag; - } - } - } - - void insertStorageClass(Type** ppType, StorageClass storageClass) { - if (! *ppType) { - *ppType = createType(TY_UNKNOWN, NULL, NULL); - } - if ((*ppType)->storageClass != SC_DEFAULT) { - error("Only one storage class allowed."); - } else { - (*ppType)->storageClass = storageClass; - } - } - - Type* acceptPrimitiveType(bool allowStorageClass) { - Type* pType = NULL; - for (bool keepGoing = true; keepGoing;) { - switch(tok) { - case TOK_AUTO: - insertStorageClass(&pType, SC_AUTO); - break; - case TOK_REGISTER: - insertStorageClass(&pType, SC_REGISTER); - break; - case TOK_STATIC: - insertStorageClass(&pType, SC_STATIC); - break; - case TOK_EXTERN: - insertStorageClass(&pType, SC_EXTERN); - break; - case TOK_TYPEDEF: - insertStorageClass(&pType, SC_TYPEDEF); - break; - case TOK_INT: - insertTypeSpecifier(&pType, TY_INT); - break; - case TOK_SHORT: - insertTypeSpecifier(&pType, TY_SHORT); - break; - case TOK_CHAR: - insertTypeSpecifier(&pType, TY_CHAR); - break; - case TOK_VOID: - insertTypeSpecifier(&pType, TY_VOID); - break; - case TOK_FLOAT: - insertTypeSpecifier(&pType, TY_FLOAT); - break; - case TOK_DOUBLE: - insertTypeSpecifier(&pType, TY_DOUBLE); - break; - case TOK_STRUCT: - case TOK_UNION: - { - insertTypeSpecifier(&pType, TY_STRUCT); - bool isStruct = (tok == TOK_STRUCT); - next(); - pType = acceptStruct(pType, isStruct); - keepGoing = false; - } - break; - default: - // Is it a typedef? - if (isSymbol(tok)) { - VariableInfo* pV = VI(tok); - if (pV && pV->pType->storageClass == SC_TYPEDEF) { - if (! pType) { - pType = createType(TY_UNKNOWN, NULL, NULL); - } - StorageClass storageClass = pType->storageClass; - *pType = *pV->pType; - pType->storageClass = storageClass; - } else { - keepGoing = false; - } - } else { - keepGoing = false; - } - } - if (keepGoing) { - next(); - } - } - if (pType) { - if (pType->tag == TY_UNKNOWN) { - pType->tag = TY_INT; - } - if (allowStorageClass) { - switch(pType->storageClass) { - case SC_AUTO: error("auto not supported."); break; - case SC_REGISTER: error("register not supported."); break; - case SC_STATIC: error("static not supported."); break; - case SC_EXTERN: error("extern not supported."); break; - default: break; - } - } else { - if (pType->storageClass != SC_DEFAULT) { - error("An explicit storage class is not allowed in this type declaration"); - } - } - } - return pType; - } - - Type* acceptStruct(Type* pStructType, bool isStruct) { - tokenid_t structTag = acceptSymbol(); - bool isDeclaration = accept('{'); - bool fail = false; - - if (structTag) { - Token* pToken = &mTokenTable[structTag]; - VariableInfo* pStructInfo = pToken->mpStructInfo; - bool needToDeclare = !pStructInfo; - if (pStructInfo) { - if (isDeclaration) { - if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) { - if (pStructInfo->pType->pHead->length == -1) { - // we're filling in a forward declaration. - needToDeclare = false; - } else { - error("A struct with the same name is already defined at this level."); - fail = true; - } - } else { - needToDeclare = true; - } - } - if (!fail) { - assert(pStructInfo->isStructTag); - pStructType->pHead = pStructInfo->pType; - pStructType->pTail = pStructType->pHead->pTail; - } - } - - if (needToDeclare) { - // This is a new struct name - pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag); - StorageClass storageClass = pStructType->storageClass; - pStructType = createType(TY_STRUCT, NULL, NULL); - pStructType->structTag = structTag; - pStructType->pHead = pStructType; - pStructType->storageClass = storageClass; - if (! isDeclaration) { - // A forward declaration - pStructType->length = -1; - } - pToken->mpStructInfo->pType = pStructType; - } - } else { - // An anonymous struct - pStructType->pHead = pStructType; - } - - if (isDeclaration) { - size_t offset = 0; - size_t structSize = 0; - size_t structAlignment = 0; - Type** pParamHolder = & pStructType->pHead->pTail; - while (tok != '}' && tok != EOF) { - Type* pPrimitiveType = expectPrimitiveType(false); - if (pPrimitiveType) { - while (tok != ';' && tok != EOF) { - Type* pItem = acceptDeclaration(pPrimitiveType, true, false); - if (!pItem) { - break; - } - if (lookupStructMember(pStructType, pItem->id)) { - String buf; - decodeToken(buf, pItem->id, false); - error("Duplicate struct member %s", buf.getUnwrapped()); - } - Type* pStructElement = createType(TY_PARAM, pItem, NULL); - size_t alignment = pGen->alignmentOf(pItem); - if (alignment > structAlignment) { - structAlignment = alignment; - } - size_t alignmentMask = alignment - 1; - offset = (offset + alignmentMask) & ~alignmentMask; - pStructElement->length = offset; - size_t size = pGen->sizeOf(pItem); - if (isStruct) { - offset += size; - structSize = offset; - } else { - if (size >= structSize) { - structSize = size; - } - } - *pParamHolder = pStructElement; - pParamHolder = &pStructElement->pTail; - accept(','); - } - skip(';'); - } else { - // Some sort of syntax error, skip token and keep trying - next(); - } - } - if (!fail) { - pStructType->pHead->length = structSize; - pStructType->pHead->alignment = structAlignment | (isStruct << 31); - } - skip('}'); - } - if (fail) { - pStructType = NULL; - } - return pStructType; - } - - Type* lookupStructMember(Type* pStruct, tokenid_t memberId) { - for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) { - if (pStructElement->pHead->id == memberId) { - return pStructElement; - } - } - return NULL; - } - - Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) { - tokenid_t declName = 0; - bool reportFailure = false; - StorageClass storageClass = pType->storageClass; - pType = acceptDecl2(pType, declName, nameAllowed, - nameRequired, reportFailure); - if (declName) { - // Clone the parent type so we can set a unique ID - Type* pOldType = pType; - pType = createType(pType->tag, pType->pHead, pType->pTail); - *pType = *pOldType; - pType->id = declName; - pType->storageClass = storageClass; - } else if (nameRequired) { - error("Expected a variable name"); - } -#if 0 - fprintf(stderr, "Parsed a declaration: "); - printType(pType); -#endif - if (reportFailure) { - return NULL; - } - return pType; - } - - Type* expectDeclaration(Type* pBaseType) { - bool nameRequired = pBaseType->tag != TY_STRUCT; - Type* pType = acceptDeclaration(pBaseType, true, nameRequired); - if (! pType) { - error("Expected a declaration"); - } - return pType; - } - - /* Used for accepting types that appear in casts */ - Type* acceptCastTypeDeclaration() { - Type* pType = acceptPrimitiveType(false); - if (pType) { - pType = acceptDeclaration(pType, false, false); - } - return pType; - } - - Type* expectCastTypeDeclaration() { - Type* pType = acceptCastTypeDeclaration(); - if (! pType) { - error("Expected a declaration"); - } - return pType; - } - - Type* acceptDecl2(Type* pType, tokenid_t& declName, - bool nameAllowed, bool nameRequired, - bool& reportFailure) { - while (accept('*')) { - pType = createType(TY_POINTER, pType, NULL); - } - pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, - reportFailure); - return pType; - } - - Type* acceptDecl3(Type* pType, tokenid_t& declName, - bool nameAllowed, bool nameRequired, - bool& reportFailure) { - // direct-dcl : - // name - // (dcl) - // direct-dcl() - // direct-dcl[] - Type* pNewHead = NULL; - if (accept('(')) { - pNewHead = acceptDecl2(pNewHead, declName, nameAllowed, - nameRequired, reportFailure); - skip(')'); - } else if ((declName = acceptSymbol()) != 0) { - if (nameAllowed == false && declName) { - error("Symbol %s not allowed here", nameof(declName)); - reportFailure = true; - } - } else if (nameRequired && ! declName) { - String temp; - decodeToken(temp, tok, true); - error("Expected name. Got %s", temp.getUnwrapped()); - reportFailure = true; - } - for(;;) { - if (accept('(')) { - // Function declaration - Type* pTail = acceptArgs(nameAllowed); - pType = createType(TY_FUNC, pType, pTail); - skip(')'); - } if (accept('[')) { - if (tok != ']') { - if (tok != TOK_NUM || tokc <= 0) { - error("Expected positive integer constant"); - } else { - Type* pDecayType = createPtrType(pType); - pType = createType(TY_ARRAY, pType, pDecayType); - pType->length = tokc; - } - next(); - } - skip(']'); - } else { - break; - } - } - - if (pNewHead) { - Type* pA = pNewHead; - while (pA->pHead) { - pA = pA->pHead; - } - pA->pHead = pType; - pType = pNewHead; - } - return pType; - } - - Type* acceptArgs(bool nameAllowed) { - Type* pHead = NULL; - Type* pTail = NULL; - for(;;) { - Type* pBaseArg = acceptPrimitiveType(false); - if (pBaseArg) { - Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false); - if (pArg) { - Type* pParam = createType(TY_PARAM, pArg, NULL); - if (!pHead) { - pHead = pParam; - pTail = pParam; - } else { - pTail->pTail = pParam; - pTail = pParam; - } - } - } - if (! accept(',')) { - break; - } - } - return pHead; - } - - Type* expectPrimitiveType(bool allowStorageClass) { - Type* pType = acceptPrimitiveType(allowStorageClass); - if (!pType) { - String buf; - decodeToken(buf, tok, true); - error("Expected a type, got %s", buf.getUnwrapped()); - } - return pType; - } - - void checkLVal() { - if (pGen->getR0ExpressionType() != ET_LVALUE) { - error("Expected an lvalue"); - } - } - - void addGlobalSymbol(Type* pDecl) { - tokenid_t t = pDecl->id; - VariableInfo* pVI = VI(t); - if(pVI && pVI->pAddress) { - reportDuplicate(t); - } - mGlobals.add(pDecl); - } - - void reportDuplicate(tokenid_t t) { - error("Duplicate definition of %s", nameof(t)); - } - - void addLocalSymbol(Type* pDecl) { - tokenid_t t = pDecl->id; - if (mLocals.isDefinedAtCurrentLevel(t)) { - reportDuplicate(t); - } - mLocals.add(pDecl); - } - - bool checkUndeclaredStruct(Type* pBaseType) { - if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) { - String temp; - decodeToken(temp, pBaseType->structTag, false); - error("Undeclared struct %s", temp.getUnwrapped()); - return true; - } - return false; - } - - void localDeclarations(Type* pBaseType) { - intptr_t a; - - while (pBaseType) { - while (tok != ';' && tok != EOF) { - Type* pDecl = expectDeclaration(pBaseType); - if (!pDecl) { - break; - } - if (!pDecl->id) { - break; - } - if (checkUndeclaredStruct(pDecl)) { - break; - } - addLocalSymbol(pDecl); - if (pDecl->tag == TY_FUNC) { - if (tok == '{') { - error("Nested functions are not allowed. Did you forget a '}' ?"); - break; - } - // Else it's a forward declaration of a function. - } else if (pDecl->storageClass != SC_TYPEDEF) { - int variableAddress = 0; - size_t alignment = pGen->alignmentOf(pDecl); - assert(alignment > 0); - size_t alignmentMask = ~ (alignment - 1); - size_t sizeOf = pGen->sizeOf(pDecl); - assert(sizeOf > 0); - loc = (loc + alignment - 1) & alignmentMask; - size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask; - loc = loc + alignedSize; - variableAddress = -loc; - VI(pDecl->id)->pAddress = (void*) variableAddress; - if (accept('=')) { - /* assignment */ - pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE); - pGen->pushR0(); - expr(); - pGen->forceR0RVal(); - pGen->storeR0ToTOS(); - } - } - if (tok == ',') - next(); - } - skip(';'); - pBaseType = acceptPrimitiveType(true); - } - } - - bool checkSymbol() { - return checkSymbol(tok); - } - - void decodeToken(String& buffer, tokenid_t token, bool quote) { - if (token == EOF ) { - buffer.printf("EOF"); - } else if (token == TOK_NUM) { - buffer.printf("numeric constant %d(0x%x)", tokc, tokc); - } else if (token == TOK_NUM_FLOAT) { - buffer.printf("numeric constant float %g", tokd); - } else if (token == TOK_NUM_DOUBLE) { - buffer.printf("numeric constant double %g", tokd); - } else if (token >= 0 && token < 256) { - if (token < 32) { - buffer.printf("'\\x%02x'", token); - } else { - buffer.printf("'%c'", token); - } - } else { - if (quote) { - if (token >= TOK_KEYWORD && token < TOK_SYMBOL) { - buffer.printf("keyword \"%s\"", nameof(token)); - } else { - buffer.printf("symbol \"%s\"", nameof(token)); - } - } else { - buffer.printf("%s", nameof(token)); - } - } - } - - void printToken(tokenid_t token) { - String buffer; - decodeToken(buffer, token, true); - fprintf(stderr, "%s\n", buffer.getUnwrapped()); - } - - bool checkSymbol(tokenid_t token) { - bool result = token >= TOK_SYMBOL; - if (!result) { - String temp; - decodeToken(temp, token, true); - error("Expected symbol. Got %s", temp.getUnwrapped()); - } - return result; - } - - tokenid_t acceptSymbol() { - tokenid_t result = 0; - if (tok >= TOK_SYMBOL) { - result = tok; - next(); - } - return result; - } - - void globalDeclarations() { - mpCurrentSymbolStack = &mGlobals; - while (tok != EOF) { - Type* pBaseType = expectPrimitiveType(true); - if (!pBaseType) { - break; - } - Type* pDecl = expectDeclaration(pBaseType); - if (!pDecl) { - break; - } - if (!pDecl->id) { - skip(';'); - continue; - } - - if (checkUndeclaredStruct(pDecl)) { - skip(';'); - continue; - } - if (! isDefined(pDecl->id)) { - addGlobalSymbol(pDecl); - } - VariableInfo* name = VI(pDecl->id); - if (name && name->pAddress) { - error("Already defined global %s", nameof(pDecl->id)); - } - if (pDecl->tag < TY_FUNC) { - // it's a variable declaration - for(;;) { - if (pDecl->storageClass == SC_TYPEDEF) { - // Do not allocate storage. - } else { - if (name && !name->pAddress) { - name->pAddress = (int*) allocGlobalSpace( - pGen->alignmentOf(name->pType), - pGen->sizeOf(name->pType)); - } - if (accept('=')) { - if (tok == TOK_NUM) { - if (name) { - * (int*) name->pAddress = tokc; - } - next(); - } else { - error("Expected an integer constant"); - } - } - } - if (!accept(',')) { - break; - } - pDecl = expectDeclaration(pBaseType); - if (!pDecl) { - break; - } - if (! isDefined(pDecl->id)) { - addGlobalSymbol(pDecl); - } - name = VI(pDecl->id); - } - skip(';'); - } else { - // Function declaration - if (accept(';')) { - // forward declaration. - } else if (tok != '{') { - error("expected '{'"); - } else { - mpCurrentArena = &mLocalArena; - mpCurrentSymbolStack = &mLocals; - if (name) { - /* patch forward references */ - pGen->resolveForward((int) name->pForward); - /* put function address */ - name->pAddress = (void*) pCodeBuf->getPC(); - } - // Calculate stack offsets for parameters - mLocals.pushLevel(); - intptr_t a = 8; - int argCount = 0; - for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) { - Type* pArg = pP->pHead; - if (pArg->id) { - addLocalSymbol(pArg); - } - /* read param name and compute offset */ - Type* pPassingType = passingType(pArg); - size_t alignment = pGen->alignmentOf(pPassingType); - a = (a + alignment - 1) & ~ (alignment-1); - if (pArg->id) { - VI(pArg->id)->pAddress = (void*) a; - } - a = a + pGen->sizeOf(pPassingType); - argCount++; - } - rsym = loc = 0; - pReturnType = pDecl->pHead; - a = pGen->functionEntry(pDecl); - block(0, 0, true); - pGen->gsym(rsym); - pGen->functionExit(pDecl, a, loc); - mLocals.popLevel(); - mpCurrentArena = &mGlobalArena; - mpCurrentSymbolStack = &mGlobals; - } - } - } - } - - Type* passingType(Type* pType) { - switch (pType->tag) { - case TY_CHAR: - case TY_SHORT: - return mkpInt; - default: - return pType; - } - } - - char* allocGlobalSpace(size_t alignment, size_t bytes) { - size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1); - size_t end = base + bytes; - if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) { - error("Global space exhausted"); - assert(false); - return NULL; - } - char* result = (char*) base; - glo = (char*) end; - return result; - } - - void cleanup() { - if (pGlobalBase != 0) { - free(pGlobalBase); - pGlobalBase = 0; - } - if (pGen) { - delete pGen; - pGen = 0; - } - if (pCodeBuf) { - delete pCodeBuf; - pCodeBuf = 0; - } - if (file) { - delete file; - file = 0; - } - } - - // One-time initialization, when class is constructed. - void init() { - mpSymbolLookupFn = 0; - mpSymbolLookupContext = 0; - } - - void clear() { - tok = 0; - tokc = 0; - tokl = 0; - ch = 0; - rsym = 0; - loc = 0; - glo = 0; - macroLevel = -1; - file = 0; - pGlobalBase = 0; - pCodeBuf = 0; - pGen = 0; - mPragmaStringCount = 0; - mCompileResult = 0; - mLineNumber = 1; - mbBumpLine = false; - mbSuppressMacroExpansion = false; - } - - void setArchitecture(const char* architecture) { - delete pGen; - pGen = 0; - - delete pCodeBuf; - pCodeBuf = new CodeBuf(); - - if (architecture != NULL) { -#ifdef PROVIDE_ARM_CODEGEN - if (! pGen && strcmp(architecture, "arm") == 0) { - pGen = new ARMCodeGenerator(); - pCodeBuf = new ARMCodeBuf(pCodeBuf); - } -#endif -#ifdef PROVIDE_X86_CODEGEN - if (! pGen && strcmp(architecture, "x86") == 0) { - pGen = new X86CodeGenerator(); - } -#endif - if (!pGen ) { - error("Unknown architecture %s\n", architecture); - } - } - - if (pGen == NULL) { -#if defined(DEFAULT_ARM_CODEGEN) - pGen = new ARMCodeGenerator(); - pCodeBuf = new ARMCodeBuf(pCodeBuf); -#elif defined(DEFAULT_X86_CODEGEN) - pGen = new X86CodeGenerator(); -#endif - } - if (pGen == NULL) { - error("No code generator defined."); - } else { - pGen->setErrorSink(this); - pGen->setTypes(mkpInt); - } - } - -public: - struct args { - args() { - architecture = 0; - } - const char* architecture; - }; - - Compiler() { - init(); - clear(); - } - - ~Compiler() { - cleanup(); - } - - void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) { - mpSymbolLookupFn = pFn; - mpSymbolLookupContext = pContext; - } - - int compile(const char* text, size_t textLength) { - int result; - - mpCurrentArena = &mGlobalArena; - createPrimitiveTypes(); - cleanup(); - clear(); - mTokenTable.setArena(&mGlobalArena); - mGlobals.setArena(&mGlobalArena); - mGlobals.setTokenTable(&mTokenTable); - mLocals.setArena(&mLocalArena); - mLocals.setTokenTable(&mTokenTable); - - internKeywords(); - setArchitecture(NULL); - if (!pGen) { - return -1; - } -#ifdef PROVIDE_TRACE_CODEGEN - pGen = new TraceCodeGenerator(pGen); -#endif - pGen->setErrorSink(this); - - if (pCodeBuf) { - pCodeBuf->init(ALLOC_SIZE); - } - pGen->init(pCodeBuf); - file = new TextInputStream(text, textLength); - pGlobalBase = (char*) calloc(1, ALLOC_SIZE); - glo = pGlobalBase; - inp(); - next(); - globalDeclarations(); - checkForUndefinedForwardReferences(); - result = pGen->finishCompile(); - if (result == 0) { - if (mErrorBuf.len()) { - result = -2; - } - } - mCompileResult = result; - return result; - } - - void createPrimitiveTypes() { - mkpInt = createType(TY_INT, NULL, NULL); - mkpShort = createType(TY_SHORT, NULL, NULL); - mkpChar = createType(TY_CHAR, NULL, NULL); - mkpVoid = createType(TY_VOID, NULL, NULL); - mkpFloat = createType(TY_FLOAT, NULL, NULL); - mkpDouble = createType(TY_DOUBLE, NULL, NULL); - mkpIntFn = createType(TY_FUNC, mkpInt, NULL); - mkpIntPtr = createPtrType(mkpInt); - mkpCharPtr = createPtrType(mkpChar); - mkpFloatPtr = createPtrType(mkpFloat); - mkpDoublePtr = createPtrType(mkpDouble); - mkpPtrIntFn = createPtrType(mkpIntFn); - } - - void checkForUndefinedForwardReferences() { - mGlobals.forEach(static_ufrcFn, this); - } - - static bool static_ufrcFn(VariableInfo* value, void* context) { - Compiler* pCompiler = (Compiler*) context; - return pCompiler->undefinedForwardReferenceCheck(value); - } - - bool undefinedForwardReferenceCheck(VariableInfo* value) { - if (!value->pAddress && value->pForward) { - error("Undefined forward reference: %s", - mTokenTable[value->tok].pText); - } - return true; - } - - /* Look through the symbol table to find a symbol. - * If found, return its value. - */ - void* lookup(const char* name) { - if (mCompileResult == 0) { - tokenid_t tok = mTokenTable.intern(name, strlen(name)); - VariableInfo* pVariableInfo = VI(tok); - if (pVariableInfo) { - return pVariableInfo->pAddress; - } - } - return NULL; - } - - void getPragmas(ACCsizei* actualStringCount, - ACCsizei maxStringCount, ACCchar** strings) { - int stringCount = mPragmaStringCount; - if (actualStringCount) { - *actualStringCount = stringCount; - } - if (stringCount > maxStringCount) { - stringCount = maxStringCount; - } - if (strings) { - char* pPragmas = mPragmas.getUnwrapped(); - while (stringCount-- > 0) { - *strings++ = pPragmas; - pPragmas += strlen(pPragmas) + 1; - } - } - } - - void getProgramBinary(ACCvoid** base, ACCsizei* length) { - *base = pCodeBuf->getBase(); - *length = (ACCsizei) pCodeBuf->getSize(); - } - - char* getErrorMessage() { - return mErrorBuf.getUnwrapped(); - } -}; - -const char* Compiler::operatorChars = - "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@"; - -const char Compiler::operatorLevel[] = - {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, - 5, 5, /* ==, != */ - 9, 10, /* &&, || */ - 6, 7, 8, /* & ^ | */ - 2, 2 /* ~ ! */ - }; - -#ifdef PROVIDE_X86_CODEGEN -const int Compiler::X86CodeGenerator::operatorHelper[] = { - 0x1, // ++ - 0xff, // -- - 0xc1af0f, // * - 0xf9f79991, // / - 0xf9f79991, // % (With manual assist to swap results) - 0xc801, // + - 0xd8f7c829, // - - 0xe0d391, // << - 0xf8d391, // >> - 0xe, // <= - 0xd, // >= - 0xc, // < - 0xf, // > - 0x4, // == - 0x5, // != - 0x0, // && - 0x1, // || - 0xc821, // & - 0xc831, // ^ - 0xc809, // | - 0xd0f7, // ~ - 0x4 // ! -}; -#endif - -struct ACCscript { - ACCscript() { - text = 0; - textLength = 0; - accError = ACC_NO_ERROR; - } - - ~ACCscript() { - delete text; - } - - void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) { - compiler.registerSymbolCallback(pFn, pContext); - } - - void setError(ACCenum error) { - if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) { - accError = error; - } - } - - ACCenum getError() { - ACCenum result = accError; - accError = ACC_NO_ERROR; - return result; - } - - Compiler compiler; - char* text; - int textLength; - ACCenum accError; -}; - - -extern "C" -ACCscript* accCreateScript() { - return new ACCscript(); -} - -extern "C" -ACCenum accGetError( ACCscript* script ) { - return script->getError(); -} - -extern "C" -void accDeleteScript(ACCscript* script) { - delete script; -} - -extern "C" -void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn, - ACCvoid* pContext) { - script->registerSymbolCallback(pFn, pContext); -} - -extern "C" -void accScriptSource(ACCscript* script, - ACCsizei count, - const ACCchar ** string, - const ACCint * length) { - int totalLength = 0; - for(int i = 0; i < count; i++) { - int len = -1; - const ACCchar* s = string[i]; - if (length) { - len = length[i]; - } - if (len < 0) { - len = strlen(s); - } - totalLength += len; - } - delete script->text; - char* text = new char[totalLength + 1]; - script->text = text; - script->textLength = totalLength; - char* dest = text; - for(int i = 0; i < count; i++) { - int len = -1; - const ACCchar* s = string[i]; - if (length) { - len = length[i]; - } - if (len < 0) { - len = strlen(s); - } - memcpy(dest, s, len); - dest += len; - } - text[totalLength] = '\0'; - -#ifdef DEBUG_SAVE_INPUT_TO_FILE - LOGD("Saving input to file..."); - int counter; - char path[PATH_MAX]; - for (counter = 0; counter < 4096; counter++) { - sprintf(path, DEBUG_DUMP_PATTERN, counter); - if(access(path, F_OK) != 0) { - break; - } - } - if (counter < 4096) { - LOGD("Saving input to file %s", path); - FILE* fd = fopen(path, "w"); - if (fd) { - fwrite(text, totalLength, 1, fd); - fclose(fd); - LOGD("Saved input to file %s", path); - } else { - LOGD("Could not save. errno: %d", errno); - } - } -#endif -} - -extern "C" -void accCompileScript(ACCscript* script) { - int result = script->compiler.compile(script->text, script->textLength); - if (result) { - script->setError(ACC_INVALID_OPERATION); - } -} - -extern "C" -void accGetScriptiv(ACCscript* script, - ACCenum pname, - ACCint * params) { - switch (pname) { - case ACC_INFO_LOG_LENGTH: - *params = 0; - break; - } -} - -extern "C" -void accGetScriptInfoLog(ACCscript* script, - ACCsizei maxLength, - ACCsizei * length, - ACCchar * infoLog) { - char* message = script->compiler.getErrorMessage(); - int messageLength = strlen(message) + 1; - if (length) { - *length = messageLength; - } - if (infoLog && maxLength > 0) { - int trimmedLength = maxLength < messageLength ? - maxLength : messageLength; - memcpy(infoLog, message, trimmedLength); - infoLog[trimmedLength] = 0; - } -} - -extern "C" -void accGetScriptLabel(ACCscript* script, const ACCchar * name, - ACCvoid ** address) { - void* value = script->compiler.lookup(name); - if (value) { - *address = value; - } else { - script->setError(ACC_INVALID_VALUE); - } -} - -extern "C" -void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount, - ACCsizei maxStringCount, ACCchar** strings){ - script->compiler.getPragmas(actualStringCount, maxStringCount, strings); -} - -extern "C" -void accGetProgramBinary(ACCscript* script, - ACCvoid** base, ACCsizei* length) { - script->compiler.getProgramBinary(base, length); -} - - -} // namespace acc - |