From 93d4776d4632c1fe7eefc81e7cf2160ebe50b53a Mon Sep 17 00:00:00 2001 From: "karlklose@chromium.org" Date: Mon, 21 Mar 2011 14:31:15 +0000 Subject: [PATCH] ARM: Add optimization for constant RHS in DoMulI. Patch by ARM Ltd. Review URL: http://codereview.chromium.org/6708025 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7288 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/lithium-codegen-arm.cc | 137 +++++++++++++++++++++++++++++++++-------- src/arm/macro-assembler-arm.cc | 3 +- src/utils.h | 4 +- 3 files changed, 113 insertions(+), 31 deletions(-) diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 6a16067..e6b9148 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1013,40 +1013,123 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, void LCodeGen::DoMulI(LMulI* instr) { - Register scratch = scratch0(); - Register left = ToRegister(instr->InputAt(0)); - Register right = EmitLoadRegister(instr->InputAt(1), scratch); + LOperand* left_op = instr->InputAt(0); + LOperand* right_op = instr->InputAt(1); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) && - !instr->InputAt(1)->IsConstantOperand()) { - __ orr(ToRegister(instr->TempAt(0)), left, right); - } + Register scratch = scratch0(); + Register left = ToRegister(left_op); + + ASSERT(left_op->Equals(instr->result())); + + bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); + bool bailout_on_minus_zero = + instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); + + if (right_op->IsConstantOperand()) { + // Use optimized code for specific constants. + int32_t constant = ToInteger32(LConstantOperand::cast(right_op)); + Condition overflow_deopt_cond = kNoCondition; + switch (constant) { + case -1: + overflow_deopt_cond = can_overflow ? vs : kNoCondition; + __ rsb(left, + left, + Operand(0), + can_overflow ? SetCC : LeaveCC); + break; + case 0: + if (bailout_on_minus_zero) { + // If left is strictly negative and the constant is null, the + // result is -0. Deoptimize if required, otherwise return 0. + __ cmp(left, Operand(0)); + DeoptimizeIf(mi, instr->environment()); + } + __ mov(left, Operand(0)); + break; + case 1: + // Do nothing. + break; + default: + // Multiplying by powers of two and powers of two plus or minus + // one can be done faster with shifted operands. + // For other constants we emit standard code. + int32_t mask = constant >> 31; + uint32_t constant_abs = (constant + mask) ^ mask; + if (IsPowerOf2(constant_abs)) { + if (!can_overflow) { + int32_t shift = WhichPowerOf2(constant_abs); + __ mov(left, Operand(left, LSL, shift)); + if (constant < 0) __ rsb(left, left, Operand(0)); + } else { + // scratch:left = left * constant. + __ mov(ip, Operand(constant)); + __ smull(left, scratch, left, ip); + __ cmp(scratch, Operand(left, ASR, 31)); + overflow_deopt_cond = ne; + } + } else if (IsPowerOf2(constant_abs - 1)) { + int32_t shift = WhichPowerOf2(constant_abs - 1); + __ add(left, + left, + Operand(left, LSL, shift), + can_overflow ? SetCC : LeaveCC); + overflow_deopt_cond = can_overflow ? vs : kNoCondition; + if (constant < 0) __ rsb(left, left, Operand(0)); + } else if (IsPowerOf2(constant_abs + 1)) { + int32_t shift = WhichPowerOf2(constant_abs + 1); + __ rsb(left, + left, + Operand(left, LSL, shift), + can_overflow ? SetCC : LeaveCC); + overflow_deopt_cond = can_overflow ? vs : kNoCondition; + if (constant < 0) __ rsb(left, left, Operand(0)); + } else { + if (!can_overflow) { + __ mov(ip, Operand(constant)); + __ mul(left, left, ip); + } else { + // scratch:left = left * constant. + __ mov(ip, Operand(constant)); + __ smull(left, scratch, left, ip); + __ cmp(scratch, Operand(left, ASR, 31)); + overflow_deopt_cond = ne; + } + } + break; + } - if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { - // scratch:left = left * right. - __ smull(left, scratch, left, right); - __ mov(ip, Operand(left, ASR, 31)); - __ cmp(ip, Operand(scratch)); - DeoptimizeIf(ne, instr->environment()); + if (can_overflow && (constant != 0) && (constant != 1)) { + ASSERT(overflow_deopt_cond != kNoCondition); + DeoptimizeIf(overflow_deopt_cond, instr->environment()); + } + if (bailout_on_minus_zero && (constant < 0)) { + // The case of a null constant was handled separately. + // If constant is negative and left is null, the result should be -0. + __ cmp(left, Operand(0)); + DeoptimizeIf(eq, instr->environment()); + } } else { - __ mul(left, left, right); - } - - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - // Bail out if the result is supposed to be negative zero. - Label done; - __ tst(left, Operand(left)); - __ b(ne, &done); - if (instr->InputAt(1)->IsConstantOperand()) { - if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) { - DeoptimizeIf(al, instr->environment()); - } + Register right = EmitLoadRegister(right_op, scratch); + if (bailout_on_minus_zero) { + __ orr(ToRegister(instr->TempAt(0)), left, right); + } + if (can_overflow) { + // scratch:left = left * right. + __ smull(left, scratch, left, right); + __ cmp(scratch, Operand(left, ASR, 31)); + DeoptimizeIf(ne, instr->environment()); } else { - // Test the non-zero operand for negative sign. + __ mul(left, left, right); + } + if (bailout_on_minus_zero) { + // Bail out if the result is supposed to be negative zero. + Label done; + __ cmp(left, Operand(0)); + __ b(ne, &done); __ cmp(ToRegister(instr->TempAt(0)), Operand(0)); DeoptimizeIf(mi, instr->environment()); + __ bind(&done); } - __ bind(&done); } } diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index ce653ea..6954ced 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -294,7 +294,8 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2, !src2.must_use_constant_pool() && Isolate::Current()->cpu_features()->IsSupported(ARMv7) && IsPowerOf2(src2.immediate() + 1)) { - ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond); + ubfx(dst, src1, 0, + WhichPowerOf2(static_cast(src2.immediate()) + 1), cond); } else { and_(dst, src1, src2, LeaveCC, cond); diff --git a/src/utils.h b/src/utils.h index b89f284..2328051 100644 --- a/src/utils.h +++ b/src/utils.h @@ -52,11 +52,9 @@ static inline bool IsPowerOf2(T x) { // X must be a power of 2. Returns the number of trailing zeros. -template -static inline int WhichPowerOf2(T x) { +static inline int WhichPowerOf2(uint32_t x) { ASSERT(IsPowerOf2(x)); ASSERT(x != 0); - if (x < 0) return 31; int bits = 0; #ifdef DEBUG int original_x = x; -- 2.7.4