DCHECK_GE(arraysize(outputs), output_count);
DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
DCHECK_GE(arraysize(outputs), output_count);
DCHECK_NE(kMode_None, AddressingModeField::decode(opcode));
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
selector->Emit(cont->Encode(kArmVcmpF64), nullptr,
g.UseRegister(m.left().node()),
g.UseRegister(m.right().node()), g.Label(cont->true_block()),
- g.Label(cont->false_block()));
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
selector->Emit(
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
InstructionOperand* const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
selector->Emit(opcode, nullptr, value_operand, value_operand,
- g.Label(cont->true_block()), g.Label(cont->false_block()));
+ g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
value_operand);
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
- g.Label(cont->false_block()));
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
g.UseRegister(m.left().node()),
g.TempImmediate(
base::bits::CountTrailingZeros32(m.right().Value())),
- g.Label(cont.true_block()), g.Label(cont.false_block()));
+ g.Label(cont.true_block()),
+ g.Label(cont.false_block()))->MarkAsControl();
return;
}
return VisitWordCompare(this, value, kArm64Tst32, &cont, true,
g.UseRegister(m.left().node()),
g.TempImmediate(
base::bits::CountTrailingZeros64(m.right().Value())),
- g.Label(cont.true_block()), g.Label(cont.false_block()));
+ g.Label(cont.true_block()),
+ g.Label(cont.false_block()))->MarkAsControl();
return;
}
return VisitWordCompare(this, value, kArm64Tst, &cont, true,
// Branch could not be combined with a compare, compare against 0 and branch.
Emit(cont.Encode(kArm64CompareAndBranch32), NULL, g.UseRegister(value),
- g.Label(cont.true_block()), g.Label(cont.false_block()));
+ g.Label(cont.true_block()),
+ g.Label(cont.false_block()))->MarkAsControl();
}
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
IA32OperandGenerator g(selector);
if (cont->IsBranch()) {
selector->Emit(cont->Encode(opcode), NULL, left, right,
- g.Label(cont->true_block()), g.Label(cont->false_block()));
+ g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
// TODO(titzer): Needs byte register.
void InstructionSelector::VisitGoto(BasicBlock* target) {
// jump to the next block.
OperandGenerator g(this);
- Emit(kArchJmp, NULL, g.Label(target));
+ Emit(kArchJmp, NULL, g.Label(target))->MarkAsControl();
}
return FlagsConditionField::decode(opcode());
}
- // TODO(titzer): make call into a flag.
+ // TODO(titzer): make control and call into flags.
static Instruction* New(Zone* zone, InstructionCode opcode) {
return New(zone, opcode, 0, NULL, 0, NULL, 0, NULL);
}
opcode, output_count, outputs, input_count, inputs, temp_count, temps);
}
+ // TODO(titzer): another holdover from lithium days; register allocator
+ // should not need to know about control instructions.
+ Instruction* MarkAsControl() {
+ bit_field_ = IsControlField::update(bit_field_, true);
+ return this;
+ }
Instruction* MarkAsCall() {
bit_field_ = IsCallField::update(bit_field_, true);
return this;
}
+ bool IsControl() const { return IsControlField::decode(bit_field_); }
bool IsCall() const { return IsCallField::decode(bit_field_); }
bool NeedsPointerMap() const { return IsCall(); }
bool HasPointerMap() const { return pointer_map_ != NULL; }
explicit Instruction(InstructionCode opcode)
: opcode_(opcode),
bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
- TempCountField::encode(0) | IsCallField::encode(false)),
+ TempCountField::encode(0) | IsCallField::encode(false) |
+ IsControlField::encode(false)),
pointer_map_(NULL) {}
Instruction(InstructionCode opcode, size_t output_count,
bit_field_(OutputCountField::encode(output_count) |
InputCountField::encode(input_count) |
TempCountField::encode(temp_count) |
- IsCallField::encode(false)),
+ IsCallField::encode(false) | IsControlField::encode(false)),
pointer_map_(NULL) {
for (size_t i = 0; i < output_count; ++i) {
operands_[i] = outputs[i];
typedef BitField<size_t, 8, 16> InputCountField;
typedef BitField<size_t, 24, 6> TempCountField;
typedef BitField<bool, 30, 1> IsCallField;
+ typedef BitField<bool, 31, 1> IsControlField;
InstructionCode opcode_;
uint32_t bit_field_;
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
- g.Label(cont->false_block()));
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
// TODO(plind): Revisit and test this path.
InstructionOperand* const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0),
- g.Label(cont->true_block()), g.Label(cont->false_block()));
+ g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
g.TempImmediate(0));
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
- g.Label(cont->false_block()));
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
InstructionOperand* const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0),
- g.Label(cont->true_block()), g.Label(cont->false_block()));
+ g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
g.TempImmediate(0));
if (pos.Value() <= range->Start().Value()) return range;
// We can't properly connect liveranges if split occured at the end
- // a block.
+ // of control instruction.
DCHECK(pos.IsInstructionStart() ||
- code()
- ->GetInstructionBlock(pos.InstructionIndex())
- ->last_instruction_index() != pos.InstructionIndex());
+ !InstructionAt(pos.InstructionIndex())->IsControl());
int vreg = GetVirtualRegister();
if (!AllocationOk()) return nullptr;
DCHECK_GE(arraysize(inputs), input_count);
DCHECK_GE(arraysize(outputs), output_count);
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count,
- inputs);
+ Instruction* instr = selector->Emit(cont->Encode(opcode), output_count,
+ outputs, input_count, inputs);
+ if (cont->IsBranch()) instr->MarkAsControl();
}
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()),
- g.Label(cont->false_block()));
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
DCHECK(cont->IsSet());
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right);
R.allocCode();
TestInstr* i0 = TestInstr::New(R.zone(), 100);
- TestInstr* g = TestInstr::New(R.zone(), 103);
+ TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
R.code->StartBlock(b0->GetRpoNumber());
R.code->AddInstruction(i0);
R.code->AddInstruction(g);
R.allocCode();
TestInstr* i0 = TestInstr::New(R.zone(), 100);
- TestInstr* g = TestInstr::New(R.zone(), 103);
+ TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
R.code->StartBlock(b0->GetRpoNumber());
R.code->AddInstruction(i0);
R.code->AddInstruction(g);
R.code->EndBlock(b0->GetRpoNumber());
TestInstr* i1 = TestInstr::New(R.zone(), 102);
- TestInstr* g1 = TestInstr::New(R.zone(), 104);
+ TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
R.code->StartBlock(b1->GetRpoNumber());
R.code->AddInstruction(i1);
R.code->AddInstruction(g1);
R.allocCode();
TestInstr* i0 = TestInstr::New(R.zone(), 100);
- TestInstr* g = TestInstr::New(R.zone(), 103);
+ TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
R.code->StartBlock(b0->GetRpoNumber());
R.code->AddInstruction(i0);
R.code->AddInstruction(g);
int Jump(int target) {
Start();
InstructionOperand* ops[] = {UseRpo(target)};
- sequence_.AddInstruction(
- Instruction::New(main_zone(), kArchJmp, 0, NULL, 1, ops, 0, NULL));
+ sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1,
+ ops, 0, NULL)->MarkAsControl());
int pos = static_cast<int>(sequence_.instructions().size() - 1);
End();
return pos;
InstructionOperand* ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
FlagsConditionField::encode(kEqual);
- sequence_.AddInstruction(
- Instruction::New(main_zone(), code, 0, NULL, 2, ops, 0, NULL));
+ sequence_.AddInstruction(Instruction::New(main_zone(), code, 0, NULL, 2,
+ ops, 0, NULL)->MarkAsControl());
int pos = static_cast<int>(sequence_.instructions().size() - 1);
End();
return pos;
ConvertInputOp(Imm()), ConvertInputOp(Imm())};
InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
FlagsConditionField::encode(kEqual);
- auto instruction = NewInstruction(opcode, 0, nullptr, 4, inputs);
+ auto instruction =
+ NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
return AddInstruction(NewIndex(), instruction);
}
int InstructionSequenceTest::EmitFallThrough() {
- auto instruction = NewInstruction(kArchNop, 0, nullptr);
+ auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
return AddInstruction(NewIndex(), instruction);
}
int InstructionSequenceTest::EmitJump() {
InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
- auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs);
+ auto instruction =
+ NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
return AddInstruction(NewIndex(), instruction);
}