[masm] First implementation of inline addition / subtraction
authorSimon Hausmann <simon.hausmann@digia.com>
Sun, 2 Dec 2012 00:04:34 +0000 (01:04 +0100)
committerLars Knoll <lars.knoll@digia.com>
Sun, 2 Dec 2012 14:21:20 +0000 (15:21 +0100)
Change-Id: I4e54ae0feded8d99737245c870e0dfbb9b80247e
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
qv4isel_masm.cpp
qv4isel_masm_p.h

index 5f95442..37ad3fe 100644 (file)
@@ -484,6 +484,8 @@ void InstructionSelection::visitMove(IR::Move *s)
                     (b->right->asTemp() || b->right->asConst())) {
                     Value (*op)(const Value, const Value, ExecutionContext *) = 0;
                     const char* opName = 0;
+                    MemBinOpWithOverFlow inlineMemBinOp = 0;
+                    ImmBinOpWithOverFlow inlineImmBinOp = 0;
 
                     switch ((IR::AluOp) b->op) {
                     case IR::OpInvalid:
@@ -498,8 +500,18 @@ void InstructionSelection::visitMove(IR::Move *s)
                     case IR::OpBitAnd: setOp(op, opName, __qmljs_bit_and); break;
                     case IR::OpBitOr: setOp(op, opName, __qmljs_bit_or); break;
                     case IR::OpBitXor: setOp(op, opName, __qmljs_bit_xor); break;
-                    case IR::OpAdd: setOp(op, opName, __qmljs_add); break;
-                    case IR::OpSub: setOp(op, opName, __qmljs_sub); break;
+                    case IR::OpAdd: {
+                        setOp(op, opName, __qmljs_add);
+                        inlineMemBinOp = &JSC::MacroAssembler::branchAdd32;
+                        inlineImmBinOp = &JSC::MacroAssembler::branchAdd32;
+                        break;
+                    }
+                    case IR::OpSub: {
+                        setOp(op, opName, __qmljs_sub);
+                        inlineMemBinOp = &JSC::MacroAssembler::branchSub32;
+                        inlineImmBinOp = &JSC::MacroAssembler::branchSub32;
+                        break;
+                    }
                     case IR::OpMul: setOp(op, opName, __qmljs_mul); break;
                     case IR::OpDiv: setOp(op, opName, __qmljs_div); break;
                     case IR::OpMod: setOp(op, opName, __qmljs_mod); break;
@@ -524,7 +536,11 @@ void InstructionSelection::visitMove(IR::Move *s)
                     }
 
                     if (op) {
-                        generateFunctionCallImp(t, opName, op, b->left, b->right, ContextRegister);
+                        if (inlineMemBinOp && inlineImmBinOp
+                            && generateArithmeticIntegerInlineBinOp(t, b->left, b->right, inlineMemBinOp, inlineImmBinOp, op, opName))
+                            return;
+                        else
+                            generateFunctionCallImp(t, opName, op, b->left, b->right, ContextRegister);
                     }
                     return;
                 }
@@ -803,3 +819,75 @@ void InstructionSelection::copyValue(Result result, Source source)
     storeDouble(FPGpr0, result);
 #endif
 }
