Commit ab9ac994 authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[TurboFan] Use the FlagsContinuation more effectively

We can reduce boilerplate if we pass the continuation to
some InstructionSelector::Emit.* methods.

Change-Id: I0221f446129cc086122d3f77a00de7d1256d3ee1
bug: v8:7310
Reviewed-on: https://chromium-review.googlesource.com/934454
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51847}
parent dc247d4b
......@@ -248,9 +248,9 @@ void VisitBinop(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand inputs[5];
InstructionOperand inputs[3];
size_t input_count = 0;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
if (m.left().node() == m.right().node()) {
......@@ -281,33 +281,16 @@ void VisitBinop(InstructionSelector* selector, Node* node,
inputs[input_count++] = g.UseRegister(m.right().node());
}
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
}
outputs[output_count++] = g.DefineAsRegister(node);
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_NE(0u, output_count);
DCHECK_EQ(1u, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.UseImmediate(cont->trap_id());
selector->Emit(opcode, output_count, outputs, input_count, inputs);
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
......@@ -889,22 +872,14 @@ void VisitShift(InstructionSelector* selector, Node* node,
TryMatchShift try_match_shift, FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
InstructionCode opcode = kArmMov;
InstructionOperand inputs[4];
InstructionOperand inputs[2];
size_t input_count = 2;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
CHECK(try_match_shift(selector, &opcode, node, &inputs[0], &inputs[1]));
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
}
outputs[output_count++] = g.DefineAsRegister(node);
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_NE(0u, output_count);
......@@ -912,17 +887,8 @@ void VisitShift(InstructionSelector* selector, Node* node,
DCHECK_GE(arraysize(outputs), output_count);
DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.UseImmediate(cont->trap_id());
selector->Emit(opcode, output_count, outputs, input_count, inputs);
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
......@@ -1279,25 +1245,10 @@ void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
// 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->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), temp_operand,
result_operand, shift_31);
} else {
DCHECK(cont->IsTrap());
InstructionOperand in[] = {temp_operand, result_operand, shift_31,
g.UseImmediate(cont->trap_id())};
selector->Emit(opcode, 0, nullptr, 4, in);
}
InstructionCode opcode =
kArmCmp | AddressingModeField::encode(kMode_Operand2_R_ASR_I);
selector->EmitWithContinuation(opcode, temp_operand, result_operand, shift_31,
cont);
}
} // namespace
......@@ -1578,22 +1529,7 @@ namespace {
void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
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, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), left, right,
g.UseImmediate(cont->trap_id()));
}
selector->EmitWithContinuation(opcode, left, right, cont);
}
......@@ -1734,7 +1670,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand inputs[5];
InstructionOperand inputs[3];
size_t input_count = 0;
InstructionOperand outputs[2];
size_t output_count = 0;
......@@ -1767,28 +1703,12 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
}
}
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
} else if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.UseImmediate(cont->trap_id());
selector->Emit(opcode, output_count, outputs, input_count, inputs);
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
......@@ -1934,23 +1854,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
// Continuation could not be combined with a compare, emit compare against 0.
ArmOperandGenerator g(this);
InstructionCode const opcode =
cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
kArmTst | AddressingModeField::encode(kMode_Operand2_R);
InstructionOperand const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
Emit(opcode, g.NoOutput(), value_operand, value_operand,
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
EmitDeoptimize(opcode, g.NoOutput(), value_operand, value_operand,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
value_operand);
} else {
DCHECK(cont->IsTrap());
Emit(opcode, g.NoOutput(), value_operand, value_operand,
g.UseImmediate(cont->trap_id()));
}
EmitWithContinuation(opcode, value_operand, value_operand, cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
......
......@@ -416,9 +416,9 @@ void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode, ImmediateMode operand_mode,
FlagsContinuation* cont) {
Arm64OperandGenerator g(selector);
InstructionOperand inputs[5];
InstructionOperand inputs[3];
size_t input_count = 0;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
Node* left_node = node->InputAt(0);
......@@ -467,35 +467,17 @@ void VisitBinop(InstructionSelector* selector, Node* node,
inputs[input_count++] = g.UseRegister(right_node);
}
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
}
if (!IsComparisonField::decode(properties)) {
outputs[output_count++] = g.DefineAsRegister(node);
}
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK((output_count != 0) || IsComparisonField::decode(properties));
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.UseImmediate(cont->trap_id());
selector->Emit(opcode, output_count, outputs, input_count, inputs);
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
......@@ -1386,23 +1368,9 @@ void EmitInt32MulWithOverflow(InstructionSelector* selector, Node* node,
InstructionOperand right = g.UseRegister(m.right().node());
selector->Emit(kArm64Smull, result, left, right);
InstructionCode opcode = cont->Encode(kArm64Cmp) |
AddressingModeField::encode(kMode_Operand2_R_SXTW);
if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), result, result,
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
InstructionOperand in[] = {result, result};
selector->EmitDeoptimize(opcode, 0, nullptr, 2, in, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), result, result);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), result, result,
g.UseImmediate(cont->trap_id()));
}
InstructionCode opcode =
kArm64Cmp | AddressingModeField::encode(kMode_Operand2_R_SXTW);
selector->EmitWithContinuation(opcode, result, result, cont);
}
} // namespace
......@@ -1767,22 +1735,7 @@ namespace {
void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) {
Arm64OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
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, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), left, right,
g.UseImmediate(cont->trap_id()));
}
selector->EmitWithContinuation(opcode, left, right, cont);
}
......@@ -1936,16 +1889,8 @@ FlagsCondition MapForCbz(FlagsCondition cond) {
void EmitBranchOrDeoptimize(InstructionSelector* selector,
InstructionCode opcode, InstructionOperand value,
FlagsContinuation* cont) {
Arm64OperandGenerator g(selector);
if (cont->IsBranch()) {
selector->Emit(cont->Encode(opcode), g.NoOutput(), value,
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else {
DCHECK(cont->IsDeoptimize());
selector->EmitDeoptimize(cont->Encode(opcode), g.NoOutput(), value,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
}
DCHECK(cont->IsBranch() || cont->IsDeoptimize());
selector->EmitWithContinuation(opcode, value, cont);
}
// Try to emit TBZ, TBNZ, CBZ or CBNZ for certain comparisons of {node}
......@@ -1977,14 +1922,12 @@ bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, uint32_t value,
InstructionOperand temp = g.TempRegister();
selector->Emit(kArm64U64MoveFloat64, temp,
g.UseRegister(node->InputAt(0)));
selector->Emit(cont->Encode(kArm64TestAndBranch), g.NoOutput(), temp,
g.TempImmediate(63), g.Label(cont->true_block()),
g.Label(cont->false_block()));
selector->EmitWithContinuation(kArm64TestAndBranch, temp,
g.TempImmediate(63), cont);
return true;
}
selector->Emit(cont->Encode(kArm64TestAndBranch32), g.NoOutput(),
g.UseRegister(node), g.TempImmediate(31),
g.Label(cont->true_block()), g.Label(cont->false_block()));
selector->EmitWithContinuation(kArm64TestAndBranch32, g.UseRegister(node),
g.TempImmediate(31), cont);
return true;
}
case kEqual:
......@@ -1999,11 +1942,9 @@ bool TryEmitCbzOrTbz(InstructionSelector* selector, Node* node, uint32_t value,
// In the code generator, Equal refers to a bit being cleared. We want
// the opposite here so negate the condition.
cont->Negate();
selector->Emit(cont->Encode(kArm64TestAndBranch32), g.NoOutput(),
g.UseRegister(m_and.left().node()),
g.TempImmediate(base::bits::CountTrailingZeros(value)),
g.Label(cont->true_block()),
g.Label(cont->false_block()));
selector->EmitWithContinuation(
kArm64TestAndBranch32, g.UseRegister(m_and.left().node()),
g.TempImmediate(base::bits::CountTrailingZeros(value)), cont);
return true;
}
}
......@@ -2115,10 +2056,10 @@ bool TryEmitTestAndBranch(InstructionSelector* selector, Node* node,
base::bits::IsPowerOfTwo(m.right().Value())) {
// If the mask has only one bit set, we can use tbz/tbnz.
DCHECK((cont->condition() == kEqual) || (cont->condition() == kNotEqual));
selector->Emit(
cont->Encode(kOpcode), g.NoOutput(), g.UseRegister(m.left().node()),
selector->EmitWithContinuation(
kOpcode, g.UseRegister(m.left().node()),
g.TempImmediate(base::bits::CountTrailingZeros(m.right().Value())),
g.Label(cont->true_block()), g.Label(cont->false_block()));
cont);
return true;
}
return false;
......@@ -2211,7 +2152,7 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
// Merge the Word64Equal(x, 0) comparison into a cbz instruction.
if ((cont->IsBranch() || cont->IsDeoptimize()) &&
!cont->IsPoisoned()) {
EmitBranchOrDeoptimize(this, cont->Encode(kArm64CompareAndBranch),
EmitBranchOrDeoptimize(this, kArm64CompareAndBranch,
g.UseRegister(left), cont);
return;
}
......@@ -2320,25 +2261,13 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
}
// Branch could not be combined with a compare, compare against 0 and branch.
if (cont->IsBranch()) {
if (cont->IsPoisoned()) {
// We need an instruction that sets flags for poisoning to work.
Emit(cont->Encode(kArm64Tst32), g.NoOutput(), g.UseRegister(value),
g.UseRegister(value), g.Label(cont->true_block()),
g.Label(cont->false_block()));
} else {
Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(),
g.UseRegister(value), g.Label(cont->true_block()),
g.Label(cont->false_block()));
}
} else if (cont->IsDeoptimize()) {
EmitDeoptimize(cont->Encode(kArm64Tst32), g.NoOutput(),
g.UseRegister(value), g.UseRegister(value), cont->kind(),
cont->reason(), cont->feedback(), cont->frame_state());
if (!cont->IsPoisoned() && cont->IsBranch()) {
Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(),
g.UseRegister(value), g.Label(cont->true_block()),
g.Label(cont->false_block()));
} else {
DCHECK(cont->IsTrap());
Emit(cont->Encode(kArm64Tst32), g.NoOutput(), g.UseRegister(value),
g.UseRegister(value), g.UseImmediate(cont->trap_id()));
EmitWithContinuation(cont->Encode(kArm64Tst32), g.UseRegister(value),
g.UseRegister(value), cont);
}
}
......
......@@ -422,7 +422,7 @@ void VisitBinop(InstructionSelector* selector, Node* node,
Node* right = m.right().node();
InstructionOperand inputs[6];
size_t input_count = 0;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
// TODO(turbofan): match complex addressing modes.
......@@ -463,29 +463,15 @@ void VisitBinop(InstructionSelector* selector, Node* node,
}
}
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
}
outputs[output_count++] = g.DefineSameAsFirst(node);
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsByteRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_NE(0u, output_count);
DCHECK_EQ(1u, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
......@@ -1081,51 +1067,20 @@ void VisitCompareWithMemoryOperand(InstructionSelector* selector,
DCHECK_EQ(IrOpcode::kLoad, left->opcode());
IA32OperandGenerator g(selector);
size_t input_count = 0;
InstructionOperand inputs[6];
InstructionOperand inputs[4];
AddressingMode addressing_mode =
g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
opcode |= AddressingModeField::encode(addressing_mode);
opcode = cont->Encode(opcode);
inputs[input_count++] = right;
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
selector->Emit(opcode, 0, nullptr, input_count, inputs);
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
InstructionOperand output = g.DefineAsRegister(cont->result());
selector->Emit(opcode, 1, &output, input_count, inputs);
} else {
DCHECK(cont->IsTrap());
inputs[input_count++] = g.UseImmediate(cont->trap_id());
selector->Emit(opcode, 0, nullptr, input_count, inputs);
}
selector->EmitWithContinuation(opcode, 0, nullptr, input_count, inputs, cont);
}
// Shared routine for multiple compare operations.
void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) {
IA32OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
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, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), left, right,
g.UseImmediate(cont->trap_id()));
}
selector->EmitWithContinuation(opcode, left, right, cont);
}
......@@ -1300,8 +1255,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
InstructionCode opcode = cont->Encode(kIA32StackCheck);
CHECK(cont->IsBranch());
selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
g.Label(cont->false_block()));
selector->EmitWithContinuation(opcode, cont);
return;
}
}
......
......@@ -387,210 +387,6 @@ class OperandGenerator {
InstructionSelector* selector_;
};
// The flags continuation is a way to combine a branch or a materialization
// of a boolean value with an instruction that sets the flags register.
// The whole instruction is treated as a unit by the register allocator, and
// thus no spills or moves can be introduced between the flags-setting
// instruction and the branch or set it should be combined with.
class FlagsContinuation final {
public:
FlagsContinuation() : mode_(kFlags_none) {}
// Creates a new flags continuation from the given condition and true/false
// blocks.
static FlagsContinuation ForBranch(FlagsCondition condition,
BasicBlock* true_block,
BasicBlock* false_block,
LoadPoisoning masking) {
FlagsMode mode = masking == LoadPoisoning::kDoPoison
? kFlags_branch_and_poison
: kFlags_branch;
return FlagsContinuation(mode, condition, true_block, false_block);
}
static FlagsContinuation ForBranchAndPoison(FlagsCondition condition,
BasicBlock* true_block,
BasicBlock* false_block) {
return FlagsContinuation(kFlags_branch_and_poison, condition, true_block,
false_block);
}
// Creates a new flags continuation for an eager deoptimization exit.
static FlagsContinuation ForDeoptimize(FlagsCondition condition,
DeoptimizeKind kind,
DeoptimizeReason reason,
VectorSlotPair const& feedback,
Node* frame_state,
LoadPoisoning masking) {
FlagsMode mode = masking == LoadPoisoning::kDoPoison
? kFlags_deoptimize_and_poison
: kFlags_deoptimize;
return FlagsContinuation(mode, condition, kind, reason, feedback,
frame_state);
}
// Creates a new flags continuation for a boolean value.
static FlagsContinuation ForSet(FlagsCondition condition, Node* result) {
return FlagsContinuation(condition, result);
}
// Creates a new flags continuation for a wasm trap.
static FlagsContinuation ForTrap(FlagsCondition condition,
Runtime::FunctionId trap_id, Node* result) {
return FlagsContinuation(condition, trap_id, result);
}
bool IsNone() const { return mode_ == kFlags_none; }
bool IsBranch() const {
return mode_ == kFlags_branch || mode_ == kFlags_branch_and_poison;
}
bool IsDeoptimize() const {
return mode_ == kFlags_deoptimize || mode_ == kFlags_deoptimize_and_poison;
}
bool IsPoisoned() const {
return mode_ == kFlags_branch_and_poison ||
mode_ == kFlags_deoptimize_and_poison;
}
bool IsSet() const { return mode_ == kFlags_set; }
bool IsTrap() const { return mode_ == kFlags_trap; }
FlagsCondition condition() const {
DCHECK(!IsNone());
return condition_;
}
DeoptimizeKind kind() const {
DCHECK(IsDeoptimize());
return kind_;
}
DeoptimizeReason reason() const {
DCHECK(IsDeoptimize());
return reason_;
}
VectorSlotPair const& feedback() const {
DCHECK(IsDeoptimize());
return feedback_;
}
Node* frame_state() const {
DCHECK(IsDeoptimize());
return frame_state_or_result_;
}
Node* result() const {
DCHECK(IsSet());
return frame_state_or_result_;
}
Runtime::FunctionId trap_id() const {
DCHECK(IsTrap());
return trap_id_;
}
BasicBlock* true_block() const {
DCHECK(IsBranch());
return true_block_;
}
BasicBlock* false_block() const {
DCHECK(IsBranch());
return false_block_;
}
void Negate() {
DCHECK(!IsNone());
condition_ = NegateFlagsCondition(condition_);
}
void Commute() {
DCHECK(!IsNone());
condition_ = CommuteFlagsCondition(condition_);
}
void Overwrite(FlagsCondition condition) { condition_ = condition; }
void OverwriteAndNegateIfEqual(FlagsCondition condition) {
DCHECK(condition_ == kEqual || condition_ == kNotEqual);
bool negate = condition_ == kEqual;
condition_ = condition;
if (negate) Negate();
}
void OverwriteUnsignedIfSigned() {
switch (condition_) {
case kSignedLessThan:
condition_ = kUnsignedLessThan;
break;
case kSignedLessThanOrEqual:
condition_ = kUnsignedLessThanOrEqual;
break;
case kSignedGreaterThan:
condition_ = kUnsignedGreaterThan;
break;
case kSignedGreaterThanOrEqual:
condition_ = kUnsignedGreaterThanOrEqual;
break;
default:
break;
}
}
// Encodes this flags continuation into the given opcode.
InstructionCode Encode(InstructionCode opcode) {
opcode |= FlagsModeField::encode(mode_);
if (mode_ != kFlags_none) {
opcode |= FlagsConditionField::encode(condition_);
}
return opcode;
}
private:
FlagsContinuation(FlagsMode mode, FlagsCondition condition,
BasicBlock* true_block, BasicBlock* false_block)
: mode_(mode),
condition_(condition),
true_block_(true_block),
false_block_(false_block) {
DCHECK(mode == kFlags_branch || mode == kFlags_branch_and_poison);
DCHECK_NOT_NULL(true_block);
DCHECK_NOT_NULL(false_block);
}
FlagsContinuation(FlagsMode mode, FlagsCondition condition,
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback, Node* frame_state)
: mode_(mode),
condition_(condition),
kind_(kind),
reason_(reason),
feedback_(feedback),
frame_state_or_result_(frame_state) {
DCHECK(mode == kFlags_deoptimize || mode == kFlags_deoptimize_and_poison);
DCHECK_NOT_NULL(frame_state);
}
FlagsContinuation(FlagsCondition condition, Node* result)
: mode_(kFlags_set),
condition_(condition),
frame_state_or_result_(result) {
DCHECK_NOT_NULL(result);
}
FlagsContinuation(FlagsCondition condition, Runtime::FunctionId trap_id,
Node* result)
: mode_(kFlags_trap),
condition_(condition),
frame_state_or_result_(result),
trap_id_(trap_id) {
DCHECK_NOT_NULL(result);
}
FlagsMode const mode_;
FlagsCondition condition_;
DeoptimizeKind kind_; // Only valid if mode_ == kFlags_deoptimize*
DeoptimizeReason reason_; // Only valid if mode_ == kFlags_deoptimize*
VectorSlotPair feedback_; // Only valid if mode_ == kFlags_deoptimize*
Node* frame_state_or_result_; // Only valid if mode_ == kFlags_deoptimize*
// or mode_ == kFlags_set.
BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch*.
BasicBlock* false_block_; // Only valid if mode_ == kFlags_branch*.
Runtime::FunctionId trap_id_; // Only valid if mode_ == kFlags_trap.
};
} // namespace compiler
} // namespace internal
} // namespace v8
......
......@@ -38,6 +38,8 @@ InstructionSelector::InstructionSelector(
schedule_(schedule),
current_block_(nullptr),
instructions_(zone),
continuation_inputs_(sequence->zone()),
continuation_outputs_(sequence->zone()),
defined_(node_count, false, zone),
used_(node_count, false, zone),
effect_level_(node_count, 0, zone),
......@@ -53,6 +55,8 @@ InstructionSelector::InstructionSelector(
frame_(frame),
instruction_selection_failed_(false) {
instructions_.reserve(node_count);
continuation_inputs_.reserve(5);
continuation_outputs_.reserve(2);
}
bool InstructionSelector::SelectInstructions() {
......@@ -651,6 +655,105 @@ size_t InstructionSelector::AddInputsToFrameStateDescriptor(
return entries;
}
Instruction* InstructionSelector::EmitWithContinuation(
InstructionCode opcode, FlagsContinuation* cont) {
return EmitWithContinuation(opcode, 0, nullptr, 0, nullptr, cont);
}
Instruction* InstructionSelector::EmitWithContinuation(
InstructionCode opcode, InstructionOperand a, FlagsContinuation* cont) {
return EmitWithContinuation(opcode, 0, nullptr, 1, &a, cont);
}
Instruction* InstructionSelector::EmitWithContinuation(
InstructionCode opcode, InstructionOperand a, InstructionOperand b,
FlagsContinuation* cont) {
InstructionOperand inputs[] = {a, b};
return EmitWithContinuation(opcode, 0, nullptr, arraysize(inputs), inputs,
cont);
}
Instruction* InstructionSelector::EmitWithContinuation(
InstructionCode opcode, InstructionOperand a, InstructionOperand b,
InstructionOperand c, FlagsContinuation* cont) {
InstructionOperand inputs[] = {a, b, c};
return EmitWithContinuation(opcode, 0, nullptr, arraysize(inputs), inputs,
cont);
}
Instruction* InstructionSelector::EmitWithContinuation(
InstructionCode opcode, size_t output_count, InstructionOperand* outputs,
size_t input_count, InstructionOperand* inputs, FlagsContinuation* cont) {
OperandGenerator g(this);
opcode = cont->Encode(opcode);
continuation_inputs_.resize(0);
for (size_t i = 0; i < input_count; i++) {
continuation_inputs_.push_back(inputs[i]);
}
continuation_outputs_.resize(0);
for (size_t i = 0; i < output_count; i++) {
continuation_outputs_.push_back(outputs[i]);
}
if (cont->IsBranch()) {
continuation_inputs_.push_back(g.Label(cont->true_block()));
continuation_inputs_.push_back(g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
opcode |= MiscField::encode(static_cast<int>(input_count));
AppendDeoptimizeArguments(&continuation_inputs_, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
continuation_outputs_.push_back(g.DefineAsRegister(cont->result()));
} else if (cont->IsTrap()) {
continuation_inputs_.push_back(g.UseImmediate(cont->trap_id()));
} else {
DCHECK(cont->IsNone());
}
size_t const emit_inputs_size = continuation_inputs_.size();
auto* emit_inputs =
emit_inputs_size ? &continuation_inputs_.front() : nullptr;
size_t const emit_outputs_size = continuation_outputs_.size();
auto* emit_outputs =
emit_outputs_size ? &continuation_outputs_.front() : nullptr;
return Emit(opcode, emit_outputs_size, emit_outputs, emit_inputs_size,
emit_inputs, 0, nullptr);
}
void InstructionSelector::AppendDeoptimizeArguments(
InstructionOperandVector* args, DeoptimizeKind kind,
DeoptimizeReason reason, VectorSlotPair const& feedback,
Node* frame_state) {
OperandGenerator g(this);
FrameStateDescriptor* const descriptor = GetFrameStateDescriptor(frame_state);
DCHECK_NE(DeoptimizeKind::kLazy, kind);
int const state_id =
sequence()->AddDeoptimizationEntry(descriptor, kind, reason, feedback);
args->push_back(g.TempImmediate(state_id));
StateObjectDeduplicator deduplicator(instruction_zone());
AddInputsToFrameStateDescriptor(descriptor, frame_state, &g, &deduplicator,
args, FrameStateInputKind::kAny,
instruction_zone());
}
Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, size_t output_count, InstructionOperand* outputs,
size_t input_count, InstructionOperand* inputs, DeoptimizeKind kind,
DeoptimizeReason reason, VectorSlotPair const& feedback,
Node* frame_state) {
InstructionOperandVector args(instruction_zone());
for (size_t i = 0; i < input_count; ++i) {
args.push_back(inputs[i]);
}
opcode |= MiscField::encode(static_cast<int>(input_count));
AppendDeoptimizeArguments(&args, kind, reason, feedback, frame_state);
return Emit(opcode, output_count, outputs, args.size(), &args.front(), 0,
nullptr);
}
// An internal helper class for generating the operands to calls.
// TODO(bmeurer): Get rid of the CallBuffer business and make
......@@ -2638,53 +2741,6 @@ void InstructionSelector::VisitTrapUnless(Node* node,
VisitWordCompareZero(node, node->InputAt(0), &cont);
}
Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, InstructionOperand output, InstructionOperand a,
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback, Node* frame_state) {
size_t output_count = output.IsInvalid() ? 0 : 1;
InstructionOperand inputs[] = {a};
size_t input_count = arraysize(inputs);
return EmitDeoptimize(opcode, output_count, &output, input_count, inputs,
kind, reason, feedback, frame_state);
}
Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, InstructionOperand output, InstructionOperand a,
InstructionOperand b, DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback, Node* frame_state) {
size_t output_count = output.IsInvalid() ? 0 : 1;
InstructionOperand inputs[] = {a, b};
size_t input_count = arraysize(inputs);
return EmitDeoptimize(opcode, output_count, &output, input_count, inputs,
kind, reason, feedback, frame_state);
}
Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, size_t output_count, InstructionOperand* outputs,
size_t input_count, InstructionOperand* inputs, DeoptimizeKind kind,
DeoptimizeReason reason, VectorSlotPair const& feedback,
Node* frame_state) {
OperandGenerator g(this);
FrameStateDescriptor* const descriptor = GetFrameStateDescriptor(frame_state);
InstructionOperandVector args(instruction_zone());
args.reserve(input_count + 1 + descriptor->GetTotalSize());
for (size_t i = 0; i < input_count; ++i) {
args.push_back(inputs[i]);
}
opcode |= MiscField::encode(static_cast<int>(input_count));
DCHECK_NE(DeoptimizeKind::kLazy, kind);
int const state_id =
sequence()->AddDeoptimizationEntry(descriptor, kind, reason, feedback);
args.push_back(g.TempImmediate(state_id));
StateObjectDeduplicator deduplicator(instruction_zone());
AddInputsToFrameStateDescriptor(descriptor, frame_state, &g, &deduplicator,
&args, FrameStateInputKind::kAny,
instruction_zone());
return Emit(opcode, output_count, outputs, args.size(), &args.front(), 0,
nullptr);
}
void InstructionSelector::EmitIdentity(Node* node) {
OperandGenerator g(this);
MarkAsUsed(node->InputAt(0));
......
This diff is collapsed.
......@@ -174,9 +174,9 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
MipsOperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand inputs[4];
InstructionOperand inputs[2];
size_t input_count = 0;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
if (TryMatchImmediate(selector, &opcode, m.right().node(), &input_count,
......@@ -194,13 +194,6 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
}
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.TempImmediate(cont->trap_id());
}
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
......@@ -209,23 +202,14 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
} else {
outputs[output_count++] = g.DefineAsRegister(node);
}
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_NE(0u, output_count);
DCHECK_EQ(1u, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
static void VisitBinop(InstructionSelector* selector, Node* node,
......@@ -1341,22 +1325,7 @@ namespace {
static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) {
MipsOperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
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, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), left, right,
g.TempImmediate(cont->trap_id()));
}
selector->EmitWithContinuation(opcode, left, right, cont);
}
......@@ -1555,23 +1524,8 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
// Continuation could not be combined with a compare, emit compare against 0.
MipsOperandGenerator g(this);
InstructionCode const opcode = cont->Encode(kMipsCmp);
InstructionOperand const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
EmitDeoptimize(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
g.TempImmediate(0));
} else {
DCHECK(cont->IsTrap());
Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
g.TempImmediate(cont->trap_id()));
}
EmitWithContinuation(kMipsCmp, value_operand, g.TempImmediate(0), cont);
}
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
......
......@@ -268,9 +268,9 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand inputs[4];
InstructionOperand inputs[2];
size_t input_count = 0;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
if (TryMatchImmediate(selector, &opcode, m.right().node(), &input_count,
......@@ -288,13 +288,6 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
inputs[input_count++] = g.UseOperand(m.right().node(), opcode);
}
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.TempImmediate(cont->trap_id());
}
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
......@@ -303,23 +296,14 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
} else {
outputs[output_count++] = g.DefineAsRegister(node);
}
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_NE(0u, output_count);
DCHECK_EQ(1u, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
static void VisitBinop(InstructionSelector* selector, Node* node,
......@@ -1834,22 +1818,7 @@ namespace {
static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
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, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), left, right,
g.TempImmediate(cont->trap_id()));
}
selector->EmitWithContinuation(opcode, left, right, cont);
}
......@@ -2051,22 +2020,8 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
void EmitWordCompareZero(InstructionSelector* selector, Node* value,
FlagsContinuation* cont) {
Mips64OperandGenerator g(selector);
InstructionCode opcode = cont->Encode(kMips64Cmp);
InstructionOperand const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
g.Label(cont->true_block()), g.Label(cont->false_block()));
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, g.NoOutput(), value_operand,
g.TempImmediate(0), cont->kind(), cont->reason(),
cont->feedback(), cont->frame_state());
} else if (cont->IsTrap()) {
selector->Emit(opcode, g.NoOutput(), value_operand, g.TempImmediate(0),
g.TempImmediate(cont->trap_id()));
} else {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
g.TempImmediate(0));
}
selector->EmitWithContinuation(kMips64Cmp, g.UseRegister(value),
g.TempImmediate(0), cont);
}
} // namespace
......
......@@ -416,9 +416,9 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
InstructionOperand inputs[6];
InstructionOperand inputs[4];
size_t input_count = 0;
InstructionOperand outputs[2];
InstructionOperand outputs[1];
size_t output_count = 0;
// TODO(turbofan): match complex addressing modes.
......@@ -465,23 +465,14 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
}
outputs[output_count++] = g.DefineSameAsFirst(node);
if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
}
DCHECK_NE(0u, input_count);
DCHECK_NE(0u, output_count);
DCHECK_EQ(1u, output_count);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
selector->EmitWithContinuation(opcode, output_count, outputs, input_count,
inputs, cont);
}
......@@ -1524,51 +1515,20 @@ void VisitCompareWithMemoryOperand(InstructionSelector* selector,
DCHECK_EQ(IrOpcode::kLoad, left->opcode());
X64OperandGenerator g(selector);
size_t input_count = 0;
InstructionOperand inputs[6];
InstructionOperand inputs[4];
AddressingMode addressing_mode =
g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
opcode |= AddressingModeField::encode(addressing_mode);
opcode = cont->Encode(opcode);
inputs[input_count++] = right;
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
selector->Emit(opcode, 0, nullptr, input_count, inputs);
} else if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
cont->kind(), cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
InstructionOperand output = g.DefineAsRegister(cont->result());
selector->Emit(opcode, 1, &output, input_count, inputs);
} else {
DCHECK(cont->IsTrap());
inputs[input_count++] = g.UseImmediate(cont->trap_id());
selector->Emit(opcode, 0, nullptr, input_count, inputs);
}
selector->EmitWithContinuation(opcode, 0, nullptr, input_count, inputs, cont);
}
// Shared routine for multiple compare operations.
void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right,
FlagsContinuation* cont) {
X64OperandGenerator g(selector);
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
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, cont->kind(),
cont->reason(), cont->feedback(),
cont->frame_state());
} else if (cont->IsSet()) {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
} else {
DCHECK(cont->IsTrap());
selector->Emit(opcode, g.NoOutput(), left, right,
g.UseImmediate(cont->trap_id()));
}
selector->EmitWithContinuation(opcode, left, right, cont);
}
......@@ -1745,8 +1705,7 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
InstructionCode opcode = cont->Encode(kX64StackCheck);
CHECK(cont->IsBranch());
selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()),
g.Label(cont->false_block()));
selector->EmitWithContinuation(opcode, cont);
return;
}
}
......
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