Compute the controlling type variable accurately.
Some polymorphic instructions don't return the controlling type variable, so it has to be computed from the designated operand instead. - Add a requires_typevar_operand() method to the operand constraints which indicates that. - Add a ctrl_typevar(dfg) method to InstructionData which computes the controlling type variable correctly, and returns VOID for monomorphic instructions. - Use ctrl_typevar(dfg) to drive the level-1 encoding table lookups.
This commit is contained in:
@@ -417,10 +417,20 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
get_constraint(i.ins[idx], ctrl_typevar, type_sets))
|
get_constraint(i.ins[idx], ctrl_typevar, type_sets))
|
||||||
offset = operand_seqs.add(constraints)
|
offset = operand_seqs.add(constraints)
|
||||||
fixed_results = len(i.value_results)
|
fixed_results = len(i.value_results)
|
||||||
|
# Can the controlling type variable be inferred from the designated
|
||||||
|
# operand?
|
||||||
use_typevar_operand = i.is_polymorphic and i.use_typevar_operand
|
use_typevar_operand = i.is_polymorphic and i.use_typevar_operand
|
||||||
|
# Can the controlling type variable be inferred from the result?
|
||||||
|
use_result = (fixed_results > 0 and
|
||||||
|
i.outs[i.value_results[0]].typevar != ctrl_typevar)
|
||||||
|
# Are we required to use the designated operand instead of the
|
||||||
|
# result?
|
||||||
|
requires_typevar_operand = use_typevar_operand and not use_result
|
||||||
fmt.comment(
|
fmt.comment(
|
||||||
'{}: fixed_results={}, use_typevar_operand={}'
|
('{}: fixed_results={}, use_typevar_operand={}, ' +
|
||||||
.format(i.camel_name, fixed_results, use_typevar_operand))
|
'requires_typevar_operand={}')
|
||||||
|
.format(i.camel_name, fixed_results, use_typevar_operand,
|
||||||
|
requires_typevar_operand))
|
||||||
fmt.comment('Constraints={}'.format(constraints))
|
fmt.comment('Constraints={}'.format(constraints))
|
||||||
if i.is_polymorphic:
|
if i.is_polymorphic:
|
||||||
fmt.comment(
|
fmt.comment(
|
||||||
@@ -430,6 +440,8 @@ def gen_type_constraints(fmt, instrs):
|
|||||||
flags = fixed_results
|
flags = fixed_results
|
||||||
if use_typevar_operand:
|
if use_typevar_operand:
|
||||||
flags |= 8
|
flags |= 8
|
||||||
|
if requires_typevar_operand:
|
||||||
|
flags |= 0x10
|
||||||
|
|
||||||
with fmt.indented('OpcodeConstraints {', '},'):
|
with fmt.indented('OpcodeConstraints {', '},'):
|
||||||
fmt.line('flags: {:#04x},'.format(flags))
|
fmt.line('flags: {:#04x},'.format(flags))
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use ir::{Value, Type, Ebb, JumpTable, SigRef, FuncRef};
|
|||||||
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
|
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
|
||||||
use ir::condcodes::*;
|
use ir::condcodes::*;
|
||||||
use ir::types;
|
use ir::types;
|
||||||
|
use ir::DataFlowGraph;
|
||||||
|
|
||||||
use ref_slice::*;
|
use ref_slice::*;
|
||||||
use packed_option::PackedOption;
|
use packed_option::PackedOption;
|
||||||
@@ -492,6 +493,27 @@ impl InstructionData {
|
|||||||
_ => CallInfo::NotACall,
|
_ => CallInfo::NotACall,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the controlling type variable, or `VOID` if this instruction isn't polymorphic.
|
||||||
|
///
|
||||||
|
/// In most cases, the controlling type variable is the same as the first result type, but some
|
||||||
|
/// opcodes require us to read the type of the designated type variable operand from `dfg`.
|
||||||
|
pub fn ctrl_typevar(&self, dfg: &DataFlowGraph) -> Type {
|
||||||
|
let constraints = self.opcode().constraints();
|
||||||
|
|
||||||
|
if !constraints.is_polymorphic() {
|
||||||
|
types::VOID
|
||||||
|
} 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()
|
||||||
|
.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
|
||||||
|
// `idata` itself, when possible.
|
||||||
|
self.first_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about branch and jump instructions.
|
/// Information about branch and jump instructions.
|
||||||
@@ -537,8 +559,12 @@ pub struct OpcodeConstraints {
|
|||||||
/// Bit 3:
|
/// Bit 3:
|
||||||
/// This opcode is polymorphic and the controlling type variable can be inferred from the
|
/// This opcode is polymorphic and the controlling type variable can be inferred from the
|
||||||
/// designated input operand. This is the `typevar_operand` index given to the
|
/// designated input operand. This is the `typevar_operand` index given to the
|
||||||
/// `InstructionFormat` meta language object. When bit 0 is not set, the controlling type
|
/// `InstructionFormat` meta language object. When this bit is not set, the controlling
|
||||||
/// variable must be the first output value instead.
|
/// type variable must be the first output value instead.
|
||||||
|
///
|
||||||
|
/// Bit 4:
|
||||||
|
/// This opcode is polymorphic and the controlling type variable does *not* appear as the
|
||||||
|
/// first result type.
|
||||||
flags: u8,
|
flags: u8,
|
||||||
|
|
||||||
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
/// Permitted set of types for the controlling type variable as an index into `TYPE_SETS`.
|
||||||
@@ -559,6 +585,16 @@ impl OpcodeConstraints {
|
|||||||
(self.flags & 0x8) != 0
|
(self.flags & 0x8) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is it necessary to look at the designated value input operand in order to determine the
|
||||||
|
/// controlling type variable, or is it good enough to use the first return type?
|
||||||
|
///
|
||||||
|
/// Most polymorphic instructions produce a single result with the type of the controlling type
|
||||||
|
/// variable. A few polymorphic instructions either don't produce any results, or produce
|
||||||
|
/// results with a fixed type. These instructions return `true`.
|
||||||
|
pub fn requires_typevar_operand(self) -> bool {
|
||||||
|
(self.flags & 0x10) != 0
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the number of *fixed* result values produced by this opcode.
|
/// Get the number of *fixed* result values produced by this opcode.
|
||||||
/// This does not include `variable_args` produced by calls.
|
/// This does not include `variable_args` produced by calls.
|
||||||
pub fn fixed_results(self) -> usize {
|
pub fn fixed_results(self) -> usize {
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ impl TargetIsa for Isa {
|
|||||||
registers::INFO.clone()
|
registers::INFO.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
||||||
lookup_enclist(inst.first_type(),
|
lookup_enclist(inst.ctrl_typevar(dfg),
|
||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
self.cpumode,
|
self.cpumode,
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ impl TargetIsa for Isa {
|
|||||||
registers::INFO.clone()
|
registers::INFO.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
||||||
lookup_enclist(inst.first_type(),
|
lookup_enclist(inst.ctrl_typevar(dfg),
|
||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
&enc_tables::LEVEL1_A64[..],
|
&enc_tables::LEVEL1_A64[..],
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ impl TargetIsa for Isa {
|
|||||||
registers::INFO.clone()
|
registers::INFO.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
||||||
lookup_enclist(inst.first_type(),
|
lookup_enclist(inst.ctrl_typevar(dfg),
|
||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
self.cpumode,
|
self.cpumode,
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ impl TargetIsa for Isa {
|
|||||||
registers::INFO.clone()
|
registers::INFO.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
|
||||||
lookup_enclist(inst.first_type(),
|
lookup_enclist(inst.ctrl_typevar(dfg),
|
||||||
inst.opcode(),
|
inst.opcode(),
|
||||||
self.cpumode,
|
self.cpumode,
|
||||||
&enc_tables::LEVEL2[..])
|
&enc_tables::LEVEL2[..])
|
||||||
|
|||||||
Reference in New Issue
Block a user