Add result values to call instructions too.

The make_inst_results() method now understands direct and indirect
calls, and can allocate result values matching the return types of the
function call.
This commit is contained in:
Jakob Stoklund Olesen
2016-10-18 12:31:37 -07:00
parent 1bcb8e25a2
commit cdb63a547e
2 changed files with 70 additions and 10 deletions

View File

@@ -2,7 +2,7 @@
use ir::{Ebb, Inst, Value, Type, SigRef, Signature, FuncRef};
use ir::entities::{NO_VALUE, ExpandedValue};
use ir::instructions::InstructionData;
use ir::instructions::{InstructionData, CallInfo};
use ir::extfunc::ExtFuncData;
use entity_map::{EntityMap, PrimaryEntityData};
@@ -213,6 +213,7 @@ impl DataFlowGraph {
pub fn make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize {
let constraints = self.insts[inst].opcode().constraints();
let fixed_results = constraints.fixed_results();
let mut total_results = fixed_results;
// Additional values form a linked list starting from the second result value. Generate
// the list backwards so we don't have to modify value table entries in place. (This
@@ -220,20 +221,41 @@ impl DataFlowGraph {
// choice, but since it is only visible in extremely rare instructions with 3+ results,
// we don't care).
let mut head = NO_VALUE;
let mut first_type = Type::default();
let mut first_type = None;
let mut rev_num = 1;
// TBD: Function call return values for direct and indirect function calls.
// Get the call signature if this is a function call.
if let Some(sig) = self.call_signature(inst) {
// Create result values corresponding to the call return types.
let var_results = self.signatures[sig].return_types.len();
total_results += var_results;
if fixed_results > 0 {
for res_idx in (1..fixed_results).rev() {
for res_idx in (0..var_results).rev() {
if let Some(ty) = first_type {
head = self.make_value(ValueData::Inst {
ty: ty,
num: (total_results - rev_num) as u16,
inst: inst,
next: head,
});
rev_num += 1;
}
first_type = Some(self.signatures[sig].return_types[res_idx].value_type);
}
}
// Then the fixed results whic will appear at the front of the list.
for res_idx in (0..fixed_results).rev() {
if let Some(ty) = first_type {
head = self.make_value(ValueData::Inst {
ty: constraints.result_type(res_idx, ctrl_typevar),
num: res_idx as u16,
ty: ty,
num: (total_results - rev_num) as u16,
inst: inst,
next: head,
});
rev_num += 1;
}
first_type = constraints.result_type(0, ctrl_typevar);
first_type = Some(constraints.result_type(res_idx, ctrl_typevar));
}
// Update the second_result pointer in `inst`.
@@ -242,9 +264,9 @@ impl DataFlowGraph {
.second_result_mut()
.expect("instruction format doesn't allow multiple results") = head;
}
*self.insts[inst].first_type_mut() = first_type;
*self.insts[inst].first_type_mut() = first_type.unwrap_or_default();
fixed_results
total_results
}
/// Get the first result of an instruction.
@@ -265,6 +287,16 @@ impl DataFlowGraph {
},
}
}
/// Get the call signature of a direct or indirect call instruction.
/// Returns `None` if `inst` is not a call instruction.
pub fn call_signature(&self, inst: Inst) -> Option<SigRef> {
match self.insts[inst].analyze_call() {
CallInfo::NotACall => None,
CallInfo::Direct(f, _) => Some(self.ext_funcs[f].signature),
CallInfo::Indirect(s, _) => Some(s),
}
}
}
/// Allow immutable access to instructions via indexing.

View File

@@ -388,6 +388,21 @@ impl InstructionData {
}
}
/// Return information about a call instruction.
///
/// Any instruction that can call another function reveals its call signature here.
pub fn analyze_call<'a>(&'a self) -> CallInfo<'a> {
match self {
&InstructionData::Call { ref data, .. } => {
CallInfo::Direct(data.func_ref, &data.varargs)
}
&InstructionData::IndirectCall { ref data, .. } => {
CallInfo::Indirect(data.sig_ref, &data.varargs)
}
_ => CallInfo::NotACall,
}
}
/// Return true if an instruction is terminating, or false otherwise.
pub fn is_terminating<'a>(&'a self) -> bool {
match self {
@@ -413,6 +428,19 @@ pub enum BranchInfo<'a> {
Table(JumpTable),
}
/// Information about call instructions.
pub enum CallInfo<'a> {
/// This is not a call instruction.
NotACall,
/// This is a direct call to an external function declared in the preamble. See
/// `DataFlowGraph.ext_funcs`.
Direct(FuncRef, &'a [Value]),
/// This is an indirect call with the specified signature. See `DataFlowGraph.signatures`.
Indirect(SigRef, &'a [Value]),
}
/// Value type constraints for a given opcode.
///
/// The `InstructionFormat` determines the constraints on most operands, but `Value` operands and