ARM: Add optimization for constant RHS in DoMulI.
Patch by ARM Ltd. Review URL: http://codereview.chromium.org/7027033 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8172 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
f09d3ac1c6
commit
799c3e92b9
@ -2666,9 +2666,11 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
||||
// 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) ? BinaryOpIC::HEAP_NUMBER
|
||||
: BinaryOpIC::INT32) {
|
||||
__ bind(&return_heap_number);
|
||||
// We are using vfp registers so r5 is available.
|
||||
heap_number_result = r5;
|
||||
GenerateHeapResultAllocation(masm,
|
||||
@ -2842,7 +2844,11 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
||||
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_ <= BinaryOpIC::INT32))) {
|
||||
__ bind(&transition);
|
||||
GenerateTypeTransition(masm);
|
||||
}
|
||||
|
@ -1412,13 +1412,16 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstant(instr->MostConstantOperand());
|
||||
LOperand* temp = NULL;
|
||||
if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
||||
(instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
!right->IsConstantOperand())) {
|
||||
temp = TempRegister();
|
||||
}
|
||||
LMulI* mul = new LMulI(left, right, temp);
|
||||
return AssignEnvironment(DefineSameAsFirst(mul));
|
||||
return AssignEnvironment(DefineSameAsFirst(new LMulI(left, right, temp)));
|
||||
|
||||
} else if (instr->representation().IsDouble()) {
|
||||
return DoArithmeticD(Token::MUL, instr);
|
||||
|
||||
} else {
|
||||
return DoArithmeticT(Token::MUL, instr);
|
||||
}
|
||||
|
@ -1118,40 +1118,98 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
|
||||
|
||||
|
||||
void LCodeGen::DoMulI(LMulI* instr) {
|
||||
ASSERT(instr->result()->Equals(instr->InputAt(0)));
|
||||
Register scratch = scratch0();
|
||||
Register result = ToRegister(instr->result());
|
||||
Register left = ToRegister(instr->InputAt(0));
|
||||
Register right = EmitLoadRegister(instr->InputAt(1), scratch);
|
||||
LOperand* right_op = instr->InputAt(1);
|
||||
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
||||
!instr->InputAt(1)->IsConstantOperand()) {
|
||||
__ orr(ToRegister(instr->TempAt(0)), left, right);
|
||||
}
|
||||
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
||||
bool bailout_on_minus_zero =
|
||||
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
||||
|
||||
if (right_op->IsConstantOperand() && !can_overflow) {
|
||||
// Use optimized code for specific constants.
|
||||
int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
|
||||
|
||||
if (bailout_on_minus_zero && (constant < 0)) {
|
||||
// The case of a null constant will be handled separately.
|
||||
// If constant is negative and left is null, the result should be -0.
|
||||
__ cmp(left, Operand(0));
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
|
||||
switch (constant) {
|
||||
case -1:
|
||||
__ rsb(result, left, Operand(0));
|
||||
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(result, Operand(0));
|
||||
break;
|
||||
case 1:
|
||||
// Nothing to do.
|
||||
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) ||
|
||||
IsPowerOf2(constant_abs - 1) ||
|
||||
IsPowerOf2(constant_abs + 1)) {
|
||||
if (IsPowerOf2(constant_abs)) {
|
||||
int32_t shift = WhichPowerOf2(constant_abs);
|
||||
__ mov(result, Operand(left, LSL, shift));
|
||||
} else if (IsPowerOf2(constant_abs - 1)) {
|
||||
int32_t shift = WhichPowerOf2(constant_abs - 1);
|
||||
__ add(result, left, Operand(left, LSL, shift));
|
||||
} else if (IsPowerOf2(constant_abs + 1)) {
|
||||
int32_t shift = WhichPowerOf2(constant_abs + 1);
|
||||
__ rsb(result, left, Operand(left, LSL, shift));
|
||||
}
|
||||
|
||||
// Correct the sign of the result is the constant is negative.
|
||||
if (constant < 0) __ rsb(result, result, Operand(0));
|
||||
|
||||
} else {
|
||||
// Generate standard code.
|
||||
__ mov(ip, Operand(constant));
|
||||
__ mul(result, left, ip);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
} 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.
|
||||
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());
|
||||
}
|
||||
if (can_overflow) {
|
||||
// scratch:result = left * right.
|
||||
__ smull(result, scratch, left, right);
|
||||
__ cmp(scratch, Operand(result, ASR, 31));
|
||||
DeoptimizeIf(ne, instr->environment());
|
||||
} else {
|
||||
// Test the non-zero operand for negative sign.
|
||||
__ mul(result, left, right);
|
||||
}
|
||||
|
||||
if (bailout_on_minus_zero) {
|
||||
// Bail out if the result is supposed to be negative zero.
|
||||
Label done;
|
||||
__ cmp(result, Operand(0));
|
||||
__ b(ne, &done);
|
||||
__ cmp(ToRegister(instr->TempAt(0)), Operand(0));
|
||||
DeoptimizeIf(mi, instr->environment());
|
||||
__ bind(&done);
|
||||
}
|
||||
__ bind(&done);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -330,7 +330,8 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
|
||||
!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);
|
||||
|
@ -52,11 +52,9 @@ static inline bool IsPowerOf2(T x) {
|
||||
|
||||
|
||||
// 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;
|
||||
|
Loading…
Reference in New Issue
Block a user