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:
@@ -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())
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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 ''
|
||||
|
||||
@@ -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=())
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -151,11 +151,11 @@ pub enum InstructionData {
|
||||
ty: Type,
|
||||
args: [Value; 3],
|
||||
},
|
||||
TernaryOverflow {
|
||||
MultiAry {
|
||||
opcode: Opcode,
|
||||
ty: Type,
|
||||
second_result: PackedOption<Value>,
|
||||
data: Box<TernaryOverflowData>,
|
||||
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
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")?;
|
||||
|
||||
Reference in New Issue
Block a user