Revisit expanded instructions for legalization.

When an illegal instruction is replaced with other instructions, back up
and revisit the expanded instructions. The new instructions need to have
encodings assigned too.

This also allows for expansions to contain illegal instructions that
need to be legalized themselves.
This commit is contained in:
Jakob Stoklund Olesen
2016-11-04 09:44:11 -07:00
parent 1c57f43643
commit a2b7769a51
3 changed files with 50 additions and 39 deletions

View File

@@ -11,8 +11,10 @@ ebb0(v1: i64, v2: i64):
; regex: VX=vx\d+
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
; check: $(v3l=$V) = band $v1l, $v2l
; check: $(v3h=$V) = band $v1h, $v2h
; check: [R#ec
; sameln: $(v3l=$V) = band $v1l, $v2l
; check: [R#ec
; sameln: $(v3h=$V) = band $v1h, $v2h
; check: $v3 = iconcat_lohi $v3l, $v3h
function bitwise_or(i64, i64) -> i64 {
@@ -24,8 +26,10 @@ ebb0(v1: i64, v2: i64):
; regex: VX=vx\d+
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
; check: $(v3l=$V) = bor $v1l, $v2l
; check: $(v3h=$V) = bor $v1h, $v2h
; check: [R#cc
; sameln: $(v3l=$V) = bor $v1l, $v2l
; check: [R#cc
; sameln: $(v3h=$V) = bor $v1h, $v2h
; check: $v3 = iconcat_lohi $v3l, $v3h
function bitwise_xor(i64, i64) -> i64 {
@@ -37,6 +41,8 @@ ebb0(v1: i64, v2: i64):
; regex: VX=vx\d+
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
; check: $(v3l=$V) = bxor $v1l, $v2l
; check: $(v3h=$V) = bxor $v1h, $v2h
; check: [R#8c
; sameln: $(v3l=$V) = bxor $v1l, $v2l
; check: [R#8c
; sameln: $(v3h=$V) = bxor $v1h, $v2h
; check: $v3 = iconcat_lohi $v3l, $v3h

View File

@@ -139,8 +139,6 @@ def gen_xform(xform, fmt):
`inst: Inst` is the variable to be replaced. It is pointed to by `pos:
Cursor`.
`dfg: DataFlowGraph` is available and mutable.
Produce an `Option<Inst>` result at the end.
"""
# Unwrap the source instruction, create local variables for the input
# variables.
@@ -150,9 +148,6 @@ def gen_xform(xform, fmt):
for dst in xform.dst.rtl:
emit_dst_inst(dst, fmt)
# TODO: Return the first replacement instruction.
fmt.line('None')
def gen_xform_group(xgrp, fmt):
# type: (XFormGroup, Formatter) -> None
@@ -165,8 +160,7 @@ def gen_xform_group(xgrp, fmt):
fmt.line('#[allow(unused_variables,unused_assignments)]')
with fmt.indented(
'fn ' + xgrp.name +
'(pos: &mut Cursor, dfg: &mut DataFlowGraph) -> ' +
'Option<Inst> {',
'(pos: &mut Cursor, dfg: &mut DataFlowGraph) -> bool {',
'}'):
# Gen the instruction to be legalized. The cursor we're passed must be
# pointing at an instruction.
@@ -179,7 +173,8 @@ def gen_xform_group(xgrp, fmt):
'Opcode::{} => {{'.format(inst.camel_name), '}'):
gen_xform(xform, fmt)
# We'll assume there are uncovered opcodes.
fmt.line('_ => None,')
fmt.line('_ => return false,')
fmt.line('true')
def generate(isas, out_dir):

View File

@@ -13,7 +13,7 @@
//! The legalizer does not deal with register allocation constraints. These constraints are derived
//! from the encoding recipes, and solved later by the register allocator.
use ir::{Function, Cursor, DataFlowGraph, InstructionData, Opcode, Inst, InstBuilder};
use ir::{Function, Cursor, DataFlowGraph, InstructionData, Opcode, InstBuilder};
use ir::condcodes::IntCC;
use isa::{TargetIsa, Legalize};
@@ -27,36 +27,46 @@ pub fn legalize_function(func: &mut Function, isa: &TargetIsa) {
func.encodings.resize(func.dfg.num_insts());
let mut pos = Cursor::new(&mut func.layout);
while let Some(_ebb) = pos.next_ebb() {
// Keep track of the cursor position before the instruction being processed, so we can
// double back when replacing instructions.
let mut prev_pos = pos.position();
while let Some(inst) = pos.next_inst() {
match isa.encode(&func.dfg, &func.dfg[inst]) {
Ok(encoding) => func.encodings[inst] = encoding,
Err(Legalize::Expand) => {
expand(&mut pos, &mut func.dfg);
}
Err(Legalize::Narrow) => {
narrow(&mut pos, &mut func.dfg);
}
// TODO: We should transform the instruction into legal equivalents.
Ok(encoding) => *func.encodings.ensure(inst) = encoding,
Err(action) => {
// We should transform the instruction into legal equivalents.
// Possible strategies are:
// 1. Expand instruction into sequence of legal instructions. Possibly
// iteratively.
// 2. Split the controlling type variable into high and low parts. This applies
// both to SIMD vector types which can be halved and to integer types such
// as `i64` used on a 32-bit ISA.
// 3. Promote the controlling type variable to a larger type. This typically
// means expressing `i8` and `i16` arithmetic in terms if `i32` operations
// on RISC targets. (It may or may not be beneficial to promote small vector
// types versus splitting them.)
// 4. Convert to library calls. For example, floating point operations on an
// ISA with no IEEE 754 support.
//
// The iteration scheme used here is not going to cut it. Transforming
// instructions involves changing `function.layout` which is impossiblr while
// it is referenced by the two iterators. We need a layout cursor that can
// maintain a position *and* permit inserting and replacing instructions.
// 1. Legalize::Expand: Expand instruction into sequence of legal instructions.
// Possibly iteratively. ()
// 2. Legalize::Narrow: Split the controlling type variable into high and low
// parts. This applies both to SIMD vector types which can be halved and to
// integer types such as `i64` used on a 32-bit ISA. ().
// 3. TODO: Promote the controlling type variable to a larger type. This
// typically means expressing `i8` and `i16` arithmetic in terms if `i32`
// operations on RISC targets. (It may or may not be beneficial to promote
// small vector types versus splitting them.)
// 4. TODO: Convert to library calls. For example, floating point operations on
// an ISA with no IEEE 754 support.
let changed = match action {
Legalize::Expand => expand(&mut pos, &mut func.dfg),
Legalize::Narrow => narrow(&mut pos, &mut func.dfg),
};
// If the current instruction was replaced, we need to double back and revisit
// the expanded sequence. This is both to assign encodings and possible to
// expand further.
// There's a risk of infinite looping here if the legalization patterns are
// unsound. Should we attempt to detect that?
if changed {
pos.set_position(prev_pos);
}
}
}
// Remember this position in case we need to double back.
prev_pos = pos.position();
}
}
}
// Include legalization patterns that were generated by gen_legalizer.py from the XForms in