+
+bool InstructionSelection::generateArithmeticIntegerInlineBinOp(IR::Temp* target, IR::Expr* left, IR::Expr* right,
+            MemBinOpWithOverFlow memOp, ImmBinOpWithOverFlow immOp, FallbackOp fallbackOp, const char* fallbackOpName)
+{
+    VM::Value leftConst;
+    if (left->asConst()) {
+        leftConst = convertToValue(left->asConst());
+        if (!leftConst.tryIntegerConversion())
+            return false;
+    }
+    VM::Value rightConst;
+    if (right->asConst()) {
+        rightConst = convertToValue(right->asConst());
+        if (!rightConst.tryIntegerConversion())
+            return false;
+    }
+
+    Jump leftTypeCheck;
+    if (left->asTemp()) {
+        Address typeAddress = loadTempAddress(ScratchRegister, left->asTemp());
+        typeAddress.offset += offsetof(VM::Value, tag);
+        leftTypeCheck = branch32(NotEqual, typeAddress, TrustedImm32(VM::Value::_Integer_Type));
+    }
+
+    Jump rightTypeCheck;
+    if (right->asTemp()) {
+        Address typeAddress = loadTempAddress(ScratchRegister, right->asTemp());
+        typeAddress.offset += offsetof(VM::Value, tag);
+        rightTypeCheck = branch32(NotEqual, typeAddress, TrustedImm32(VM::Value::_Integer_Type));
+    }
+
+    if (left->asTemp()) {
+        Address leftValue = loadTempAddress(ScratchRegister, left->asTemp());
+        leftValue.offset += offsetof(VM::Value, int_32);
+        load32(leftValue, IntegerOpRegister);
+    } else { // left->asConst()
+        move(TrustedImm32(leftConst.integerValue()), IntegerOpRegister);
+    }
+
+    Jump overflowCheck;
+
+    if (right->asTemp()) {
+        Address rightValue = loadTempAddress(ScratchRegister, right->asTemp());
+        rightValue.offset += offsetof(VM::Value, int_32);
+
+        overflowCheck = (this->*memOp)(Overflow, rightValue, IntegerOpRegister);
+    } else { // right->asConst()
+        VM::Value value = convertToValue(right->asConst());
+        overflowCheck = (this->*immOp)(Overflow, TrustedImm32(value.integerValue()), IntegerOpRegister);
+    }
+
+    Address resultAddr = loadTempAddress(ScratchRegister, target);
+    Address resultValueAddr = resultAddr;
+    resultValueAddr.offset += offsetof(VM::Value, int_32);
+    store32(IntegerOpRegister, resultValueAddr);
+
+    Address resultTypeAddr = resultAddr;
+    resultTypeAddr.offset += offsetof(VM::Value, tag);
+    store32(TrustedImm32(VM::Value::_Integer_Type), resultTypeAddr);
+
+    Jump finishBinOp = jump();
+
+    if (leftTypeCheck.isSet())
+        leftTypeCheck.link(this);
+    if (rightTypeCheck.isSet())
+        rightTypeCheck.link(this);
+    overflowCheck.link(this);
+    generateFunctionCallImp(target, fallbackOpName, fallbackOp, left, right, ContextRegister);
+
+    finishBinOp.link(this);
+    return true;
+}
index 1b3cee1..55e75d3 100644 (file)
@@ -77,6 +77,7 @@ protected:
     static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
     static const RegisterID CalleeSavedFirstRegister = ScratchRegister;
     static const RegisterID CalleeSavedLastRegister = ScratchRegister;
+    static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
     static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
 
     static const int RegisterSize = 4;
@@ -97,6 +98,7 @@ protected:
     static const RegisterID ContextRegister = JSC::X86Registers::r14;
     static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
     static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+    static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
     static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
 
     static const int RegisterSize = 8;
@@ -126,6 +128,7 @@ protected:
     static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
     static const RegisterID CalleeSavedFirstRegister = JSC::ARMRegisters::r4;
     static const RegisterID CalleeSavedLastRegister = JSC::ARMRegisters::r11;
+    static const RegisterID IntegerOpRegister = JSC::X86Registers::r0;
     static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
 
     static const int RegisterSize = 4;
@@ -608,6 +611,13 @@ private:
 #endif
     }
 
+    typedef VM::Value (*FallbackOp)(const VM::Value, const VM::Value, VM::ExecutionContext*);
+
+    typedef Jump (JSC::MacroAssembler::*MemBinOpWithOverFlow)(ResultCondition, Address, RegisterID);
+    typedef Jump (JSC::MacroAssembler::*ImmBinOpWithOverFlow)(ResultCondition, TrustedImm32, RegisterID);
+    bool generateArithmeticIntegerInlineBinOp(IR::Temp* target, IR::Expr* left, IR::Expr* right,
+            MemBinOpWithOverFlow memOp, ImmBinOpWithOverFlow immOp, FallbackOp fallback, const char* fallbackOpName);
+
     VM::ExecutionEngine *_engine;
     IR::Function *_function;
     IR::BasicBlock *_block;