Commit b015229c authored by rodolph.perfetta's avatar rodolph.perfetta Committed by Commit Bot

handle WASM trap in the instruction scheduler.

Review-Url: https://codereview.chromium.org/2916143003
Cr-Commit-Position: refs/heads/master@{#45694}
parent c1862b9f
...@@ -111,8 +111,8 @@ int InstructionScheduler::GetTargetInstructionFlags( ...@@ -111,8 +111,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kIA32Idiv: case kIA32Idiv:
case kIA32Udiv: case kIA32Udiv:
return (instr->addressing_mode() == kMode_None) return (instr->addressing_mode() == kMode_None)
? kMayNeedDeoptCheck ? kMayNeedDeoptOrTrapCheck
: kMayNeedDeoptCheck | kIsLoadOperation | kHasSideEffect; : kMayNeedDeoptOrTrapCheck | kIsLoadOperation | kHasSideEffect;
case kIA32Movsxbl: case kIA32Movsxbl:
case kIA32Movzxbl: case kIA32Movzxbl:
......
...@@ -77,7 +77,6 @@ void InstructionScheduler::ScheduleGraphNode::AddSuccessor( ...@@ -77,7 +77,6 @@ void InstructionScheduler::ScheduleGraphNode::AddSuccessor(
node->unscheduled_predecessors_count_++; node->unscheduled_predecessors_count_++;
} }
InstructionScheduler::InstructionScheduler(Zone* zone, InstructionScheduler::InstructionScheduler(Zone* zone,
InstructionSequence* sequence) InstructionSequence* sequence)
: zone_(zone), : zone_(zone),
...@@ -86,16 +85,15 @@ InstructionScheduler::InstructionScheduler(Zone* zone, ...@@ -86,16 +85,15 @@ InstructionScheduler::InstructionScheduler(Zone* zone,
last_side_effect_instr_(nullptr), last_side_effect_instr_(nullptr),
pending_loads_(zone), pending_loads_(zone),
last_live_in_reg_marker_(nullptr), last_live_in_reg_marker_(nullptr),
last_deopt_(nullptr), last_deopt_or_trap_(nullptr),
operands_map_(zone) {} operands_map_(zone) {}
void InstructionScheduler::StartBlock(RpoNumber rpo) { void InstructionScheduler::StartBlock(RpoNumber rpo) {
DCHECK(graph_.empty()); DCHECK(graph_.empty());
DCHECK(last_side_effect_instr_ == nullptr); DCHECK(last_side_effect_instr_ == nullptr);
DCHECK(pending_loads_.empty()); DCHECK(pending_loads_.empty());
DCHECK(last_live_in_reg_marker_ == nullptr); DCHECK(last_live_in_reg_marker_ == nullptr);
DCHECK(last_deopt_ == nullptr); DCHECK(last_deopt_or_trap_ == nullptr);
DCHECK(operands_map_.empty()); DCHECK(operands_map_.empty());
sequence()->StartBlock(rpo); sequence()->StartBlock(rpo);
} }
...@@ -112,7 +110,7 @@ void InstructionScheduler::EndBlock(RpoNumber rpo) { ...@@ -112,7 +110,7 @@ void InstructionScheduler::EndBlock(RpoNumber rpo) {
last_side_effect_instr_ = nullptr; last_side_effect_instr_ = nullptr;
pending_loads_.clear(); pending_loads_.clear();
last_live_in_reg_marker_ = nullptr; last_live_in_reg_marker_ = nullptr;
last_deopt_ = nullptr; last_deopt_or_trap_ = nullptr;
operands_map_.clear(); operands_map_.clear();
} }
...@@ -137,9 +135,9 @@ void InstructionScheduler::AddInstruction(Instruction* instr) { ...@@ -137,9 +135,9 @@ void InstructionScheduler::AddInstruction(Instruction* instr) {
} }
// Make sure that instructions are not scheduled before the last // Make sure that instructions are not scheduled before the last
// deoptimization point when they depend on it. // deoptimization or trap point when they depend on it.
if ((last_deopt_ != nullptr) && DependsOnDeoptimization(instr)) { if ((last_deopt_or_trap_ != nullptr) && DependsOnDeoptOrTrap(instr)) {
last_deopt_->AddSuccessor(new_node); last_deopt_or_trap_->AddSuccessor(new_node);
} }
// Instructions with side effects and memory operations can't be // Instructions with side effects and memory operations can't be
...@@ -160,13 +158,13 @@ void InstructionScheduler::AddInstruction(Instruction* instr) { ...@@ -160,13 +158,13 @@ void InstructionScheduler::AddInstruction(Instruction* instr) {
last_side_effect_instr_->AddSuccessor(new_node); last_side_effect_instr_->AddSuccessor(new_node);
} }
pending_loads_.push_back(new_node); pending_loads_.push_back(new_node);
} else if (instr->IsDeoptimizeCall()) { } else if (instr->IsDeoptimizeCall() || instr->IsTrap()) {
// Ensure that deopts are not reordered with respect to side-effect // Ensure that deopts or traps are not reordered with respect to
// instructions. // side-effect instructions.
if (last_side_effect_instr_ != nullptr) { if (last_side_effect_instr_ != nullptr) {
last_side_effect_instr_->AddSuccessor(new_node); last_side_effect_instr_->AddSuccessor(new_node);
} }
last_deopt_ = new_node; last_deopt_or_trap_ = new_node;
} }
// Look for operand dependencies. // Look for operand dependencies.
......
...@@ -21,10 +21,11 @@ enum ArchOpcodeFlags { ...@@ -21,10 +21,11 @@ enum ArchOpcodeFlags {
kHasSideEffect = 2, // The instruction has some side effects (memory kHasSideEffect = 2, // The instruction has some side effects (memory
// store, function call...) // store, function call...)
kIsLoadOperation = 4, // The instruction is a memory load. kIsLoadOperation = 4, // The instruction is a memory load.
kMayNeedDeoptCheck = 8, // The instruction might be associated with a deopt kMayNeedDeoptOrTrapCheck = 8, // The instruction may be associated with a
// check. This is the case of instruction which can // deopt or trap check which must be run before
// blow up with particular inputs (e.g.: division by // instruction e.g. div on Intel platform which
// zero on Intel platforms). // will raise an exception when the divisor is
// zero.
}; };
class InstructionScheduler final : public ZoneObject { class InstructionScheduler final : public ZoneObject {
...@@ -166,17 +167,22 @@ class InstructionScheduler final : public ZoneObject { ...@@ -166,17 +167,22 @@ class InstructionScheduler final : public ZoneObject {
return (GetInstructionFlags(instr) & kIsLoadOperation) != 0; return (GetInstructionFlags(instr) & kIsLoadOperation) != 0;
} }
// Return true if this instruction is usually associated with a deopt check // The scheduler will not move the following instructions before the last
// to validate its input. // deopt/trap check:
bool MayNeedDeoptCheck(const Instruction* instr) const { // * loads (this is conservative)
return (GetInstructionFlags(instr) & kMayNeedDeoptCheck) != 0; // * instructions with side effect
// * other deopts/traps
// Any other instruction can be moved, apart from those that raise exceptions
// on specific inputs - these are filtered out by the deopt/trap check.
bool MayNeedDeoptOrTrapCheck(const Instruction* instr) const {
return (GetInstructionFlags(instr) & kMayNeedDeoptOrTrapCheck) != 0;
} }
// Return true if the instruction cannot be moved before the last deopt // Return true if the instruction cannot be moved before the last deopt or
// point we encountered. // trap point we encountered.
bool DependsOnDeoptimization(const Instruction* instr) const { bool DependsOnDeoptOrTrap(const Instruction* instr) const {
return MayNeedDeoptCheck(instr) || instr->IsDeoptimizeCall() || return MayNeedDeoptOrTrapCheck(instr) || instr->IsDeoptimizeCall() ||
HasSideEffect(instr) || IsLoadOperation(instr); instr->IsTrap() || HasSideEffect(instr) || IsLoadOperation(instr);
} }
// Identify nops used as a definition point for live-in registers at // Identify nops used as a definition point for live-in registers at
...@@ -217,8 +223,9 @@ class InstructionScheduler final : public ZoneObject { ...@@ -217,8 +223,9 @@ class InstructionScheduler final : public ZoneObject {
// other instructions in the basic block. // other instructions in the basic block.
ScheduleGraphNode* last_live_in_reg_marker_; ScheduleGraphNode* last_live_in_reg_marker_;
// Last deoptimization instruction encountered while building the graph. // Last deoptimization or trap instruction encountered while building the
ScheduleGraphNode* last_deopt_; // graph.
ScheduleGraphNode* last_deopt_or_trap_;
// Keep track of definition points for virtual registers. This is used to // Keep track of definition points for virtual registers. This is used to
// record operand dependencies in the scheduling graph. // record operand dependencies in the scheduling graph.
......
...@@ -897,6 +897,10 @@ class V8_EXPORT_PRIVATE Instruction final { ...@@ -897,6 +897,10 @@ class V8_EXPORT_PRIVATE Instruction final {
FlagsModeField::decode(opcode()) == kFlags_deoptimize; FlagsModeField::decode(opcode()) == kFlags_deoptimize;
} }
bool IsTrap() const {
return FlagsModeField::decode(opcode()) == kFlags_trap;
}
bool IsJump() const { return arch_opcode() == ArchOpcode::kArchJmp; } bool IsJump() const { return arch_opcode() == ArchOpcode::kArchJmp; }
bool IsRet() const { return arch_opcode() == ArchOpcode::kArchRet; } bool IsRet() const { return arch_opcode() == ArchOpcode::kArchRet; }
bool IsTailCall() const { bool IsTailCall() const {
......
...@@ -189,8 +189,8 @@ int InstructionScheduler::GetTargetInstructionFlags( ...@@ -189,8 +189,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64Udiv: case kX64Udiv:
case kX64Udiv32: case kX64Udiv32:
return (instr->addressing_mode() == kMode_None) return (instr->addressing_mode() == kMode_None)
? kMayNeedDeoptCheck ? kMayNeedDeoptOrTrapCheck
: kMayNeedDeoptCheck | kIsLoadOperation | kHasSideEffect; : kMayNeedDeoptOrTrapCheck | kIsLoadOperation | kHasSideEffect;
case kX64Movsxbl: case kX64Movsxbl:
case kX64Movzxbl: case kX64Movzxbl:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment