Remove more old backend ISA concepts (#3402)

This also paves the way for unifying TargetIsa and MachBackend, since now they map one to one. In theory the two traits could be merged, which would be nice to limit the number of total concepts. Also they have quite different responsibilities, so it might be fine to keep them separate.

Interestingly, this PR started as removing RegInfo from the TargetIsa trait since the adapter returned a dummy value there. From the fallout, noticed that all Display implementations didn't needed an ISA anymore (since these were only used to render ISA specific registers). Also the whole family of RegInfo / ValueLoc / RegUnit was exclusively used for the old backend, and these could be removed. Notably, some IR instructions needed to be removed, because they were using RegUnit too: this was the oddball of regfill / regmove / regspill / copy_special, which were IR instructions inserted by the old regalloc. Fare thee well!
This commit is contained in:
Benjamin Bouvier
2021-10-04 10:36:12 +02:00
committed by GitHub
parent 76afcab0c2
commit 43a86f14d5
71 changed files with 302 additions and 2059 deletions

View File

@@ -7,9 +7,6 @@ block0(v0: i32):
jump block1(v0)
block1(v1: i32):
regmove.i32 v0, %x10 -> %x20
; check: block1(v1: i32):
; check: regmove.i32 v0, %x10 -> %x20
v2 = iconst.i32 1
brz v1, block3(v1)
jump block2

View File

@@ -183,42 +183,6 @@ block0(v1: i32):
; nextln: store_complex v3, v1+v2
; nextln: store_complex v3, v1+v2+1
; Register diversions.
; This test file has no ISA, so we can unly use register unit numbers.
function %diversion(i32) {
ss0 = spill_slot 4
block0(v1: i32):
regmove v1, %10 -> %20
regmove v1, %20 -> %10
regspill v1, %10 -> ss0
regfill v1, ss0 -> %10
return
}
; sameln: function %diversion(i32) fast {
; nextln: ss0 = spill_slot 4
; check: block0(v1: i32):
; nextln: regmove v1, %10 -> %20
; nextln: regmove v1, %20 -> %10
; nextln: regspill v1, %10 -> ss0
; nextln: regfill v1, ss0 -> %10
; nextln: return
; nextln: }
; Register copies.
function %copy_special() {
block0:
copy_special %10 -> %20
copy_special %20 -> %10
return
}
; sameln: function %copy_special() fast {
; nextln: block0:
; nextln: copy_special %10 -> %20
; nextln: copy_special %20 -> %10
; nextln: return
; nextln: }
function %cond_traps(i32) {
block0(v0: i32):
trapz v0, stk_ovf

View File

@@ -1,15 +1,5 @@
test simple-gvn
function %other_side_effects(i32) -> i32 {
block0(v0: i32):
regmove v0, %10 -> %20
regmove v0, %10 -> %20
regmove v0, %20 -> %10
; check: regmove v0, %10 -> %20
; check: regmove v0, %10 -> %20
return v0
}
function %differing_typevars() -> i64 {
block0:
v0 = iconst.i32 7

View File

@@ -51,7 +51,6 @@ mod test_run;
mod test_safepoint;
mod test_simple_gvn;
mod test_simple_preopt;
mod test_stack_maps;
mod test_unwind;
mod test_verifier;
@@ -127,7 +126,6 @@ fn new_subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn subtest::SubTest>
"safepoint" => test_safepoint::subtest(parsed),
"simple-gvn" => test_simple_gvn::subtest(parsed),
"simple_preopt" => test_simple_preopt::subtest(parsed),
"stack_maps" => test_stack_maps::subtest(parsed),
"unwind" => test_unwind::subtest(parsed),
"verifier" => test_verifier::subtest(parsed),
_ => anyhow::bail!("unknown test command '{}'", parsed.command),
@@ -136,9 +134,8 @@ fn new_subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn subtest::SubTest>
fn pretty_anyhow_error(
func: &cranelift_codegen::ir::Function,
isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
err: cranelift_codegen::CodegenError,
) -> anyhow::Error {
let s = cranelift_codegen::print_errors::pretty_error(func, isa, err);
let s = cranelift_codegen::print_errors::pretty_error(func, err);
anyhow::anyhow!("{}", s)
}

View File

@@ -179,9 +179,8 @@ fn run_one_test<'a>(
// Should we run the verifier before this test?
if !context.verified && test.needs_verifier() {
verify_function(&func, context.flags_or_isa()).map_err(|errors| {
anyhow::anyhow!("{}", pretty_verifier_error(&func, isa, None, errors))
})?;
verify_function(&func, context.flags_or_isa())
.map_err(|errors| anyhow::anyhow!("{}", pretty_verifier_error(&func, None, errors)))?;
context.verified = true;
}

View File

@@ -31,6 +31,6 @@ impl SubTest for TestCat {
}
fn run(&self, func: Cow<Function>, context: &Context) -> anyhow::Result<()> {
subtest::run_filecheck(&func.display(context.isa).to_string(), context)
subtest::run_filecheck(&func.display().to_string(), context)
}
}

View File

@@ -6,7 +6,6 @@ use crate::subtest::{run_filecheck, Context, SubTest};
use cranelift_codegen;
use cranelift_codegen::binemit::{self, CodeInfo};
use cranelift_codegen::ir;
use cranelift_codegen::isa;
use cranelift_reader::TestCommand;
use log::info;
use std::borrow::Cow;
@@ -43,12 +42,12 @@ impl SubTest for TestCompile {
let CodeInfo { total_size, .. } = comp_ctx
.compile(isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, e))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, e))?;
info!(
"Generated {} bytes of code:\n{}",
total_size,
comp_ctx.func.display(isa)
comp_ctx.func.display()
);
let disasm = comp_ctx
@@ -102,11 +101,4 @@ impl binemit::CodeSink for SizeSink {
fn begin_jumptables(&mut self) {}
fn begin_rodata(&mut self) {}
fn end_codegen(&mut self) {}
fn add_stack_map(
&mut self,
_: &[ir::entities::Value],
_: &ir::Function,
_: &dyn isa::TargetIsa,
) {
}
}

