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

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

Merge change 6597

* changes:
  Implement x86 floating point operations
parents de394b23 a39749f6
Loading
Loading
Loading
Loading
+215 −43
Original line number Diff line number Diff line
@@ -316,7 +316,7 @@ class Compiler : public ErrorSink {
         * Pops TOS.
         * op specifies the comparison.
         */
        virtual void gcmp(int op) = 0;
        virtual void gcmp(int op, Type* pResultType) = 0;

        /* Perform the arithmetic op specified by op. TOS is the
         * left argument, R0 is the right argument.
@@ -327,7 +327,7 @@ class Compiler : public ErrorSink {
        /* Compare 0 against R0, and store the boolean result in R0.
         * op specifies the comparison.
         */
        virtual void gUnaryCmp(int op) = 0;
        virtual void gUnaryCmp(int op, Type* pResultType) = 0;

        /* Perform the arithmetic op specified by op. 0 is the
         * left argument, R0 is the right argument.
@@ -647,7 +647,7 @@ class Compiler : public ErrorSink {
            return o4(branch | encodeAddress(t));
        }

        virtual void gcmp(int op) {
        virtual void gcmp(int op, Type* pResultType) {
            LOG_API("gcmp(%d);\n", op);
            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
            mStackUse -= 4;
@@ -729,12 +729,12 @@ class Compiler : public ErrorSink {
            popType();
        }

        virtual void gUnaryCmp(int op) {
            LOG_API("gcmp(%d);\n", op);
        virtual void gUnaryCmp(int op, Type* pResultType) {
            LOG_API("gUnaryCmp(%d);\n", op);
            o4(0xE3A01000);  // mov    r1, #0
            o4(0xE1510000); // cmp r1, r1
            switch(op) {
            case OP_NOT_EQUALS:
            case OP_LOGICAL_NOT:
                o4(0x03A00000); // moveq r0,#0
                o4(0x13A00001); // movne r0,#1
                break;
@@ -742,14 +742,12 @@ class Compiler : public ErrorSink {
                error("Unknown unary comparison op %d", op);
                break;
            }
            setR0Type(pResultType);
        }

        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
@@ -1219,7 +1217,14 @@ class Compiler : public ErrorSink {
            return psym(0x84 + l, t);
        }

        virtual void gcmp(int op) {
        virtual void gcmp(int op, Type* pResultType) {
            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 */
@@ -1228,17 +1233,110 @@ class Compiler : public ErrorSink {
                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(pResultType);
        }

        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) {
                // TODO: Deal with pointer arithmetic
                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;
                }
                popType();
                setR0Type(pResultType);
                printf("genop: result type %d\n", pResultType->tag);
            }
        }



        virtual void gUnaryCmp(int op) {
        virtual void gUnaryCmp(int op, Type* pResultType) {
            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 */
@@ -1247,10 +1345,53 @@ class Compiler : public ErrorSink {
                            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("genUnaryCmp unsupported type");
                        break;
                }
            }
            setR0Type(pResultType);
        }

        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() {
@@ -1592,6 +1733,34 @@ class Compiler : public ErrorSink {
            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
                }
            }
        }
    };

