diff --git a/lib/cretonne/meta/base/formats.py b/lib/cretonne/meta/base/formats.py index 98547bbbd7..9d0cba38d9 100644 --- a/lib/cretonne/meta/base/formats.py +++ b/lib/cretonne/meta/base/formats.py @@ -30,9 +30,10 @@ BinaryOverflow = InstructionFormat(VALUE, VALUE, multiple_results=True) # The fma instruction has the same constraint on all inputs. Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1) -# Carry in *and* carry out for `iadd_carry` and friends. -TernaryOverflow = InstructionFormat( - VALUE, VALUE, VALUE, multiple_results=True, boxed_storage=True) +# Catch-all for instructions with many outputs and inputs and no immediate +# operands. +MultiAry = InstructionFormat( + VARIABLE_ARGS, multiple_results=True, value_list=True) InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE) ExtractLane = InstructionFormat(VALUE, ('lane', uimm8)) @@ -49,8 +50,6 @@ Call = InstructionFormat( IndirectCall = InstructionFormat( sig_ref, VALUE, VARIABLE_ARGS, multiple_results=True, value_list=True) -Return = InstructionFormat(VARIABLE_ARGS, value_list=True) -ReturnReg = InstructionFormat(VALUE, VARIABLE_ARGS, value_list=True) # Finally extract the names of global variables in this module. InstructionFormat.extract_names(globals()) diff --git a/lib/cretonne/meta/cdsl/formats.py b/lib/cretonne/meta/cdsl/formats.py index 910afb6052..b1784498ee 100644 --- a/lib/cretonne/meta/cdsl/formats.py +++ b/lib/cretonne/meta/cdsl/formats.py @@ -82,7 +82,7 @@ class InstructionFormat(object): if not self.has_value_list: assert self.typevar_operand < self.num_value_operands, \ "typevar_operand must indicate a 'value' operand" - elif self.num_value_operands != 0: + elif self.has_value_list or self.num_value_operands > 0: # Default to the first 'value' operand, if there is one. self.typevar_operand = 0 @@ -176,12 +176,26 @@ class InstructionFormat(object): has_varargs = (VARIABLE_ARGS in tuple(op.kind for op in ins)) sig = (multiple_results, imm_kinds, num_values, has_varargs) - if sig not in InstructionFormat._registry: - raise RuntimeError( - "No instruction format matches ins = ({}){}".format( - ", ".join(map(str, sig[1])), - "[multiple results]" if multiple_results else "")) - return InstructionFormat._registry[sig] + if sig in InstructionFormat._registry: + return InstructionFormat._registry[sig] + + # Try another value list format as an alternative. + sig = (True, imm_kinds, num_values, has_varargs) + if sig in InstructionFormat._registry: + return InstructionFormat._registry[sig] + + sig = (multiple_results, imm_kinds, 0, True) + if sig in InstructionFormat._registry: + return InstructionFormat._registry[sig] + + sig = (True, imm_kinds, 0, True) + if sig in InstructionFormat._registry: + return InstructionFormat._registry[sig] + + raise RuntimeError( + 'No instruction format matches multiple_results={},' + 'imms={}, vals={}, varargs={}'.format( + multiple_results, imm_kinds, num_values, has_varargs)) @staticmethod def extract_names(globs): diff --git a/lib/cretonne/meta/gen_legalizer.py b/lib/cretonne/meta/gen_legalizer.py index 7c36700dc7..9da3e9a985 100644 --- a/lib/cretonne/meta/gen_legalizer.py +++ b/lib/cretonne/meta/gen_legalizer.py @@ -50,10 +50,12 @@ def unwrap_inst(iref, node, fmt): fmt.line('{},'.format(m)) if nvops == 1: fmt.line('arg,') - elif nvops != 0: - fmt.line('args,') + elif iform.has_value_list or nvops > 1: + fmt.line('ref args,') fmt.line('..') fmt.outdented_line('} = dfg[inst] {') + if iform.has_value_list: + fmt.line('let args = args.as_slice(&dfg.value_lists);') # Generate the values for the tuple. outs = list() prefix = 'data.' if iform.boxed_storage else '' diff --git a/lib/cretonne/meta/isa/riscv/recipes.py b/lib/cretonne/meta/isa/riscv/recipes.py index ea7e019eb4..0dce091713 100644 --- a/lib/cretonne/meta/isa/riscv/recipes.py +++ b/lib/cretonne/meta/isa/riscv/recipes.py @@ -11,7 +11,7 @@ instruction formats described in the reference: from __future__ import absolute_import from cdsl.isa import EncRecipe from cdsl.predicates import IsSignedInt -from base.formats import Binary, BinaryImm, ReturnReg +from base.formats import Binary, BinaryImm, MultiAry from .registers import GPR # The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit @@ -86,4 +86,4 @@ I = EncRecipe( # I-type encoding for `jalr` as a return instruction. We won't use the # immediate offset. # The variable return values are not encoded. -Iret = EncRecipe('Iret', ReturnReg, ins=GPR, outs=()) +Iret = EncRecipe('Iret', MultiAry, ins=GPR, outs=()) diff --git a/lib/cretonne/src/ir/builder.rs b/lib/cretonne/src/ir/builder.rs index b6d6a16b6b..8880351d9b 100644 --- a/lib/cretonne/src/ir/builder.rs +++ b/lib/cretonne/src/ir/builder.rs @@ -3,7 +3,7 @@ //! A `Builder` provides a convenient interface for inserting instructions into a Cretonne //! function. Many of its methods are generated from the meta language instruction definitions. -use ir::{types, instructions}; +use ir::types; use ir::{InstructionData, DataFlowGraph, Cursor}; use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, ValueList}; use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64}; diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index 1292836d6d..de34a708c9 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -151,11 +151,11 @@ pub enum InstructionData { ty: Type, args: [Value; 3], }, - TernaryOverflow { + MultiAry { opcode: Opcode, ty: Type, second_result: PackedOption, - data: Box, + args: ValueList, }, InsertLane { opcode: Opcode, @@ -213,16 +213,6 @@ pub enum InstructionData { sig_ref: SigRef, args: ValueList, }, - Return { - opcode: Opcode, - ty: Type, - args: ValueList, - }, - ReturnReg { - opcode: Opcode, - ty: Type, - args: ValueList, - }, } /// A variable list of `Value` operands used for function call arguments and passing arguments to @@ -289,19 +279,6 @@ impl Default for VariableArgs { } } -/// Payload data for ternary instructions with multiple results, such as `iadd_carry`. -#[derive(Clone, Debug)] -pub struct TernaryOverflowData { - /// Value arguments. - pub args: [Value; 3], -} - -impl Display for TernaryOverflowData { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}, {}, {}", self.args[0], self.args[1], self.args[2]) - } -} - /// Analyzing an instruction. /// /// Avoid large matches on instruction formats by using the methods defined here to examine diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index e6880de697..1f9bfd4524 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -238,7 +238,15 @@ fn write_instruction(w: &mut Write, BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm), BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]), - TernaryOverflow { ref data, .. } => writeln!(w, " {}", data), + MultiAry { ref args, .. } => { + if args.is_empty() { + writeln!(w, "") + } else { + writeln!(w, + " {}", + DisplayValues(args.as_slice(&func.dfg.value_lists))) + } + } InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]), ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane), IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]), @@ -280,20 +288,6 @@ fn write_instruction(w: &mut Write, args[0], DisplayValues(&args[1..])) } - Return { ref args, .. } => { - if args.is_empty() { - writeln!(w, "") - } else { - writeln!(w, - " {}", - DisplayValues(args.as_slice(&func.dfg.value_lists))) - } - } - ReturnReg { ref args, .. } => { - writeln!(w, - " {}", - DisplayValues(args.as_slice(&func.dfg.value_lists))) - } } } diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index bd7d65c3ee..c982a5be0c 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -14,8 +14,7 @@ use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotDa 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}; +use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs}; use cretonne::isa::{self, TargetIsa, Encoding}; use cretonne::settings; use testfile::{TestFile, Details, Comment}; @@ -193,8 +192,8 @@ impl<'a> Context<'a> { self.map.rewrite_values(args, loc)?; } - InstructionData::TernaryOverflow { ref mut data, .. } => { - self.map.rewrite_values(&mut data.args, loc)?; + InstructionData::MultiAry { ref mut args, .. } => { + self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; } InstructionData::Jump { ref mut destination, ref mut args, .. } => { @@ -214,14 +213,6 @@ impl<'a> Context<'a> { InstructionData::IndirectCall { ref mut args, .. } => { self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; } - - InstructionData::Return { ref mut args, .. } => { - self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; - } - - InstructionData::ReturnReg { ref mut args, .. } => { - self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; - } } } } @@ -1388,18 +1379,13 @@ impl<'a> Parser<'a> { args: [ctrl_arg, true_arg, false_arg], } } - InstructionFormat::TernaryOverflow => { - // Names here refer to the `iadd_carry` instruction. - let lhs = self.match_value("expected SSA value first operand")?; - self.match_token(Token::Comma, "expected ',' between operands")?; - let rhs = self.match_value("expected SSA value second operand")?; - self.match_token(Token::Comma, "expected ',' between operands")?; - let cin = self.match_value("expected SSA value third operand")?; - InstructionData::TernaryOverflow { + InstructionFormat::MultiAry => { + let args = self.parse_value_list()?; + InstructionData::MultiAry { opcode: opcode, ty: VOID, second_result: None.into(), - data: Box::new(TernaryOverflowData { args: [lhs, rhs, cin] }), + args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), } } InstructionFormat::Jump => { @@ -1505,27 +1491,6 @@ impl<'a> Parser<'a> { args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists), } } - InstructionFormat::Return => { - let args = self.parse_value_list()?; - InstructionData::Return { - opcode: opcode, - ty: VOID, - args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), - } - } - InstructionFormat::ReturnReg => { - let raddr = self.match_value("expected SSA value return address operand")?; - let args = if self.optional(Token::Comma) { - self.parse_value_list()? - } else { - VariableArgs::new() - }; - InstructionData::ReturnReg { - opcode: opcode, - ty: VOID, - args: args.into_value_list(&[raddr], &mut ctx.function.dfg.value_lists), - } - } InstructionFormat::BranchTable => { let arg = self.match_value("expected SSA value operand")?; self.match_token(Token::Comma, "expected ',' between operands")?;