Simplify the back-end of InstBuilder.

We don't want to distinguish between single-result and multiple-result
instructions any longer.

- Merge the simple_instruction() and complex_instruction() builder
  methods into a single build() that can handle all cases.
- All format constructors now take a ctrl_type argument. Previously,
  some would take a result_type argument.
- Instruction constructors no longer attempt to compute a single result
  type. Just pass a ctrl_type and let the backend decide.

Fix one format constructor call in legalizer/split.rs which now takes a
ctrl_type instead of a result type.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-12 08:34:59 -07:00
parent 322a8db839
commit 71338bb31f
4 changed files with 36 additions and 112 deletions

View File

@@ -24,21 +24,11 @@ pub trait InstBuilderBase<'f>: Sized {
fn data_flow_graph(&self) -> &DataFlowGraph;
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
/// Insert a simple instruction and return a reference to it.
/// Insert an instruction and return a reference to it, consuming the builder.
///
/// A 'simple' instruction has at most one result, and the `data.ty` field must contain the
/// result type or `VOID` for an instruction with no result values.
fn simple_instruction(self, data: InstructionData) -> (Inst, &'f mut DataFlowGraph);
/// Insert a simple instruction and return a reference to it.
///
/// A 'complex' instruction may produce multiple results, and the result types may depend on a
/// controlling type variable. For non-polymorphic instructions with multiple results, pass
/// `VOID` for the `ctrl_typevar` argument.
fn complex_instruction(self,
data: InstructionData,
ctrl_typevar: Type)
-> (Inst, &'f mut DataFlowGraph);
/// The result types may depend on a controlling type variable. For non-polymorphic
/// instructions with multiple results, pass `VOID` for the `ctrl_typevar` argument.
fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph);
}
// Include trait code generated by `lib/cretonne/meta/gen_instr.py`.
@@ -79,16 +69,7 @@ impl<'c, 'fc, 'fd> InstBuilderBase<'fd> for InsertBuilder<'c, 'fc, 'fd> {
self.dfg
}
fn simple_instruction(self, data: InstructionData) -> (Inst, &'fd mut DataFlowGraph) {
let inst = self.dfg.make_inst(data);
self.pos.insert_inst(inst);
(inst, self.dfg)
}
fn complex_instruction(self,
data: InstructionData,
ctrl_typevar: Type)
-> (Inst, &'fd mut DataFlowGraph) {
fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'fd mut DataFlowGraph) {
let inst = self.dfg.make_inst(data);
self.dfg.make_inst_results(inst, ctrl_typevar);
self.pos.insert_inst(inst);
@@ -98,20 +79,12 @@ impl<'c, 'fc, 'fd> InstBuilderBase<'fd> for InsertBuilder<'c, 'fc, 'fd> {
/// Instruction builder that replaces an existing instruction.
///
/// The inserted instruction will have the same `Inst` number as the old one. This is the only way
/// of rewriting the first result value of an instruction since this is a `ExpandedValue::Direct`
/// variant which encodes the instruction number directly.
/// The inserted instruction will have the same `Inst` number as the old one.
///
/// If the old instruction produced a value, the same value number will refer to the new
/// instruction's first result, so if that value has any uses the type should stay the same.
///
/// If the old instruction still has secondary result values attached, it is assumed that the new
/// instruction produces the same number and types of results. The old secondary values are
/// preserved. If the replacement instruction format does not support multiple results, the builder
/// panics. It is a bug to leave result values dangling.
///
/// If the old instruction was capable of producing secondary results, but the values have been
/// detached, new result values are generated by calling `DataFlowGraph::make_inst_results()`.
/// If the old instruction still has result values attached, it is assumed that the new instruction
/// produces the same number and types of results. The old result values are preserved. If the
/// replacement instruction format does not support multiple results, the builder panics. It is a
/// bug to leave result values dangling.
pub struct ReplaceBuilder<'f> {
dfg: &'f mut DataFlowGraph,
inst: Inst,
@@ -136,46 +109,20 @@ impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
self.dfg
}
fn simple_instruction(self, data: InstructionData) -> (Inst, &'f mut DataFlowGraph) {
// The replacement instruction cannot generate multiple results, so verify that the old
// instruction's secondary results have been detached.
let old_second_value = self.dfg[self.inst].second_result();
assert_eq!(old_second_value,
None,
"Secondary result values {:?} would be left dangling by replacing {} with {}",
self.dfg.inst_results(self.inst),
self.dfg[self.inst].opcode(),
data.opcode());
// Splat the new instruction on top of the old one.
self.dfg[self.inst] = data;
(self.inst, self.dfg)
}
fn complex_instruction(self,
data: InstructionData,
ctrl_typevar: Type)
-> (Inst, &'f mut DataFlowGraph) {
// If the old instruction still has secondary results attached, we'll keep them.
let old_second_value = self.dfg[self.inst].second_result();
fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
// Splat the new instruction on top of the old one.
self.dfg[self.inst] = data;
if old_second_value.is_none() {
// The old secondary values were either detached or non-existent.
// Construct new ones and set the first result type too.
if !self.dfg.has_results(self.inst) {
// The old result values were either detached or non-existent.
// Construct new ones.
self.dfg.make_inst_results(self.inst, ctrl_typevar);
} else {
// Reattach the old secondary values.
let old_second_value = self.dfg.inst_results(self.inst).get(1).cloned();
if let Some(val_ref) = self.dfg[self.inst].second_result_mut() {
// Don't check types here. Leave that to the verifier.
*val_ref = old_second_value.into();
} else {
// Actually, this instruction format should have called `simple_instruction()`, but
// we don't have a rule against calling `complex_instruction()` even when it is
// overkill.
panic!("Secondary result values left dangling");
}
// Normally, make_inst_results() would also set the first result type, but we're not

View File

@@ -633,7 +633,12 @@ impl DataFlowGraph {
.expect("Instruction has no results")
}
/// Iterate through all the results of an instruction.
/// Test if `inst` has any result values currently.
pub fn has_results(&self, inst: Inst) -> bool {
!self.results[inst].is_empty()
}
/// Return all the results of an instruction.
pub fn inst_results(&self, inst: Inst) -> &[Value] {
self.results[inst].as_slice(&self.value_lists)
}

View File

@@ -228,7 +228,7 @@ fn split_value(dfg: &mut DataFlowGraph,
// need to insert a split instruction before returning.
pos.goto_top(ebb);
pos.next_inst();
let concat_inst = dfg.ins(pos).Binary(concat, ty, lo, hi).0;
let concat_inst = dfg.ins(pos).Binary(concat, split_type, lo, hi).0;
let concat_val = dfg.first_result(concat_inst);
dfg.change_to_alias(value, concat_val);