#endif // PROVIDE_X86_CODEGEN
@@ -1656,9 +1825,9 @@ class Compiler : public ErrorSink {
            return result;
        }

        virtual void gcmp(int op) {
            fprintf(stderr, "gcmp(%d)\n", op);
            mpBase->gcmp(op);
        virtual void gcmp(int op, Type* pResultType) {
            fprintf(stderr, "gcmp(%d, pResultType)\n", op);
            mpBase->gcmp(op, pResultType);
        }

        virtual void genOp(int op) {
@@ -1667,9 +1836,9 @@ class Compiler : public ErrorSink {
        }


        virtual void gUnaryCmp(int op) {
            fprintf(stderr, "gUnaryCmp(%d)\n", op);
            mpBase->gUnaryCmp(op);
        virtual void gUnaryCmp(int op, Type* pResultType) {
            fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op);
            mpBase->gUnaryCmp(op, pResultType);
        }

        virtual void genUnaryOp(int op) {
@@ -2923,9 +3092,12 @@ class Compiler : public ErrorSink {
                /* -, +, !, ~ */
                unary(false);
                if (t == '!')
                    pGen->gUnaryCmp(a);
                else
                    pGen->gUnaryCmp(a, mkpInt);
                else if (t == '+') {
                    // ignore unary plus.
                } else {
                    pGen->genUnaryOp(a);
                }
            } else if (t == '(') {
                expr();
                skip(')');
@@ -3090,7 +3262,7 @@ class Compiler : public ErrorSink {
                    binaryOp(level);

                    if ((level == 4) | (level == 5)) {
                        pGen->gcmp(t);
                        pGen->gcmp(t, mkpInt);
                    } else {
                        pGen->genOp(t);
                    }
@@ -3665,7 +3837,7 @@ class Compiler : public ErrorSink {
    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) > ALLOC_SIZE) {
        if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
            error("Global space exhausted");
            return NULL;
        }
+115 −0
Original line number Diff line number Diff line
// Test floating point operations.

void unaryOps() {
    // Unary ops
    printf("-%g = %g\n", 1.1, -1.1);
    printf("!%g = %d\n", 1.2, !1.2);
    printf("!%g = %d\n", 0.0, !0,0);
}

void binaryOps() {
    printf("double op double:\n");
    printf("%g + %g = %g\n", 1.0, 2.0, 1.0 + 2.0);
    printf("%g - %g = %g\n", 1.0, 2.0, 1.0 - 2.0);
    printf("%g * %g = %g\n", 1.0, 2.0, 1.0 * 2.0);
    printf("%g / %g = %g\n", 1.0, 2.0, 1.0 / 2.0);

    printf("float op float:\n");
    printf("%g + %g = %g\n", 1.0f, 2.0f, 1.0f + 2.0f);
    printf("%g - %g = %g\n", 1.0f, 2.0f, 1.0f - 2.0f);
    printf("%g * %g = %g\n", 1.0f, 2.0f, 1.0f * 2.0f);
    printf("%g / %g = %g\n", 1.0f, 2.0f, 1.0f / 2.0f);

    printf("double op float:\n");
    printf("%g + %g = %g\n", 1.0, 2.0f, 1.0 + 2.0f);
    printf("%g - %g = %g\n", 1.0, 2.0f, 1.0 - 2.0f);
    printf("%g * %g = %g\n", 1.0, 2.0f, 1.0 * 2.0f);
    printf("%g / %g = %g\n", 1.0, 2.0f, 1.0 / 2.0f);

    printf("double op int:\n");
    printf("%g + %d = %g\n", 1.0, 2, 1.0 + 2);
    printf("%g - %d = %g\n", 1.0, 2, 1.0 - 2);
    printf("%g * %d = %g\n", 1.0, 2, 1.0 * 2);
    printf("%g / %d = %g\n", 1.0, 2, 1.0 / 2);

    printf("int op double:\n");
    printf("%d + %g = %g\n", 1, 2.0, 1 + 2.0);
    printf("%d - %g = %g\n", 1, 2.0, 1 - 2.0);
    printf("%d * %g = %g\n", 1, 2.0, 1 * 2.0);
    printf("%d / %g = %g\n", 1, 2.0, 1 / 2.0);
}

void comparisonTestdd(double a, double b) {
    printf("%g op %g: < %d   <= %d   == %d   >= %d   > %d   != %d\n",
           a, b, a < b, a <= b, a == b, a >= b, a > b, a != b);
}

void comparisonOpsdd() {
    printf("double op double:\n");
    comparisonTestdd(1.0, 2.0);
    comparisonTestdd(1.0, 1.0);
    comparisonTestdd(2.0, 1.0);
}


void comparisonTestdf(double a, float b) {
    printf("%g op %g: < %d   <= %d   == %d   >= %d   > %d   != %d\n",
           a, b, a < b, a <= b, a == b, a >= b, a > b, a != b);
}

void comparisonOpsdf() {
    printf("double op float:\n");
    comparisonTestdf(1.0, 2.0f);
    comparisonTestdf(1.0, 1.0f);
    comparisonTestdf(2.0, 1.0f);
}

void comparisonTestff(float a, float b) {
    printf("%g op %g: < %d   <= %d   == %d   >= %d   > %d   != %d\n",
           a, b, a < b, a <= b, a == b, a >= b, a > b, a != b);
}

void comparisonOpsff() {
    printf("float op float:\n");
    comparisonTestff(1.0f, 2.0f);
    comparisonTestff(1.0f, 1.0f);
    comparisonTestff(2.0f, 1.0f);
}
void comparisonTestid(int a, double b) {
    printf("%d op %g: < %d   <= %d   == %d   >= %d   > %d   != %d\n",
           a, b, a < b, a <= b, a == b, a >= b, a > b, a != b);
}

void comparisonOpsid() {
    printf("int op double:\n");
    comparisonTestid(1, 2.0f);
    comparisonTestid(1, 1.0f);
    comparisonTestid(2, 1.0f);
}
void comparisonTestdi(double a, int b) {
    printf("%g op %d: < %d   <= %d   == %d   >= %d   > %d   != %d\n",
           a, b, a < b, a <= b, a == b, a >= b, a > b, a != b);
}

void comparisonOpsdi() {
    printf("double op int:\n");
    comparisonTestdi(1.0f, 2);
    comparisonTestdi(1.0f, 1);
    comparisonTestdi(2.0f, 1);
}

void comparisonOps() {
    comparisonOpsdd();
    comparisonOpsdf();
    comparisonOpsff();
    comparisonOpsid();
    comparisonOpsdi();
}


int main() {
    unaryOps();
    binaryOps();
    comparisonOps();
    return 0;
}