Add a ReplaceBuilder instruction builder.

The DataFlowGraph::replace(inst) method returns an instruction builder
that will replace an instruction in-place.

This will be used when transforming instructions, replacing an old
instruction with a new (legal) way of computing its primary value. Since
primary result values are essentially instruction pointers, this is the
only way of replacing the definition of a value.

If secondary result values match the old instruction in both number and
types, they can be reused. If not, added a detach_secondary_results()
method for detaching old secondary values.
This commit is contained in:
Jakob Stoklund Olesen
2016-10-20 13:09:37 -07:00
parent 634de93337
commit bb0bb1e91c
2 changed files with 141 additions and 2 deletions

View File

@@ -92,3 +92,91 @@ impl<'c, 'fc, 'fd> InstBuilderBase<'fd> for InsertBuilder<'c, 'fc, 'fd> {
(inst, self.dfg)
}
}
/// 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.
///
/// 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 replacemant 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()`.
pub struct ReplaceBuilder<'f> {
dfg: &'f mut DataFlowGraph,
inst: Inst,
}
impl<'f> ReplaceBuilder<'f> {
/// Create a `ReplaceBuilder` that will overwrite `inst`.
pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> ReplaceBuilder {
ReplaceBuilder {
dfg: dfg,
inst: inst,
}
}
}
impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
fn data_flow_graph(&self) -> &DataFlowGraph {
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().unwrap_or_default();
assert_eq!(old_second_value,
Value::default(),
"Secondary result values {:?} would be left dangling by replacing {} with {}",
self.dfg.inst_results(self.inst).collect::<Vec<_>>(),
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().unwrap_or_default();
// Splat the new instruction on top of the old one.
self.dfg[self.inst] = data;
if old_second_value == Value::default() {
// The old secondary values were either detached or non-existent.
// Construct new ones and set the first result type too.
self.dfg.make_inst_results(self.inst, ctrl_typevar);
} else {
// Reattach the old secondary values.
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;
} 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
// going to call that, so set it manually.
*self.dfg[self.inst].first_type_mut() =
self.dfg.compute_result_type(self.inst, 0, ctrl_typevar).unwrap_or_default();
}
(self.inst, self.dfg)
}
}