Stop tracking if instruction formats have multiple results.

All instruction formats can represent multiple results now, so a few
redundant formats can be removed: UnarySplit and BinaryOverflow.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-13 12:24:20 -07:00
parent bf74445eac
commit d3235eb81f
7 changed files with 10 additions and 65 deletions

View File

@@ -18,14 +18,10 @@ Unary = InstructionFormat(VALUE)
UnaryImm = InstructionFormat(imm64) UnaryImm = InstructionFormat(imm64)
UnaryIeee32 = InstructionFormat(ieee32) UnaryIeee32 = InstructionFormat(ieee32)
UnaryIeee64 = InstructionFormat(ieee64) UnaryIeee64 = InstructionFormat(ieee64)
UnarySplit = InstructionFormat(VALUE, multiple_results=True)
Binary = InstructionFormat(VALUE, VALUE) Binary = InstructionFormat(VALUE, VALUE)
BinaryImm = InstructionFormat(VALUE, imm64) BinaryImm = InstructionFormat(VALUE, imm64)
# Generate result + overflow flag.
BinaryOverflow = InstructionFormat(VALUE, VALUE, multiple_results=True)
# The select instructions are controlled by the second VALUE operand. # The select instructions are controlled by the second VALUE operand.
# The first VALUE operand is the controlling flag which has a derived type. # The first VALUE operand is the controlling flag which has a derived type.
# The fma instruction has the same constraint on all inputs. # The fma instruction has the same constraint on all inputs.
@@ -33,7 +29,7 @@ Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1)
# Catch-all for instructions with many outputs and inputs and no immediate # Catch-all for instructions with many outputs and inputs and no immediate
# operands. # operands.
MultiAry = InstructionFormat(VARIABLE_ARGS, multiple_results=True) MultiAry = InstructionFormat(VARIABLE_ARGS)
InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE) InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE)
ExtractLane = InstructionFormat(VALUE, ('lane', uimm8)) ExtractLane = InstructionFormat(VALUE, ('lane', uimm8))
@@ -47,11 +43,8 @@ Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS)
BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS) BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS)
BranchTable = InstructionFormat(VALUE, jump_table) BranchTable = InstructionFormat(VALUE, jump_table)
Call = InstructionFormat( Call = InstructionFormat(func_ref, VARIABLE_ARGS)
func_ref, VARIABLE_ARGS, multiple_results=True) IndirectCall = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS)
IndirectCall = InstructionFormat(
sig_ref, VALUE, VARIABLE_ARGS,
multiple_results=True)
Load = InstructionFormat(memflags, VALUE, offset32) Load = InstructionFormat(memflags, VALUE, offset32)
Store = InstructionFormat(memflags, VALUE, VALUE, offset32) Store = InstructionFormat(memflags, VALUE, VALUE, offset32)

View File

