Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18166558 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 6322

* changes:
  Start teaching the code generator about types.
parents 73aaaac1 9eed7a2c
Loading
Loading
Loading
Loading
+240 −76
Original line number Diff line number Diff line
@@ -68,6 +68,8 @@ public:
};

class Compiler : public ErrorSink {
    struct Type;

    class CodeBuf {
        char* ind; // Output code pointer
        char* pProgramBase;
@@ -157,8 +159,7 @@ class Compiler : public ErrorSink {
     * architecture.
     *
     * The code generator implements the following abstract machine:
     * R0 - the main accumulator.
     * R1 - the secondary accumulator.
     * R0 - the accumulator.
     * FP - a frame pointer for accessing function arguments and local
     *      variables.
     * SP - a stack pointer for storing intermediate results while evaluating
@@ -168,7 +169,7 @@ class Compiler : public ErrorSink {
     * 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 and R1 registers are not saved across function calls. The
     * The R0 register is not saved across function calls. The
     * FP and SP registers are saved.
     */

@@ -232,41 +233,42 @@ class Compiler : public ErrorSink {
         */
        virtual int gtst(bool l, int t) = 0;

        /* Compare R1 against R0, and store the boolean result in R0.
        /* 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. R1 is the
        /* 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;

        /* Set R1 to 0.
        /* Compare 0 against R0, and store the boolean result in R0.
         * op specifies the comparison.
         */
        virtual void clearR1() = 0;
        virtual void gUnaryCmp(int op) = 0;

        /* Push R0 onto the stack.
        /* Perform the arithmetic op specified by op. 0 is the
         * left argument, R0 is the right argument.
         */
        virtual void pushR0() = 0;
        virtual void genUnaryOp(int op) = 0;

        /* Pop R1 off of the stack.
        /* Push R0 onto the stack.
         */
        virtual void popR1() = 0;
        virtual void pushR0() = 0;

        /* Store R0 to the address stored in R1.
         * isInt is true if a whole 4-byte integer value
         * should be stored, otherwise a 1-byte character
         * value should be stored.
        /* Store R0 to the address stored in TOS.
         * The TOS is popped.
         * pPointerType is the type of the pointer (of the input R0).
         */
        virtual void storeR0ToR1(bool isInt) = 0;
        virtual void storeR0ToTOS(Type* pPointerType) = 0;

        /* Load R0 from the address stored in R0.
         * isInt is true if a whole 4-byte integer value
         * should be loaded, otherwise a 1-byte character
         * value should be loaded.
         * pPointerType is the type of the pointer (of the input R0).
         */
        virtual void loadR0FromR0(bool isInt) = 0;
        virtual void loadR0FromR0(Type* pPointerType) = 0;

        /* Load the absolute address of a variable to R0.
         * If ea <= LOCAL, then this is a local variable, or an
@@ -362,6 +364,16 @@ class Compiler : public ErrorSink {
         */
        virtual int jumpOffset() = 0;

        /**
         * Stack alignment (in bytes) for this type of data
         */
        virtual size_t stackAlignment(Type* type) = 0;

        /**
         * Array element alignment (in bytes) for this type of data.
         */
        virtual size_t sizeOf(Type* type) = 0;

    protected:
        /*
         * Output a byte. Handles all values, 0..ff.
@@ -392,6 +404,12 @@ class Compiler : public ErrorSink {
            mErrorSink->verror(fmt, ap);
            va_end(ap);
        }

        void assert(bool test) {
            if (!test) {
                error("code generator assertion failed.");
            }
        }
    private:
        CodeBuf* pCodeBuf;
        ErrorSink* mErrorSink;
@@ -489,6 +507,8 @@ class Compiler : public ErrorSink {

        virtual void gcmp(int op) {
            LOG_API("gcmp(%d);\n", op);
            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
            mStackUse -= 4;
            o4(0xE1510000); // cmp r1, r1
            switch(op) {
            case OP_EQUALS:
@@ -523,6 +543,8 @@ class Compiler : public ErrorSink {

        virtual void genOp(int op) {
            LOG_API("genOp(%d);\n", op);
            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
            mStackUse -= 4;
            switch(op) {
            case OP_MUL:
                o4(0x0E0000091); // mul     r0,r1,r0
@@ -563,9 +585,38 @@ class Compiler : public ErrorSink {
            }
        }

        virtual void clearR1() {
            LOG_API("clearR1();\n");
        virtual void gUnaryCmp(int op) {
            LOG_API("gcmp(%d);\n", op);
            o4(0xE3A01000);  // mov    r1, #0
            o4(0xE1510000); // cmp r1, r1
            switch(op) {
            case OP_NOT_EQUALS:
                o4(0x03A00000); // moveq r0,#0
                o4(0x13A00001); // movne r0,#1
                break;
             default:
                error("Unknown unary comparison op %d", op);
                break;
            }
        }

        virtual void genUnaryOp(int op) {
            LOG_API("genOp(%d);\n", op);
            switch(op) {
            case OP_PLUS:
                // Do nothing
                break;
            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;
            }
        }

        virtual void pushR0() {
@@ -575,28 +626,38 @@ class Compiler : public ErrorSink {
            LOG_STACK("pushR0: %d\n", mStackUse);
        }

        virtual void popR1() {
            LOG_API("popR1();\n");
        virtual void storeR0ToTOS(Type* pPointerType) {
            LOG_API("storeR0ToTOS(%d);\n", isInt);
            assert(pPointerType->tag == TY_POINTER);
            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
            mStackUse -= 4;
            LOG_STACK("popR1: %d\n", mStackUse);
        }

        virtual void storeR0ToR1(bool isInt) {
            LOG_API("storeR0ToR1(%d);\n", isInt);
            if (isInt) {
            switch (pPointerType->pHead->tag) {
                case TY_INT:
                    o4(0xE5810000); // str r0, [r1]
            } else {
                    break;
                case TY_CHAR:
                    o4(0xE5C10000); // strb r0, [r1]
                    break;
                default:
                    assert(false);
                    break;
            }
        }

        virtual void loadR0FromR0(bool isInt) {
            LOG_API("loadR0FromR0(%d);\n", isInt);
            if (isInt)
        virtual void loadR0FromR0(Type* pPointerType) {
            LOG_API("loadR0FromR0(%d);\n", pPointerType);
            assert(pPointerType->tag == TY_POINTER);
            switch (pPointerType->pHead->tag) {
                case TY_INT:
                    o4(0xE5900000); // ldr r0, [r0]
            else
                    break;
                case TY_CHAR:
                    o4(0xE5D00000); // ldrb r0, [r0]
                    break;
                default:
                    assert(false);
                    break;
            }
        }

        virtual void leaR0(int ea) {
@@ -834,6 +895,37 @@ class Compiler : public ErrorSink {
            return 0;
        }

        /**
         * Stack alignment (in bytes) for this type of data
         */
        virtual size_t stackAlignment(Type* pType){
            switch(pType->tag) {
                case TY_DOUBLE:
                    return 8;
                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_CHAR:
                    return 1;
                default:
                    return 0;
                case TY_FLOAT:
                    return 4;
                case TY_DOUBLE:
                    return 8;
                case TY_POINTER:
                    return 4;
            }
        }
    private:
        static FILE* disasmOut;

@@ -937,6 +1029,7 @@ class Compiler : public ErrorSink {

        virtual void gcmp(int op) {
            int t = decodeOp(op);
            o(0x59); /* pop %ecx */
            o(0xc139); /* cmp %eax,%ecx */
            li(0);
            o(0x0f); /* setxx %al */
@@ -945,32 +1038,60 @@ class Compiler : public ErrorSink {
        }

        virtual void genOp(int op) {
            o(0x59); /* pop %ecx */
            o(decodeOp(op));
            if (op == OP_MOD)
                o(0x92); /* xchg %edx, %eax */
        }

        virtual void clearR1() {
        virtual void gUnaryCmp(int op) {
            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);
        }

        virtual void genUnaryOp(int op) {
            oad(0xb9, 0); /* movl $0, %ecx */
            o(decodeOp(op));
        }

        virtual void pushR0() {
            o(0x50); /* push %eax */
        }

        virtual void popR1() {
        virtual void storeR0ToTOS(Type* pPointerType) {
            assert(pPointerType->tag == TY_POINTER);
            o(0x59); /* pop %ecx */
            switch (pPointerType->pHead->tag) {
                case TY_INT:
                    o(0x0189); /* movl %eax/%al, (%ecx) */
                    break;
                case TY_CHAR:
                    o(0x0188); /* movl %eax/%al, (%ecx) */
                    break;
                default:
                    assert(false);
                    break;
            }

        virtual void storeR0ToR1(bool isInt) {
            o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
        }

        virtual void loadR0FromR0(bool isInt) {
            if (isInt)
        virtual void loadR0FromR0(Type* pPointerType) {
            assert(pPointerType->tag == TY_POINTER);
            switch (pPointerType->pHead->tag) {
                case TY_INT:
                    o(0x8b); /* mov (%eax), %eax */
            else
                    break;
                case TY_CHAR:
                    o(0xbe0f); /* movsbl (%eax), %eax */
                    break;
                default:
                    assert(false);
                    break;
            }
            ob(0); /* add zero in code */
        }

@@ -1055,6 +1176,38 @@ class Compiler : public ErrorSink {
            return err;
        }

        /**
         * Stack alignment (in bytes) for this type of data
         */
        virtual size_t stackAlignment(Type* pType){
            switch(pType->tag) {
                case TY_DOUBLE:
                    return 8;
                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_CHAR:
                    return 1;
                default:
                    return 0;
                case TY_FLOAT:
                    return 4;
                case TY_DOUBLE:
                    return 8;
                case TY_POINTER:
                    return 4;
            }
        }

    private:

        /** Output 1 to 4 bytes.
@@ -1166,9 +1319,15 @@ class Compiler : public ErrorSink {
            mpBase->genOp(op);
        }

        virtual void clearR1() {
            fprintf(stderr, "clearR1()\n");
            mpBase->clearR1();

        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() {
@@ -1176,19 +1335,14 @@ class Compiler : public ErrorSink {
            mpBase->pushR0();
        }

        virtual void popR1() {
            fprintf(stderr, "popR1()\n");
            mpBase->popR1();
        }

        virtual void storeR0ToR1(bool isInt) {
            fprintf(stderr, "storeR0ToR1(%d)\n", isInt);
            mpBase->storeR0ToR1(isInt);
        virtual void storeR0ToTOS(Type* pPointerType) {
            fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType);
            mpBase->storeR0ToTOS(pPointerType);
        }

        virtual void loadR0FromR0(bool isInt) {
            fprintf(stderr, "loadR0FromR0(%d)\n", isInt);
            mpBase->loadR0FromR0(isInt);
        virtual void loadR0FromR0(Type* pPointerType) {
            fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType);
            mpBase->loadR0FromR0(pPointerType);
        }

        virtual void leaR0(int ea) {
@@ -1262,6 +1416,20 @@ class Compiler : public ErrorSink {
            fprintf(stderr, "finishCompile() = %d\n", result);
            return result;
        }

        /**
         * Stack alignment (in bytes) for this type of data
         */
        virtual size_t stackAlignment(Type* pType){
            return mpBase->stackAlignment(pType);
        }

        /**
         * Array element alignment (in bytes) for this type of data.
         */
        virtual size_t sizeOf(Type* pType){
            return mpBase->sizeOf(pType);
        }
    };

#endif // PROVIDE_TRACE_CODEGEN
@@ -1760,8 +1928,6 @@ class Compiler : public ErrorSink {
        int oldCh;
    };

    struct Type;

    struct VariableInfo {
        void* pAddress;
        void* pForward; // For a forward direction, linked list of data to fix up
@@ -1876,9 +2042,9 @@ class Compiler : public ErrorSink {
    SymbolStack mLocals;

    // Prebuilt types, makes things slightly faster.
    Type* mkpInt;
    Type* mkpChar;
    Type* mkpVoid;
    Type* mkpInt;        // int
    Type* mkpChar;       // char
    Type* mkpVoid;       // void
    Type* mkpFloat;
    Type* mkpDouble;
    Type* mkpIntPtr;
@@ -2381,11 +2547,10 @@ class Compiler : public ErrorSink {
            } else if (c == 2) {
                /* -, +, !, ~ */
                unary(false);
                pGen->clearR1();
                if (t == '!')
                    pGen->gcmp(a);
                    pGen->gUnaryCmp(a);
                else
                    pGen->genOp(a);
                    pGen->genUnaryOp(a);
            } else if (t == '(') {
                expr();
                skip(')');
@@ -2415,10 +2580,9 @@ class Compiler : public ErrorSink {
                if (accept('=')) {
                    pGen->pushR0();
                    expr();
                    pGen->popR1();
                    pGen->storeR0ToR1(t == TOK_INT);
                    pGen->storeR0ToTOS(pCast);
                } else if (t) {
                    pGen->loadR0FromR0(t == TOK_INT);
                    pGen->loadR0FromR0(pCast);
                }
                // Else we fall through to the function call below, with
                // t == 0 to trigger an indirect function call. Hack!
@@ -2515,7 +2679,6 @@ class Compiler : public ErrorSink {
                } else {
                    pGen->pushR0();
                    binaryOp(level);
                    pGen->popR1();

                    if ((level == 4) | (level == 5)) {
                        pGen->gcmp(t);
@@ -2958,6 +3121,7 @@ class Compiler : public ErrorSink {
                }
                int variableAddress = 0;
                addLocalSymbol(pDecl);
                loc = loc + pGen->sizeOf(pDecl);
                loc = loc + 4;
                variableAddress = -loc;
                VI(pDecl->id)->pAddress = (void*) variableAddress;