View File

@@ -37,9 +37,9 @@ impl SubTest for TestDCE {
comp_ctx.compute_loop_analysis();
comp_ctx
.dce(context.flags_or_isa())
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, Into::into(e)))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, Into::into(e)))?;
let text = comp_ctx.func.display(context.isa).to_string();
let text = comp_ctx.func.display().to_string();
run_filecheck(&text, context)
}
}

View File

@@ -39,9 +39,9 @@ impl SubTest for TestLegalizer {
comp_ctx.compute_cfg();
comp_ctx
.legalize(isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, e))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, e))?;
let text = comp_ctx.func.display(Some(isa)).to_string();
let text = comp_ctx.func.display().to_string();
run_filecheck(&text, context)
}
}

View File

@@ -42,9 +42,9 @@ impl SubTest for TestLICM {
comp_ctx.compute_loop_analysis();
comp_ctx
.licm(isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, Into::into(e)))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, Into::into(e)))?;
let text = comp_ctx.func.display(context.isa).to_string();
let text = comp_ctx.func.display().to_string();
run_filecheck(&text, context)
}
}

View File

@@ -37,8 +37,8 @@ impl SubTest for TestPreopt {
comp_ctx.compute_cfg();
comp_ctx
.preopt(isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, Into::into(e)))?;
let text = &comp_ctx.func.display(isa).to_string();
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, Into::into(e)))?;
let text = &comp_ctx.func.display().to_string();
log::debug!("After peepmatic-based simple_preopt:\n{}", text);
// Only actually run the filecheck if peepmatic is enabled, because it

View File

@@ -40,9 +40,9 @@ impl SubTest for TestPreopt {
let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());
optimize(&mut comp_ctx, isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, Into::into(e)))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, Into::into(e)))?;
let text = comp_ctx.func.display(context.isa).to_string();
let text = comp_ctx.func.display().to_string();
run_filecheck(&text, context)
}
}

View File

@@ -25,10 +25,10 @@ impl SubTest for TestSafepoint {
comp_ctx.compute_cfg();
comp_ctx
.legalize(isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, e))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, e))?;
comp_ctx.compute_domtree();
let text = comp_ctx.func.display(context.isa).to_string();
let text = comp_ctx.func.display().to_string();
run_filecheck(&text, context)
}
}

