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:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ use ir::entities::{NO_VALUE, ExpandedValue};
|
||||
use ir::instructions::{InstructionData, CallInfo};
|
||||
use ir::extfunc::ExtFuncData;
|
||||
use entity_map::{EntityMap, PrimaryEntityData};
|
||||
use ir::builder::ReplaceBuilder;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::u16;
|
||||
|
||||
@@ -269,6 +271,27 @@ impl DataFlowGraph {
|
||||
total_results
|
||||
}
|
||||
|
||||
/// Create a `ReplaceBuilder` that will replace `inst` with a new instruction in place.
|
||||
pub fn replace(&mut self, inst: Inst) -> ReplaceBuilder {
|
||||
ReplaceBuilder::new(self, inst)
|
||||
}
|
||||
|
||||
/// Detach secondary instruction results, and return them as an iterator.
|
||||
///
|
||||
/// If `inst` produces two or more results, detach these secondary result values from `inst`,
|
||||
/// and return an iterator that will enumerate them. The first result value cannot be detached.
|
||||
///
|
||||
/// Use this method to detach secondary values before using `replace(inst)` to provide an
|
||||
/// alternate instruction for computing the primary result value.
|
||||
pub fn detach_secondary_results(&mut self, inst: Inst) -> Values {
|
||||
let second_result =
|
||||
self[inst].second_result_mut().map(|r| mem::replace(r, NO_VALUE)).unwrap_or_default();
|
||||
Values {
|
||||
dfg: self,
|
||||
cur: second_result,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the first result of an instruction.
|
||||
///
|
||||
/// If `Inst` doesn't produce any results, this returns a `Value` with a `VOID` type.
|
||||
@@ -277,7 +300,7 @@ impl DataFlowGraph {
|
||||
}
|
||||
|
||||
/// Iterate through all the results of an instruction.
|
||||
pub fn inst_results<'a>(&'a self, inst: Inst) -> Values<'a> {
|
||||
pub fn inst_results(&self, inst: Inst) -> Values {
|
||||
Values {
|
||||
dfg: self,
|
||||
cur: if self.insts[inst].first_type().is_void() {
|
||||
@@ -297,6 +320,34 @@ impl DataFlowGraph {
|
||||
CallInfo::Indirect(s, _) => Some(s),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the type of an instruction result from opcode constraints and call signatures.
|
||||
///
|
||||
/// This computes the same sequence of result types that `make_inst_results()` above would
|
||||
/// assign to the created result values, but it does not depend on `make_inst_results()` being
|
||||
/// called first.
|
||||
///
|
||||
/// Returns `None` if asked about a result index that is too large.
|
||||
pub fn compute_result_type(&self,
|
||||
inst: Inst,
|
||||
result_idx: usize,
|
||||
ctrl_typevar: Type)
|
||||
-> Option<Type> {
|
||||
let constraints = self.insts[inst].opcode().constraints();
|
||||
let fixed_results = constraints.fixed_results();
|
||||
|
||||
if result_idx < fixed_results {
|
||||
return Some(constraints.result_type(result_idx, ctrl_typevar));
|
||||
}
|
||||
|
||||
// Not a fixed result, try to extract a return type from the call signature.
|
||||
self.call_signature(inst).and_then(|sigref| {
|
||||
self.signatures[sigref]
|
||||
.return_types
|
||||
.get(result_idx - fixed_results)
|
||||
.map(|&arg| arg.value_type)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow immutable access to instructions via indexing.
|
||||
@@ -369,7 +420,7 @@ impl DataFlowGraph {
|
||||
}
|
||||
|
||||
/// Iterate through the arguments to an EBB.
|
||||
pub fn ebb_args<'a>(&'a self, ebb: Ebb) -> Values<'a> {
|
||||
pub fn ebb_args(&self, ebb: Ebb) -> Values {
|
||||
Values {
|
||||
dfg: self,
|
||||
cur: self.ebbs[ebb].first_arg,
|
||||
|
||||
Reference in New Issue
Block a user