diff --git a/lib/cretonne/meta/base/formats.py b/lib/cretonne/meta/base/formats.py index 9b29c54775..9f7a805940 100644 --- a/lib/cretonne/meta/base/formats.py +++ b/lib/cretonne/meta/base/formats.py @@ -42,15 +42,15 @@ ExtractLane = InstructionFormat(VALUE, ('lane', uimm8)) IntCompare = InstructionFormat(intcc, VALUE, VALUE) FloatCompare = InstructionFormat(floatcc, VALUE, VALUE) -Jump = InstructionFormat(ebb, VARIABLE_ARGS, boxed_storage=True) -Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS, boxed_storage=True) +Jump = InstructionFormat(ebb, VARIABLE_ARGS, value_list=True) +Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS, value_list=True) BranchTable = InstructionFormat(VALUE, jump_table) Call = InstructionFormat( func_ref, VARIABLE_ARGS, multiple_results=True, value_list=True) IndirectCall = InstructionFormat( sig_ref, VALUE, VARIABLE_ARGS, - multiple_results=True, boxed_storage=True) + multiple_results=True, value_list=True) Return = InstructionFormat(VARIABLE_ARGS, boxed_storage=True) ReturnReg = InstructionFormat(VALUE, VARIABLE_ARGS, boxed_storage=True) diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index b8afeb3eb7..376bfc0d56 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -206,12 +206,19 @@ def gen_instruction_data_impl(fmt): fmt.doc_comment('Get the controlling type variable operand.') with fmt.indented( - 'pub fn typevar_operand(&self) -> Option {', '}'): + 'pub fn typevar_operand(&self, pool: &ValueListPool) -> ' + 'Option {', '}'): with fmt.indented('match *self {', '}'): for f in InstructionFormat.all_formats: n = 'InstructionData::' + f.name if f.typevar_operand is None: fmt.line(n + ' { .. } => None,') + elif f.has_value_list: + # We keep all arguments in a value list. + i = f.value_operands.index(f.typevar_operand) + fmt.line( + '{} {{ ref args, .. }} => ' + 'args.get({}, pool),'.format(n, i)) elif len(f.value_operands) == 1: # We have a single value operand called 'arg'. if f.boxed_storage: diff --git a/lib/cretonne/src/cfg.rs b/lib/cretonne/src/cfg.rs index 9b0f3f15e7..c3cf19efe4 100644 --- a/lib/cretonne/src/cfg.rs +++ b/lib/cretonne/src/cfg.rs @@ -75,7 +75,7 @@ impl ControlFlowGraph { for ebb in &func.layout { for inst in func.layout.ebb_insts(ebb) { - match func.dfg[inst].analyze_branch() { + match func.dfg[inst].analyze_branch(&func.dfg.value_lists) { BranchInfo::SingleDest(dest, _) => { self.add_edge((ebb, inst), dest); } @@ -148,7 +148,7 @@ impl ControlFlowGraph { #[cfg(test)] mod tests { use super::*; - use ir::{Function, InstBuilder, Cursor, VariableArgs, types}; + use ir::{Function, InstBuilder, Cursor, types}; #[test] fn empty() { @@ -197,12 +197,12 @@ mod tests { let cur = &mut Cursor::new(&mut func.layout); cur.insert_ebb(ebb0); - br_ebb0_ebb2 = dfg.ins(cur).brnz(cond, ebb2, VariableArgs::new()); - jmp_ebb0_ebb1 = dfg.ins(cur).jump(ebb1, VariableArgs::new()); + br_ebb0_ebb2 = dfg.ins(cur).brnz(cond, ebb2, &[]); + jmp_ebb0_ebb1 = dfg.ins(cur).jump(ebb1, &[]); cur.insert_ebb(ebb1); - br_ebb1_ebb1 = dfg.ins(cur).brnz(cond, ebb1, VariableArgs::new()); - jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, VariableArgs::new()); + br_ebb1_ebb1 = dfg.ins(cur).brnz(cond, ebb1, &[]); + jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, &[]); cur.insert_ebb(ebb2); } diff --git a/lib/cretonne/src/dominator_tree.rs b/lib/cretonne/src/dominator_tree.rs index fd2c6cfb50..8c90b46160 100644 --- a/lib/cretonne/src/dominator_tree.rs +++ b/lib/cretonne/src/dominator_tree.rs @@ -209,7 +209,7 @@ impl DominatorTree { #[cfg(test)] mod test { use super::*; - use ir::{Function, InstBuilder, Cursor, VariableArgs, types}; + use ir::{Function, InstBuilder, Cursor, types}; use cfg::ControlFlowGraph; #[test] @@ -238,14 +238,14 @@ mod test { let cur = &mut Cursor::new(&mut func.layout); cur.insert_ebb(ebb3); - jmp_ebb3_ebb1 = dfg.ins(cur).jump(ebb1, VariableArgs::new()); + jmp_ebb3_ebb1 = dfg.ins(cur).jump(ebb1, &[]); cur.insert_ebb(ebb1); - br_ebb1_ebb0 = dfg.ins(cur).brnz(cond, ebb0, VariableArgs::new()); - jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, VariableArgs::new()); + br_ebb1_ebb0 = dfg.ins(cur).brnz(cond, ebb0, &[]); + jmp_ebb1_ebb2 = dfg.ins(cur).jump(ebb2, &[]); cur.insert_ebb(ebb2); - dfg.ins(cur).jump(ebb0, VariableArgs::new()); + dfg.ins(cur).jump(ebb0, &[]); cur.insert_ebb(ebb0); } diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index 2425b8814a..d7393c9293 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -196,12 +196,14 @@ pub enum InstructionData { Jump { opcode: Opcode, ty: Type, - data: Box, + destination: Ebb, + args: ValueList, }, Branch { opcode: Opcode, ty: Type, - data: Box, + destination: Ebb, + args: ValueList, }, BranchTable { opcode: Opcode, @@ -220,7 +222,8 @@ pub enum InstructionData { opcode: Opcode, ty: Type, second_result: PackedOption, - data: Box, + sig_ref: SigRef, + args: ValueList, }, Return { opcode: Opcode, @@ -255,9 +258,10 @@ impl VariableArgs { self.0.is_empty() } - /// Convert this to a value list in `pool`. - pub fn into_value_list(self, pool: &mut ValueListPool) -> ValueList { + /// Convert this to a value list in `pool` with `fixed` prepended. + pub fn into_value_list(self, fixed: &[Value], pool: &mut ValueListPool) -> ValueList { let mut vlist = ValueList::default(); + vlist.extend(fixed.iter().cloned(), pool); vlist.extend(self.0, pool); vlist } @@ -327,85 +331,6 @@ impl Display for TernaryOverflowData { } } -/// Payload data for jump instructions. These need to carry lists of EBB arguments that won't fit -/// in the allowed `InstructionData` size. -#[derive(Clone, Debug)] -pub struct JumpData { - /// Jump destination EBB. - pub destination: Ebb, - /// Arguments passed to destination EBB. - pub varargs: VariableArgs, -} - -impl Display for JumpData { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if self.varargs.is_empty() { - write!(f, "{}", self.destination) - } else { - write!(f, "{}({})", self.destination, self.varargs) - } - } -} - -/// Payload data for branch instructions. These need to carry lists of EBB arguments that won't fit -/// in the allowed `InstructionData` size. -#[derive(Clone, Debug)] -pub struct BranchData { - /// Value argument controlling the branch. - pub arg: Value, - /// Branch destination EBB. - pub destination: Ebb, - /// Arguments passed to destination EBB. - pub varargs: VariableArgs, -} - -impl BranchData { - /// Get references to the arguments. - pub fn arguments(&self) -> [&[Value]; 2] { - [ref_slice(&self.arg), &self.varargs] - } - - /// Get mutable references to the arguments. - pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] { - [ref_slice_mut(&mut self.arg), &mut self.varargs] - } -} - -impl Display for BranchData { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}, {}", self.arg, self.destination)?; - if !self.varargs.is_empty() { - write!(f, "({})", self.varargs)?; - } - Ok(()) - } -} - -/// Payload of an indirect call instruction. -#[derive(Clone, Debug)] -pub struct IndirectCallData { - /// Callee function. - pub arg: Value, - - /// Signature of the callee function. - pub sig_ref: SigRef, - - /// Dynamically sized array containing call argument values. - pub varargs: VariableArgs, -} - -impl IndirectCallData { - /// Get references to the arguments. - pub fn arguments(&self) -> [&[Value]; 2] { - [ref_slice(&self.arg), &self.varargs] - } - - /// Get mutable references to the arguments. - pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] { - [ref_slice_mut(&mut self.arg), &mut self.varargs] - } -} - /// Payload of a return instruction. #[derive(Clone, Debug)] pub struct ReturnData { @@ -467,13 +392,13 @@ impl InstructionData { /// /// Any instruction that can transfer control to another EBB reveals its possible destinations /// here. - pub fn analyze_branch<'a>(&'a self) -> BranchInfo<'a> { + pub fn analyze_branch<'a>(&'a self, pool: &'a ValueListPool) -> BranchInfo<'a> { match self { - &InstructionData::Jump { ref data, .. } => { - BranchInfo::SingleDest(data.destination, &data.varargs) + &InstructionData::Jump { destination, ref args, .. } => { + BranchInfo::SingleDest(destination, &args.as_slice(pool)) } - &InstructionData::Branch { ref data, .. } => { - BranchInfo::SingleDest(data.destination, &data.varargs) + &InstructionData::Branch { destination, ref args, .. } => { + BranchInfo::SingleDest(destination, &args.as_slice(pool)[1..]) } &InstructionData::BranchTable { table, .. } => BranchInfo::Table(table), _ => BranchInfo::NotABranch, @@ -488,8 +413,8 @@ impl InstructionData { &InstructionData::Call { func_ref, ref args, .. } => { CallInfo::Direct(func_ref, &args.as_slice(pool)) } - &InstructionData::IndirectCall { ref data, .. } => { - CallInfo::Indirect(data.sig_ref, &data.varargs) + &InstructionData::IndirectCall { sig_ref, ref args, .. } => { + CallInfo::Indirect(sig_ref, &args.as_slice(pool)) } _ => CallInfo::NotACall, } @@ -507,7 +432,7 @@ impl InstructionData { } else if constraints.requires_typevar_operand() { // Not all instruction formats have a designated operand, but in that case // `requires_typevar_operand()` should never be true. - dfg.value_type(self.typevar_operand() + dfg.value_type(self.typevar_operand(&dfg.value_lists) .expect("Instruction format doesn't have a designated operand, bad opcode.")) } else { // For locality of reference, we prefer to get the controlling type variable from diff --git a/lib/cretonne/src/regalloc/live_value_tracker.rs b/lib/cretonne/src/regalloc/live_value_tracker.rs index bcbbb62fe1..c45da220e4 100644 --- a/lib/cretonne/src/regalloc/live_value_tracker.rs +++ b/lib/cretonne/src/regalloc/live_value_tracker.rs @@ -217,7 +217,7 @@ impl LiveValueTracker { -> (&[LiveValue], &[LiveValue]) { // Save a copy of the live values before any branches or jumps that could be somebody's // immediate dominator. - match dfg[inst].analyze_branch() { + match dfg[inst].analyze_branch(&dfg.value_lists) { BranchInfo::NotABranch => {} _ => self.save_idom_live_set(inst), } diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index 8cba9757f9..5e8968c48b 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -225,6 +225,7 @@ fn write_instruction(w: &mut Write, } // Then the operands, depending on format. + let pool = &func.dfg.value_lists; use ir::instructions::InstructionData::*; match func.dfg[inst] { Nullary { .. } => writeln!(w, ""), @@ -244,8 +245,28 @@ fn write_instruction(w: &mut Write, ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane), IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]), FloatCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]), - Jump { ref data, .. } => writeln!(w, " {}", data), - Branch { ref data, .. } => writeln!(w, " {}", data), + Jump { destination, ref args, .. } => { + if args.is_empty() { + writeln!(w, " {}", destination) + } else { + writeln!(w, + " {}({})", + destination, + DisplayValues(args.as_slice(pool))) + } + } + Branch { destination, ref args, .. } => { + let args = args.as_slice(pool); + if args.len() == 1 { + writeln!(w, " {}, {}", args[0], destination) + } else { + writeln!(w, + " {}, {}({})", + args[0], + destination, + DisplayValues(&args[1..])) + } + } BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table), Call { func_ref, ref args, .. } => { writeln!(w, @@ -253,8 +274,13 @@ fn write_instruction(w: &mut Write, func_ref, DisplayValues(args.as_slice(&func.dfg.value_lists))) } - IndirectCall { ref data, .. } => { - writeln!(w, " {}, {}({})", data.sig_ref, data.arg, data.varargs) + IndirectCall { sig_ref, ref args, .. } => { + let args = args.as_slice(pool); + writeln!(w, + " {}, {}({})", + sig_ref, + args[0], + DisplayValues(&args[1..])) } Return { ref data, .. } => { if data.varargs.is_empty() { diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index c009270f54..26fbe234a0 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -15,8 +15,7 @@ use cretonne::ir::types::VOID; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::entities::AnyEntity; use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, - TernaryOverflowData, JumpData, BranchData, IndirectCallData, - ReturnData, ReturnRegData}; + TernaryOverflowData, ReturnData, ReturnRegData}; use cretonne::isa::{self, TargetIsa, Encoding}; use cretonne::settings; use testfile::{TestFile, Details, Comment}; @@ -200,24 +199,22 @@ impl<'a> Context<'a> { self.map.rewrite_values(&mut data.args, loc)?; } - InstructionData::Jump { ref mut data, .. } => { - self.map.rewrite_ebb(&mut data.destination, loc)?; - self.map.rewrite_values(&mut data.varargs, loc)?; + InstructionData::Jump { ref mut destination, ref mut args, .. } => { + self.map.rewrite_ebb(destination, loc)?; + self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; } - InstructionData::Branch { ref mut data, .. } => { - self.map.rewrite_value(&mut data.arg, loc)?; - self.map.rewrite_ebb(&mut data.destination, loc)?; - self.map.rewrite_values(&mut data.varargs, loc)?; + InstructionData::Branch { ref mut destination, ref mut args, .. } => { + self.map.rewrite_ebb(destination, loc)?; + self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; } InstructionData::Call { ref mut args, .. } => { self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; } - InstructionData::IndirectCall { ref mut data, .. } => { - self.map.rewrite_value(&mut data.arg, loc)?; - self.map.rewrite_values(&mut data.varargs, loc)?; + InstructionData::IndirectCall { ref mut args, .. } => { + self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; } InstructionData::Return { ref mut data, .. } => { @@ -1209,7 +1206,7 @@ impl<'a> Parser<'a> { // TBD: If it is defined in another block, the type should have been specified // explicitly. It is unfortunate that the correctness of IL depends on the // layout of the blocks. - let ctrl_src_value = inst_data.typevar_operand() + let ctrl_src_value = inst_data.typevar_operand(&ctx.function.dfg.value_lists) .expect("Constraints <-> Format inconsistency"); ctx.function.dfg.value_type(match ctx.map.get_value(ctrl_src_value) { Some(v) => v, @@ -1429,10 +1426,8 @@ impl<'a> Parser<'a> { InstructionData::Jump { opcode: opcode, ty: VOID, - data: Box::new(JumpData { - destination: ebb_num, - varargs: args, - }), + destination: ebb_num, + args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), } } InstructionFormat::Branch => { @@ -1443,11 +1438,8 @@ impl<'a> Parser<'a> { InstructionData::Branch { opcode: opcode, ty: VOID, - data: Box::new(BranchData { - arg: ctrl_arg, - destination: ebb_num, - varargs: args, - }), + destination: ebb_num, + args: args.into_value_list(&[ctrl_arg], &mut ctx.function.dfg.value_lists), } } InstructionFormat::InsertLane => { @@ -1511,7 +1503,7 @@ impl<'a> Parser<'a> { ty: VOID, second_result: None.into(), func_ref: func_ref, - args: args.into_value_list(&mut ctx.function.dfg.value_lists), + args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), } } InstructionFormat::IndirectCall => { @@ -1526,11 +1518,8 @@ impl<'a> Parser<'a> { opcode: opcode, ty: VOID, second_result: None.into(), - data: Box::new(IndirectCallData { - sig_ref: sig_ref, - arg: callee, - varargs: args, - }), + sig_ref: sig_ref, + args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists), } } InstructionFormat::Return => { diff --git a/src/print_cfg.rs b/src/print_cfg.rs index d8261dad10..206f5430c2 100644 --- a/src/print_cfg.rs +++ b/src/print_cfg.rs @@ -59,7 +59,7 @@ impl<'a> CFGPrinter<'a> { // Add all outgoing branch instructions to the label. for inst in self.func.layout.ebb_insts(ebb) { let idata = &self.func.dfg[inst]; - match idata.analyze_branch() { + match idata.analyze_branch(&self.func.dfg.value_lists) { BranchInfo::SingleDest(dest, _) => { write!(w, " | <{}>{} {}", inst, idata.opcode(), dest)? }