aboutsummaryrefslogtreecommitdiffstats
path: root/qv4isel_masm.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-12-02 01:04:34 +0100
committerLars Knoll <lars.knoll@digia.com>2012-12-02 15:21:20 +0100
commit4c2f11c67dadb684a602ecad397763804b62adf9 (patch)
tree2cba0f5222e99d0cc7de0bb2c020fa784d7ae5e7 /qv4isel_masm.cpp
parentd2eb5c6510bb05f6cd7e7bd06e9957bdf85a515f (diff)
[masm] First implementation of inline addition / subtraction
Change-Id: I4e54ae0feded8d99737245c870e0dfbb9b80247e Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'qv4isel_masm.cpp')
-rw-r--r--qv4isel_masm.cpp94
1 files changed, 91 insertions, 3 deletions
diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp
index 5f95442009..37ad3fe9bc 100644
--- a/qv4isel_masm.cpp
+++ b/qv4isel_masm.cpp
@@ -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;
+}