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
This commit is contained in:
parent
4bb55fd341
commit
93d4776d46
@ -1013,40 +1013,123 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
|
|||||||
|
|
||||||
|
|
||||||
void LCodeGen::DoMulI(LMulI* instr) {
|
void LCodeGen::DoMulI(LMulI* instr) {
|
||||||
|
LOperand* left_op = instr->InputAt(0);
|
||||||
|
LOperand* right_op = instr->InputAt(1);
|
||||||
|
|
||||||
Register scratch = scratch0();
|
Register scratch = scratch0();
|
||||||
Register left = ToRegister(instr->InputAt(0));
|
Register left = ToRegister(left_op);
|
||||||
Register right = EmitLoadRegister(instr->InputAt(1), scratch);
|
|
||||||
|
|
||||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
ASSERT(left_op->Equals(instr->result()));
|
||||||
!instr->InputAt(1)->IsConstantOperand()) {
|
|
||||||
__ orr(ToRegister(instr->TempAt(0)), left, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
||||||
// scratch:left = left * right.
|
bool bailout_on_minus_zero =
|
||||||
__ smull(left, scratch, left, right);
|
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
||||||
__ mov(ip, Operand(left, ASR, 31));
|
|
||||||
__ cmp(ip, Operand(scratch));
|
if (right_op->IsConstantOperand()) {
|
||||||
DeoptimizeIf(ne, instr->environment());
|
// 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 {
|
} else {
|
||||||
__ mul(left, left, right);
|
Register right = EmitLoadRegister(right_op, scratch);
|
||||||
}
|
if (bailout_on_minus_zero) {
|
||||||
|
__ orr(ToRegister(instr->TempAt(0)), left, right);
|
||||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
}
|
||||||
// Bail out if the result is supposed to be negative zero.
|
if (can_overflow) {
|
||||||
Label done;
|
// scratch:left = left * right.
|
||||||
__ tst(left, Operand(left));
|
__ smull(left, scratch, left, right);
|
||||||
__ b(ne, &done);
|
__ cmp(scratch, Operand(left, ASR, 31));
|
||||||
if (instr->InputAt(1)->IsConstantOperand()) {
|
DeoptimizeIf(ne, instr->environment());
|
||||||
if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
|
|
||||||
DeoptimizeIf(al, instr->environment());
|
|
||||||
}
|
|
||||||
} else {
|
} 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));
|
__ cmp(ToRegister(instr->TempAt(0)), Operand(0));
|
||||||
DeoptimizeIf(mi, instr->environment());
|
DeoptimizeIf(mi, instr->environment());
|
||||||
|
__ bind(&done);
|
||||||
}
|
}
|
||||||
__ bind(&done);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +294,8 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
|
|||||||
!src2.must_use_constant_pool() &&
|
!src2.must_use_constant_pool() &&
|
||||||
Isolate::Current()->cpu_features()->IsSupported(ARMv7) &&
|
Isolate::Current()->cpu_features()->IsSupported(ARMv7) &&
|
||||||
IsPowerOf2(src2.immediate() + 1)) {
|
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 {
|
} else {
|
||||||
and_(dst, src1, src2, LeaveCC, cond);
|
and_(dst, src1, src2, LeaveCC, cond);
|
||||||
|
@ -52,11 +52,9 @@ static inline bool IsPowerOf2(T x) {
|
|||||||
|
|
||||||
|
|
||||||
// X must be a power of 2. Returns the number of trailing zeros.
|
// X must be a power of 2. Returns the number of trailing zeros.
|
||||||
template <typename T>
|
static inline int WhichPowerOf2(uint32_t x) {
|
||||||
static inline int WhichPowerOf2(T x) {
|
|
||||||
ASSERT(IsPowerOf2(x));
|
ASSERT(IsPowerOf2(x));
|
||||||
ASSERT(x != 0);
|
ASSERT(x != 0);
|
||||||
if (x < 0) return 31;
|
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
int original_x = x;
|
int original_x = x;
|
||||||
|
Loading…
Reference in New Issue
Block a user