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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user