From a2b7769a518e10d19320f02b75fc282c3adcb2a2 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 4 Nov 2016 09:44:11 -0700 Subject: [PATCH] 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. --- .../filetests/isa/riscv/legalize-i64.cton | 18 ++++-- lib/cretonne/meta/gen_legalizer.py | 11 +--- lib/cretonne/src/legalizer.rs | 60 +++++++++++-------- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/cranelift/filetests/isa/riscv/legalize-i64.cton b/cranelift/filetests/isa/riscv/legalize-i64.cton index 2aa4be9e58..916986fe68 100644 --- a/cranelift/filetests/isa/riscv/legalize-i64.cton +++ b/cranelift/filetests/isa/riscv/legalize-i64.cton @@ -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 diff --git a/lib/cretonne/meta/gen_legalizer.py b/lib/cretonne/meta/gen_legalizer.py index d6b0f5eb2c..3efb120124 100644 --- a/lib/cretonne/meta/gen_legalizer.py +++ b/lib/cretonne/meta/gen_legalizer.py @@ -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` 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 {', + '(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): diff --git a/lib/cretonne/src/legalizer.rs b/lib/cretonne/src/legalizer.rs index 2a84ee520c..a83485b5e2 100644 --- a/lib/cretonne/src/legalizer.rs +++ b/lib/cretonne/src/legalizer.rs @@ -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,34 +27,44 @@ 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); + Ok(encoding) => *func.encodings.ensure(inst) = encoding, + Err(action) => { + // We should transform the instruction into legal equivalents. + // Possible strategies are: + // 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); + } } - Err(Legalize::Narrow) => { - narrow(&mut pos, &mut func.dfg); - } - // TODO: 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. } + + // Remember this position in case we need to double back. + prev_pos = pos.position(); } } }