ARM: Improve register allocation and constraints.
Gives ~20% boost for Crypto benchmark on A9. BUG=none TEST=none Review URL: http://codereview.chromium.org//7148018 Patch from Martyn Capewell <m.m.capewell@googlemail.com>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8381 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8677fd370c
commit
322d246e7e
@ -167,13 +167,14 @@ struct SwVfpRegister {
|
||||
|
||||
// Double word VFP register.
|
||||
struct DwVfpRegister {
|
||||
// d0 has been excluded from allocation. This is following ia32
|
||||
// where xmm0 is excluded. This should be revisited.
|
||||
// Currently d0 is used as a scratch register.
|
||||
// d1 has also been excluded from allocation to be used as a scratch
|
||||
// register as well.
|
||||
static const int kNumRegisters = 16;
|
||||
static const int kNumAllocatableRegisters = 15;
|
||||
// A few double registers are reserved: one as a scratch register and one to
|
||||
// hold 0.0, that does not fit in the immediate field of vmov instructions.
|
||||
// d14: 0.0
|
||||
// d15: scratch register.
|
||||
static const int kNumReservedRegisters = 2;
|
||||
static const int kNumAllocatableRegisters = kNumRegisters -
|
||||
kNumReservedRegisters;
|
||||
|
||||
static int ToAllocationIndex(DwVfpRegister reg) {
|
||||
ASSERT(reg.code() != 0);
|
||||
@ -188,6 +189,7 @@ struct DwVfpRegister {
|
||||
static const char* AllocationIndexToString(int index) {
|
||||
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
|
||||
const char* const names[] = {
|
||||
"d0",
|
||||
"d1",
|
||||
"d2",
|
||||
"d3",
|
||||
@ -200,9 +202,7 @@ struct DwVfpRegister {
|
||||
"d10",
|
||||
"d11",
|
||||
"d12",
|
||||
"d13",
|
||||
"d14",
|
||||
"d15"
|
||||
"d13"
|
||||
};
|
||||
return names[index];
|
||||
}
|
||||
@ -306,6 +306,7 @@ const DwVfpRegister d15 = { 15 };
|
||||
// Aliases for double registers.
|
||||
const DwVfpRegister kFirstCalleeSavedDoubleReg = d8;
|
||||
const DwVfpRegister kLastCalleeSavedDoubleReg = d15;
|
||||
const DwVfpRegister kDoubleRegZero = d14;
|
||||
|
||||
|
||||
// Coprocessor register
|
||||
|
@ -3541,6 +3541,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
|
||||
CpuFeatures::Scope scope(VFP3);
|
||||
// Save callee-saved vfp registers.
|
||||
__ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
|
||||
// Set up the reserved register for 0.0.
|
||||
__ vmov(kDoubleRegZero, 0.0);
|
||||
}
|
||||
|
||||
// Get address of argv, see stm above.
|
||||
|
@ -823,7 +823,7 @@ LInstruction* LChunkBuilder::DoBit(Token::Value op,
|
||||
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
return DefineSameAsFirst(new LBitI(op, left, right));
|
||||
return DefineAsRegister(new LBitI(op, left, right));
|
||||
} else {
|
||||
ASSERT(instr->representation().IsTagged());
|
||||
ASSERT(instr->left()->representation().IsTagged());
|
||||
@ -862,7 +862,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
|
||||
right = chunk_->DefineConstantOperand(constant);
|
||||
constant_value = constant->Integer32Value() & 0x1f;
|
||||
} else {
|
||||
right = UseRegister(right_value);
|
||||
right = UseRegisterAtStart(right_value);
|
||||
}
|
||||
|
||||
// Shift operations can only deoptimize if we do a logical shift
|
||||
@ -879,7 +879,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
|
||||
}
|
||||
|
||||
LInstruction* result =
|
||||
DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
|
||||
DefineAsRegister(new LShiftI(op, left, right, does_deopt));
|
||||
return does_deopt ? AssignEnvironment(result) : result;
|
||||
}
|
||||
|
||||
@ -893,7 +893,7 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
|
||||
LOperand* left = UseRegisterAtStart(instr->left());
|
||||
LOperand* right = UseRegisterAtStart(instr->right());
|
||||
LArithmeticD* result = new LArithmeticD(op, left, right);
|
||||
return DefineSameAsFirst(result);
|
||||
return DefineAsRegister(result);
|
||||
}
|
||||
|
||||
|
||||
@ -1237,15 +1237,15 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
|
||||
LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
|
||||
switch (op) {
|
||||
case kMathAbs:
|
||||
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
||||
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
|
||||
case kMathFloor:
|
||||
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
|
||||
case kMathSqrt:
|
||||
return DefineSameAsFirst(result);
|
||||
return DefineAsRegister(result);
|
||||
case kMathRound:
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
case kMathPowHalf:
|
||||
return DefineSameAsFirst(result);
|
||||
return DefineAsRegister(result);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
@ -1323,7 +1323,7 @@ LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
|
||||
LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
|
||||
ASSERT(instr->value()->representation().IsInteger32());
|
||||
ASSERT(instr->representation().IsInteger32());
|
||||
return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value())));
|
||||
return DefineAsRegister(new LBitNotI(UseRegisterAtStart(instr->value())));
|
||||
}
|
||||
|
||||
|
||||
@ -1372,11 +1372,14 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) {
|
||||
mod = new LModI(dividend,
|
||||
divisor,
|
||||
TempRegister(),
|
||||
FixedTemp(d1),
|
||||
FixedTemp(d2));
|
||||
FixedTemp(d10),
|
||||
FixedTemp(d11));
|
||||
}
|
||||
|
||||
return AssignEnvironment(DefineSameAsFirst(mod));
|
||||
bool needs_env = (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
|
||||
instr->CheckFlag(HValue::kCanBeDivByZero));
|
||||
return needs_env ? AssignEnvironment(DefineAsRegister(mod))
|
||||
: DefineAsRegister(mod);
|
||||
} else if (instr->representation().IsTagged()) {
|
||||
return DoArithmeticT(Token::MOD, instr);
|
||||
} else {
|
||||
@ -1396,15 +1399,18 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) {
|
||||
if (instr->representation().IsInteger32()) {
|
||||
ASSERT(instr->left()->representation().IsInteger32());
|
||||
ASSERT(instr->right()->representation().IsInteger32());
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* left;
|
||||
LOperand* right = UseOrConstant(instr->MostConstantOperand());
|
||||
LOperand* temp = NULL;
|
||||
if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
||||
(instr->CheckFlag(HValue::kCanOverflow) ||
|
||||
!right->IsConstantOperand())) {
|
||||
left = UseRegister(instr->LeastConstantOperand());
|
||||
temp = TempRegister();
|
||||
} else {
|
||||
left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
}
|
||||
return AssignEnvironment(DefineSameAsFirst(new LMulI(left, right, temp)));
|
||||
return AssignEnvironment(DefineAsRegister(new LMulI(left, right, temp)));
|
||||
|
||||
} else if (instr->representation().IsDouble()) {
|
||||
return DoArithmeticD(Token::MUL, instr);
|
||||
@ -1422,7 +1428,7 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) {
|
||||
LOperand* left = UseRegisterAtStart(instr->left());
|
||||
LOperand* right = UseOrConstantAtStart(instr->right());
|
||||
LSubI* sub = new LSubI(left, right);
|
||||
LInstruction* result = DefineSameAsFirst(sub);
|
||||
LInstruction* result = DefineAsRegister(sub);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow)) {
|
||||
result = AssignEnvironment(result);
|
||||
}
|
||||
@ -1442,7 +1448,7 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
|
||||
LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
||||
LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
||||
LAddI* add = new LAddI(left, right);
|
||||
LInstruction* result = DefineSameAsFirst(add);
|
||||
LInstruction* result = DefineAsRegister(add);
|
||||
if (instr->CheckFlag(HValue::kCanOverflow)) {
|
||||
result = AssignEnvironment(result);
|
||||
}
|
||||
@ -1608,7 +1614,7 @@ LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
|
||||
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
|
||||
LOperand* object = UseRegister(instr->value());
|
||||
LValueOf* result = new LValueOf(object, TempRegister());
|
||||
return AssignEnvironment(DefineSameAsFirst(result));
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
}
|
||||
|
||||
|
||||
@ -1663,7 +1669,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
|
||||
: NULL;
|
||||
LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d3)
|
||||
LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d11)
|
||||
: NULL;
|
||||
res = DefineSameAsFirst(new LTaggedToI(value, temp1, temp2, temp3));
|
||||
res = AssignEnvironment(res);
|
||||
@ -1757,14 +1763,14 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
|
||||
Representation input_rep = value->representation();
|
||||
LOperand* reg = UseRegister(value);
|
||||
if (input_rep.IsDouble()) {
|
||||
return DefineAsRegister(new LClampDToUint8(reg, FixedTemp(d1)));
|
||||
return DefineAsRegister(new LClampDToUint8(reg, FixedTemp(d11)));
|
||||
} else if (input_rep.IsInteger32()) {
|
||||
return DefineAsRegister(new LClampIToUint8(reg));
|
||||
} else {
|
||||
ASSERT(input_rep.IsTagged());
|
||||
// Register allocator doesn't (yet) support allocation of double
|
||||
// temps. Reserve d1 explicitly.
|
||||
LClampTToUint8* result = new LClampTToUint8(reg, FixedTemp(d1));
|
||||
LClampTToUint8* result = new LClampTToUint8(reg, FixedTemp(d11));
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
}
|
||||
}
|
||||
@ -1788,7 +1794,7 @@ LInstruction* LChunkBuilder::DoToInt32(HToInt32* instr) {
|
||||
ASSERT(input_rep.IsTagged());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LOperand* temp3 = FixedTemp(d3);
|
||||
LOperand* temp3 = FixedTemp(d11);
|
||||
LTaggedToI* res = new LTaggedToI(reg, temp1, temp2, temp3);
|
||||
return AssignEnvironment(DefineSameAsFirst(res));
|
||||
}
|
||||
@ -1926,7 +1932,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
|
||||
LOperand* obj = UseRegisterAtStart(instr->object());
|
||||
LOperand* key = UseRegisterAtStart(instr->key());
|
||||
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
|
||||
return AssignEnvironment(DefineSameAsFirst(result));
|
||||
return AssignEnvironment(DefineAsRegister(result));
|
||||
}
|
||||
|
||||
|
||||
|
@ -873,6 +873,7 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
|
||||
void LCodeGen::DoModI(LModI* instr) {
|
||||
if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
||||
Register dividend = ToRegister(instr->InputAt(0));
|
||||
Register result = ToRegister(instr->result());
|
||||
|
||||
int32_t divisor =
|
||||
HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
||||
@ -882,17 +883,15 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
Label positive_dividend, done;
|
||||
__ cmp(dividend, Operand(0));
|
||||
__ b(pl, &positive_dividend);
|
||||
__ rsb(dividend, dividend, Operand(0));
|
||||
__ and_(dividend, dividend, Operand(divisor - 1));
|
||||
__ rsb(dividend, dividend, Operand(0), SetCC);
|
||||
__ rsb(result, dividend, Operand(0));
|
||||
__ and_(dividend, result, Operand(divisor - 1), SetCC);
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
__ b(ne, &done);
|
||||
DeoptimizeIf(al, instr->environment());
|
||||
} else {
|
||||
__ b(&done);
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
__ rsb(result, dividend, Operand(0));
|
||||
__ b(&done);
|
||||
__ bind(&positive_dividend);
|
||||
__ and_(dividend, dividend, Operand(divisor - 1));
|
||||
__ and_(result, dividend, Operand(divisor - 1));
|
||||
__ bind(&done);
|
||||
return;
|
||||
}
|
||||
@ -908,8 +907,6 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
|
||||
DwVfpRegister quotient = double_scratch0();
|
||||
|
||||
ASSERT(result.is(left));
|
||||
|
||||
ASSERT(!dividend.is(divisor));
|
||||
ASSERT(!dividend.is(quotient));
|
||||
ASSERT(!divisor.is(quotient));
|
||||
@ -925,6 +922,8 @@ void LCodeGen::DoModI(LModI* instr) {
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
|
||||
__ Move(result, left);
|
||||
|
||||
// (0 % x) must yield 0 (if x is finite, which is the case here).
|
||||
__ cmp(left, Operand(0));
|
||||
__ b(eq, &done);
|
||||
@ -1120,9 +1119,9 @@ 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());
|
||||
// Note that result may alias left.
|
||||
Register left = ToRegister(instr->InputAt(0));
|
||||
LOperand* right_op = instr->InputAt(1);
|
||||
|
||||
@ -1155,7 +1154,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
||||
__ mov(result, Operand(0));
|
||||
break;
|
||||
case 1:
|
||||
// Nothing to do.
|
||||
__ Move(result, left);
|
||||
break;
|
||||
default:
|
||||
// Multiplying by powers of two and powers of two plus or minus
|
||||
@ -1217,30 +1216,29 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoBitI(LBitI* instr) {
|
||||
LOperand* left = instr->InputAt(0);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
ASSERT(left->IsRegister());
|
||||
Register result = ToRegister(left);
|
||||
Operand right_operand(no_reg);
|
||||
LOperand* left_op = instr->InputAt(0);
|
||||
LOperand* right_op = instr->InputAt(1);
|
||||
ASSERT(left_op->IsRegister());
|
||||
Register left = ToRegister(left_op);
|
||||
Register result = ToRegister(instr->result());
|
||||
Operand right(no_reg);
|
||||
|
||||
if (right->IsStackSlot() || right->IsArgument()) {
|
||||
Register right_reg = EmitLoadRegister(right, ip);
|
||||
right_operand = Operand(right_reg);
|
||||
if (right_op->IsStackSlot() || right_op->IsArgument()) {
|
||||
right = Operand(EmitLoadRegister(right_op, ip));
|
||||
} else {
|
||||
ASSERT(right->IsRegister() || right->IsConstantOperand());
|
||||
right_operand = ToOperand(right);
|
||||
ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
|
||||
right = ToOperand(right_op);
|
||||
}
|
||||
|
||||
switch (instr->op()) {
|
||||
case Token::BIT_AND:
|
||||
__ and_(result, ToRegister(left), right_operand);
|
||||
__ and_(result, left, right);
|
||||
break;
|
||||
case Token::BIT_OR:
|
||||
__ orr(result, ToRegister(left), right_operand);
|
||||
__ orr(result, left, right);
|
||||
break;
|
||||
case Token::BIT_XOR:
|
||||
__ eor(result, ToRegister(left), right_operand);
|
||||
__ eor(result, left, right);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1250,54 +1248,62 @@ void LCodeGen::DoBitI(LBitI* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoShiftI(LShiftI* instr) {
|
||||
// Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
|
||||
// result may alias either of them.
|
||||
LOperand* right_op = instr->InputAt(1);
|
||||
Register left = ToRegister(instr->InputAt(0));
|
||||
Register result = ToRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
LOperand* left = instr->InputAt(0);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
ASSERT(left->IsRegister());
|
||||
Register result = ToRegister(left);
|
||||
if (right->IsRegister()) {
|
||||
// Mask the right operand.
|
||||
__ and_(scratch, ToRegister(right), Operand(0x1F));
|
||||
if (right_op->IsRegister()) {
|
||||
// Mask the right_op operand.
|
||||
__ and_(scratch, ToRegister(right_op), Operand(0x1F));
|
||||
switch (instr->op()) {
|
||||
case Token::SAR:
|
||||
__ mov(result, Operand(result, ASR, scratch));
|
||||
__ mov(result, Operand(left, ASR, scratch));
|
||||
break;
|
||||
case Token::SHR:
|
||||
if (instr->can_deopt()) {
|
||||
__ mov(result, Operand(result, LSR, scratch), SetCC);
|
||||
__ mov(result, Operand(left, LSR, scratch), SetCC);
|
||||
DeoptimizeIf(mi, instr->environment());
|
||||
} else {
|
||||
__ mov(result, Operand(result, LSR, scratch));
|
||||
__ mov(result, Operand(left, LSR, scratch));
|
||||
}
|
||||
break;
|
||||
case Token::SHL:
|
||||
__ mov(result, Operand(result, LSL, scratch));
|
||||
__ mov(result, Operand(left, LSL, scratch));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int value = ToInteger32(LConstantOperand::cast(right));
|
||||
// Mask the right_op operand.
|
||||
int value = ToInteger32(LConstantOperand::cast(right_op));
|
||||
uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
|
||||
switch (instr->op()) {
|
||||
case Token::SAR:
|
||||
if (shift_count != 0) {
|
||||
__ mov(result, Operand(result, ASR, shift_count));
|
||||
__ mov(result, Operand(left, ASR, shift_count));
|
||||
} else {
|
||||
__ Move(result, left);
|
||||
}
|
||||
break;
|
||||
case Token::SHR:
|
||||
if (shift_count == 0 && instr->can_deopt()) {
|
||||
__ tst(result, Operand(0x80000000));
|
||||
DeoptimizeIf(ne, instr->environment());
|
||||
if (shift_count != 0) {
|
||||
__ mov(result, Operand(left, LSR, shift_count));
|
||||
} else {
|
||||
__ mov(result, Operand(result, LSR, shift_count));
|
||||
if (instr->can_deopt()) {
|
||||
__ tst(left, Operand(0x80000000));
|
||||
DeoptimizeIf(ne, instr->environment());
|
||||
}
|
||||
__ Move(result, left);
|
||||
}
|
||||
break;
|
||||
case Token::SHL:
|
||||
if (shift_count != 0) {
|
||||
__ mov(result, Operand(result, LSL, shift_count));
|
||||
__ mov(result, Operand(left, LSL, shift_count));
|
||||
} else {
|
||||
__ Move(result, left);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1311,16 +1317,16 @@ void LCodeGen::DoShiftI(LShiftI* instr) {
|
||||
void LCodeGen::DoSubI(LSubI* instr) {
|
||||
LOperand* left = instr->InputAt(0);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
LOperand* result = instr->result();
|
||||
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
||||
SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
||||
|
||||
if (right->IsStackSlot() || right->IsArgument()) {
|
||||
Register right_reg = EmitLoadRegister(right, ip);
|
||||
__ sub(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
|
||||
__ sub(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
||||
} else {
|
||||
ASSERT(right->IsRegister() || right->IsConstantOperand());
|
||||
__ sub(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
|
||||
__ sub(ToRegister(result), ToRegister(left), ToOperand(right), set_cond);
|
||||
}
|
||||
|
||||
if (can_overflow) {
|
||||
@ -1339,7 +1345,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) {
|
||||
ASSERT(instr->result()->IsDoubleRegister());
|
||||
DwVfpRegister result = ToDoubleRegister(instr->result());
|
||||
double v = instr->value();
|
||||
__ vmov(result, v);
|
||||
__ Vmov(result, v);
|
||||
}
|
||||
|
||||
|
||||
@ -1388,14 +1394,16 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
|
||||
Register input = ToRegister(instr->InputAt(0));
|
||||
Register result = ToRegister(instr->result());
|
||||
Register map = ToRegister(instr->TempAt(0));
|
||||
ASSERT(input.is(result));
|
||||
Label done;
|
||||
|
||||
// If the object is a smi return the object.
|
||||
__ JumpIfSmi(input, &done);
|
||||
__ tst(input, Operand(kSmiTagMask));
|
||||
__ Move(result, input, eq);
|
||||
__ b(eq, &done);
|
||||
|
||||
// If the object is not a value type, return the object.
|
||||
__ CompareObjectType(input, map, map, JS_VALUE_TYPE);
|
||||
__ Move(result, input, ne);
|
||||
__ b(ne, &done);
|
||||
__ ldr(result, FieldMemOperand(input, JSValue::kValueOffset));
|
||||
|
||||
@ -1404,9 +1412,9 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
||||
LOperand* input = instr->InputAt(0);
|
||||
ASSERT(input->Equals(instr->result()));
|
||||
__ mvn(ToRegister(input), Operand(ToRegister(input)));
|
||||
Register input = ToRegister(instr->InputAt(0));
|
||||
Register result = ToRegister(instr->result());
|
||||
__ mvn(result, Operand(input));
|
||||
}
|
||||
|
||||
|
||||
@ -1424,16 +1432,16 @@ void LCodeGen::DoThrow(LThrow* instr) {
|
||||
void LCodeGen::DoAddI(LAddI* instr) {
|
||||
LOperand* left = instr->InputAt(0);
|
||||
LOperand* right = instr->InputAt(1);
|
||||
ASSERT(left->Equals(instr->result()));
|
||||
LOperand* result = instr->result();
|
||||
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
||||
SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
||||
|
||||
if (right->IsStackSlot() || right->IsArgument()) {
|
||||
Register right_reg = EmitLoadRegister(right, ip);
|
||||
__ add(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
|
||||
__ add(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
||||
} else {
|
||||
ASSERT(right->IsRegister() || right->IsConstantOperand());
|
||||
__ add(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
|
||||
__ add(ToRegister(result), ToRegister(left), ToOperand(right), set_cond);
|
||||
}
|
||||
|
||||
if (can_overflow) {
|
||||
@ -1445,18 +1453,19 @@ void LCodeGen::DoAddI(LAddI* instr) {
|
||||
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
|
||||
DoubleRegister left = ToDoubleRegister(instr->InputAt(0));
|
||||
DoubleRegister right = ToDoubleRegister(instr->InputAt(1));
|
||||
DoubleRegister result = ToDoubleRegister(instr->result());
|
||||
switch (instr->op()) {
|
||||
case Token::ADD:
|
||||
__ vadd(left, left, right);
|
||||
__ vadd(result, left, right);
|
||||
break;
|
||||
case Token::SUB:
|
||||
__ vsub(left, left, right);
|
||||
__ vsub(result, left, right);
|
||||
break;
|
||||
case Token::MUL:
|
||||
__ vmul(left, left, right);
|
||||
__ vmul(result, left, right);
|
||||
break;
|
||||
case Token::DIV:
|
||||
__ vdiv(left, left, right);
|
||||
__ vdiv(result, left, right);
|
||||
break;
|
||||
case Token::MOD: {
|
||||
// Save r0-r3 on the stack.
|
||||
@ -1468,7 +1477,7 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
|
||||
ExternalReference::double_fp_operation(Token::MOD, isolate()),
|
||||
0, 2);
|
||||
// Move the result in the double result register.
|
||||
__ GetCFunctionDoubleResult(ToDoubleRegister(instr->result()));
|
||||
__ GetCFunctionDoubleResult(result);
|
||||
|
||||
// Restore r0-r3.
|
||||
__ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
|
||||
@ -1561,7 +1570,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
||||
|
||||
// Test double values. Zero and NaN are false.
|
||||
Label call_stub;
|
||||
DoubleRegister dbl_scratch = d0;
|
||||
DoubleRegister dbl_scratch = double_scratch0();
|
||||
Register scratch = scratch0();
|
||||
__ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
|
||||
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
|
||||
@ -2607,7 +2616,6 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
|
||||
Register key = EmitLoadRegister(instr->key(), scratch0());
|
||||
Register result = ToRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
ASSERT(result.is(elements));
|
||||
|
||||
// Load the result.
|
||||
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
|
||||
@ -2927,8 +2935,8 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
|
||||
ASSERT(instr->InputAt(0)->Equals(instr->result()));
|
||||
Register input = ToRegister(instr->InputAt(0));
|
||||
Register result = ToRegister(instr->result());
|
||||
Register scratch = scratch0();
|
||||
|
||||
// Deoptimize if not a heap number.
|
||||
@ -2942,10 +2950,10 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
|
||||
scratch = no_reg;
|
||||
__ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
|
||||
// Check the sign of the argument. If the argument is positive, just
|
||||
// return it. We do not need to patch the stack since |input| and
|
||||
// |result| are the same register and |input| would be restored
|
||||
// unchanged by popping safepoint registers.
|
||||
// return it.
|
||||
__ tst(exponent, Operand(HeapNumber::kSignMask));
|
||||
// Move the input to the result if necessary.
|
||||
__ Move(result, input);
|
||||
__ b(eq, &done);
|
||||
|
||||
// Input is negative. Reverse its sign.
|
||||
@ -2985,7 +2993,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
|
||||
__ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
|
||||
__ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
|
||||
|
||||
__ StoreToSafepointRegisterSlot(tmp1, input);
|
||||
__ StoreToSafepointRegisterSlot(tmp1, result);
|
||||
}
|
||||
|
||||
__ bind(&done);
|
||||
@ -2994,11 +3002,13 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
|
||||
|
||||
void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
|
||||
Register input = ToRegister(instr->InputAt(0));
|
||||
Register result = ToRegister(instr->result());
|
||||
__ cmp(input, Operand(0));
|
||||
__ Move(result, input, pl);
|
||||
// We can make rsb conditional because the previous cmp instruction
|
||||
// will clear the V (overflow) flag and rsb won't set this flag
|
||||
// if input is positive.
|
||||
__ rsb(input, input, Operand(0), SetCC, mi);
|
||||
__ rsb(result, input, Operand(0), SetCC, mi);
|
||||
// Deoptimize on overflow.
|
||||
DeoptimizeIf(vs, instr->environment());
|
||||
}
|
||||
@ -3018,11 +3028,11 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
|
||||
LUnaryMathOperation* instr_;
|
||||
};
|
||||
|
||||
ASSERT(instr->InputAt(0)->Equals(instr->result()));
|
||||
Representation r = instr->hydrogen()->value()->representation();
|
||||
if (r.IsDouble()) {
|
||||
DwVfpRegister input = ToDoubleRegister(instr->InputAt(0));
|
||||
__ vabs(input, input);
|
||||
DwVfpRegister result = ToDoubleRegister(instr->result());
|
||||
__ vabs(result, input);
|
||||
} else if (r.IsInteger32()) {
|
||||
EmitIntegerMathAbs(instr);
|
||||
} else {
|
||||
@ -3100,7 +3110,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
|
||||
// Save the original sign for later comparison.
|
||||
__ and_(scratch2, scratch1, Operand(HeapNumber::kSignMask));
|
||||
|
||||
__ vmov(double_scratch0(), 0.5);
|
||||
__ Vmov(double_scratch0(), 0.5);
|
||||
__ vadd(input, input, double_scratch0());
|
||||
|
||||
// Check sign of the result: if the sign changed, the input
|
||||
@ -3137,24 +3147,17 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
|
||||
|
||||
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
|
||||
DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
||||
ASSERT(ToDoubleRegister(instr->result()).is(input));
|
||||
__ vsqrt(input, input);
|
||||
DoubleRegister result = ToDoubleRegister(instr->result());
|
||||
__ vsqrt(result, input);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
|
||||
DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
||||
Register scratch = scratch0();
|
||||
SwVfpRegister single_scratch = double_scratch0().low();
|
||||
DoubleRegister double_scratch = double_scratch0();
|
||||
ASSERT(ToDoubleRegister(instr->result()).is(input));
|
||||
|
||||
DoubleRegister result = ToDoubleRegister(instr->result());
|
||||
// Add +0 to convert -0 to +0.
|
||||
__ mov(scratch, Operand(0));
|
||||
__ vmov(single_scratch, scratch);
|
||||
__ vcvt_f64_s32(double_scratch, single_scratch);
|
||||
__ vadd(input, input, double_scratch);
|
||||
__ vsqrt(input, input);
|
||||
__ vadd(result, input, kDoubleRegZero);
|
||||
__ vsqrt(result, result);
|
||||
}
|
||||
|
||||
|
||||
@ -3753,8 +3756,8 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
|
||||
void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
|
||||
Label slow;
|
||||
Register reg = ToRegister(instr->InputAt(0));
|
||||
DoubleRegister dbl_scratch = d0;
|
||||
SwVfpRegister flt_scratch = s0;
|
||||
DoubleRegister dbl_scratch = double_scratch0();
|
||||
SwVfpRegister flt_scratch = dbl_scratch.low();
|
||||
|
||||
// Preserve the value of all registers.
|
||||
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
||||
@ -3863,8 +3866,8 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
|
||||
bool deoptimize_on_undefined,
|
||||
LEnvironment* env) {
|
||||
Register scratch = scratch0();
|
||||
SwVfpRegister flt_scratch = s0;
|
||||
ASSERT(!result_reg.is(d0));
|
||||
SwVfpRegister flt_scratch = double_scratch0().low();
|
||||
ASSERT(!result_reg.is(double_scratch0()));
|
||||
|
||||
Label load_smi, heap_number, done;
|
||||
|
||||
|
@ -148,7 +148,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
HGraph* graph() const { return chunk_->graph(); }
|
||||
|
||||
Register scratch0() { return r9; }
|
||||
DwVfpRegister double_scratch0() { return d0; }
|
||||
DwVfpRegister double_scratch0() { return d15; }
|
||||
|
||||
int GetNextEmittedBlock(int block);
|
||||
LInstruction* GetNextInstruction();
|
||||
|
@ -309,9 +309,9 @@ void MacroAssembler::Move(Register dst, Handle<Object> value) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Move(Register dst, Register src) {
|
||||
void MacroAssembler::Move(Register dst, Register src, Condition cond) {
|
||||
if (!dst.is(src)) {
|
||||
mov(dst, src);
|
||||
mov(dst, src, LeaveCC, cond);
|
||||
}
|
||||
}
|
||||
|
||||
@ -755,6 +755,23 @@ void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
|
||||
vmrs(fpscr_flags, cond);
|
||||
}
|
||||
|
||||
void MacroAssembler::Vmov(const DwVfpRegister dst,
|
||||
const double imm,
|
||||
const Condition cond) {
|
||||
ASSERT(CpuFeatures::IsEnabled(VFP3));
|
||||
static const DoubleRepresentation minus_zero(-0.0);
|
||||
static const DoubleRepresentation zero(0.0);
|
||||
DoubleRepresentation value(imm);
|
||||
// Handle special values first.
|
||||
if (value.bits == zero.bits) {
|
||||
vmov(dst, kDoubleRegZero, cond);
|
||||
} else if (value.bits == minus_zero.bits) {
|
||||
vneg(dst, kDoubleRegZero, cond);
|
||||
} else {
|
||||
vmov(dst, imm, cond);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::EnterFrame(StackFrame::Type type) {
|
||||
// r0-r3: preserved
|
||||
@ -3112,7 +3129,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
|
||||
Label done;
|
||||
Label in_bounds;
|
||||
|
||||
vmov(temp_double_reg, 0.0);
|
||||
Vmov(temp_double_reg, 0.0);
|
||||
VFPCompareAndSetFlags(input_reg, temp_double_reg);
|
||||
b(gt, &above_zero);
|
||||
|
||||
@ -3122,7 +3139,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
|
||||
|
||||
// Double value is >= 255, return 255.
|
||||
bind(&above_zero);
|
||||
vmov(temp_double_reg, 255.0);
|
||||
Vmov(temp_double_reg, 255.0);
|
||||
VFPCompareAndSetFlags(input_reg, temp_double_reg);
|
||||
b(le, &in_bounds);
|
||||
mov(result_reg, Operand(255));
|
||||
@ -3130,7 +3147,7 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
|
||||
|
||||
// In 0-255 range, round and truncate.
|
||||
bind(&in_bounds);
|
||||
vmov(temp_double_reg, 0.5);
|
||||
Vmov(temp_double_reg, 0.5);
|
||||
vadd(temp_double_reg, input_reg, temp_double_reg);
|
||||
vcvt_u32_f64(s0, temp_double_reg);
|
||||
vmov(result_reg, s0);
|
||||
|
@ -143,7 +143,7 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
// Register move. May do nothing if the registers are identical.
|
||||
void Move(Register dst, Handle<Object> value);
|
||||
void Move(Register dst, Register src);
|
||||
void Move(Register dst, Register src, Condition cond = al);
|
||||
void Move(DoubleRegister dst, DoubleRegister src);
|
||||
|
||||
// Load an object from the root table.
|
||||
@ -312,6 +312,10 @@ class MacroAssembler: public Assembler {
|
||||
const Register fpscr_flags,
|
||||
const Condition cond = al);
|
||||
|
||||
void Vmov(const DwVfpRegister dst,
|
||||
const double imm,
|
||||
const Condition cond = al);
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Activation frames
|
||||
|
Loading…
Reference in New Issue
Block a user