From: Benedikt Meurer Date: Mon, 9 Mar 2015 11:06:30 +0000 (+0100) Subject: [x86] Faster/shorter code for stack checks. X-Git-Tag: upstream/4.7.83~3975 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d18bfa11308ec056ca5a4ad1a7bb63fa519e37b9;p=platform%2Fupstream%2Fv8.git [x86] Faster/shorter code for stack checks. Avoid loading the stack pointer and the stack limit into allocatable registers first, but generate a cmp rsp,[limit] instead. R=dcarney@chromium.org Review URL: https://codereview.chromium.org/989203002 Cr-Commit-Position: refs/heads/master@{#27065} --- diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index fcea57f93..3f452e8cb 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -730,6 +730,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kCheckedStoreFloat64: ASSEMBLE_CHECKED_STORE_FLOAT(movsd); break; + case kIA32StackCheck: { + ExternalReference const stack_limit = + ExternalReference::address_of_stack_limit(isolate()); + __ cmp(esp, Operand::StaticVariable(stack_limit)); + break; + } } } diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h index b5a5225ad..355e49832 100644 --- a/src/compiler/ia32/instruction-codes-ia32.h +++ b/src/compiler/ia32/instruction-codes-ia32.h @@ -66,7 +66,8 @@ namespace compiler { V(IA32Movsd) \ V(IA32Lea) \ V(IA32Push) \ - V(IA32StoreWriteBarrier) + V(IA32StoreWriteBarrier) \ + V(IA32StackCheck) // Addressing modes represent the "shape" of inputs to an instruction. diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index 54184302c..5797becfc 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -841,6 +841,26 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node, FlagsContinuation* cont) { + IA32OperandGenerator g(selector); + Int32BinopMatcher m(node); + if (m.left().IsLoad() && m.right().IsLoadStackPointer()) { + LoadMatcher mleft(m.left().node()); + ExternalReference js_stack_limit = + ExternalReference::address_of_stack_limit(selector->isolate()); + if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) { + // Compare(Load(js_stack_limit), LoadStackPointer) + if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); + InstructionCode opcode = cont->Encode(kIA32StackCheck); + if (cont->IsBranch()) { + selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()), + g.Label(cont->false_block()))->MarkAsControl(); + } else { + DCHECK(cont->IsSet()); + selector->Emit(opcode, g.DefineAsRegister(cont->result())); + } + return; + } + } VisitWordCompare(selector, node, kIA32Cmp, cont); } diff --git a/src/compiler/instruction-selector.h b/src/compiler/instruction-selector.h index 59a00d52e..b6278b1f3 100644 --- a/src/compiler/instruction-selector.h +++ b/src/compiler/instruction-selector.h @@ -129,6 +129,8 @@ class InstructionSelector FINAL { int GetVirtualRegister(const Node* node); const std::map GetVirtualRegistersForTesting() const; + Isolate* isolate() const { return sequence()->isolate(); } + private: friend class OperandGenerator; diff --git a/src/compiler/node-matchers.h b/src/compiler/node-matchers.h index 1a29bb830..48ff3d732 100644 --- a/src/compiler/node-matchers.h +++ b/src/compiler/node-matchers.h @@ -7,6 +7,8 @@ #include +// TODO(turbofan): Move ExternalReference out of assembler.h +#include "src/assembler.h" #include "src/compiler/node.h" #include "src/compiler/operator.h" #include "src/unique.h" @@ -155,6 +157,32 @@ struct HeapObjectMatcher FINAL }; +// A pattern matcher for external reference constants. +struct ExternalReferenceMatcher FINAL + : public ValueMatcher { + explicit ExternalReferenceMatcher(Node* node) + : ValueMatcher(node) {} +}; + + +// For shorter pattern matching code, this struct matches the inputs to +// machine-level load operations. +template +struct LoadMatcher : public NodeMatcher { + explicit LoadMatcher(Node* node) + : NodeMatcher(node), object_(InputAt(0)), index_(InputAt(1)) {} + + typedef Object ObjectMatcher; + + Object const& object() const { return object_; } + IntPtrMatcher const& index() const { return index_; } + + private: + Object const object_; + IntPtrMatcher const index_; +}; + + // For shorter pattern matching code, this struct matches both the left and // right hand sides of a binary operation and can put constants on the right // if they appear on the left hand side of a commutative operation. diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h index 693f2fc87..b578aca73 100644 --- a/src/compiler/raw-machine-assembler.h +++ b/src/compiler/raw-machine-assembler.h @@ -90,6 +90,9 @@ class RawMachineAssembler : public GraphBuilder { Unique val = Unique::CreateUninitialized(object); return NewNode(common()->HeapConstant(val)); } + Node* ExternalConstant(ExternalReference address) { + return NewNode(common()->ExternalConstant(address)); + } Node* Projection(int index, Node* a) { return NewNode(common()->Projection(index), a); @@ -97,14 +100,14 @@ class RawMachineAssembler : public GraphBuilder { // Memory Operations. Node* Load(MachineType rep, Node* base) { - return Load(rep, base, Int32Constant(0)); + return Load(rep, base, IntPtrConstant(0)); } Node* Load(MachineType rep, Node* base, Node* index) { return NewNode(machine()->Load(rep), base, index, graph()->start(), graph()->start()); } void Store(MachineType rep, Node* base, Node* value) { - Store(rep, base, Int32Constant(0), value); + Store(rep, base, IntPtrConstant(0), value); } void Store(MachineType rep, Node* base, Node* index, Node* value) { NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base, @@ -281,6 +284,9 @@ class RawMachineAssembler : public GraphBuilder { Node* Int64LessThan(Node* a, Node* b) { return NewNode(machine()->Int64LessThan(), a, b); } + Node* Uint64LessThan(Node* a, Node* b) { + return NewNode(machine()->Uint64LessThan(), a, b); + } Node* Int64LessThanOrEqual(Node* a, Node* b) { return NewNode(machine()->Int64LessThanOrEqual(), a, b); } @@ -407,6 +413,9 @@ class RawMachineAssembler : public GraphBuilder { return NewNode(machine()->Float64InsertHighWord32(), a, b); } + // Stack operations. + Node* LoadStackPointer() { return NewNode(machine()->LoadStackPointer()); } + // Parameters. Node* Parameter(size_t index); diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index b808e4e89..f8c439faa 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -1051,6 +1051,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kCheckedStoreFloat64: ASSEMBLE_CHECKED_STORE_FLOAT(movsd); break; + case kX64StackCheck: + __ CompareRoot(rsp, Heap::kStackLimitRootIndex); + break; } } // NOLINT(readability/fn_size) diff --git a/src/compiler/x64/instruction-codes-x64.h b/src/compiler/x64/instruction-codes-x64.h index 6af32b019..e3a6b1a5c 100644 --- a/src/compiler/x64/instruction-codes-x64.h +++ b/src/compiler/x64/instruction-codes-x64.h @@ -87,7 +87,8 @@ namespace compiler { V(X64Dec32) \ V(X64Inc32) \ V(X64Push) \ - V(X64StoreWriteBarrier) + V(X64StoreWriteBarrier) \ + V(X64StackCheck) // Addressing modes represent the "shape" of inputs to an instruction. diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index b00eee16d..fa39e58eb 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -987,10 +987,12 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { } +namespace { + // Shared routine for multiple compare operations. -static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, - InstructionOperand left, InstructionOperand right, - FlagsContinuation* cont) { +void VisitCompare(InstructionSelector* selector, InstructionCode opcode, + InstructionOperand left, InstructionOperand right, + FlagsContinuation* cont) { X64OperandGenerator g(selector); opcode = cont->Encode(opcode); if (cont->IsBranch()) { @@ -1005,9 +1007,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, // Shared routine for multiple compare operations. -static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, - Node* left, Node* right, FlagsContinuation* cont, - bool commutative) { +void VisitCompare(InstructionSelector* selector, InstructionCode opcode, + Node* left, Node* right, FlagsContinuation* cont, + bool commutative) { X64OperandGenerator g(selector); if (commutative && g.CanBeBetterLeftOperand(right)) { std::swap(left, right); @@ -1017,8 +1019,8 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, // Shared routine for multiple word compare operations. -static void VisitWordCompare(InstructionSelector* selector, Node* node, - InstructionCode opcode, FlagsContinuation* cont) { +void VisitWordCompare(InstructionSelector* selector, Node* node, + InstructionCode opcode, FlagsContinuation* cont) { X64OperandGenerator g(selector); Node* const left = node->InputAt(0); Node* const right = node->InputAt(1); @@ -1036,22 +1038,51 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node, } +// Shared routine for 64-bit word comparison operations. +void VisitWord64Compare(InstructionSelector* selector, Node* node, + FlagsContinuation* cont) { + X64OperandGenerator g(selector); + Int64BinopMatcher m(node); + if (m.left().IsLoad() && m.right().IsLoadStackPointer()) { + LoadMatcher mleft(m.left().node()); + ExternalReference js_stack_limit = + ExternalReference::address_of_stack_limit(selector->isolate()); + if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) { + // Compare(Load(js_stack_limit), LoadStackPointer) + if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); + InstructionCode opcode = cont->Encode(kX64StackCheck); + if (cont->IsBranch()) { + selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()), + g.Label(cont->false_block()))->MarkAsControl(); + } else { + DCHECK(cont->IsSet()); + selector->Emit(opcode, g.DefineAsRegister(cont->result())); + } + return; + } + } + VisitWordCompare(selector, node, kX64Cmp, cont); +} + + // Shared routine for comparison with zero. -static void VisitCompareZero(InstructionSelector* selector, Node* node, - InstructionCode opcode, FlagsContinuation* cont) { +void VisitCompareZero(InstructionSelector* selector, Node* node, + InstructionCode opcode, FlagsContinuation* cont) { X64OperandGenerator g(selector); VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont); } // Shared routine for multiple float64 compare operations (inputs commuted). -static void VisitFloat64Compare(InstructionSelector* selector, Node* node, - FlagsContinuation* cont) { +void VisitFloat64Compare(InstructionSelector* selector, Node* node, + FlagsContinuation* cont) { Node* const left = node->InputAt(0); Node* const right = node->InputAt(1); VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false); } +} // namespace + void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, BasicBlock* fbranch) { @@ -1093,16 +1124,16 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, return VisitWordCompare(this, value, kX64Cmp32, &cont); case IrOpcode::kWord64Equal: cont.OverwriteAndNegateIfEqual(kEqual); - return VisitWordCompare(this, value, kX64Cmp, &cont); + return VisitWord64Compare(this, value, &cont); case IrOpcode::kInt64LessThan: cont.OverwriteAndNegateIfEqual(kSignedLessThan); - return VisitWordCompare(this, value, kX64Cmp, &cont); + return VisitWord64Compare(this, value, &cont); case IrOpcode::kInt64LessThanOrEqual: cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); - return VisitWordCompare(this, value, kX64Cmp, &cont); + return VisitWord64Compare(this, value, &cont); case IrOpcode::kUint64LessThan: cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); - return VisitWordCompare(this, value, kX64Cmp, &cont); + return VisitWord64Compare(this, value, &cont); case IrOpcode::kFloat64Equal: cont.OverwriteAndNegateIfEqual(kUnorderedEqual); return VisitFloat64Compare(this, value, &cont); @@ -1140,7 +1171,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, case IrOpcode::kInt32Sub: return VisitWordCompare(this, value, kX64Cmp32, &cont); case IrOpcode::kInt64Sub: - return VisitWordCompare(this, value, kX64Cmp, &cont); + return VisitWord64Compare(this, value, &cont); case IrOpcode::kWord32And: return VisitWordCompare(this, value, kX64Test32, &cont); case IrOpcode::kWord64And: @@ -1302,7 +1333,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) { if (CanCover(user, value)) { switch (value->opcode()) { case IrOpcode::kInt64Sub: - return VisitWordCompare(this, value, kX64Cmp, &cont); + return VisitWord64Compare(this, value, &cont); case IrOpcode::kWord64And: return VisitWordCompare(this, value, kX64Test, &cont); default: @@ -1311,7 +1342,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) { } return VisitCompareZero(this, value, kX64Cmp, &cont); } - VisitWordCompare(this, node, kX64Cmp, &cont); + VisitWord64Compare(this, node, &cont); } @@ -1337,19 +1368,19 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { void InstructionSelector::VisitInt64LessThan(Node* node) { FlagsContinuation cont(kSignedLessThan, node); - VisitWordCompare(this, node, kX64Cmp, &cont); + VisitWord64Compare(this, node, &cont); } void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { FlagsContinuation cont(kSignedLessThanOrEqual, node); - VisitWordCompare(this, node, kX64Cmp, &cont); + VisitWord64Compare(this, node, &cont); } void InstructionSelector::VisitUint64LessThan(Node* node) { FlagsContinuation cont(kUnsignedLessThan, node); - VisitWordCompare(this, node, kX64Cmp, &cont); + VisitWord64Compare(this, node, &cont); } diff --git a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc index afa1e9424..a93b3fcaf 100644 --- a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -666,6 +666,29 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { } } + +// ----------------------------------------------------------------------------- +// Miscellaneous. + + +TEST_F(InstructionSelectorTest, Uint32LessThanWithLoadAndLoadStackPointer) { + StreamBuilder m(this, kMachBool); + Node* const sl = m.Load( + kMachPtr, + m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))); + Node* const sp = m.LoadStackPointer(); + Node* const n = m.Uint32LessThan(sl, sp); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32StackCheck, s[0]->arch_opcode()); + ASSERT_EQ(0U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition()); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index 1f374c0f8..13899c5c3 100644 --- a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -1030,6 +1030,25 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { // Miscellaneous. +TEST_F(InstructionSelectorTest, Uint64LessThanWithLoadAndLoadStackPointer) { + StreamBuilder m(this, kMachBool); + Node* const sl = m.Load( + kMachPtr, + m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))); + Node* const sp = m.LoadStackPointer(); + Node* const n = m.Uint64LessThan(sl, sp); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64StackCheck, s[0]->arch_opcode()); + ASSERT_EQ(0U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition()); +} + + TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) { TRACED_FORRANGE(int64_t, x, 32, 63) { StreamBuilder m(this, kMachInt64, kMachInt32);