Revision: 7582
Author: [email protected]
Date: Mon Apr 11 23:44:15 2011
Log: ARM: Add optimization for constant RHS in DoMulI.
Patch by ARM Ltd.
Review URL: http://codereview.chromium.org/6756033
http://code.google.com/p/v8/source/detail?r=7582
Modified:
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/utils.h
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Apr 11 02:39:21
2011
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Apr 11 23:44:15
2011
@@ -2375,9 +2375,11 @@
// DIV just falls through to allocating a heap number.
}
+ __ bind(&return_heap_number);
+ // Return a heap number, or fall through to type transition or
runtime
+ // call if we can't.
if (result_type_ >= (op_ == Token::DIV) ? TRBinaryOpIC::HEAP_NUMBER
: TRBinaryOpIC::INT32) {
- __ bind(&return_heap_number);
// We are using vfp registers so r5 is available.
heap_number_result = r5;
GenerateHeapResultAllocation(masm,
@@ -2540,7 +2542,11 @@
UNREACHABLE();
}
- if (transition.is_linked()) {
+ // We never expect DIV to yield an integer result, so we always generate
+ // type transition code for DIV operations expecting an integer result:
the
+ // code will fall through to this type transition.
+ if (transition.is_linked() ||
+ ((op_ == Token::DIV) && (result_type_ <= TRBinaryOpIC::INT32))) {
__ bind(&transition);
GenerateTypeTransition(masm);
}
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Apr 8
07:30:10 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Apr 11
23:44:15 2011
@@ -1069,40 +1069,130 @@
void LCodeGen::DoMulI(LMulI* instr) {
+ LOperand* left_op = instr->InputAt(0);
+ LOperand* right_op = instr->InputAt(1);
+
Register scratch = scratch0();
- Register left = ToRegister(instr->InputAt(0));
- Register right = EmitLoadRegister(instr->InputAt(1), scratch);
-
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
- !instr->InputAt(1)->IsConstantOperand()) {
- __ orr(ToRegister(instr->TempAt(0)), left, right);
- }
-
- 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());
+ 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 (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;
- __ cmp(left, Operand(0));
- __ 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);
+ }
}
}
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Apr 11
02:04:30 2011
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Apr 11
23:44:15 2011
@@ -297,7 +297,8 @@
!src2.must_use_constant_pool() &&
CpuFeatures::IsSupported(ARMv7) &&
IsPowerOf2(src2.immediate() + 1)) {
- ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond);
+ ubfx(dst, src1, 0,
+ WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond);
} else {
and_(dst, src1, src2, LeaveCC, cond);
=======================================
--- /branches/bleeding_edge/src/utils.h Mon Mar 21 09:10:05 2011
+++ /branches/bleeding_edge/src/utils.h Mon Apr 11 23:44:15 2011
@@ -52,11 +52,9 @@
// X must be a power of 2. Returns the number of trailing zeros.
-template <typename T>
-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;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev