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

@@ -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,