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:
Jakob Stoklund Olesen
2017-02-21 16:18:45 -08:00
parent 20ff2f0025
commit a7d24ab1dc
6 changed files with 60 additions and 12 deletions

View File

@@ -417,10 +417,20 @@ def gen_type_constraints(fmt, instrs):
get_constraint(i.ins[idx], ctrl_typevar, type_sets))
offset = operand_seqs.add(constraints)
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
# 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(
'{}: fixed_results={}, use_typevar_operand={}'
.format(i.camel_name, fixed_results, use_typevar_operand))
('{}: 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))
if i.is_polymorphic:
fmt.comment(
@@ -430,6 +440,8 @@ def gen_type_constraints(fmt, instrs):
flags = fixed_results
if use_typevar_operand:
flags |= 8
if requires_typevar_operand:
flags |= 0x10
with fmt.indented('OpcodeConstraints {', '},'):
fmt.line('flags: {:#04x},'.format(flags))

View File

@@ -14,6 +14,7 @@ use ir::{Value, Type, Ebb, JumpTable, SigRef, FuncRef};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
use ir::condcodes::*;
use ir::types;
use ir::DataFlowGraph;
use ref_slice::*;
use packed_option::PackedOption;
@@ -492,6 +493,27 @@ impl InstructionData {
_ => 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.
@@ -537,8 +559,12 @@ pub struct OpcodeConstraints {
/// Bit 3:
/// 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
/// `InstructionFormat` meta language object. When bit 0 is not set, the controlling type
/// variable must be the first output value instead.
/// `InstructionFormat` meta language object. When this bit is not set, the controlling
/// 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,
/// 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
}
/// 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.
/// This does not include `variable_args` produced by calls.
pub fn fixed_results(self) -> usize {

View File

@@ -53,8 +53,8 @@ impl TargetIsa for Isa {
registers::INFO.clone()
}
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.first_type(),
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.ctrl_typevar(dfg),
inst.opcode(),
self.cpumode,
&enc_tables::LEVEL2[..])

View File

@@ -46,8 +46,8 @@ impl TargetIsa for Isa {
registers::INFO.clone()
}
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.first_type(),
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.ctrl_typevar(dfg),
inst.opcode(),
&enc_tables::LEVEL1_A64[..],
&enc_tables::LEVEL2[..])

View File

@@ -53,8 +53,8 @@ impl TargetIsa for Isa {
registers::INFO.clone()
}
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.first_type(),
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.ctrl_typevar(dfg),
inst.opcode(),
self.cpumode,
&enc_tables::LEVEL2[..])

View File

@@ -53,8 +53,8 @@ impl TargetIsa for Isa {
registers::INFO.clone()
}
fn encode(&self, _: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.first_type(),
fn encode(&self, dfg: &DataFlowGraph, inst: &InstructionData) -> Result<Encoding, Legalize> {
lookup_enclist(inst.ctrl_typevar(dfg),
inst.opcode(),
self.cpumode,
&enc_tables::LEVEL2[..])