diff --git a/cranelift/filetests/isa/riscv/regmove.cton b/cranelift/filetests/isa/riscv/regmove.cton new file mode 100644 index 0000000000..c316f74f21 --- /dev/null +++ b/cranelift/filetests/isa/riscv/regmove.cton @@ -0,0 +1,15 @@ +; Test tracking of register moves. +test binemit +isa riscv + +function %regmoves(i32 link [%x1]) -> i32 link [%x1] { +ebb0(v9999: i32): + [-,%x10] v1 = iconst.i32 1 + [-,%x7] v2 = iadd_imm v1, 1000 ; bin: 3e850393 + regmove v1, %x10 -> %x11 ; bin: 00050593 + [-,%x7] v3 = iadd_imm v1, 1000 ; bin: 3e858393 + regmove v1, %x11 -> %x10 ; bin: 00058513 + [-,%x7] v4 = iadd_imm v1, 1000 ; bin: 3e850393 + + return v9999 +} diff --git a/cranelift/src/filetest/binemit.rs b/cranelift/src/filetest/binemit.rs index d359cea794..09a6955b5e 100644 --- a/cranelift/src/filetest/binemit.rs +++ b/cranelift/src/filetest/binemit.rs @@ -10,6 +10,7 @@ use cretonne::binemit; use cretonne::ir; use cretonne::ir::entities::AnyEntity; use cretonne::isa::TargetIsa; +use cretonne::regalloc::RegDiversions; use cton_reader::TestCommand; use filetest::subtest::{SubTest, Context, Result}; use utils::{match_directive, pretty_error}; @@ -147,7 +148,9 @@ impl SubTest for TestBinEmit { // Now emit all instructions. let mut sink = TextSink::new(isa); + let mut divert = RegDiversions::new(); for ebb in func.layout.ebbs() { + divert.clear(); // Correct header offsets should have been computed by `relax_branches()`. assert_eq!(sink.offset, func.offsets[ebb], @@ -160,7 +163,7 @@ impl SubTest for TestBinEmit { // Send legal encodings into the emitter. if enc.is_legal() { let before = sink.offset; - isa.emit_inst(&func, inst, &mut sink); + isa.emit_inst(&func, inst, &mut divert, &mut sink); let emitted = sink.offset - before; // Verify the encoding recipe sizes against the ISAs emit_inst implementation. assert_eq!(emitted, diff --git a/cranelift/src/filetest/compile.rs b/cranelift/src/filetest/compile.rs index f3766f001f..5d00ee63c2 100644 --- a/cranelift/src/filetest/compile.rs +++ b/cranelift/src/filetest/compile.rs @@ -52,7 +52,7 @@ impl SubTest for TestCompile { // Finally verify that the returned code size matches the emitted bytes. let mut sink = SizeSink { offset: 0 }; binemit::emit_function(&comp_ctx.func, - |func, inst, sink| isa.emit_inst(func, inst, sink), + |func, inst, div, sink| isa.emit_inst(func, inst, div, sink), &mut sink); if sink.offset != code_size { diff --git a/lib/cretonne/meta/gen_binemit.py b/lib/cretonne/meta/gen_binemit.py index 858fc36b39..8e734c5ff1 100644 --- a/lib/cretonne/meta/gen_binemit.py +++ b/lib/cretonne/meta/gen_binemit.py @@ -31,6 +31,9 @@ def gen_recipe(recipe, fmt): want_outs = any(isinstance(o, RegClass) or isinstance(o, Stack) for o in recipe.outs) + # Regmove instructions get special treatment. + is_regmove = (recipe.format.name == 'RegMove') + # First unpack the instruction. with fmt.indented( 'if let InstructionData::{} {{'.format(iform.name), @@ -46,7 +49,7 @@ def gen_recipe(recipe, fmt): fmt.outdented_line('} = func.dfg[inst] {') # Normalize to an `args` array. - if want_args: + if want_args and not is_regmove: if iform.has_value_list: fmt.line('let args = args.as_slice(&func.dfg.value_lists);') elif nvops == 1: @@ -56,11 +59,11 @@ def gen_recipe(recipe, fmt): # Don't bother with fixed registers. args = '' for i, arg in enumerate(recipe.ins): - if isinstance(arg, RegClass): + if isinstance(arg, RegClass) and not is_regmove: v = 'in_reg{}'.format(i) args += ', ' + v fmt.line( - 'let {} = func.locations[args[{}]].unwrap_reg();' + 'let {} = divert.reg(args[{}], &func.locations);' .format(v, i)) elif isinstance(arg, Stack): v = 'in_ss{}'.format(i) @@ -93,6 +96,11 @@ def gen_recipe(recipe, fmt): 'let {} = func.locations[results[{}]].unwrap_stack();' .format(v, i)) + # Special handling for regmove instructions. Update the register + # diversion tracker. + if recipe.format.name == 'RegMove': + fmt.line('divert.regmove(arg, src, dst);') + # Call hand-written code. If the recipe contains a code snippet, use # that. Otherwise cal a recipe function in the target ISA's binemit # module. @@ -118,13 +126,15 @@ def gen_isa(isa, fmt): # No encoding recipes: Emit a stub. with fmt.indented( 'pub fn emit_inst' - '(func: &Function, inst: Inst, _sink: &mut CS) {', '}'): + '(func: &Function, inst: Inst, ' + '_divert: &mut RegDiversions, _sink: &mut CS) {', '}'): fmt.line('bad_encoding(func, inst)') else: fmt.line('#[allow(unused_variables, unreachable_code)]') with fmt.indented( 'pub fn emit_inst' - '(func: &Function, inst: Inst, sink: &mut CS) {', '}'): + '(func: &Function, inst: Inst, ' + 'divert: &mut RegDiversions, sink: &mut CS) {', '}'): fmt.line('let bits = func.encodings[inst].bits();') with fmt.indented('match func.encodings[inst].recipe() {', '}'): for i, recipe in enumerate(isa.all_recipes): diff --git a/lib/cretonne/src/binemit/mod.rs b/lib/cretonne/src/binemit/mod.rs index 02076270d0..a4a62f869f 100644 --- a/lib/cretonne/src/binemit/mod.rs +++ b/lib/cretonne/src/binemit/mod.rs @@ -10,6 +10,7 @@ pub use self::relaxation::relax_branches; pub use self::memorysink::{MemoryCodeSink, RelocSink}; use ir::{Ebb, FuncRef, JumpTable, Function, Inst}; +use regalloc::RegDiversions; /// Offset in bytes from the beginning of the function. /// @@ -64,13 +65,14 @@ pub fn bad_encoding(func: &Function, inst: Inst) -> ! { /// appropriate instruction emitter. pub fn emit_function(func: &Function, emit_inst: EI, sink: &mut CS) where CS: CodeSink, - EI: Fn(&Function, Inst, &mut CS) + EI: Fn(&Function, Inst, &mut RegDiversions, &mut CS) { + let mut divert = RegDiversions::new(); for ebb in func.layout.ebbs() { + divert.clear(); assert_eq!(func.offsets[ebb], sink.offset()); for inst in func.layout.ebb_insts(ebb) { - emit_inst(func, inst, sink); + emit_inst(func, inst, &mut divert, sink); } - } } diff --git a/lib/cretonne/src/isa/arm32/binemit.rs b/lib/cretonne/src/isa/arm32/binemit.rs index cf12bdbde2..bbae03432c 100644 --- a/lib/cretonne/src/isa/arm32/binemit.rs +++ b/lib/cretonne/src/isa/arm32/binemit.rs @@ -2,6 +2,7 @@ use binemit::{CodeSink, bad_encoding}; use ir::{Function, Inst}; +use regalloc::RegDiversions; include!(concat!(env!("OUT_DIR"), "/binemit-arm32.rs")); diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs index 5591a2aece..769adc376d 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -91,8 +91,12 @@ impl TargetIsa for Isa { abi::allocatable_registers(func) } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { - binemit::emit_inst(func, inst, sink) + fn emit_inst(&self, + func: &ir::Function, + inst: ir::Inst, + divert: &mut regalloc::RegDiversions, + sink: &mut CodeSink) { + binemit::emit_inst(func, inst, divert, sink) } fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) { diff --git a/lib/cretonne/src/isa/arm64/binemit.rs b/lib/cretonne/src/isa/arm64/binemit.rs index 120115c0d8..ecff1662bc 100644 --- a/lib/cretonne/src/isa/arm64/binemit.rs +++ b/lib/cretonne/src/isa/arm64/binemit.rs @@ -2,6 +2,7 @@ use binemit::{CodeSink, bad_encoding}; use ir::{Function, Inst}; +use regalloc::RegDiversions; include!(concat!(env!("OUT_DIR"), "/binemit-arm64.rs")); diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs index 316d1957f5..a1b0ac2478 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -84,8 +84,12 @@ impl TargetIsa for Isa { abi::allocatable_registers(func) } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { - binemit::emit_inst(func, inst, sink) + fn emit_inst(&self, + func: &ir::Function, + inst: ir::Inst, + divert: &mut regalloc::RegDiversions, + sink: &mut CodeSink) { + binemit::emit_inst(func, inst, divert, sink) } fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) { diff --git a/lib/cretonne/src/isa/intel/binemit.rs b/lib/cretonne/src/isa/intel/binemit.rs index d3c9716680..61c6f512a9 100644 --- a/lib/cretonne/src/isa/intel/binemit.rs +++ b/lib/cretonne/src/isa/intel/binemit.rs @@ -3,6 +3,7 @@ use binemit::{CodeSink, Reloc, bad_encoding}; use ir::{Function, Inst, InstructionData}; use isa::RegUnit; +use regalloc::RegDiversions; include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs")); diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index 81e3127811..93a2ed2c09 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -91,8 +91,12 @@ impl TargetIsa for Isa { abi::allocatable_registers(func, &self.shared_flags) } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { - binemit::emit_inst(func, inst, sink) + fn emit_inst(&self, + func: &ir::Function, + inst: ir::Inst, + divert: &mut regalloc::RegDiversions, + sink: &mut CodeSink) { + binemit::emit_inst(func, inst, divert, sink) } fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) { diff --git a/lib/cretonne/src/isa/mod.rs b/lib/cretonne/src/isa/mod.rs index 0604c0f271..6665de5f42 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/cretonne/src/isa/mod.rs @@ -215,7 +215,11 @@ pub trait TargetIsa { /// /// Note that this will call `put*` methods on the trait object via its vtable which is not the /// fastest way of emitting code. - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut binemit::CodeSink); + fn emit_inst(&self, + func: &ir::Function, + inst: ir::Inst, + divert: &mut regalloc::RegDiversions, + sink: &mut binemit::CodeSink); /// Emit a whole function into memory. /// diff --git a/lib/cretonne/src/isa/riscv/binemit.rs b/lib/cretonne/src/isa/riscv/binemit.rs index d193981887..86cbb6b82c 100644 --- a/lib/cretonne/src/isa/riscv/binemit.rs +++ b/lib/cretonne/src/isa/riscv/binemit.rs @@ -4,6 +4,7 @@ use binemit::{CodeSink, Reloc, bad_encoding}; use ir::{Function, Inst, InstructionData}; use isa::RegUnit; use predicates::is_signed_int; +use regalloc::RegDiversions; include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs")); diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs index 6be2432a35..b70f6185b8 100644 --- a/lib/cretonne/src/isa/riscv/mod.rs +++ b/lib/cretonne/src/isa/riscv/mod.rs @@ -91,8 +91,12 @@ impl TargetIsa for Isa { abi::allocatable_registers(func, &self.isa_flags) } - fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { - binemit::emit_inst(func, inst, sink) + fn emit_inst(&self, + func: &ir::Function, + inst: ir::Inst, + divert: &mut regalloc::RegDiversions, + sink: &mut CodeSink) { + binemit::emit_inst(func, inst, divert, sink) } fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {