Allow Const's as operands to Binop
authorLars Knoll <lars.knoll@digia.com>
Thu, 25 Oct 2012 14:31:12 +0000 (16:31 +0200)
committerErik Verbruggen <erik.verbruggen@digia.com>
Mon, 12 Nov 2012 08:40:06 +0000 (09:40 +0100)
This allows us to use expressions such as
%x = %y + const
in the IR.

This still requires an implementation for moth.

Change-Id: I134e96ddad08bcbe4f3ea5fa27c5338a96acac80
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
moth/qv4isel_moth.cpp
qmljs_runtime.h
qv4codegen.cpp
qv4ir.cpp
qv4ir_p.h
qv4isel_masm.cpp
qv4isel_masm_p.h

index 3ab6e05..23cef69 100644 (file)
@@ -394,8 +394,8 @@ void InstructionSelection::visitMove(IR::Move *s)
         } else if (IR::Binop *b = s->source->asBinop()) {
             Instruction::Binop binop;
             binop.alu = aluOpFunction(b->op);
-            binop.lhsTempIndex = b->left->index;
-            binop.rhsTempIndex = b->right->index;
+//            binop.lhsTempIndex = b->left->index;
+//            binop.rhsTempIndex = b->right->index;
             addInstruction(binop);
         } else if (IR::Call *c = s->source->asCall()) {
             if (c->base->asName()) {
@@ -554,8 +554,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
     } else if (IR::Binop *b = s->cond->asBinop()) {
         Instruction::Binop binop;
         binop.alu = aluOpFunction(b->op);
-        binop.lhsTempIndex = b->left->index;
-        binop.rhsTempIndex = b->right->index;
+//        binop.lhsTempIndex = b->left->index;
+//        binop.rhsTempIndex = b->right->index;
         addInstruction(binop);
     } else {
         Q_UNREACHABLE();
index 85ec5ea..751fd12 100644 (file)
@@ -228,6 +228,9 @@ struct Value
     static inline bool integerCompatible(Value a, Value b) {
         return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt;
     }
+    static inline bool bothDouble(Value a, Value b) {
+        return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
+    }
     inline bool tryIntegerConversion() {
         bool b = isConvertibleToInt();
         if (b)
@@ -908,7 +911,7 @@ inline Value __qmljs_add(Value left, Value right, Context *ctx)
     if (Value::integerCompatible(left, right))
         return add_int32(left.integerValue(), right.integerValue());
 
-    if (left.isDouble() & right.isDouble())
+    if (Value::bothDouble(left, right))
         return Value::fromDouble(left.doubleValue() + right.doubleValue());
 
     return __qmljs_add_helper(left, right, ctx);
@@ -1064,7 +1067,7 @@ inline Bool __qmljs_cmp_gt(Value left, Value right, Context *ctx)
 
     if (Value::integerCompatible(left, right))
         return left.integerValue() > right.integerValue();
-    if (left.isDouble() && right.isDouble()) {
+    if (Value::bothDouble(left, right)) {
         return left.doubleValue() > right.doubleValue();
     } else if (left.isString() && right.isString()) {
         return __qmljs_string_compare(ctx, right.stringValue(), left.stringValue());
@@ -1084,7 +1087,7 @@ inline Bool __qmljs_cmp_lt(Value left, Value right, Context *ctx)
 
     if (Value::integerCompatible(left, right))
         return left.integerValue() < right.integerValue();
-    if (left.isDouble() && right.isDouble()) {
+    if (Value::bothDouble(left, right)) {
         return left.doubleValue() < right.doubleValue();
     } else if (left.isString() && right.isString()) {
         return __qmljs_string_compare(ctx, left.stringValue(), right.stringValue());
@@ -1104,7 +1107,7 @@ inline Bool __qmljs_cmp_ge(Value left, Value right, Context *ctx)
 
     if (Value::integerCompatible(left, right))
         return left.integerValue() >= right.integerValue();
-    if (left.isDouble() && right.isDouble()) {
+    if (Value::bothDouble(left, right)) {
         return left.doubleValue() >= right.doubleValue();
     } else if (left.isString() && right.isString()) {
         return !__qmljs_string_compare(ctx, left.stringValue(), right.stringValue());
@@ -1124,7 +1127,7 @@ inline Bool __qmljs_cmp_le(Value left, Value right, Context *ctx)
 
     if (Value::integerCompatible(left, right))
         return left.integerValue() <= right.integerValue();
-    if (left.isDouble() && right.isDouble()) {
+    if (Value::bothDouble(left, right)) {
         return left.doubleValue() <= right.doubleValue();
     } else if (left.isString() && right.isString()) {
         return !__qmljs_string_compare(ctx, right.stringValue(), left.stringValue());
@@ -1140,7 +1143,7 @@ inline Bool __qmljs_cmp_eq(Value left, Value right, Context *ctx)
     TRACE2(left, right);
 
     // need to test for doubles first as NaN != NaN
-    if (left.isDouble() && right.isDouble())
+    if (Value::bothDouble(left, right))
         return left.doubleValue() == right.doubleValue();
     if (left.val == right.val)
         return true;
index 8f8db30..0276cd3 100644 (file)
@@ -489,20 +489,22 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right)
         }
     }
 
-    if (!left->asTemp()) {
+    if (!left->asTemp() && !left->asConst()) {
         const unsigned t = _block->newTemp();
         move(_block->TEMP(t), left);
         left = _block->TEMP(t);
     }
 
-    if (!right->asTemp()) {
+    if (!right->asTemp() && !right->asConst()) {
         const unsigned t = _block->newTemp();
         move(_block->TEMP(t), right);
         right = _block->TEMP(t);
     }
 
-    assert(left->asTemp() && right->asTemp());
-    return _block->BINOP(op, left->asTemp(), right->asTemp());
+    assert(left->asTemp() || left->asConst());
+    assert(right->asTemp() || right->asConst());
+
+    return _block->BINOP(op, left, right);
 }
 
 IR::Expr *Codegen::call(IR::Expr *base, IR::ExprList *args)
index 21b0fe7..811c802 100644 (file)
--- a/qv4ir.cpp
+++ b/qv4ir.cpp
@@ -477,7 +477,7 @@ Expr *BasicBlock::UNOP(AluOp op, Temp *expr)
     return e;
 }
 
-Expr *BasicBlock::BINOP(AluOp op, Temp *left, Temp *right)
+Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
 {
     Binop *e = function->New<Binop>();
     e->init(op, left, right);
index 9e004a5..f736b02 100644 (file)
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -341,10 +341,10 @@ struct Unop: Expr {
 
 struct Binop: Expr {
     AluOp op;
-    Temp *left;
-    Temp *right;
+    Expr *left; // Temp or Const
+    Expr *right; // Temp or Const
 
-    void init(AluOp op, Temp *left, Temp *right)
+    void init(AluOp op, Expr *left, Expr *right)
     {
         this->op = op;
         this->left = left;
@@ -682,7 +682,7 @@ struct BasicBlock {
     Closure *CLOSURE(Function *function);
 
     Expr *UNOP(AluOp op, Temp *expr);
-    Expr *BINOP(AluOp op, Temp *left, Temp *right);
+    Expr *BINOP(AluOp op, Expr *left, Expr *right);
     Expr *CALL(Expr *base, ExprList *args = 0);
     Expr *NEW(Expr *base, ExprList *args = 0);
     Expr *SUBSCRIPT(Temp *base, Temp *index);
index 2deab59..250d324 100644 (file)
@@ -440,9 +440,8 @@ void InstructionSelection::visitMove(IR::Move *s)
                     return;
                 }
             } else if (IR::Binop *b = s->source->asBinop()) {
-                IR::Temp *l = b->left->asTemp();
-                IR::Temp *r = b->right->asTemp();
-                if (l && r) {
+                if ((b->left->asTemp() || b->left->asConst()) &&
+                    (b->right->asTemp() || b->right->asConst())) {
                     Value (*op)(const Value, const Value, Context *) = 0;
                     const char* opName = 0;
 
@@ -485,7 +484,7 @@ void InstructionSelection::visitMove(IR::Move *s)
                     }
 
                     if (op) {
-                        generateFunctionCallImp(t, opName, op, l, r, ContextRegister);
+                        generateFunctionCallImp(t, opName, op, b->left, b->right, ContextRegister);
                     }
                     return;
                 }
@@ -670,9 +669,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
         jumpToBlock(s->iffalse);
         return;
     } else if (IR::Binop *b = s->cond->asBinop()) {
-        IR::Temp *l = b->left->asTemp();
-        IR::Temp *r = b->right->asTemp();
-        if (l && r) {
+        if ((b->left->asTemp() || b->left->asConst()) &&
+            (b->right->asTemp() || b->right->asConst())) {
             Bool (*op)(const Value, const Value, Context *ctx) = 0;
             const char *opName = 0;
             switch (b->op) {
@@ -689,7 +687,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
             case IR::OpIn: setOp(op, opName, __qmljs_cmp_in); break;
             } // switch
 
-            generateFunctionCallImp(ReturnValueRegister, opName, op, l, r, ContextRegister);
+            generateFunctionCallImp(ReturnValueRegister, opName, op, b->left, b->right, ContextRegister);
 
             Jump target = branch32(NotEqual, ReturnValueRegister, TrustedImm32(0));
             _patches[s->iftrue].append(target);
index 32f71ae..a4ab604 100644 (file)
@@ -283,6 +283,45 @@ private:
             load64(addr, dest);
         }
     }
+
+    void loadArgument(IR::Const* c, RegisterID dest)
+    {
+        VM::Value v;
+        switch (c->type) {
+        case IR::NullType:
+            v = VM::Value::nullValue();
+            break;
+        case IR::UndefinedType:
+            v = VM::Value::undefinedValue();
+            break;
+        case IR::BoolType:
+            v = VM::Value::fromBoolean(c->value != 0);
+            break;
+        case IR::NumberType: {
+            int ival = (int)c->value;
+            if (ival == c->value) {
+                v = VM::Value::fromInt32(ival);
+            } else {
+                v = VM::Value::fromDouble(c->value);
+            }
+        }
+        }
+        move(TrustedImm64(v.val), dest);
+    }
+
+    void loadArgument(IR::Expr* expr, RegisterID dest)
+    {
+        if (!expr) {
+            VM::Value undefined = VM::Value::undefinedValue();
+            move(TrustedImm64(undefined.val), dest);
+        } else if (expr->asTemp()){
+            loadArgument(expr->asTemp(), dest);
+        } else if (expr->asConst()) {
+            loadArgument(expr->asConst(), dest);
+        } else {
+            assert(!"unimplemented expression type in loadArgument");
+        }
+    }
 #endif
 
     void loadArgument(VM::String* string, RegisterID dest)
@@ -363,6 +402,45 @@ private:
         }
     }
 
+    void push(IR::Const* c)
+    {
+        VM::Value v;
+        switch (c->type) {
+        case IR::NullType:
+            v = VM::Value::nullValue();
+            break;
+        case IR::UndefinedType:
+            v = VM::Value::undefinedValue();
+            break;
+        case IR::BoolType:
+            v = VM::Value::fromBoolean(c->value != 0);
+            break;
+        case IR::NumberType: {
+            int ival = (int)c->value;
+            if (ival == c->value) {
+                v = VM::Value::fromInt32(ival);
+            } else {
+                v = VM::Value::fromDouble(c->value);
+            }
+        }
+        }
+        push(v);
+    }
+
+    void push(IR::Expr* e)
+    {
+        if (!e) {
+            VM::Value undefined = VM::Value::undefinedValue();
+            push(undefined);
+        } else if (IR::Const *c = e->asConst())
+            push(c);
+        else if (IR::Temp *t = e->asTemp()) {
+            push(t);
+        } else {
+            assert(!"Trying to push an expression that is not a Temp or Const");
+        }
+    }
+
     void push(TrustedImmPtr ptr)
     {
         move(TrustedImmPtr(ptr), ScratchRegister);
@@ -400,6 +478,8 @@ private:
     { return RegisterSize; }
     static inline int sizeOfArgument(IR::Temp*)
     { return 8; } // Size of value
+    static inline int sizeOfArgument(IR::Expr*)
+    { return 8; } // Size of value
     static inline int sizeOfArgument(const Pointer&)
     { return sizeof(void*); }
     static inline int sizeOfArgument(VM::String* string)