diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/cretonne/src/ir/dfg.rs index b913f505e6..35b0af4dc6 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/cretonne/src/ir/dfg.rs @@ -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 { + 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. diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index f7fb6f3d94..daab56d09c 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -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