@@ -18,13 +18,6 @@ class InstructionFormat(object):
identified structurally, i.e., the format of an instruction is derived from identified structurally, i.e., the format of an instruction is derived from
the kinds of operands used in its declaration. the kinds of operands used in its declaration.
Most instruction formats produce a single result, or no result at all. If
an instruction can produce more than one result, the `multiple_results`
flag must be set on its format. All results are of the `value` kind, and
the instruction format does not keep track of how many results are
produced. Some instructions, like `call`, may have a variable number of
results.
The instruction format stores two separate lists of operands: Immediates The instruction format stores two separate lists of operands: Immediates
and values. Immediate operands (including entity references) are and values. Immediate operands (including entity references) are
represented as explicit members in the `InstructionData` variants. The represented as explicit members in the `InstructionData` variants. The
@@ -40,16 +33,14 @@ class InstructionFormat(object):
:param name: Instruction format name in CamelCase. This is used as a Rust :param name: Instruction format name in CamelCase. This is used as a Rust
variant name in both the `InstructionData` and `InstructionFormat` variant name in both the `InstructionData` and `InstructionFormat`
enums. enums.
:param multiple_results: Set to `True` if this instruction format allows
more than one result to be produced.
:param typevar_operand: Index of the value input operand that is used to :param typevar_operand: Index of the value input operand that is used to
infer the controlling type variable. By default, this is `0`, the first infer the controlling type variable. By default, this is `0`, the first
`value` operand. The index is relative to the values only, ignoring `value` operand. The index is relative to the values only, ignoring
immediate operands. immediate operands.
""" """
# Map (multiple_results, imm_kinds, num_value_operands) -> format # Map (imm_kinds, num_value_operands) -> format
_registry = dict() # type: Dict[Tuple[bool, Tuple[OperandKind, ...], int, bool], InstructionFormat] # noqa _registry = dict() # type: Dict[Tuple[Tuple[OperandKind, ...], int, bool], InstructionFormat] # noqa
# All existing formats. # All existing formats.
all_formats = list() # type: List[InstructionFormat] all_formats = list() # type: List[InstructionFormat]
@@ -57,7 +48,6 @@ class InstructionFormat(object):
def __init__(self, *kinds, **kwargs): def __init__(self, *kinds, **kwargs):
# type: (*Union[OperandKind, Tuple[str, OperandKind]], **Any) -> None # noqa # type: (*Union[OperandKind, Tuple[str, OperandKind]], **Any) -> None # noqa
self.name = kwargs.get('name', None) # type: str self.name = kwargs.get('name', None) # type: str
self.multiple_results = kwargs.get('multiple_results', False)
# The number of value operands stored in the format, or `None` when # The number of value operands stored in the format, or `None` when
# `has_value_list` is set. # `has_value_list` is set.
@@ -81,9 +71,7 @@ class InstructionFormat(object):
# Compute a signature for the global registry. # Compute a signature for the global registry.
imm_kinds = tuple(f.kind for f in self.imm_fields) imm_kinds = tuple(f.kind for f in self.imm_fields)
sig = ( sig = (imm_kinds, self.num_value_operands, self.has_value_list)
self.multiple_results, imm_kinds, self.num_value_operands,
self.has_value_list)
if sig in InstructionFormat._registry: if sig in InstructionFormat._registry:
raise RuntimeError( raise RuntimeError(
"Format '{}' has the same signature as existing format '{}'" "Format '{}' has the same signature as existing format '{}'"
@@ -158,37 +146,24 @@ class InstructionFormat(object):
:py:class:`Instruction` arguments of the same name, except they must be :py:class:`Instruction` arguments of the same name, except they must be
tuples of :py:`Operand` objects. tuples of :py:`Operand` objects.
""" """
if len(outs) == 1:
multiple_results = outs[0].kind == VARIABLE_ARGS
else:
multiple_results = len(outs) > 1
# Construct a signature. # Construct a signature.
imm_kinds = tuple(op.kind for op in ins if op.is_immediate()) imm_kinds = tuple(op.kind for op in ins if op.is_immediate())
num_values = sum(1 for op in ins if op.is_value()) num_values = sum(1 for op in ins if op.is_value())
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 = (imm_kinds, num_values, has_varargs)
if sig in InstructionFormat._registry: if sig in InstructionFormat._registry:
return InstructionFormat._registry[sig] return InstructionFormat._registry[sig]
# Try another value list format as an alternative. # Try another value list format as an alternative.
sig = (True, imm_kinds, num_values, has_varargs) sig = (imm_kinds, 0, True)
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: if sig in InstructionFormat._registry:
return InstructionFormat._registry[sig] return InstructionFormat._registry[sig]
raise RuntimeError( raise RuntimeError(
'No instruction format matches multiple_results={},' 'No instruction format matches '
'imms={}, vals={}, varargs={}'.format( 'imms={}, vals={}, varargs={}'.format(
multiple_results, imm_kinds, num_values, has_varargs)) imm_kinds, num_values, has_varargs))
@staticmethod @staticmethod
def extract_names(globs): def extract_names(globs):

View File

@@ -207,8 +207,6 @@ class EncRecipe(object):
if not format.has_value_list: if not format.has_value_list:
assert len(self.ins) == format.num_value_operands assert len(self.ins) == format.num_value_operands
self.outs = self._verify_constraints(outs) self.outs = self._verify_constraints(outs)
if len(self.outs) > 1:
assert format.multiple_results
def __str__(self): def __str__(self):
# type: () -> str # type: () -> str

View File

@@ -105,14 +105,12 @@ pub enum InstructionData {
UnaryImm { opcode: Opcode, imm: Imm64 }, UnaryImm { opcode: Opcode, imm: Imm64 },
UnaryIeee32 { opcode: Opcode, imm: Ieee32 }, UnaryIeee32 { opcode: Opcode, imm: Ieee32 },
UnaryIeee64 { opcode: Opcode, imm: Ieee64 }, UnaryIeee64 { opcode: Opcode, imm: Ieee64 },
UnarySplit { opcode: Opcode, arg: Value },
Binary { opcode: Opcode, args: [Value; 2] }, Binary { opcode: Opcode, args: [Value; 2] },
BinaryImm { BinaryImm {
opcode: Opcode, opcode: Opcode,
arg: Value, arg: Value,
imm: Imm64, imm: Imm64,
}, },
BinaryOverflow { opcode: Opcode, args: [Value; 2] },
Ternary { opcode: Opcode, args: [Value; 3] }, Ternary { opcode: Opcode, args: [Value; 3] },
MultiAry { opcode: Opcode, args: ValueList }, MultiAry { opcode: Opcode, args: ValueList },
InsertLane { InsertLane {

View File

@@ -255,10 +255,8 @@ impl<'a> Verifier<'a> {
&UnaryImm { .. } | &UnaryImm { .. } |
&UnaryIeee32 { .. } | &UnaryIeee32 { .. } |
&UnaryIeee64 { .. } | &UnaryIeee64 { .. } |
&UnarySplit { .. } |
&Binary { .. } | &Binary { .. } |
&BinaryImm { .. } | &BinaryImm { .. } |
&BinaryOverflow { .. } |
&Ternary { .. } | &Ternary { .. } |
&InsertLane { .. } | &InsertLane { .. } |
&ExtractLane { .. } | &ExtractLane { .. } |

View File

@@ -245,10 +245,8 @@ pub fn write_operands(w: &mut Write, dfg: &DataFlowGraph, inst: Inst) -> Result
UnaryImm { imm, .. } => write!(w, " {}", imm), UnaryImm { imm, .. } => write!(w, " {}", imm),
UnaryIeee32 { imm, .. } => write!(w, " {}", imm), UnaryIeee32 { imm, .. } => write!(w, " {}", imm),
UnaryIeee64 { imm, .. } => write!(w, " {}", imm), UnaryIeee64 { imm, .. } => write!(w, " {}", imm),
UnarySplit { arg, .. } => write!(w, " {}", arg),
Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]), Binary { args, .. } => write!(w, " {}, {}", args[0], args[1]),
BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm), BinaryImm { arg, imm, .. } => write!(w, " {}, {}", arg, imm),
BinaryOverflow { args, .. } => write!(w, " {}, {}", args[0], args[1]),
Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]), Ternary { args, .. } => write!(w, " {}, {}, {}", args[0], args[1], args[2]),
MultiAry { ref args, .. } => { MultiAry { ref args, .. } => {
if args.is_empty() { if args.is_empty() {

View File

@@ -1429,12 +1429,6 @@ impl<'a> Parser<'a> {
imm: self.match_ieee64("expected immediate 64-bit float operand")?, imm: self.match_ieee64("expected immediate 64-bit float operand")?,
} }
} }
InstructionFormat::UnarySplit => {
InstructionData::UnarySplit {
opcode: opcode,
arg: self.match_value("expected SSA value operand")?,
}
}
InstructionFormat::Binary => { InstructionFormat::Binary => {
let lhs = self.match_value("expected SSA value first operand")?; let lhs = self.match_value("expected SSA value first operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?; self.match_token(Token::Comma, "expected ',' between operands")?;
@@ -1454,15 +1448,6 @@ impl<'a> Parser<'a> {
imm: rhs, imm: rhs,
} }
} }
InstructionFormat::BinaryOverflow => {
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")?;
InstructionData::BinaryOverflow {
opcode: opcode,
args: [lhs, rhs],
}
}
InstructionFormat::Ternary => { InstructionFormat::Ternary => {
// Names here refer to the `select` instruction. // Names here refer to the `select` instruction.
// This format is also use by `fma`. // This format is also use by `fma`.