View File

@@ -36,9 +36,9 @@ impl SubTest for TestSimpleGVN {
comp_ctx.flowgraph();
comp_ctx
.simple_gvn(context.flags_or_isa())
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, Into::into(e)))?;
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, Into::into(e)))?;
let text = comp_ctx.func.display(context.isa).to_string();
let text = comp_ctx.func.display().to_string();
run_filecheck(&text, context)
}
}

View File

@@ -38,8 +38,8 @@ impl SubTest for TestSimplePreopt {
comp_ctx.compute_cfg();
comp_ctx
.preopt(isa)
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, e))?;
let text = &comp_ctx.func.display(isa).to_string();
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, e))?;
let text = &comp_ctx.func.display().to_string();
log::debug!("After simple_preopt:\n{}", text);
// Only actually run the filecheck if peepmatic is *not* enabled,

View File

@@ -1,109 +0,0 @@
use crate::subtest::{run_filecheck, Context, SubTest};
use cranelift_codegen::binemit::{self, Addend, CodeOffset, CodeSink, Reloc, StackMap};
use cranelift_codegen::ir::*;
use cranelift_codegen::isa::TargetIsa;
use cranelift_reader::TestCommand;
use std::borrow::Cow;
use std::fmt::Write;
struct TestStackMaps;
pub fn subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn SubTest>> {
assert_eq!(parsed.command, "stack_maps");
if !parsed.options.is_empty() {
anyhow::bail!("No options allowed on {}", parsed);
}
Ok(Box::new(TestStackMaps))
}
impl SubTest for TestStackMaps {
fn name(&self) -> &'static str {
"stack_maps"
}
fn run(&self, func: Cow<Function>, context: &Context) -> anyhow::Result<()> {
let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());
comp_ctx
.compile(context.isa.expect("`test stack_maps` requires an isa"))
.map_err(|e| crate::pretty_anyhow_error(&comp_ctx.func, context.isa, e))?;
let mut sink = TestStackMapsSink::default();
// TODO remove entirely? seems a bit meaningless now
binemit::emit_function(
&comp_ctx.func,
|func, inst, sink, isa| {
if func.dfg[inst].opcode() == Opcode::Safepoint {
writeln!(&mut sink.text, "{}", func.dfg.display_inst(inst, isa)).unwrap();
}
},
&mut sink,
context.isa.expect("`test stack_maps` requires an isa"),
);
let mut text = comp_ctx.func.display(context.isa).to_string();
text.push('\n');
text.push_str("Stack maps:\n");
text.push('\n');
text.push_str(&sink.text);
run_filecheck(&text, context)
}
}
#[derive(Default)]
struct TestStackMapsSink {
offset: u32,
text: String,
}
impl CodeSink for TestStackMapsSink {
fn offset(&self) -> CodeOffset {
self.offset
}
fn put1(&mut self, _: u8) {
self.offset += 1;
}
fn put2(&mut self, _: u16) {
self.offset += 2;
}
fn put4(&mut self, _: u32) {
self.offset += 4;
}
fn put8(&mut self, _: u64) {
self.offset += 8;
}
fn reloc_external(&mut self, _: SourceLoc, _: Reloc, _: &ExternalName, _: Addend) {}
fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset) {}
fn reloc_jt(&mut self, _: Reloc, _: JumpTable) {}
fn trap(&mut self, _: TrapCode, _: SourceLoc) {}
fn begin_jumptables(&mut self) {}
fn begin_rodata(&mut self) {}
fn end_codegen(&mut self) {}
fn add_stack_map(&mut self, val_list: &[Value], func: &Function, isa: &dyn TargetIsa) {
let map = StackMap::from_values(&val_list, func, isa);
writeln!(&mut self.text, " - mapped words: {}", map.mapped_words()).unwrap();
write!(&mut self.text, " - live: [").unwrap();
let mut needs_comma_space = false;
for i in 0..(map.mapped_words() as usize) {
if map.get_bit(i) {
if needs_comma_space {
write!(&mut self.text, ", ").unwrap();
}
needs_comma_space = true;
write!(&mut self.text, "{}", i).unwrap();
}
}
writeln!(&mut self.text, "]").unwrap();
}
}