[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}
This commit is contained in:
parent
82a28adf05
commit
d18bfa1130
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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<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);
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,8 @@ class InstructionSelector FINAL {
|
||||
int GetVirtualRegister(const Node* node);
|
||||
const std::map<NodeId, int> GetVirtualRegistersForTesting() const;
|
||||
|
||||
Isolate* isolate() const { return sequence()->isolate(); }
|
||||
|
||||
private:
|
||||
friend class OperandGenerator;
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
// 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<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
|
||||
// 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.
|
||||
|
@ -90,6 +90,9 @@ class RawMachineAssembler : public GraphBuilder {
|
||||
Unique<HeapObject> val = Unique<HeapObject>::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);
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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<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.
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user