Commit d18bfa11 authored by Benedikt Meurer's avatar Benedikt Meurer

[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}
parent 82a28adf
...@@ -730,6 +730,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -730,6 +730,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kCheckedStoreFloat64: case kCheckedStoreFloat64:
ASSEMBLE_CHECKED_STORE_FLOAT(movsd); ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
break; break;
case kIA32StackCheck: {
ExternalReference const stack_limit =
ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
break;
}
} }
} }
......
...@@ -66,7 +66,8 @@ namespace compiler { ...@@ -66,7 +66,8 @@ namespace compiler {
V(IA32Movsd) \ V(IA32Movsd) \
V(IA32Lea) \ V(IA32Lea) \
V(IA32Push) \ V(IA32Push) \
V(IA32StoreWriteBarrier) V(IA32StoreWriteBarrier) \
V(IA32StackCheck)
// Addressing modes represent the "shape" of inputs to an instruction. // Addressing modes represent the "shape" of inputs to an instruction.
......
...@@ -841,6 +841,26 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -841,6 +841,26 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
IA32OperandGenerator g(selector);
Int32BinopMatcher m(node);
if (m.left().IsLoad() && m.right().IsLoadStackPointer()) {
LoadMatcher<ExternalReferenceMatcher> 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); VisitWordCompare(selector, node, kIA32Cmp, cont);
} }
......
...@@ -129,6 +129,8 @@ class InstructionSelector FINAL { ...@@ -129,6 +129,8 @@ class InstructionSelector FINAL {
int GetVirtualRegister(const Node* node); int GetVirtualRegister(const Node* node);
const std::map<NodeId, int> GetVirtualRegistersForTesting() const; const std::map<NodeId, int> GetVirtualRegistersForTesting() const;
Isolate* isolate() const { return sequence()->isolate(); }
private: private:
friend class OperandGenerator; friend class OperandGenerator;
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <cmath> #include <cmath>
// TODO(turbofan): Move ExternalReference out of assembler.h
#include "src/assembler.h"
#include "src/compiler/node.h" #include "src/compiler/node.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/unique.h" #include "src/unique.h"
...@@ -155,6 +157,32 @@ struct HeapObjectMatcher FINAL ...@@ -155,6 +157,32 @@ struct HeapObjectMatcher FINAL
}; };
// A pattern matcher for external reference constants.
struct ExternalReferenceMatcher FINAL
: public ValueMatcher<ExternalReference, IrOpcode::kExternalConstant> {
explicit ExternalReferenceMatcher(Node* node)
: ValueMatcher<ExternalReference, IrOpcode::kExternalConstant>(node) {}
};
// For shorter pattern matching code, this struct matches the inputs to
// machine-level load operations.
template <typename Object>
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 // 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 // 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. // if they appear on the left hand side of a commutative operation.
......
...@@ -90,6 +90,9 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -90,6 +90,9 @@ class RawMachineAssembler : public GraphBuilder {
Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object); Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
return NewNode(common()->HeapConstant(val)); return NewNode(common()->HeapConstant(val));
} }
Node* ExternalConstant(ExternalReference address) {
return NewNode(common()->ExternalConstant(address));
}
Node* Projection(int index, Node* a) { Node* Projection(int index, Node* a) {
return NewNode(common()->Projection(index), a); return NewNode(common()->Projection(index), a);
...@@ -97,14 +100,14 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -97,14 +100,14 @@ class RawMachineAssembler : public GraphBuilder {
// Memory Operations. // Memory Operations.
Node* Load(MachineType rep, Node* base) { 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) { Node* Load(MachineType rep, Node* base, Node* index) {
return NewNode(machine()->Load(rep), base, index, graph()->start(), return NewNode(machine()->Load(rep), base, index, graph()->start(),
graph()->start()); graph()->start());
} }
void Store(MachineType rep, Node* base, Node* value) { 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) { void Store(MachineType rep, Node* base, Node* index, Node* value) {
NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base, NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base,
...@@ -281,6 +284,9 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -281,6 +284,9 @@ class RawMachineAssembler : public GraphBuilder {
Node* Int64LessThan(Node* a, Node* b) { Node* Int64LessThan(Node* a, Node* b) {
return NewNode(machine()->Int64LessThan(), a, 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) { Node* Int64LessThanOrEqual(Node* a, Node* b) {
return NewNode(machine()->Int64LessThanOrEqual(), a, b); return NewNode(machine()->Int64LessThanOrEqual(), a, b);
} }
...@@ -407,6 +413,9 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -407,6 +413,9 @@ class RawMachineAssembler : public GraphBuilder {
return NewNode(machine()->Float64InsertHighWord32(), a, b); return NewNode(machine()->Float64InsertHighWord32(), a, b);
} }
// Stack operations.
Node* LoadStackPointer() { return NewNode(machine()->LoadStackPointer()); }
// Parameters. // Parameters.
Node* Parameter(size_t index); Node* Parameter(size_t index);
......
...@@ -1051,6 +1051,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -1051,6 +1051,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kCheckedStoreFloat64: case kCheckedStoreFloat64:
ASSEMBLE_CHECKED_STORE_FLOAT(movsd); ASSEMBLE_CHECKED_STORE_FLOAT(movsd);
break; break;
case kX64StackCheck:
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
break;
} }
} // NOLINT(readability/fn_size) } // NOLINT(readability/fn_size)
......
...@@ -87,7 +87,8 @@ namespace compiler { ...@@ -87,7 +87,8 @@ namespace compiler {
V(X64Dec32) \ V(X64Dec32) \
V(X64Inc32) \ V(X64Inc32) \
V(X64Push) \ V(X64Push) \
V(X64StoreWriteBarrier) V(X64StoreWriteBarrier) \
V(X64StackCheck)
// Addressing modes represent the "shape" of inputs to an instruction. // Addressing modes represent the "shape" of inputs to an instruction.
......
...@@ -987,10 +987,12 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { ...@@ -987,10 +987,12 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
} }
namespace {
// Shared routine for multiple compare operations. // Shared routine for multiple compare operations.
static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right, InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) { FlagsContinuation* cont) {
X64OperandGenerator g(selector); X64OperandGenerator g(selector);
opcode = cont->Encode(opcode); opcode = cont->Encode(opcode);
if (cont->IsBranch()) { if (cont->IsBranch()) {
...@@ -1005,9 +1007,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -1005,9 +1007,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
// Shared routine for multiple compare operations. // Shared routine for multiple compare operations.
static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
Node* left, Node* right, FlagsContinuation* cont, Node* left, Node* right, FlagsContinuation* cont,
bool commutative) { bool commutative) {
X64OperandGenerator g(selector); X64OperandGenerator g(selector);
if (commutative && g.CanBeBetterLeftOperand(right)) { if (commutative && g.CanBeBetterLeftOperand(right)) {
std::swap(left, right); std::swap(left, right);
...@@ -1017,8 +1019,8 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -1017,8 +1019,8 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
// Shared routine for multiple word compare operations. // Shared routine for multiple word compare operations.
static void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) { InstructionCode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector); X64OperandGenerator g(selector);
Node* const left = node->InputAt(0); Node* const left = node->InputAt(0);
Node* const right = node->InputAt(1); Node* const right = node->InputAt(1);
...@@ -1036,22 +1038,51 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -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<ExternalReferenceMatcher> 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. // Shared routine for comparison with zero.
static void VisitCompareZero(InstructionSelector* selector, Node* node, void VisitCompareZero(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) { InstructionCode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector); X64OperandGenerator g(selector);
VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont); VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(0), cont);
} }
// Shared routine for multiple float64 compare operations (inputs commuted). // Shared routine for multiple float64 compare operations (inputs commuted).
static void VisitFloat64Compare(InstructionSelector* selector, Node* node, void VisitFloat64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
Node* const left = node->InputAt(0); Node* const left = node->InputAt(0);
Node* const right = node->InputAt(1); Node* const right = node->InputAt(1);
VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false); VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
} }
} // namespace
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) { BasicBlock* fbranch) {
...@@ -1093,16 +1124,16 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1093,16 +1124,16 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
return VisitWordCompare(this, value, kX64Cmp32, &cont); return VisitWordCompare(this, value, kX64Cmp32, &cont);
case IrOpcode::kWord64Equal: case IrOpcode::kWord64Equal:
cont.OverwriteAndNegateIfEqual(kEqual); cont.OverwriteAndNegateIfEqual(kEqual);
return VisitWordCompare(this, value, kX64Cmp, &cont); return VisitWord64Compare(this, value, &cont);
case IrOpcode::kInt64LessThan: case IrOpcode::kInt64LessThan:
cont.OverwriteAndNegateIfEqual(kSignedLessThan); cont.OverwriteAndNegateIfEqual(kSignedLessThan);
return VisitWordCompare(this, value, kX64Cmp, &cont); return VisitWord64Compare(this, value, &cont);
case IrOpcode::kInt64LessThanOrEqual: case IrOpcode::kInt64LessThanOrEqual:
cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
return VisitWordCompare(this, value, kX64Cmp, &cont); return VisitWord64Compare(this, value, &cont);
case IrOpcode::kUint64LessThan: case IrOpcode::kUint64LessThan:
cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
return VisitWordCompare(this, value, kX64Cmp, &cont); return VisitWord64Compare(this, value, &cont);
case IrOpcode::kFloat64Equal: case IrOpcode::kFloat64Equal:
cont.OverwriteAndNegateIfEqual(kUnorderedEqual); cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
return VisitFloat64Compare(this, value, &cont); return VisitFloat64Compare(this, value, &cont);
...@@ -1140,7 +1171,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1140,7 +1171,7 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
case IrOpcode::kInt32Sub: case IrOpcode::kInt32Sub:
return VisitWordCompare(this, value, kX64Cmp32, &cont); return VisitWordCompare(this, value, kX64Cmp32, &cont);
case IrOpcode::kInt64Sub: case IrOpcode::kInt64Sub:
return VisitWordCompare(this, value, kX64Cmp, &cont); return VisitWord64Compare(this, value, &cont);
case IrOpcode::kWord32And: case IrOpcode::kWord32And:
return VisitWordCompare(this, value, kX64Test32, &cont); return VisitWordCompare(this, value, kX64Test32, &cont);
case IrOpcode::kWord64And: case IrOpcode::kWord64And:
...@@ -1302,7 +1333,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) { ...@@ -1302,7 +1333,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
if (CanCover(user, value)) { if (CanCover(user, value)) {
switch (value->opcode()) { switch (value->opcode()) {
case IrOpcode::kInt64Sub: case IrOpcode::kInt64Sub:
return VisitWordCompare(this, value, kX64Cmp, &cont); return VisitWord64Compare(this, value, &cont);
case IrOpcode::kWord64And: case IrOpcode::kWord64And:
return VisitWordCompare(this, value, kX64Test, &cont); return VisitWordCompare(this, value, kX64Test, &cont);
default: default:
...@@ -1311,7 +1342,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) { ...@@ -1311,7 +1342,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
} }
return VisitCompareZero(this, value, kX64Cmp, &cont); return VisitCompareZero(this, value, kX64Cmp, &cont);
} }
VisitWordCompare(this, node, kX64Cmp, &cont); VisitWord64Compare(this, node, &cont);
} }
...@@ -1337,19 +1368,19 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { ...@@ -1337,19 +1368,19 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
void InstructionSelector::VisitInt64LessThan(Node* node) { void InstructionSelector::VisitInt64LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node); FlagsContinuation cont(kSignedLessThan, node);
VisitWordCompare(this, node, kX64Cmp, &cont); VisitWord64Compare(this, node, &cont);
} }
void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node); FlagsContinuation cont(kSignedLessThanOrEqual, node);
VisitWordCompare(this, node, kX64Cmp, &cont); VisitWord64Compare(this, node, &cont);
} }
void InstructionSelector::VisitUint64LessThan(Node* node) { void InstructionSelector::VisitUint64LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node); FlagsContinuation cont(kUnsignedLessThan, node);
VisitWordCompare(this, node, kX64Cmp, &cont); VisitWord64Compare(this, node, &cont);
} }
......
...@@ -666,6 +666,29 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { ...@@ -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 compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -1030,6 +1030,25 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { ...@@ -1030,6 +1030,25 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
// Miscellaneous. // 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) { TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
TRACED_FORRANGE(int64_t, x, 32, 63) { TRACED_FORRANGE(int64_t, x, 32, 63) {
StreamBuilder m(this, kMachInt64, kMachInt32); StreamBuilder m(this, kMachInt64, kMachInt32);
......
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