Merge V8 5.4.500.40
Test: Manual - built & ran d8
Change-Id: I4edfa2853d3e565b729723645395688ece3193f4
diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc
index e1cf2a6..4ae282a 100644
--- a/src/compiler/arm/code-generator-arm.cc
+++ b/src/compiler/arm/code-generator-arm.cc
@@ -136,14 +136,25 @@
FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
}
-};
+ FloatRegister InputFloat32Register(size_t index) {
+ return ToFloat32Register(instr_->InputAt(index));
+ }
+
+ FloatRegister OutputFloat32Register() {
+ return ToFloat32Register(instr_->Output());
+ }
+
+ FloatRegister ToFloat32Register(InstructionOperand* op) {
+ return LowDwVfpRegister::from_code(ToDoubleRegister(op).code()).low();
+ }
+};
namespace {
-class OutOfLineLoadFloat final : public OutOfLineCode {
+class OutOfLineLoadFloat32 final : public OutOfLineCode {
public:
- OutOfLineLoadFloat(CodeGenerator* gen, SwVfpRegister result)
+ OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
: OutOfLineCode(gen), result_(result) {}
void Generate() final {
@@ -188,7 +199,8 @@
public:
OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
Register value, Register scratch0, Register scratch1,
- RecordWriteMode mode)
+ RecordWriteMode mode,
+ UnwindingInfoWriter* unwinding_info_writer)
: OutOfLineCode(gen),
object_(object),
index_(index),
@@ -197,11 +209,13 @@
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode),
- must_save_lr_(!gen->frame_access_state()->has_frame()) {}
+ must_save_lr_(!gen->frame_access_state()->has_frame()),
+ unwinding_info_writer_(unwinding_info_writer) {}
OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index,
Register value, Register scratch0, Register scratch1,
- RecordWriteMode mode)
+ RecordWriteMode mode,
+ UnwindingInfoWriter* unwinding_info_writer)
: OutOfLineCode(gen),
object_(object),
index_(no_reg),
@@ -210,7 +224,8 @@
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode),
- must_save_lr_(!gen->frame_access_state()->has_frame()) {}
+ must_save_lr_(!gen->frame_access_state()->has_frame()),
+ unwinding_info_writer_(unwinding_info_writer) {}
void Generate() final {
if (mode_ > RecordWriteMode::kValueIsPointer) {
@@ -227,6 +242,7 @@
if (must_save_lr_) {
// We need to save and restore lr if the frame was elided.
__ Push(lr);
+ unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset());
}
RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
remembered_set_action, save_fp_mode);
@@ -239,6 +255,7 @@
__ CallStub(&stub);
if (must_save_lr_) {
__ Pop(lr);
+ unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset());
}
}
@@ -251,6 +268,7 @@
Register const scratch1_;
RecordWriteMode const mode_;
bool must_save_lr_;
+ UnwindingInfoWriter* const unwinding_info_writer_;
};
@@ -296,6 +314,10 @@
return vs;
case kNotOverflow:
return vc;
+ case kPositiveOrZero:
+ return pl;
+ case kNegative:
+ return mi;
default:
break;
}
@@ -409,23 +431,10 @@
void CodeGenerator::AssembleDeconstructFrame() {
__ LeaveFrame(StackFrame::MANUAL);
+ unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset());
}
-void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
- int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
- if (sp_slot_delta > 0) {
- __ add(sp, sp, Operand(sp_slot_delta * kPointerSize));
- }
- frame_access_state()->SetFrameAccessToDefault();
-}
-
-
-void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
- int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
- if (sp_slot_delta < 0) {
- __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
- frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
- }
+void CodeGenerator::AssemblePrepareTailCall() {
if (frame_access_state()->has_frame()) {
if (FLAG_enable_embedded_constant_pool) {
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
@@ -461,6 +470,115 @@
__ bind(&done);
}
+namespace {
+
+void FlushPendingPushRegisters(MacroAssembler* masm,
+ FrameAccessState* frame_access_state,
+ ZoneVector<Register>* pending_pushes) {
+ switch (pending_pushes->size()) {
+ case 0:
+ break;
+ case 1:
+ masm->push((*pending_pushes)[0]);
+ break;
+ case 2:
+ masm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
+ break;
+ case 3:
+ masm->Push((*pending_pushes)[0], (*pending_pushes)[1],
+ (*pending_pushes)[2]);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ frame_access_state->IncreaseSPDelta(pending_pushes->size());
+ pending_pushes->resize(0);
+}
+
+void AddPendingPushRegister(MacroAssembler* masm,
+ FrameAccessState* frame_access_state,
+ ZoneVector<Register>* pending_pushes,
+ Register reg) {
+ pending_pushes->push_back(reg);
+ if (pending_pushes->size() == 3 || reg.is(ip)) {
+ FlushPendingPushRegisters(masm, frame_access_state, pending_pushes);
+ }
+}
+
+void AdjustStackPointerForTailCall(
+ MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp,
+ ZoneVector<Register>* pending_pushes = nullptr,
+ bool allow_shrinkage = true) {
+ int current_sp_offset = state->GetSPToFPSlotCount() +
+ StandardFrameConstants::kFixedSlotCountAboveFp;
+ int stack_slot_delta = new_slot_above_sp - current_sp_offset;
+ if (stack_slot_delta > 0) {
+ if (pending_pushes != nullptr) {
+ FlushPendingPushRegisters(masm, state, pending_pushes);
+ }
+ masm->sub(sp, sp, Operand(stack_slot_delta * kPointerSize));
+ state->IncreaseSPDelta(stack_slot_delta);
+ } else if (allow_shrinkage && stack_slot_delta < 0) {
+ if (pending_pushes != nullptr) {
+ FlushPendingPushRegisters(masm, state, pending_pushes);
+ }
+ masm->add(sp, sp, Operand(-stack_slot_delta * kPointerSize));
+ state->IncreaseSPDelta(stack_slot_delta);
+ }
+}
+
+} // namespace
+
+void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
+ int first_unused_stack_slot) {
+ CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush);
+ ZoneVector<MoveOperands*> pushes(zone());
+ GetPushCompatibleMoves(instr, flags, &pushes);
+
+ if (!pushes.empty() &&
+ (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
+ first_unused_stack_slot)) {
+ ArmOperandConverter g(this, instr);
+ ZoneVector<Register> pending_pushes(zone());
+ for (auto move : pushes) {
+ LocationOperand destination_location(
+ LocationOperand::cast(move->destination()));
+ InstructionOperand source(move->source());
+ AdjustStackPointerForTailCall(
+ masm(), frame_access_state(),
+ destination_location.index() - pending_pushes.size(),
+ &pending_pushes);
+ if (source.IsStackSlot()) {
+ LocationOperand source_location(LocationOperand::cast(source));
+ __ ldr(ip, g.SlotToMemOperand(source_location.index()));
+ AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
+ ip);
+ } else if (source.IsRegister()) {
+ LocationOperand source_location(LocationOperand::cast(source));
+ AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
+ source_location.GetRegister());
+ } else if (source.IsImmediate()) {
+ AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
+ ip);
+ } else {
+ // Pushes of non-scalar data types is not supported.
+ UNIMPLEMENTED();
+ }
+ move->Eliminate();
+ }
+ FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes);
+ }
+ AdjustStackPointerForTailCall(masm(), frame_access_state(),
+ first_unused_stack_slot, nullptr, false);
+}
+
+void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
+ int first_unused_stack_slot) {
+ AdjustStackPointerForTailCall(masm(), frame_access_state(),
+ first_unused_stack_slot);
+}
+
// Assembles an instruction after register allocation, producing machine code.
CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Instruction* instr) {
@@ -487,8 +605,6 @@
}
case kArchTailCallCodeObjectFromJSFunction:
case kArchTailCallCodeObject: {
- int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
- AssembleDeconstructActivationRecord(stack_param_delta);
if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) {
AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
i.TempRegister(0), i.TempRegister(1),
@@ -503,15 +619,17 @@
__ Jump(ip);
}
DCHECK_EQ(LeaveCC, i.OutputSBit());
+ unwinding_info_writer_.MarkBlockWillExit();
frame_access_state()->ClearSPDelta();
+ frame_access_state()->SetFrameAccessToDefault();
break;
}
case kArchTailCallAddress: {
- int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
- AssembleDeconstructActivationRecord(stack_param_delta);
CHECK(!instr->InputAt(0)->IsImmediate());
__ Jump(i.InputRegister(0));
+ unwinding_info_writer_.MarkBlockWillExit();
frame_access_state()->ClearSPDelta();
+ frame_access_state()->SetFrameAccessToDefault();
break;
}
case kArchCallJSFunction: {
@@ -539,8 +657,6 @@
__ cmp(cp, kScratchReg);
__ Assert(eq, kWrongFunctionContext);
}
- int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
- AssembleDeconstructActivationRecord(stack_param_delta);
if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) {
AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
i.TempRegister(0), i.TempRegister(1),
@@ -550,6 +666,7 @@
__ Jump(ip);
DCHECK_EQ(LeaveCC, i.OutputSBit());
frame_access_state()->ClearSPDelta();
+ frame_access_state()->SetFrameAccessToDefault();
break;
}
case kArchPrepareCallCFunction: {
@@ -560,7 +677,7 @@
break;
}
case kArchPrepareTailCall:
- AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
+ AssemblePrepareTailCall();
break;
case kArchCallCFunction: {
int const num_parameters = MiscField::decode(instr->opcode());
@@ -590,6 +707,9 @@
case kArchDebugBreak:
__ stop("kArchDebugBreak");
break;
+ case kArchImpossible:
+ __ Abort(kConversionFromImpossibleValue);
+ break;
case kArchComment: {
Address comment_string = i.InputExternalReference(0).address();
__ RecordComment(reinterpret_cast<const char*>(comment_string));
@@ -646,14 +766,16 @@
AddressingModeField::decode(instr->opcode());
if (addressing_mode == kMode_Offset_RI) {
int32_t index = i.InputInt32(1);
- ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
- scratch0, scratch1, mode);
+ ool = new (zone())
+ OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
+ mode, &unwinding_info_writer_);
__ str(value, MemOperand(object, index));
} else {
DCHECK_EQ(kMode_Offset_RR, addressing_mode);
Register index(i.InputRegister(1));
- ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
- scratch0, scratch1, mode);
+ ool = new (zone())
+ OutOfLineRecordWrite(this, object, index, value, scratch0, scratch1,
+ mode, &unwinding_info_writer_);
__ str(value, MemOperand(object, index));
}
__ CheckPageFlag(object, scratch0,
@@ -674,9 +796,24 @@
__ add(i.OutputRegister(0), base, Operand(offset.offset()));
break;
}
+ case kIeee754Float64Acos:
+ ASSEMBLE_IEEE754_UNOP(acos);
+ break;
+ case kIeee754Float64Acosh:
+ ASSEMBLE_IEEE754_UNOP(acosh);
+ break;
+ case kIeee754Float64Asin:
+ ASSEMBLE_IEEE754_UNOP(asin);
+ break;
+ case kIeee754Float64Asinh:
+ ASSEMBLE_IEEE754_UNOP(asinh);
+ break;
case kIeee754Float64Atan:
ASSEMBLE_IEEE754_UNOP(atan);
break;
+ case kIeee754Float64Atanh:
+ ASSEMBLE_IEEE754_UNOP(atanh);
+ break;
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
@@ -686,15 +823,15 @@
case kIeee754Float64Cos:
ASSEMBLE_IEEE754_UNOP(cos);
break;
+ case kIeee754Float64Cosh:
+ ASSEMBLE_IEEE754_UNOP(cosh);
+ break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Expm1:
ASSEMBLE_IEEE754_UNOP(expm1);
break;
- case kIeee754Float64Atanh:
- ASSEMBLE_IEEE754_UNOP(atanh);
- break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;
@@ -707,12 +844,24 @@
case kIeee754Float64Log10:
ASSEMBLE_IEEE754_UNOP(log10);
break;
+ case kIeee754Float64Pow: {
+ MathPowStub stub(isolate(), MathPowStub::DOUBLE);
+ __ CallStub(&stub);
+ __ vmov(d0, d2);
+ break;
+ }
case kIeee754Float64Sin:
ASSEMBLE_IEEE754_UNOP(sin);
break;
+ case kIeee754Float64Sinh:
+ ASSEMBLE_IEEE754_UNOP(sinh);
+ break;
case kIeee754Float64Tan:
ASSEMBLE_IEEE754_UNOP(tan);
break;
+ case kIeee754Float64Tanh:
+ ASSEMBLE_IEEE754_UNOP(tanh);
+ break;
case kArmAdd:
__ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
i.OutputSBit());
@@ -740,6 +889,10 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
+ case kArmSmull:
+ __ smull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
+ i.InputRegister(1));
+ break;
case kArmSmmul:
__ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -932,54 +1085,54 @@
break;
case kArmVcmpF32:
if (instr->InputAt(1)->IsFPRegister()) {
- __ VFPCompareAndSetFlags(i.InputFloatRegister(0),
- i.InputFloatRegister(1));
+ __ VFPCompareAndSetFlags(i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
} else {
DCHECK(instr->InputAt(1)->IsImmediate());
// 0.0 is the only immediate supported by vcmp instructions.
DCHECK(i.InputFloat32(1) == 0.0f);
- __ VFPCompareAndSetFlags(i.InputFloatRegister(0), i.InputFloat32(1));
+ __ VFPCompareAndSetFlags(i.InputFloat32Register(0), i.InputFloat32(1));
}
DCHECK_EQ(SetCC, i.OutputSBit());
break;
case kArmVaddF32:
- __ vadd(i.OutputFloatRegister(), i.InputFloatRegister(0),
- i.InputFloatRegister(1));
+ __ vadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVsubF32:
- __ vsub(i.OutputFloatRegister(), i.InputFloatRegister(0),
- i.InputFloatRegister(1));
+ __ vsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmulF32:
- __ vmul(i.OutputFloatRegister(), i.InputFloatRegister(0),
- i.InputFloatRegister(1));
+ __ vmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmlaF32:
- __ vmla(i.OutputFloatRegister(), i.InputFloatRegister(1),
- i.InputFloatRegister(2));
+ __ vmla(i.OutputFloat32Register(), i.InputFloat32Register(1),
+ i.InputFloat32Register(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmlsF32:
- __ vmls(i.OutputFloatRegister(), i.InputFloatRegister(1),
- i.InputFloatRegister(2));
+ __ vmls(i.OutputFloat32Register(), i.InputFloat32Register(1),
+ i.InputFloat32Register(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVdivF32:
- __ vdiv(i.OutputFloatRegister(), i.InputFloatRegister(0),
- i.InputFloatRegister(1));
+ __ vdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVsqrtF32:
- __ vsqrt(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVabsF32:
- __ vabs(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVnegF32:
- __ vneg(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVcmpF64:
if (instr->InputAt(1)->IsFPRegister()) {
@@ -1047,19 +1200,19 @@
__ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArmVrintmF32:
- __ vrintm(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vrintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVrintmF64:
__ vrintm(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArmVrintpF32:
- __ vrintp(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vrintp(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVrintpF64:
__ vrintp(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArmVrintzF32:
- __ vrintz(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vrintz(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVrintzF64:
__ vrintz(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
@@ -1068,32 +1221,32 @@
__ vrinta(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArmVrintnF32:
- __ vrintn(i.OutputFloatRegister(), i.InputFloatRegister(0));
+ __ vrintn(i.OutputFloat32Register(), i.InputFloat32Register(0));
break;
case kArmVrintnF64:
__ vrintn(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
break;
case kArmVcvtF32F64: {
- __ vcvt_f32_f64(i.OutputFloatRegister(), i.InputDoubleRegister(0));
+ __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputDoubleRegister(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtF64F32: {
- __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloatRegister(0));
+ __ vcvt_f64_f32(i.OutputDoubleRegister(), i.InputFloat32Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtF32S32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vmov(scratch, i.InputRegister(0));
- __ vcvt_f32_s32(i.OutputFloatRegister(), scratch);
+ __ vcvt_f32_s32(i.OutputFloat32Register(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtF32U32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vmov(scratch, i.InputRegister(0));
- __ vcvt_f32_u32(i.OutputFloatRegister(), scratch);
+ __ vcvt_f32_u32(i.OutputFloat32Register(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
@@ -1113,15 +1266,23 @@
}
case kArmVcvtS32F32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
- __ vcvt_s32_f32(scratch, i.InputFloatRegister(0));
+ __ vcvt_s32_f32(scratch, i.InputFloat32Register(0));
__ vmov(i.OutputRegister(), scratch);
+ // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
+ // because INT32_MIN allows easier out-of-bounds detection.
+ __ cmn(i.OutputRegister(), Operand(1));
+ __ mov(i.OutputRegister(), Operand(INT32_MIN), SBit::LeaveCC, vs);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtU32F32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
- __ vcvt_u32_f32(scratch, i.InputFloatRegister(0));
+ __ vcvt_u32_f32(scratch, i.InputFloat32Register(0));
__ vmov(i.OutputRegister(), scratch);
+ // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
+ // because 0 allows easier out-of-bounds detection.
+ __ cmn(i.OutputRegister(), Operand(1));
+ __ adc(i.OutputRegister(), i.OutputRegister(), Operand::Zero());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
@@ -1140,11 +1301,11 @@
break;
}
case kArmVmovU32F32:
- __ vmov(i.OutputRegister(), i.InputFloatRegister(0));
+ __ vmov(i.OutputRegister(), i.InputFloat32Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmovF32U32:
- __ vmov(i.OutputFloatRegister(), i.InputRegister(0));
+ __ vmov(i.OutputFloat32Register(), i.InputRegister(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmovLowU32F64:
@@ -1167,6 +1328,11 @@
__ vmov(i.OutputDoubleRegister(), i.InputRegister(0), i.InputRegister(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArmVmovU32U32F64:
+ __ vmov(i.OutputRegister(0), i.OutputRegister(1),
+ i.InputDoubleRegister(0));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArmLdrb:
__ ldrb(i.OutputRegister(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -1197,12 +1363,12 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVldrF32: {
- __ vldr(i.OutputFloatRegister(), i.InputOffset());
+ __ vldr(i.OutputFloat32Register(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVstrF32:
- __ vstr(i.InputFloatRegister(0), i.InputOffset(1));
+ __ vstr(i.InputFloat32Register(0), i.InputOffset(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVldrF64:
@@ -1214,43 +1380,145 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmFloat32Max: {
- CpuFeatureScope scope(masm(), ARMv8);
- // (b < a) ? a : b
- SwVfpRegister a = i.InputFloatRegister(0);
- SwVfpRegister b = i.InputFloatRegister(1);
- SwVfpRegister result = i.OutputFloatRegister();
- __ VFPCompareAndSetFlags(a, b);
- __ vsel(gt, result, a, b);
- break;
- }
- case kArmFloat32Min: {
- CpuFeatureScope scope(masm(), ARMv8);
- // (a < b) ? a : b
- SwVfpRegister a = i.InputFloatRegister(0);
- SwVfpRegister b = i.InputFloatRegister(1);
- SwVfpRegister result = i.OutputFloatRegister();
- __ VFPCompareAndSetFlags(b, a);
- __ vsel(gt, result, a, b);
+ FloatRegister left_reg = i.InputFloat32Register(0);
+ FloatRegister right_reg = i.InputFloat32Register(1);
+ FloatRegister result_reg = i.OutputFloat32Register();
+ Label result_is_nan, return_left, return_right, check_zero, done;
+ __ VFPCompareAndSetFlags(left_reg, right_reg);
+ __ b(mi, &return_right);
+ __ b(gt, &return_left);
+ __ b(vs, &result_is_nan);
+ // Left equals right => check for -0.
+ __ VFPCompareAndSetFlags(left_reg, 0.0);
+ if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+ __ b(ne, &done); // left == right != 0.
+ } else {
+ __ b(ne, &return_left); // left == right != 0.
+ }
+ // At this point, both left and right are either 0 or -0.
+ // Since we operate on +0 and/or -0, vadd and vand have the same effect;
+ // the decision for vadd is easy because vand is a NEON instruction.
+ __ vadd(result_reg, left_reg, right_reg);
+ __ b(&done);
+ __ bind(&result_is_nan);
+ __ vadd(result_reg, left_reg, right_reg);
+ __ b(&done);
+ __ bind(&return_right);
+ __ Move(result_reg, right_reg);
+ if (!left_reg.is(result_reg)) __ b(&done);
+ __ bind(&return_left);
+ __ Move(result_reg, left_reg);
+ __ bind(&done);
break;
}
case kArmFloat64Max: {
- CpuFeatureScope scope(masm(), ARMv8);
- // (b < a) ? a : b
- DwVfpRegister a = i.InputDoubleRegister(0);
- DwVfpRegister b = i.InputDoubleRegister(1);
- DwVfpRegister result = i.OutputDoubleRegister();
- __ VFPCompareAndSetFlags(a, b);
- __ vsel(gt, result, a, b);
+ DwVfpRegister left_reg = i.InputDoubleRegister(0);
+ DwVfpRegister right_reg = i.InputDoubleRegister(1);
+ DwVfpRegister result_reg = i.OutputDoubleRegister();
+ Label result_is_nan, return_left, return_right, check_zero, done;
+ __ VFPCompareAndSetFlags(left_reg, right_reg);
+ __ b(mi, &return_right);
+ __ b(gt, &return_left);
+ __ b(vs, &result_is_nan);
+ // Left equals right => check for -0.
+ __ VFPCompareAndSetFlags(left_reg, 0.0);
+ if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+ __ b(ne, &done); // left == right != 0.
+ } else {
+ __ b(ne, &return_left); // left == right != 0.
+ }
+ // At this point, both left and right are either 0 or -0.
+ // Since we operate on +0 and/or -0, vadd and vand have the same effect;
+ // the decision for vadd is easy because vand is a NEON instruction.
+ __ vadd(result_reg, left_reg, right_reg);
+ __ b(&done);
+ __ bind(&result_is_nan);
+ __ vadd(result_reg, left_reg, right_reg);
+ __ b(&done);
+ __ bind(&return_right);
+ __ Move(result_reg, right_reg);
+ if (!left_reg.is(result_reg)) __ b(&done);
+ __ bind(&return_left);
+ __ Move(result_reg, left_reg);
+ __ bind(&done);
+ break;
+ }
+ case kArmFloat32Min: {
+ FloatRegister left_reg = i.InputFloat32Register(0);
+ FloatRegister right_reg = i.InputFloat32Register(1);
+ FloatRegister result_reg = i.OutputFloat32Register();
+ Label result_is_nan, return_left, return_right, check_zero, done;
+ __ VFPCompareAndSetFlags(left_reg, right_reg);
+ __ b(mi, &return_left);
+ __ b(gt, &return_right);
+ __ b(vs, &result_is_nan);
+ // Left equals right => check for -0.
+ __ VFPCompareAndSetFlags(left_reg, 0.0);
+ if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+ __ b(ne, &done); // left == right != 0.
+ } else {
+ __ b(ne, &return_left); // left == right != 0.
+ }
+ // At this point, both left and right are either 0 or -0.
+ // We could use a single 'vorr' instruction here if we had NEON support.
+ // The algorithm is: -((-L) + (-R)), which in case of L and R being
+ // different registers is most efficiently expressed as -((-L) - R).
+ __ vneg(left_reg, left_reg);
+ if (left_reg.is(right_reg)) {
+ __ vadd(result_reg, left_reg, right_reg);
+ } else {
+ __ vsub(result_reg, left_reg, right_reg);
+ }
+ __ vneg(result_reg, result_reg);
+ __ b(&done);
+ __ bind(&result_is_nan);
+ __ vadd(result_reg, left_reg, right_reg);
+ __ b(&done);
+ __ bind(&return_right);
+ __ Move(result_reg, right_reg);
+ if (!left_reg.is(result_reg)) __ b(&done);
+ __ bind(&return_left);
+ __ Move(result_reg, left_reg);
+ __ bind(&done);
break;
}
case kArmFloat64Min: {
- CpuFeatureScope scope(masm(), ARMv8);
- // (a < b) ? a : b
- DwVfpRegister a = i.InputDoubleRegister(0);
- DwVfpRegister b = i.InputDoubleRegister(1);
- DwVfpRegister result = i.OutputDoubleRegister();
- __ VFPCompareAndSetFlags(b, a);
- __ vsel(gt, result, a, b);
+ DwVfpRegister left_reg = i.InputDoubleRegister(0);
+ DwVfpRegister right_reg = i.InputDoubleRegister(1);
+ DwVfpRegister result_reg = i.OutputDoubleRegister();
+ Label result_is_nan, return_left, return_right, check_zero, done;
+ __ VFPCompareAndSetFlags(left_reg, right_reg);
+ __ b(mi, &return_left);
+ __ b(gt, &return_right);
+ __ b(vs, &result_is_nan);
+ // Left equals right => check for -0.
+ __ VFPCompareAndSetFlags(left_reg, 0.0);
+ if (left_reg.is(result_reg) || right_reg.is(result_reg)) {
+ __ b(ne, &done); // left == right != 0.
+ } else {
+ __ b(ne, &return_left); // left == right != 0.
+ }
+ // At this point, both left and right are either 0 or -0.
+ // We could use a single 'vorr' instruction here if we had NEON support.
+ // The algorithm is: -((-L) + (-R)), which in case of L and R being
+ // different registers is most efficiently expressed as -((-L) - R).
+ __ vneg(left_reg, left_reg);
+ if (left_reg.is(right_reg)) {
+ __ vadd(result_reg, left_reg, right_reg);
+ } else {
+ __ vsub(result_reg, left_reg, right_reg);
+ }
+ __ vneg(result_reg, result_reg);
+ __ b(&done);
+ __ bind(&result_is_nan);
+ __ vadd(result_reg, left_reg, right_reg);
+ __ b(&done);
+ __ bind(&return_right);
+ __ Move(result_reg, right_reg);
+ if (!left_reg.is(result_reg)) __ b(&done);
+ __ bind(&return_left);
+ __ Move(result_reg, left_reg);
+ __ bind(&done);
break;
}
case kArmFloat64SilenceNaN: {
@@ -1267,7 +1535,7 @@
frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
} else {
DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
- __ vpush(i.InputFloatRegister(0));
+ __ vpush(i.InputFloat32Register(0));
frame_access_state()->IncreaseSPDelta(1);
}
} else {
@@ -1298,7 +1566,7 @@
ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
break;
case kCheckedLoadFloat32:
- ASSEMBLE_CHECKED_LOAD_FP(Float);
+ ASSEMBLE_CHECKED_LOAD_FP(Float32);
break;
case kCheckedLoadFloat64:
ASSEMBLE_CHECKED_LOAD_FP(Double);
@@ -1313,7 +1581,7 @@
ASSEMBLE_CHECKED_STORE_INTEGER(str);
break;
case kCheckedStoreFloat32:
- ASSEMBLE_CHECKED_STORE_FP(Float);
+ ASSEMBLE_CHECKED_STORE_FP(Float32);
break;
case kCheckedStoreFloat64:
ASSEMBLE_CHECKED_STORE_FP(Double);
@@ -1418,6 +1686,9 @@
// actual final call site and just bl'ing to it here, similar to what we do
// in the lithium backend.
if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
+ DeoptimizeReason deoptimization_reason =
+ GetDeoptimizationReason(deoptimization_id);
+ __ RecordDeoptReason(deoptimization_reason, 0, deoptimization_id);
__ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
__ CheckConstPool(false, false);
return kSuccess;
@@ -1467,6 +1738,10 @@
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
+
+ if (!info()->GeneratePreagedPrologue()) {
+ unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
+ }
}
int shrink_slots = frame()->GetSpillSlotCount();
@@ -1530,6 +1805,8 @@
DwVfpRegister::from_code(last));
}
+ unwinding_info_writer_.MarkBlockWillExit();
+
if (descriptor->IsCFunctionCall()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
@@ -1601,10 +1878,7 @@
case Constant::kHeapObject: {
Handle<HeapObject> src_object = src.ToHeapObject();
Heap::RootListIndex index;
- int slot;
- if (IsMaterializableFromFrame(src_object, &slot)) {
- __ ldr(dst, g.SlotToMemOperand(slot));
- } else if (IsMaterializableFromRoot(src_object, &index)) {
+ if (IsMaterializableFromRoot(src_object, &index)) {
__ LoadRoot(dst, index);
} else {
__ Move(dst, src_object);
@@ -1622,7 +1896,7 @@
__ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
__ str(ip, dst);
} else {
- SwVfpRegister dst = g.ToFloatRegister(destination);
+ SwVfpRegister dst = g.ToFloat32Register(destination);
__ vmov(dst, src.ToFloat32());
}
} else {
@@ -1636,50 +1910,23 @@
}
}
} else if (source->IsFPRegister()) {
- MachineRepresentation rep = LocationOperand::cast(source)->representation();
- if (rep == MachineRepresentation::kFloat64) {
- DwVfpRegister src = g.ToDoubleRegister(source);
- if (destination->IsFPRegister()) {
- DwVfpRegister dst = g.ToDoubleRegister(destination);
- __ Move(dst, src);
- } else {
- DCHECK(destination->IsFPStackSlot());
- __ vstr(src, g.ToMemOperand(destination));
- }
+ DwVfpRegister src = g.ToDoubleRegister(source);
+ if (destination->IsFPRegister()) {
+ DwVfpRegister dst = g.ToDoubleRegister(destination);
+ __ Move(dst, src);
} else {
- DCHECK_EQ(MachineRepresentation::kFloat32, rep);
- SwVfpRegister src = g.ToFloatRegister(source);
- if (destination->IsFPRegister()) {
- SwVfpRegister dst = g.ToFloatRegister(destination);
- __ Move(dst, src);
- } else {
- DCHECK(destination->IsFPStackSlot());
- __ vstr(src, g.ToMemOperand(destination));
- }
+ DCHECK(destination->IsFPStackSlot());
+ __ vstr(src, g.ToMemOperand(destination));
}
} else if (source->IsFPStackSlot()) {
MemOperand src = g.ToMemOperand(source);
- MachineRepresentation rep =
- LocationOperand::cast(destination)->representation();
if (destination->IsFPRegister()) {
- if (rep == MachineRepresentation::kFloat64) {
__ vldr(g.ToDoubleRegister(destination), src);
- } else {
- DCHECK_EQ(MachineRepresentation::kFloat32, rep);
- __ vldr(g.ToFloatRegister(destination), src);
- }
} else {
DCHECK(destination->IsFPStackSlot());
- if (rep == MachineRepresentation::kFloat64) {
DwVfpRegister temp = kScratchDoubleReg;
__ vldr(temp, src);
__ vstr(temp, g.ToMemOperand(destination));
- } else {
- DCHECK_EQ(MachineRepresentation::kFloat32, rep);
- SwVfpRegister temp = kScratchDoubleReg.low();
- __ vldr(temp, src);
- __ vstr(temp, g.ToMemOperand(destination));
- }
}
} else {
UNREACHABLE();
@@ -1719,9 +1966,7 @@
__ str(temp_0, dst);
__ vstr(temp_1, src);
} else if (source->IsFPRegister()) {
- MachineRepresentation rep = LocationOperand::cast(source)->representation();
LowDwVfpRegister temp = kScratchDoubleReg;
- if (rep == MachineRepresentation::kFloat64) {
DwVfpRegister src = g.ToDoubleRegister(source);
if (destination->IsFPRegister()) {
DwVfpRegister dst = g.ToDoubleRegister(destination);
@@ -1735,30 +1980,12 @@
__ vldr(src, dst);
__ vstr(temp, dst);
}
- } else {
- DCHECK_EQ(MachineRepresentation::kFloat32, rep);
- SwVfpRegister src = g.ToFloatRegister(source);
- if (destination->IsFPRegister()) {
- SwVfpRegister dst = g.ToFloatRegister(destination);
- __ Move(temp.low(), src);
- __ Move(src, dst);
- __ Move(dst, temp.low());
- } else {
- DCHECK(destination->IsFPStackSlot());
- MemOperand dst = g.ToMemOperand(destination);
- __ Move(temp.low(), src);
- __ vldr(src, dst);
- __ vstr(temp.low(), dst);
- }
- }
} else if (source->IsFPStackSlot()) {
DCHECK(destination->IsFPStackSlot());
Register temp_0 = kScratchReg;
LowDwVfpRegister temp_1 = kScratchDoubleReg;
MemOperand src0 = g.ToMemOperand(source);
MemOperand dst0 = g.ToMemOperand(destination);
- MachineRepresentation rep = LocationOperand::cast(source)->representation();
- if (rep == MachineRepresentation::kFloat64) {
MemOperand src1(src0.rn(), src0.offset() + kPointerSize);
MemOperand dst1(dst0.rn(), dst0.offset() + kPointerSize);
__ vldr(temp_1, dst0); // Save destination in temp_1.
@@ -1767,13 +1994,6 @@
__ ldr(temp_0, src1);
__ str(temp_0, dst1);
__ vstr(temp_1, src0);
- } else {
- DCHECK_EQ(MachineRepresentation::kFloat32, rep);
- __ vldr(temp_1.low(), dst0); // Save destination in temp_1.
- __ ldr(temp_0, src0); // Then use temp_0 to copy source to destination.
- __ str(temp_0, dst0);
- __ vstr(temp_1.low(), src0);
- }
} else {
// No other combinations are possible.
UNREACHABLE();
diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h
index bc3336f..07c4033 100644
--- a/src/compiler/arm/instruction-codes-arm.h
+++ b/src/compiler/arm/instruction-codes-arm.h
@@ -27,6 +27,7 @@
V(ArmMul) \
V(ArmMla) \
V(ArmMls) \
+ V(ArmSmull) \
V(ArmSmmul) \
V(ArmSmmla) \
V(ArmUmull) \
@@ -99,13 +100,14 @@
V(ArmVmovHighU32F64) \
V(ArmVmovHighF64U32) \
V(ArmVmovF64U32U32) \
+ V(ArmVmovU32U32F64) \
V(ArmVldrF32) \
V(ArmVstrF32) \
V(ArmVldrF64) \
V(ArmVstrF64) \
V(ArmFloat32Max) \
- V(ArmFloat32Min) \
V(ArmFloat64Max) \
+ V(ArmFloat32Min) \
V(ArmFloat64Min) \
V(ArmFloat64SilenceNaN) \
V(ArmLdrb) \
diff --git a/src/compiler/arm/instruction-scheduler-arm.cc b/src/compiler/arm/instruction-scheduler-arm.cc
index 065fe52..3f38e5d 100644
--- a/src/compiler/arm/instruction-scheduler-arm.cc
+++ b/src/compiler/arm/instruction-scheduler-arm.cc
@@ -30,6 +30,7 @@
case kArmMla:
case kArmMls:
case kArmSmmul:
+ case kArmSmull:
case kArmSmmla:
case kArmUmull:
case kArmSdiv:
@@ -101,10 +102,11 @@
case kArmVmovHighU32F64:
case kArmVmovHighF64U32:
case kArmVmovF64U32U32:
- case kArmFloat64Max:
- case kArmFloat64Min:
+ case kArmVmovU32U32F64:
case kArmFloat32Max:
+ case kArmFloat64Max:
case kArmFloat32Min:
+ case kArmFloat64Min:
case kArmFloat64SilenceNaN:
return kNoOpcodeFlags;
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc
index e21e63f..4b0b6af 100644
--- a/src/compiler/arm/instruction-selector-arm.cc
+++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -273,7 +273,7 @@
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
- cont->frame_state());
+ cont->reason(), cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
@@ -338,6 +338,46 @@
}
}
+void EmitLoad(InstructionSelector* selector, InstructionCode opcode,
+ InstructionOperand* output, Node* base, Node* index) {
+ ArmOperandGenerator g(selector);
+ InstructionOperand inputs[3];
+ size_t input_count = 2;
+
+ inputs[0] = g.UseRegister(base);
+ if (g.CanBeImmediate(index, opcode)) {
+ inputs[1] = g.UseImmediate(index);
+ opcode |= AddressingModeField::encode(kMode_Offset_RI);
+ } else if ((opcode == kArmLdr) &&
+ TryMatchLSLImmediate(selector, &opcode, index, &inputs[1],
+ &inputs[2])) {
+ input_count = 3;
+ } else {
+ inputs[1] = g.UseRegister(index);
+ opcode |= AddressingModeField::encode(kMode_Offset_RR);
+ }
+ selector->Emit(opcode, 1, output, input_count, inputs);
+}
+
+void EmitStore(InstructionSelector* selector, InstructionCode opcode,
+ size_t input_count, InstructionOperand* inputs,
+ Node* index) {
+ ArmOperandGenerator g(selector);
+
+ if (g.CanBeImmediate(index, opcode)) {
+ inputs[input_count++] = g.UseImmediate(index);
+ opcode |= AddressingModeField::encode(kMode_Offset_RI);
+ } else if ((opcode == kArmStr) &&
+ TryMatchLSLImmediate(selector, &opcode, index, &inputs[2],
+ &inputs[3])) {
+ input_count = 4;
+ } else {
+ inputs[input_count++] = g.UseRegister(index);
+ opcode |= AddressingModeField::encode(kMode_Offset_RR);
+ }
+ selector->Emit(opcode, 0, nullptr, input_count, inputs);
+}
+
} // namespace
@@ -346,9 +386,6 @@
ArmOperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
- InstructionOperand inputs[3];
- size_t input_count = 0;
- InstructionOperand outputs[1];
InstructionCode opcode = kArchNop;
switch (load_rep.representation()) {
@@ -365,6 +402,8 @@
case MachineRepresentation::kWord16:
opcode = load_rep.IsUnsigned() ? kArmLdrh : kArmLdrsh;
break;
+ case MachineRepresentation::kTaggedSigned: // Fall through.
+ case MachineRepresentation::kTaggedPointer: // Fall through.
case MachineRepresentation::kTagged: // Fall through.
case MachineRepresentation::kWord32:
opcode = kArmLdr;
@@ -376,24 +415,8 @@
return;
}
- outputs[0] = g.DefineAsRegister(node);
- inputs[0] = g.UseRegister(base);
-
- if (g.CanBeImmediate(index, opcode)) {
- input_count = 2;
- inputs[1] = g.UseImmediate(index);
- opcode |= AddressingModeField::encode(kMode_Offset_RI);
- } else if ((opcode == kArmLdr) &&
- TryMatchLSLImmediate(this, &opcode, index, &inputs[1],
- &inputs[2])) {
- input_count = 3;
- } else {
- input_count = 2;
- inputs[1] = g.UseRegister(index);
- opcode |= AddressingModeField::encode(kMode_Offset_RR);
- }
-
- Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
+ InstructionOperand output = g.DefineAsRegister(node);
+ EmitLoad(this, opcode, &output, base, index);
}
@@ -445,9 +468,6 @@
code |= MiscField::encode(static_cast<int>(record_write_mode));
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
} else {
- InstructionOperand inputs[4];
- size_t input_count = 0;
-
InstructionCode opcode = kArchNop;
switch (rep) {
case MachineRepresentation::kFloat32:
@@ -463,6 +483,8 @@
case MachineRepresentation::kWord16:
opcode = kArmStrh;
break;
+ case MachineRepresentation::kTaggedSigned: // Fall through.
+ case MachineRepresentation::kTaggedPointer: // Fall through.
case MachineRepresentation::kTagged: // Fall through.
case MachineRepresentation::kWord32:
opcode = kArmStr;
@@ -474,26 +496,129 @@
return;
}
- inputs[0] = g.UseRegister(value);
- inputs[1] = g.UseRegister(base);
-
- if (g.CanBeImmediate(index, opcode)) {
- input_count = 3;
- inputs[2] = g.UseImmediate(index);
- opcode |= AddressingModeField::encode(kMode_Offset_RI);
- } else if ((opcode == kArmStr) &&
- TryMatchLSLImmediate(this, &opcode, index, &inputs[2],
- &inputs[3])) {
- input_count = 4;
- } else {
- input_count = 3;
- inputs[2] = g.UseRegister(index);
- opcode |= AddressingModeField::encode(kMode_Offset_RR);
- }
- Emit(opcode, 0, nullptr, input_count, inputs);
+ InstructionOperand inputs[4];
+ size_t input_count = 0;
+ inputs[input_count++] = g.UseRegister(value);
+ inputs[input_count++] = g.UseRegister(base);
+ EmitStore(this, opcode, input_count, inputs, index);
}
}
+void InstructionSelector::VisitUnalignedLoad(Node* node) {
+ UnalignedLoadRepresentation load_rep =
+ UnalignedLoadRepresentationOf(node->op());
+ ArmOperandGenerator g(this);
+ Node* base = node->InputAt(0);
+ Node* index = node->InputAt(1);
+
+ InstructionCode opcode = kArmLdr;
+ // Only floating point loads need to be specially handled; integer loads
+ // support unaligned access. We support unaligned FP loads by loading to
+ // integer registers first, then moving to the destination FP register.
+ switch (load_rep.representation()) {
+ case MachineRepresentation::kFloat32: {
+ InstructionOperand temp = g.TempRegister();
+ EmitLoad(this, opcode, &temp, base, index);
+ Emit(kArmVmovF32U32, g.DefineAsRegister(node), temp);
+ return;
+ }
+ case MachineRepresentation::kFloat64: {
+ // TODO(arm): use vld1.8 for this when NEON is available.
+ // Compute the address of the least-significant half of the FP value.
+ // We assume that the base node is unlikely to be an encodable immediate
+ // or the result of a shift operation, so only consider the addressing
+ // mode that should be used for the index node.
+ InstructionCode add_opcode = kArmAdd;
+ InstructionOperand inputs[3];
+ inputs[0] = g.UseRegister(base);
+
+ size_t input_count;
+ if (TryMatchImmediateOrShift(this, &add_opcode, index, &input_count,
+ &inputs[1])) {
+ // input_count has been set by TryMatchImmediateOrShift(), so increment
+ // it to account for the base register in inputs[0].
+ input_count++;
+ } else {
+ add_opcode |= AddressingModeField::encode(kMode_Operand2_R);
+ inputs[1] = g.UseRegister(index);
+ input_count = 2; // Base register and index.
+ }
+
+ InstructionOperand addr = g.TempRegister();
+ Emit(add_opcode, 1, &addr, input_count, inputs);
+
+ // Load both halves and move to an FP register.
+ InstructionOperand fp_lo = g.TempRegister();
+ InstructionOperand fp_hi = g.TempRegister();
+ opcode |= AddressingModeField::encode(kMode_Offset_RI);
+ Emit(opcode, fp_lo, addr, g.TempImmediate(0));
+ Emit(opcode, fp_hi, addr, g.TempImmediate(4));
+ Emit(kArmVmovF64U32U32, g.DefineAsRegister(node), fp_lo, fp_hi);
+ return;
+ }
+ default:
+ // All other cases should support unaligned accesses.
+ UNREACHABLE();
+ return;
+ }
+}
+
+void InstructionSelector::VisitUnalignedStore(Node* node) {
+ ArmOperandGenerator g(this);
+ Node* base = node->InputAt(0);
+ Node* index = node->InputAt(1);
+ Node* value = node->InputAt(2);
+
+ InstructionOperand inputs[4];
+ size_t input_count = 0;
+
+ UnalignedStoreRepresentation store_rep =
+ UnalignedStoreRepresentationOf(node->op());
+
+ // Only floating point stores need to be specially handled; integer stores
+ // support unaligned access. We support unaligned FP stores by moving the
+ // value to integer registers first, then storing to the destination address.
+ switch (store_rep) {
+ case MachineRepresentation::kFloat32: {
+ inputs[input_count++] = g.TempRegister();
+ Emit(kArmVmovU32F32, inputs[0], g.UseRegister(value));
+ inputs[input_count++] = g.UseRegister(base);
+ EmitStore(this, kArmStr, input_count, inputs, index);
+ return;
+ }
+ case MachineRepresentation::kFloat64: {
+ // TODO(arm): use vst1.8 for this when NEON is available.
+ // Store a 64-bit floating point value using two 32-bit integer stores.
+ // Computing the store address here would require three live temporary
+ // registers (fp<63:32>, fp<31:0>, address), so compute base + 4 after
+ // storing the least-significant half of the value.
+
+ // First, move the 64-bit FP value into two temporary integer registers.
+ InstructionOperand fp[] = {g.TempRegister(), g.TempRegister()};
+ inputs[input_count++] = g.UseRegister(value);
+ Emit(kArmVmovU32U32F64, arraysize(fp), fp, input_count,
+ inputs);
+
+ // Store the least-significant half.
+ inputs[0] = fp[0]; // Low 32-bits of FP value.
+ inputs[input_count++] = g.UseRegister(base); // First store base address.
+ EmitStore(this, kArmStr, input_count, inputs, index);
+
+ // Store the most-significant half.
+ InstructionOperand base4 = g.TempRegister();
+ Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_I), base4,
+ g.UseRegister(base), g.TempImmediate(4)); // Compute base + 4.
+ inputs[0] = fp[1]; // High 32-bits of FP value.
+ inputs[1] = base4; // Second store base + 4 address.
+ EmitStore(this, kArmStr, input_count, inputs, index);
+ return;
+ }
+ default:
+ // All other cases should support unaligned accesses.
+ UNREACHABLE();
+ return;
+ }
+}
void InstructionSelector::VisitCheckedLoad(Node* node) {
CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op());
@@ -519,6 +644,8 @@
opcode = kCheckedLoadFloat64;
break;
case MachineRepresentation::kBit: // Fall through.
+ case MachineRepresentation::kTaggedSigned: // Fall through.
+ case MachineRepresentation::kTaggedPointer: // Fall through.
case MachineRepresentation::kTagged: // Fall through.
case MachineRepresentation::kWord64: // Fall through.
case MachineRepresentation::kSimd128: // Fall through.
@@ -561,6 +688,8 @@
opcode = kCheckedStoreFloat64;
break;
case MachineRepresentation::kBit: // Fall through.
+ case MachineRepresentation::kTaggedSigned: // Fall through.
+ case MachineRepresentation::kTaggedPointer: // Fall through.
case MachineRepresentation::kTagged: // Fall through.
case MachineRepresentation::kWord64: // Fall through.
case MachineRepresentation::kSimd128: // Fall through.
@@ -758,7 +887,7 @@
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
- cont->frame_state());
+ cont->reason(), cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
@@ -961,6 +1090,9 @@
VisitRR(this, kArmRbit, node);
}
+void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); }
+
+void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
@@ -1093,6 +1225,38 @@
VisitBinop(this, node, kArmSub, kArmRsb);
}
+namespace {
+
+void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ ArmOperandGenerator g(selector);
+ Int32BinopMatcher m(node);
+ InstructionOperand result_operand = g.DefineAsRegister(node);
+ InstructionOperand temp_operand = g.TempRegister();
+ InstructionOperand outputs[] = {result_operand, temp_operand};
+ InstructionOperand inputs[] = {g.UseRegister(m.left().node()),
+ g.UseRegister(m.right().node())};
+ selector->Emit(kArmSmull, 2, outputs, 2, inputs);
+
+ // result operand needs shift operator.
+ InstructionOperand shift_31 = g.UseImmediate(31);
+ InstructionCode opcode = cont->Encode(kArmCmp) |
+ AddressingModeField::encode(kMode_Operand2_R_ASR_I);
+ if (cont->IsBranch()) {
+ selector->Emit(opcode, g.NoOutput(), temp_operand, result_operand, shift_31,
+ g.Label(cont->true_block()), g.Label(cont->false_block()));
+ } else if (cont->IsDeoptimize()) {
+ InstructionOperand in[] = {temp_operand, result_operand, shift_31};
+ selector->EmitDeoptimize(opcode, 0, nullptr, 3, in, cont->reason(),
+ cont->frame_state());
+ } else {
+ DCHECK(cont->IsSet());
+ selector->Emit(opcode, g.DefineAsRegister(cont->result()), temp_operand,
+ result_operand, shift_31);
+ }
+}
+
+} // namespace
void InstructionSelector::VisitInt32Mul(Node* node) {
ArmOperandGenerator g(this);
@@ -1260,76 +1424,30 @@
VisitRRR(this, kArmVaddF64, node);
}
-namespace {
-void VisitFloat32SubHelper(InstructionSelector* selector, Node* node) {
- ArmOperandGenerator g(selector);
- Float32BinopMatcher m(node);
- if (m.right().IsFloat32Mul() && selector->CanCover(node, m.right().node())) {
- Float32BinopMatcher mright(m.right().node());
- selector->Emit(kArmVmlsF32, g.DefineSameAsFirst(node),
- g.UseRegister(m.left().node()),
- g.UseRegister(mright.left().node()),
- g.UseRegister(mright.right().node()));
- return;
- }
- VisitRRR(selector, kArmVsubF32, node);
-}
-
-void VisitFloat64SubHelper(InstructionSelector* selector, Node* node) {
- ArmOperandGenerator g(selector);
- Float64BinopMatcher m(node);
- if (m.right().IsFloat64Mul() && selector->CanCover(node, m.right().node())) {
- Float64BinopMatcher mright(m.right().node());
- selector->Emit(kArmVmlsF64, g.DefineSameAsFirst(node),
- g.UseRegister(m.left().node()),
- g.UseRegister(mright.left().node()),
- g.UseRegister(mright.right().node()));
- return;
- }
- VisitRRR(selector, kArmVsubF64, node);
-}
-} // namespace
-
void InstructionSelector::VisitFloat32Sub(Node* node) {
ArmOperandGenerator g(this);
Float32BinopMatcher m(node);
- if (m.left().IsMinusZero()) {
- Emit(kArmVnegF32, g.DefineAsRegister(node),
- g.UseRegister(m.right().node()));
+ if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
+ Float32BinopMatcher mright(m.right().node());
+ Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+ g.UseRegister(mright.left().node()),
+ g.UseRegister(mright.right().node()));
return;
}
- VisitFloat32SubHelper(this, node);
-}
-
-void InstructionSelector::VisitFloat32SubPreserveNan(Node* node) {
- VisitFloat32SubHelper(this, node);
+ VisitRRR(this, kArmVsubF32, node);
}
void InstructionSelector::VisitFloat64Sub(Node* node) {
ArmOperandGenerator g(this);
Float64BinopMatcher m(node);
- if (m.left().IsMinusZero()) {
- if (m.right().IsFloat64RoundDown() &&
- CanCover(m.node(), m.right().node())) {
- if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub &&
- CanCover(m.right().node(), m.right().InputAt(0))) {
- Float64BinopMatcher mright0(m.right().InputAt(0));
- if (mright0.left().IsMinusZero()) {
- Emit(kArmVrintpF64, g.DefineAsRegister(node),
- g.UseRegister(mright0.right().node()));
- return;
- }
- }
- }
- Emit(kArmVnegF64, g.DefineAsRegister(node),
- g.UseRegister(m.right().node()));
+ if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
+ Float64BinopMatcher mright(m.right().node());
+ Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+ g.UseRegister(mright.left().node()),
+ g.UseRegister(mright.right().node()));
return;
}
- VisitFloat64SubHelper(this, node);
-}
-
-void InstructionSelector::VisitFloat64SubPreserveNan(Node* node) {
- VisitFloat64SubHelper(this, node);
+ VisitRRR(this, kArmVsubF64, node);
}
void InstructionSelector::VisitFloat32Mul(Node* node) {
@@ -1359,12 +1477,10 @@
}
void InstructionSelector::VisitFloat32Max(Node* node) {
- DCHECK(IsSupported(ARMv8));
VisitRRR(this, kArmFloat32Max, node);
}
void InstructionSelector::VisitFloat64Max(Node* node) {
- DCHECK(IsSupported(ARMv8));
VisitRRR(this, kArmFloat64Max, node);
}
@@ -1373,12 +1489,10 @@
}
void InstructionSelector::VisitFloat32Min(Node* node) {
- DCHECK(IsSupported(ARMv8));
VisitRRR(this, kArmFloat32Min, node);
}
void InstructionSelector::VisitFloat64Min(Node* node) {
- DCHECK(IsSupported(ARMv8));
VisitRRR(this, kArmFloat64Min, node);
}
@@ -1476,7 +1590,7 @@
// Prepare for C function call.
if (descriptor->IsCFunctionCall()) {
Emit(kArchPrepareCallCFunction |
- MiscField::encode(static_cast<int>(descriptor->CParameterCount())),
+ MiscField::encode(static_cast<int>(descriptor->ParameterCount())),
0, nullptr, 0, nullptr);
// Poke any stack arguments.
@@ -1515,7 +1629,7 @@
selector->Emit(opcode, g.NoOutput(), left, right,
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
- selector->EmitDeoptimize(opcode, g.NoOutput(), left, right,
+ selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->reason(),
cont->frame_state());
} else {
DCHECK(cont->IsSet());
@@ -1561,6 +1675,101 @@
}
}
+// Check whether we can convert:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>.
+// We only generate conditions <cond'> that are a combination of the N
+// and Z flags. This avoids the need to make this function dependent on
+// the flag-setting operation.
+bool CanUseFlagSettingBinop(FlagsCondition cond) {
+ switch (cond) {
+ case kEqual:
+ case kNotEqual:
+ case kSignedLessThan:
+ case kSignedGreaterThanOrEqual:
+ case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
+ case kUnsignedGreaterThan: // x > 0 -> x != 0
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Map <cond> to <cond'> so that the following transformation is possible:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>.
+FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) {
+ DCHECK(CanUseFlagSettingBinop(cond));
+ switch (cond) {
+ case kEqual:
+ case kNotEqual:
+ return cond;
+ case kSignedLessThan:
+ return kNegative;
+ case kSignedGreaterThanOrEqual:
+ return kPositiveOrZero;
+ case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0
+ return kEqual;
+ case kUnsignedGreaterThan: // x > 0 -> x != 0
+ return kNotEqual;
+ default:
+ UNREACHABLE();
+ return cond;
+ }
+}
+
+// Check if we can perform the transformation:
+// ((a <op> b) cmp 0), b.<cond>
+// to:
+// (a <ops> b), b.<cond'>
+// where <ops> is the flag setting version of <op>, and if so,
+// updates {node}, {opcode} and {cont} accordingly.
+void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector,
+ Node** node, Node* binop,
+ InstructionCode* opcode,
+ FlagsCondition cond,
+ FlagsContinuation* cont) {
+ InstructionCode binop_opcode;
+ InstructionCode no_output_opcode;
+ switch (binop->opcode()) {
+ case IrOpcode::kInt32Add:
+ binop_opcode = kArmAdd;
+ no_output_opcode = kArmCmn;
+ break;
+ case IrOpcode::kWord32And:
+ binop_opcode = kArmAnd;
+ no_output_opcode = kArmTst;
+ break;
+ case IrOpcode::kWord32Or:
+ binop_opcode = kArmOrr;
+ no_output_opcode = kArmOrr;
+ break;
+ case IrOpcode::kWord32Xor:
+ binop_opcode = kArmEor;
+ no_output_opcode = kArmTeq;
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+ if (selector->CanCover(*node, binop)) {
+ // The comparison is the only user of {node}.
+ cont->Overwrite(MapForFlagSettingBinop(cond));
+ *opcode = no_output_opcode;
+ *node = binop;
+ } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) {
+ // We can also handle the case where the {node} and the comparison are in
+ // the same basic block, and the comparison is the only user of {node} in
+ // this basic block ({node} has users in other basic blocks).
+ cont->Overwrite(MapForFlagSettingBinop(cond));
+ *opcode = binop_opcode;
+ *node = binop;
+ }
+}
// Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node,
@@ -1569,8 +1778,10 @@
Int32BinopMatcher m(node);
InstructionOperand inputs[5];
size_t input_count = 0;
- InstructionOperand outputs[1];
+ InstructionOperand outputs[2];
size_t output_count = 0;
+ bool has_result = (opcode != kArmCmp) && (opcode != kArmCmn) &&
+ (opcode != kArmTst) && (opcode != kArmTeq);
if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
&input_count, &inputs[1])) {
@@ -1587,6 +1798,17 @@
inputs[input_count++] = g.UseRegister(m.right().node());
}
+ if (has_result) {
+ if (cont->IsDeoptimize()) {
+ // If we can deoptimize as a result of the binop, we need to make sure
+ // that the deopt inputs are not overwritten by the binop result. One way
+ // to achieve that is to declare the output register as same-as-first.
+ outputs[output_count++] = g.DefineSameAsFirst(node);
+ } else {
+ outputs[output_count++] = g.DefineAsRegister(node);
+ }
+ }
+
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
@@ -1601,7 +1823,7 @@
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
- cont->frame_state());
+ cont->reason(), cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
@@ -1610,7 +1832,32 @@
void VisitWordCompare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
- VisitWordCompare(selector, node, kArmCmp, cont);
+ InstructionCode opcode = kArmCmp;
+ Int32BinopMatcher m(node);
+
+ FlagsCondition cond = cont->condition();
+ if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32Or() ||
+ m.left().IsWord32And() || m.left().IsWord32Xor())) {
+ // Emit flag setting instructions for comparisons against zero.
+ if (CanUseFlagSettingBinop(cond)) {
+ Node* binop = m.left().node();
+ MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
+ cond, cont);
+ }
+ } else if (m.left().Is(0) &&
+ (m.right().IsInt32Add() || m.right().IsWord32Or() ||
+ m.right().IsWord32And() || m.right().IsWord32Xor())) {
+ // Same as above, but we need to commute the condition before we
+ // continue with the rest of the checks.
+ cond = CommuteFlagsCondition(cond);
+ if (CanUseFlagSettingBinop(cond)) {
+ Node* binop = m.right().node();
+ MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode,
+ cond, cont);
+ }
+ }
+
+ VisitWordCompare(selector, node, opcode, cont);
}
@@ -1681,6 +1928,13 @@
case IrOpcode::kInt32SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
+ case IrOpcode::kInt32MulWithOverflow:
+ // ARM doesn't set the overflow flag for multiplication, so we
+ // need to test on kNotEqual. Here is the code sequence used:
+ // smull resultlow, resulthigh, left, right
+ // cmp resulthigh, Operand(resultlow, ASR, 31)
+ cont->OverwriteAndNegateIfEqual(kNotEqual);
+ return EmitInt32MulWithOverflow(selector, node, cont);
default:
break;
}
@@ -1721,7 +1975,7 @@
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
- cont->frame_state());
+ cont->reason(), cont->frame_state());
} else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
@@ -1738,14 +1992,14 @@
}
void InstructionSelector::VisitDeoptimizeIf(Node* node) {
- FlagsContinuation cont =
- FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1));
+ FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
+ kNotEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
void InstructionSelector::VisitDeoptimizeUnless(Node* node) {
- FlagsContinuation cont =
- FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1));
+ FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
+ kEqual, DeoptimizeReasonOf(node->op()), node->InputAt(1));
VisitWordCompareZero(this, node, node->InputAt(0), &cont);
}
@@ -1822,7 +2076,6 @@
VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
}
-
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
@@ -1832,6 +2085,18 @@
VisitBinop(this, node, kArmSub, kArmRsb, &cont);
}
+void InstructionSelector::VisitInt32MulWithOverflow(Node* node) {
+ if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
+ // ARM doesn't set the overflow flag for multiplication, so we need to test
+ // on kNotEqual. Here is the code sequence used:
+ // smull resultlow, resulthigh, left, right
+ // cmp resulthigh, Operand(resultlow, ASR, 31)
+ FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
+ return EmitInt32MulWithOverflow(this, node, &cont);
+ }
+ FlagsContinuation cont;
+ EmitInt32MulWithOverflow(this, node, &cont);
+}
void InstructionSelector::VisitFloat32Equal(Node* node) {
FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
@@ -1990,13 +2255,7 @@
MachineOperatorBuilder::kFloat64RoundTruncate |
MachineOperatorBuilder::kFloat64RoundTiesAway |
MachineOperatorBuilder::kFloat32RoundTiesEven |
- MachineOperatorBuilder::kFloat64RoundTiesEven |
- MachineOperatorBuilder::kFloat32Min |
- MachineOperatorBuilder::kFloat32Max |
- MachineOperatorBuilder::kFloat64Min |
- MachineOperatorBuilder::kFloat64Max |
- MachineOperatorBuilder::kFloat32Neg |
- MachineOperatorBuilder::kFloat64Neg;
+ MachineOperatorBuilder::kFloat64RoundTiesEven;
}
return flags;
}
@@ -2004,8 +2263,11 @@
// static
MachineOperatorBuilder::AlignmentRequirements
InstructionSelector::AlignmentRequirements() {
+ Vector<MachineType> req_aligned = Vector<MachineType>::New(2);
+ req_aligned[0] = MachineType::Float32();
+ req_aligned[1] = MachineType::Float64();
return MachineOperatorBuilder::AlignmentRequirements::
- FullUnalignedAccessSupport();
+ SomeUnalignedAccessUnsupported(req_aligned, req_aligned);
}
} // namespace compiler
diff --git a/src/compiler/arm/unwinding-info-writer-arm.cc b/src/compiler/arm/unwinding-info-writer-arm.cc
new file mode 100644
index 0000000..a950612
--- /dev/null
+++ b/src/compiler/arm/unwinding-info-writer-arm.cc
@@ -0,0 +1,108 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/arm/unwinding-info-writer-arm.h"
+#include "src/compiler/instruction.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+void UnwindingInfoWriter::BeginInstructionBlock(int pc_offset,
+ const InstructionBlock* block) {
+ if (!enabled()) return;
+
+ block_will_exit_ = false;
+
+ DCHECK_LT(block->rpo_number().ToInt(), block_initial_states_.size());
+ const BlockInitialState* initial_state =
+ block_initial_states_[block->rpo_number().ToInt()];
+ if (initial_state) {
+ if (initial_state->saved_lr_ != saved_lr_) {
+ eh_frame_writer_.AdvanceLocation(pc_offset);
+ if (initial_state->saved_lr_) {
+ eh_frame_writer_.RecordRegisterSavedToStack(lr, kPointerSize);
+ } else {
+ eh_frame_writer_.RecordRegisterFollowsInitialRule(lr);
+ }
+ saved_lr_ = initial_state->saved_lr_;
+ }
+ } else {
+ // The entry block always lacks an explicit initial state.
+ // The exit block may lack an explicit state, if it is only reached by
+ // the block ending in a bx lr.
+ // All the other blocks must have an explicit initial state.
+ DCHECK(block->predecessors().empty() || block->successors().empty());
+ }
+}
+
+void UnwindingInfoWriter::EndInstructionBlock(const InstructionBlock* block) {
+ if (!enabled() || block_will_exit_) return;
+
+ for (const RpoNumber& successor : block->successors()) {
+ int successor_index = successor.ToInt();
+ DCHECK_LT(successor_index, block_initial_states_.size());
+ const BlockInitialState* existing_state =
+ block_initial_states_[successor_index];
+
+ // If we already had an entry for this BB, check that the values are the
+ // same we are trying to insert.
+ if (existing_state) {
+ DCHECK_EQ(existing_state->saved_lr_, saved_lr_);
+ } else {
+ block_initial_states_[successor_index] =
+ new (zone_) BlockInitialState(saved_lr_);
+ }
+ }
+}
+
+void UnwindingInfoWriter::MarkFrameConstructed(int at_pc) {
+ if (!enabled()) return;
+
+ // Regardless of the type of frame constructed, the relevant part of the
+ // layout is always the one in the diagram:
+ //
+ // | .... | higher addresses
+ // +----------+ ^
+ // | LR | | |
+ // +----------+ | |
+ // | saved FP | | |
+ // +----------+ <-- FP v
+ // | .... | stack growth
+ //
+ // The LR is pushed on the stack, and we can record this fact at the end of
+ // the construction, since the LR itself is not modified in the process.
+ eh_frame_writer_.AdvanceLocation(at_pc);
+ eh_frame_writer_.RecordRegisterSavedToStack(lr, kPointerSize);
+ saved_lr_ = true;
+}
+
+void UnwindingInfoWriter::MarkFrameDeconstructed(int at_pc) {
+ if (!enabled()) return;
+
+ // The lr is restored by the last operation in LeaveFrame().
+ eh_frame_writer_.AdvanceLocation(at_pc);
+ eh_frame_writer_.RecordRegisterFollowsInitialRule(lr);
+ saved_lr_ = false;
+}
+
+void UnwindingInfoWriter::MarkLinkRegisterOnTopOfStack(int pc_offset) {
+ if (!enabled()) return;
+
+ eh_frame_writer_.AdvanceLocation(pc_offset);
+ eh_frame_writer_.SetBaseAddressRegisterAndOffset(sp, 0);
+ eh_frame_writer_.RecordRegisterSavedToStack(lr, 0);
+}
+
+void UnwindingInfoWriter::MarkPopLinkRegisterFromTopOfStack(int pc_offset) {
+ if (!enabled()) return;
+
+ eh_frame_writer_.AdvanceLocation(pc_offset);
+ eh_frame_writer_.SetBaseAddressRegisterAndOffset(fp, 0);
+ eh_frame_writer_.RecordRegisterFollowsInitialRule(lr);
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/src/compiler/arm/unwinding-info-writer-arm.h b/src/compiler/arm/unwinding-info-writer-arm.h
new file mode 100644
index 0000000..d47ca08
--- /dev/null
+++ b/src/compiler/arm/unwinding-info-writer-arm.h
@@ -0,0 +1,72 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_ARM_UNWINDING_INFO_WRITER_H_
+#define V8_COMPILER_ARM_UNWINDING_INFO_WRITER_H_
+
+#include "src/eh-frame.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionBlock;
+
+class UnwindingInfoWriter {
+ public:
+ explicit UnwindingInfoWriter(Zone* zone)
+ : zone_(zone),
+ eh_frame_writer_(zone),
+ saved_lr_(false),
+ block_will_exit_(false),
+ block_initial_states_(zone) {
+ if (enabled()) eh_frame_writer_.Initialize();
+ }
+
+ void SetNumberOfInstructionBlocks(int number) {
+ if (enabled()) block_initial_states_.resize(number);
+ }
+
+ void BeginInstructionBlock(int pc_offset, const InstructionBlock* block);
+ void EndInstructionBlock(const InstructionBlock* block);
+
+ void MarkLinkRegisterOnTopOfStack(int pc_offset);
+ void MarkPopLinkRegisterFromTopOfStack(int pc_offset);
+
+ void MarkFrameConstructed(int at_pc);
+ void MarkFrameDeconstructed(int at_pc);
+
+ void MarkBlockWillExit() { block_will_exit_ = true; }
+
+ void Finish(int code_size) {
+ if (enabled()) eh_frame_writer_.Finish(code_size);
+ }
+
+ EhFrameWriter* eh_frame_writer() {
+ return enabled() ? &eh_frame_writer_ : nullptr;
+ }
+
+ private:
+ bool enabled() const { return FLAG_perf_prof_unwinding_info; }
+
+ class BlockInitialState : public ZoneObject {
+ public:
+ explicit BlockInitialState(bool saved_lr) : saved_lr_(saved_lr) {}
+
+ bool saved_lr_;
+ };
+
+ Zone* zone_;
+ EhFrameWriter eh_frame_writer_;
+ bool saved_lr_;
+ bool block_will_exit_;
+
+ ZoneVector<const BlockInitialState*> block_initial_states_;
+};
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif