Track regmove instruction during binemit.
Register locations can change throughout an EBB. Make sure the emit_inst() function considers this when encoding instructions and update the register diversion tracker.
This commit is contained in:
15
cranelift/filetests/isa/riscv/regmove.cton
Normal file
15
cranelift/filetests/isa/riscv/regmove.cton
Normal file
@@ -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
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ use cretonne::binemit;
|
|||||||
use cretonne::ir;
|
use cretonne::ir;
|
||||||
use cretonne::ir::entities::AnyEntity;
|
use cretonne::ir::entities::AnyEntity;
|
||||||
use cretonne::isa::TargetIsa;
|
use cretonne::isa::TargetIsa;
|
||||||
|
use cretonne::regalloc::RegDiversions;
|
||||||
use cton_reader::TestCommand;
|
use cton_reader::TestCommand;
|
||||||
use filetest::subtest::{SubTest, Context, Result};
|
use filetest::subtest::{SubTest, Context, Result};
|
||||||
use utils::{match_directive, pretty_error};
|
use utils::{match_directive, pretty_error};
|
||||||
@@ -147,7 +148,9 @@ impl SubTest for TestBinEmit {
|
|||||||
|
|
||||||
// Now emit all instructions.
|
// Now emit all instructions.
|
||||||
let mut sink = TextSink::new(isa);
|
let mut sink = TextSink::new(isa);
|
||||||
|
let mut divert = RegDiversions::new();
|
||||||
for ebb in func.layout.ebbs() {
|
for ebb in func.layout.ebbs() {
|
||||||
|
divert.clear();
|
||||||
// Correct header offsets should have been computed by `relax_branches()`.
|
// Correct header offsets should have been computed by `relax_branches()`.
|
||||||
assert_eq!(sink.offset,
|
assert_eq!(sink.offset,
|
||||||
func.offsets[ebb],
|
func.offsets[ebb],
|
||||||
@@ -160,7 +163,7 @@ impl SubTest for TestBinEmit {
|
|||||||
// Send legal encodings into the emitter.
|
// Send legal encodings into the emitter.
|
||||||
if enc.is_legal() {
|
if enc.is_legal() {
|
||||||
let before = sink.offset;
|
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;
|
let emitted = sink.offset - before;
|
||||||
// Verify the encoding recipe sizes against the ISAs emit_inst implementation.
|
// Verify the encoding recipe sizes against the ISAs emit_inst implementation.
|
||||||
assert_eq!(emitted,
|
assert_eq!(emitted,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ impl SubTest for TestCompile {
|
|||||||
// Finally verify that the returned code size matches the emitted bytes.
|
// Finally verify that the returned code size matches the emitted bytes.
|
||||||
let mut sink = SizeSink { offset: 0 };
|
let mut sink = SizeSink { offset: 0 };
|
||||||
binemit::emit_function(&comp_ctx.func,
|
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);
|
&mut sink);
|
||||||
|
|
||||||
if sink.offset != code_size {
|
if sink.offset != code_size {
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ def gen_recipe(recipe, fmt):
|
|||||||
want_outs = any(isinstance(o, RegClass) or isinstance(o, Stack)
|
want_outs = any(isinstance(o, RegClass) or isinstance(o, Stack)
|
||||||
for o in recipe.outs)
|
for o in recipe.outs)
|
||||||
|
|
||||||
|
# Regmove instructions get special treatment.
|
||||||
|
is_regmove = (recipe.format.name == 'RegMove')
|
||||||
|
|
||||||
# First unpack the instruction.
|
# First unpack the instruction.
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'if let InstructionData::{} {{'.format(iform.name),
|
'if let InstructionData::{} {{'.format(iform.name),
|
||||||
@@ -46,7 +49,7 @@ def gen_recipe(recipe, fmt):
|
|||||||
fmt.outdented_line('} = func.dfg[inst] {')
|
fmt.outdented_line('} = func.dfg[inst] {')
|
||||||
|
|
||||||
# Normalize to an `args` array.
|
# Normalize to an `args` array.
|
||||||
if want_args:
|
if want_args and not is_regmove:
|
||||||
if iform.has_value_list:
|
if iform.has_value_list:
|
||||||
fmt.line('let args = args.as_slice(&func.dfg.value_lists);')
|
fmt.line('let args = args.as_slice(&func.dfg.value_lists);')
|
||||||
elif nvops == 1:
|
elif nvops == 1:
|
||||||
@@ -56,11 +59,11 @@ def gen_recipe(recipe, fmt):
|
|||||||
# Don't bother with fixed registers.
|
# Don't bother with fixed registers.
|
||||||
args = ''
|
args = ''
|
||||||
for i, arg in enumerate(recipe.ins):
|
for i, arg in enumerate(recipe.ins):
|
||||||
if isinstance(arg, RegClass):
|
if isinstance(arg, RegClass) and not is_regmove:
|
||||||
v = 'in_reg{}'.format(i)
|
v = 'in_reg{}'.format(i)
|
||||||
args += ', ' + v
|
args += ', ' + v
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'let {} = func.locations[args[{}]].unwrap_reg();'
|
'let {} = divert.reg(args[{}], &func.locations);'
|
||||||
.format(v, i))
|
.format(v, i))
|
||||||
elif isinstance(arg, Stack):
|
elif isinstance(arg, Stack):
|
||||||
v = 'in_ss{}'.format(i)
|
v = 'in_ss{}'.format(i)
|
||||||
@@ -93,6 +96,11 @@ def gen_recipe(recipe, fmt):
|
|||||||
'let {} = func.locations[results[{}]].unwrap_stack();'
|
'let {} = func.locations[results[{}]].unwrap_stack();'
|
||||||
.format(v, i))
|
.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
|
# Call hand-written code. If the recipe contains a code snippet, use
|
||||||
# that. Otherwise cal a recipe function in the target ISA's binemit
|
# that. Otherwise cal a recipe function in the target ISA's binemit
|
||||||
# module.
|
# module.
|
||||||
@@ -118,13 +126,15 @@ def gen_isa(isa, fmt):
|
|||||||
# No encoding recipes: Emit a stub.
|
# No encoding recipes: Emit a stub.
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn emit_inst<CS: CodeSink + ?Sized>'
|
'pub fn emit_inst<CS: CodeSink + ?Sized>'
|
||||||
'(func: &Function, inst: Inst, _sink: &mut CS) {', '}'):
|
'(func: &Function, inst: Inst, '
|
||||||
|
'_divert: &mut RegDiversions, _sink: &mut CS) {', '}'):
|
||||||
fmt.line('bad_encoding(func, inst)')
|
fmt.line('bad_encoding(func, inst)')
|
||||||
else:
|
else:
|
||||||
fmt.line('#[allow(unused_variables, unreachable_code)]')
|
fmt.line('#[allow(unused_variables, unreachable_code)]')
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn emit_inst<CS: CodeSink + ?Sized>'
|
'pub fn emit_inst<CS: CodeSink + ?Sized>'
|
||||||
'(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();')
|
fmt.line('let bits = func.encodings[inst].bits();')
|
||||||
with fmt.indented('match func.encodings[inst].recipe() {', '}'):
|
with fmt.indented('match func.encodings[inst].recipe() {', '}'):
|
||||||
for i, recipe in enumerate(isa.all_recipes):
|
for i, recipe in enumerate(isa.all_recipes):
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ pub use self::relaxation::relax_branches;
|
|||||||
pub use self::memorysink::{MemoryCodeSink, RelocSink};
|
pub use self::memorysink::{MemoryCodeSink, RelocSink};
|
||||||
|
|
||||||
use ir::{Ebb, FuncRef, JumpTable, Function, Inst};
|
use ir::{Ebb, FuncRef, JumpTable, Function, Inst};
|
||||||
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
/// Offset in bytes from the beginning of the function.
|
/// Offset in bytes from the beginning of the function.
|
||||||
///
|
///
|
||||||
@@ -64,13 +65,14 @@ pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
|
|||||||
/// appropriate instruction emitter.
|
/// appropriate instruction emitter.
|
||||||
pub fn emit_function<CS, EI>(func: &Function, emit_inst: EI, sink: &mut CS)
|
pub fn emit_function<CS, EI>(func: &Function, emit_inst: EI, sink: &mut CS)
|
||||||
where CS: CodeSink,
|
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() {
|
for ebb in func.layout.ebbs() {
|
||||||
|
divert.clear();
|
||||||
assert_eq!(func.offsets[ebb], sink.offset());
|
assert_eq!(func.offsets[ebb], sink.offset());
|
||||||
for inst in func.layout.ebb_insts(ebb) {
|
for inst in func.layout.ebb_insts(ebb) {
|
||||||
emit_inst(func, inst, sink);
|
emit_inst(func, inst, &mut divert, sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use binemit::{CodeSink, bad_encoding};
|
use binemit::{CodeSink, bad_encoding};
|
||||||
use ir::{Function, Inst};
|
use ir::{Function, Inst};
|
||||||
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-arm32.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-arm32.rs"));
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,12 @@ impl TargetIsa for Isa {
|
|||||||
abi::allocatable_registers(func)
|
abi::allocatable_registers(func)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) {
|
fn emit_inst(&self,
|
||||||
binemit::emit_inst(func, inst, sink)
|
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) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use binemit::{CodeSink, bad_encoding};
|
use binemit::{CodeSink, bad_encoding};
|
||||||
use ir::{Function, Inst};
|
use ir::{Function, Inst};
|
||||||
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-arm64.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-arm64.rs"));
|
||||||
|
|
||||||
|
|||||||
@@ -84,8 +84,12 @@ impl TargetIsa for Isa {
|
|||||||
abi::allocatable_registers(func)
|
abi::allocatable_registers(func)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) {
|
fn emit_inst(&self,
|
||||||
binemit::emit_inst(func, inst, sink)
|
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) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
use binemit::{CodeSink, Reloc, bad_encoding};
|
use binemit::{CodeSink, Reloc, bad_encoding};
|
||||||
use ir::{Function, Inst, InstructionData};
|
use ir::{Function, Inst, InstructionData};
|
||||||
use isa::RegUnit;
|
use isa::RegUnit;
|
||||||
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,12 @@ impl TargetIsa for Isa {
|
|||||||
abi::allocatable_registers(func, &self.shared_flags)
|
abi::allocatable_registers(func, &self.shared_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) {
|
fn emit_inst(&self,
|
||||||
binemit::emit_inst(func, inst, sink)
|
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) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
|
|||||||
@@ -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
|
/// Note that this will call `put*` methods on the trait object via its vtable which is not the
|
||||||
/// fastest way of emitting code.
|
/// 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.
|
/// Emit a whole function into memory.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use binemit::{CodeSink, Reloc, bad_encoding};
|
|||||||
use ir::{Function, Inst, InstructionData};
|
use ir::{Function, Inst, InstructionData};
|
||||||
use isa::RegUnit;
|
use isa::RegUnit;
|
||||||
use predicates::is_signed_int;
|
use predicates::is_signed_int;
|
||||||
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs"));
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,12 @@ impl TargetIsa for Isa {
|
|||||||
abi::allocatable_registers(func, &self.isa_flags)
|
abi::allocatable_registers(func, &self.isa_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) {
|
fn emit_inst(&self,
|
||||||
binemit::emit_inst(func, inst, sink)
|
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) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
|
|||||||
Reference in New Issue
Block a user