Coalesce some formats into MultiAry.

Allow some flexibility in the signature matching for instruction
formats. In particular, look for a value list format as a second chance
option.

The Return, ReturnReg, and TernaryOverflow formats all fit the single
MultiAry catch-all format for instructions without immediate operands.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-10 12:17:12 -08:00
parent 6021da8e1c
commit 519eb1934b
8 changed files with 50 additions and 99 deletions

View File

@@ -30,9 +30,10 @@ BinaryOverflow = InstructionFormat(VALUE, VALUE, multiple_results=True)
# The fma instruction has the same constraint on all inputs. # The fma instruction has the same constraint on all inputs.
Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1) Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1)
# Carry in *and* carry out for `iadd_carry` and friends. # Catch-all for instructions with many outputs and inputs and no immediate
TernaryOverflow = InstructionFormat( # operands.
VALUE, VALUE, VALUE, multiple_results=True, boxed_storage=True) MultiAry = InstructionFormat(
VARIABLE_ARGS, multiple_results=True, value_list=True)
InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE) InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE)
ExtractLane = InstructionFormat(VALUE, ('lane', uimm8)) ExtractLane = InstructionFormat(VALUE, ('lane', uimm8))
@@ -49,8 +50,6 @@ Call = InstructionFormat(
IndirectCall = InstructionFormat( IndirectCall = InstructionFormat(
sig_ref, VALUE, VARIABLE_ARGS, sig_ref, VALUE, VARIABLE_ARGS,
multiple_results=True, value_list=True) 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. # Finally extract the names of global variables in this module.
InstructionFormat.extract_names(globals()) InstructionFormat.extract_names(globals())

View File

@@ -82,7 +82,7 @@ class InstructionFormat(object):
if not self.has_value_list: if not self.has_value_list:
assert self.typevar_operand < self.num_value_operands, \ assert self.typevar_operand < self.num_value_operands, \
"typevar_operand must indicate a 'value' operand" "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. # Default to the first 'value' operand, if there is one.
self.typevar_operand = 0 self.typevar_operand = 0
@@ -176,13 +176,27 @@ class InstructionFormat(object):
has_varargs = (VARIABLE_ARGS in tuple(op.kind for op in ins)) has_varargs = (VARIABLE_ARGS in tuple(op.kind for op in ins))
sig = (multiple_results, imm_kinds, num_values, has_varargs) sig = (multiple_results, imm_kinds, num_values, has_varargs)
if sig not in InstructionFormat._registry: if sig 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] 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 @staticmethod
def extract_names(globs): def extract_names(globs):
""" """

View File

@@ -50,10 +50,12 @@ def unwrap_inst(iref, node, fmt):
fmt.line('{},'.format(m)) fmt.line('{},'.format(m))
if nvops == 1: if nvops == 1:
fmt.line('arg,') fmt.line('arg,')
elif nvops != 0: elif iform.has_value_list or nvops > 1:
fmt.line('args,') fmt.line('ref args,')
fmt.line('..') fmt.line('..')
fmt.outdented_line('} = dfg[inst] {') 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. # Generate the values for the tuple.
outs = list() outs = list()
prefix = 'data.' if iform.boxed_storage else '' prefix = 'data.' if iform.boxed_storage else ''

View File

@@ -11,7 +11,7 @@ instruction formats described in the reference:
from __future__ import absolute_import from __future__ import absolute_import
from cdsl.isa import EncRecipe from cdsl.isa import EncRecipe
from cdsl.predicates import IsSignedInt from cdsl.predicates import IsSignedInt
from base.formats import Binary, BinaryImm, ReturnReg from base.formats import Binary, BinaryImm, MultiAry
from .registers import GPR from .registers import GPR
# The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit # 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 # I-type encoding for `jalr` as a return instruction. We won't use the
# immediate offset. # immediate offset.
# The variable return values are not encoded. # The variable return values are not encoded.
Iret = EncRecipe('Iret', ReturnReg, ins=GPR, outs=()) Iret = EncRecipe('Iret', MultiAry, ins=GPR, outs=())

View File

@@ -3,7 +3,7 @@
//! A `Builder` provides a convenient interface for inserting instructions into a Cretonne //! 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. //! 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::{InstructionData, DataFlowGraph, Cursor};
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, ValueList}; use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, ValueList};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64}; use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64};

View File

@@ -151,11 +151,11 @@ pub enum InstructionData {
ty: Type, ty: Type,
args: [Value; 3], args: [Value; 3],
}, },
TernaryOverflow { MultiAry {
opcode: Opcode, opcode: Opcode,
ty: Type, ty: Type,
second_result: PackedOption<Value>, second_result: PackedOption<Value>,
data: Box<TernaryOverflowData>, args: ValueList,
}, },
InsertLane { InsertLane {
opcode: Opcode, opcode: Opcode,
@@ -213,16 +213,6 @@ pub enum InstructionData {
sig_ref: SigRef, sig_ref: SigRef,
args: ValueList, 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 /// 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. /// Analyzing an instruction.
/// ///
/// Avoid large matches on instruction formats by using the methods defined here to examine /// Avoid large matches on instruction formats by using the methods defined here to examine

View File

@@ -238,7 +238,15 @@ fn write_instruction(w: &mut Write,
BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm), BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm),
BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]),
Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]), 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]), InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]),
ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane), ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane),
IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]), IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
@@ -280,20 +288,6 @@ fn write_instruction(w: &mut Write,
args[0], args[0],
DisplayValues(&args[1..])) 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)))
}
} }
} }

View File

@@ -14,8 +14,7 @@ use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotDa
use cretonne::ir::types::VOID; use cretonne::ir::types::VOID;
use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
use cretonne::ir::entities::AnyEntity; use cretonne::ir::entities::AnyEntity;
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs};
TernaryOverflowData};
use cretonne::isa::{self, TargetIsa, Encoding}; use cretonne::isa::{self, TargetIsa, Encoding};
use cretonne::settings; use cretonne::settings;
use testfile::{TestFile, Details, Comment}; use testfile::{TestFile, Details, Comment};
@@ -193,8 +192,8 @@ impl<'a> Context<'a> {
self.map.rewrite_values(args, loc)?; self.map.rewrite_values(args, loc)?;
} }
InstructionData::TernaryOverflow { ref mut data, .. } => { InstructionData::MultiAry { ref mut args, .. } => {
self.map.rewrite_values(&mut data.args, loc)?; self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?;
} }
InstructionData::Jump { ref mut destination, ref mut args, .. } => { InstructionData::Jump { ref mut destination, ref mut args, .. } => {
@@ -214,14 +213,6 @@ impl<'a> Context<'a> {
InstructionData::IndirectCall { ref mut args, .. } => { InstructionData::IndirectCall { ref mut args, .. } => {
self.map.rewrite_values(args.as_mut_slice(value_lists), loc)?; 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], args: [ctrl_arg, true_arg, false_arg],
} }
} }
InstructionFormat::TernaryOverflow => { InstructionFormat::MultiAry => {
// Names here refer to the `iadd_carry` instruction. let args = self.parse_value_list()?;
let lhs = self.match_value("expected SSA value first operand")?; InstructionData::MultiAry {
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 {
opcode: opcode, opcode: opcode,
ty: VOID, ty: VOID,
second_result: None.into(), 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 => { InstructionFormat::Jump => {
@@ -1505,27 +1491,6 @@ impl<'a> Parser<'a> {
args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists), 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 => { InstructionFormat::BranchTable => {
let arg = self.match_value("expected SSA value operand")?; let arg = self.match_value("expected SSA value operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?; self.match_token(Token::Comma, "expected ',' between operands")?;