refactor Reloc to an enum of every architecture's reloc types
https://github.com/stoklund/cretonne/pull/206#issuecomment-350905016
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
a888b2a6f1
commit
88b30ff386
@@ -9,7 +9,6 @@ use std::fmt::Write;
|
|||||||
use cretonne::binemit;
|
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::regalloc::RegDiversions;
|
use cretonne::regalloc::RegDiversions;
|
||||||
use cton_reader::TestCommand;
|
use cton_reader::TestCommand;
|
||||||
use filetest::subtest::{SubTest, Context, Result};
|
use filetest::subtest::{SubTest, Context, Result};
|
||||||
@@ -28,16 +27,14 @@ pub fn subtest(parsed: &TestCommand) -> Result<Box<SubTest>> {
|
|||||||
|
|
||||||
// Code sink that generates text.
|
// Code sink that generates text.
|
||||||
struct TextSink {
|
struct TextSink {
|
||||||
rnames: &'static [&'static str],
|
|
||||||
offset: binemit::CodeOffset,
|
offset: binemit::CodeOffset,
|
||||||
text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextSink {
|
impl TextSink {
|
||||||
/// Create a new empty TextSink.
|
/// Create a new empty TextSink.
|
||||||
pub fn new(isa: &TargetIsa) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rnames: isa.reloc_names(),
|
|
||||||
offset: 0,
|
offset: 0,
|
||||||
text: String::new(),
|
text: String::new(),
|
||||||
}
|
}
|
||||||
@@ -72,25 +69,20 @@ impl binemit::CodeSink for TextSink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_ebb(&mut self, reloc: binemit::Reloc, ebb_offset: binemit::CodeOffset) {
|
fn reloc_ebb(&mut self, reloc: binemit::Reloc, ebb_offset: binemit::CodeOffset) {
|
||||||
write!(
|
write!(self.text, "{}({}) ", reloc, ebb_offset).unwrap();
|
||||||
self.text,
|
|
||||||
"{}({}) ",
|
|
||||||
self.rnames[reloc.0 as usize],
|
|
||||||
ebb_offset
|
|
||||||
).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_external(&mut self, reloc: binemit::Reloc, name: &ir::ExternalName) {
|
fn reloc_external(&mut self, reloc: binemit::Reloc, name: &ir::ExternalName) {
|
||||||
write!(
|
write!(
|
||||||
self.text,
|
self.text,
|
||||||
"{}({}) ",
|
"{}({}) ",
|
||||||
self.rnames[reloc.0 as usize],
|
reloc,
|
||||||
name,
|
name,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_jt(&mut self, reloc: binemit::Reloc, jt: ir::JumpTable) {
|
fn reloc_jt(&mut self, reloc: binemit::Reloc, jt: ir::JumpTable) {
|
||||||
write!(self.text, "{}({}) ", self.rnames[reloc.0 as usize], jt).unwrap();
|
write!(self.text, "{}({}) ", reloc, jt).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +183,7 @@ impl SubTest for TestBinEmit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now emit all instructions.
|
// Now emit all instructions.
|
||||||
let mut sink = TextSink::new(isa);
|
let mut sink = TextSink::new();
|
||||||
for ebb in func.layout.ebbs() {
|
for ebb in func.layout.ebbs() {
|
||||||
divert.clear();
|
divert.clear();
|
||||||
// Correct header offsets should have been computed by `relax_branches()`.
|
// Correct header offsets should have been computed by `relax_branches()`.
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ fnaddr4 = TailRecipe(
|
|||||||
'fnaddr4', FuncAddr, size=4, ins=(), outs=GPR,
|
'fnaddr4', FuncAddr, size=4, ins=(), outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
sink.reloc_external(RelocKind::Abs4.into(),
|
sink.reloc_external(Reloc::IntelAbs4,
|
||||||
&func.dfg.ext_funcs[func_ref].name);
|
&func.dfg.ext_funcs[func_ref].name);
|
||||||
sink.put4(0);
|
sink.put4(0);
|
||||||
''')
|
''')
|
||||||
@@ -531,7 +531,7 @@ fnaddr8 = TailRecipe(
|
|||||||
'fnaddr8', FuncAddr, size=8, ins=(), outs=GPR,
|
'fnaddr8', FuncAddr, size=8, ins=(), outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
sink.reloc_external(RelocKind::Abs8.into(),
|
sink.reloc_external(Reloc::IntelAbs8,
|
||||||
&func.dfg.ext_funcs[func_ref].name);
|
&func.dfg.ext_funcs[func_ref].name);
|
||||||
sink.put8(0);
|
sink.put8(0);
|
||||||
''')
|
''')
|
||||||
@@ -541,7 +541,7 @@ allones_fnaddr4 = TailRecipe(
|
|||||||
'allones_fnaddr4', FuncAddr, size=4, ins=(), outs=GPR,
|
'allones_fnaddr4', FuncAddr, size=4, ins=(), outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
sink.reloc_external(RelocKind::Abs4.into(),
|
sink.reloc_external(Reloc::IntelAbs4,
|
||||||
&func.dfg.ext_funcs[func_ref].name);
|
&func.dfg.ext_funcs[func_ref].name);
|
||||||
// Write the immediate as `!0` for the benefit of BaldrMonkey.
|
// Write the immediate as `!0` for the benefit of BaldrMonkey.
|
||||||
sink.put4(!0);
|
sink.put4(!0);
|
||||||
@@ -552,7 +552,7 @@ allones_fnaddr8 = TailRecipe(
|
|||||||
'allones_fnaddr8', FuncAddr, size=8, ins=(), outs=GPR,
|
'allones_fnaddr8', FuncAddr, size=8, ins=(), outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
sink.reloc_external(RelocKind::Abs8.into(),
|
sink.reloc_external(Reloc::IntelAbs8,
|
||||||
&func.dfg.ext_funcs[func_ref].name);
|
&func.dfg.ext_funcs[func_ref].name);
|
||||||
// Write the immediate as `!0` for the benefit of BaldrMonkey.
|
// Write the immediate as `!0` for the benefit of BaldrMonkey.
|
||||||
sink.put8(!0);
|
sink.put8(!0);
|
||||||
@@ -563,7 +563,7 @@ gvaddr4 = TailRecipe(
|
|||||||
'gvaddr4', UnaryGlobalVar, size=4, ins=(), outs=GPR,
|
'gvaddr4', UnaryGlobalVar, size=4, ins=(), outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
sink.reloc_external(RelocKind::Abs4.into(),
|
sink.reloc_external(Reloc::IntelAbs4,
|
||||||
&func.global_vars[global_var].symbol_name());
|
&func.global_vars[global_var].symbol_name());
|
||||||
sink.put4(0);
|
sink.put4(0);
|
||||||
''')
|
''')
|
||||||
@@ -573,7 +573,7 @@ gvaddr8 = TailRecipe(
|
|||||||
'gvaddr8', UnaryGlobalVar, size=8, ins=(), outs=GPR,
|
'gvaddr8', UnaryGlobalVar, size=8, ins=(), outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
sink.reloc_external(RelocKind::Abs8.into(),
|
sink.reloc_external(Reloc::IntelAbs8,
|
||||||
&func.global_vars[global_var].symbol_name());
|
&func.global_vars[global_var].symbol_name());
|
||||||
sink.put8(0);
|
sink.put8(0);
|
||||||
''')
|
''')
|
||||||
@@ -848,7 +848,7 @@ call_id = TailRecipe(
|
|||||||
'call_id', Call, size=4, ins=(), outs=(),
|
'call_id', Call, size=4, ins=(), outs=(),
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, BASE_REX, sink);
|
PUT_OP(bits, BASE_REX, sink);
|
||||||
sink.reloc_external(RelocKind::PCRel4.into(),
|
sink.reloc_external(Reloc::IntelPCRel4,
|
||||||
&func.dfg.ext_funcs[func_ref].name);
|
&func.dfg.ext_funcs[func_ref].name);
|
||||||
sink.put4(0);
|
sink.put4(0);
|
||||||
''')
|
''')
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ UJ = EncRecipe(
|
|||||||
UJcall = EncRecipe(
|
UJcall = EncRecipe(
|
||||||
'UJcall', Call, size=4, ins=(), outs=(),
|
'UJcall', Call, size=4, ins=(), outs=(),
|
||||||
emit='''
|
emit='''
|
||||||
sink.reloc_external(RelocKind::Call.into(),
|
sink.reloc_external(Reloc::RiscvCall,
|
||||||
&func.dfg.ext_funcs[func_ref].name);
|
&func.dfg.ext_funcs[func_ref].name);
|
||||||
// rd=%x1 is the standard link register.
|
// rd=%x1 is the standard link register.
|
||||||
put_uj(bits, 0, 1, sink);
|
put_uj(bits, 0, 1, sink);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub use self::memorysink::{MemoryCodeSink, RelocSink};
|
|||||||
|
|
||||||
use ir::{ExternalName, JumpTable, Function, Inst};
|
use ir::{ExternalName, JumpTable, Function, Inst};
|
||||||
use regalloc::RegDiversions;
|
use regalloc::RegDiversions;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
/// Offset in bytes from the beginning of the function.
|
/// Offset in bytes from the beginning of the function.
|
||||||
///
|
///
|
||||||
@@ -18,8 +19,35 @@ use regalloc::RegDiversions;
|
|||||||
/// depends on the *host* platform, not the *target* platform.
|
/// depends on the *host* platform, not the *target* platform.
|
||||||
pub type CodeOffset = u32;
|
pub type CodeOffset = u32;
|
||||||
|
|
||||||
/// Relocation kinds depend on the current ISA.
|
/// Relocation kinds for every ISA
|
||||||
pub struct Reloc(pub u16);
|
#[derive(Debug)]
|
||||||
|
pub enum Reloc {
|
||||||
|
/// Intel PC-relative 4-byte
|
||||||
|
IntelPCRel4,
|
||||||
|
/// Intel absolute 4-byte
|
||||||
|
IntelAbs4,
|
||||||
|
/// Intel absolute 8-byte
|
||||||
|
IntelAbs8,
|
||||||
|
/// Arm32 call target
|
||||||
|
Arm32Call,
|
||||||
|
/// Arm64 call target
|
||||||
|
Arm64Call,
|
||||||
|
/// RISC-V call target
|
||||||
|
RiscvCall,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Reloc {
|
||||||
|
/// Display trait implementation drops the arch, since its used in contexts where the arch is
|
||||||
|
/// already unambigious, e.g. cton syntax with isa specified. In other contexts, use Debug.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Reloc::IntelPCRel4 => write!(f, "{}", "PCRel4"),
|
||||||
|
Reloc::IntelAbs4 => write!(f, "{}", "Abs4"),
|
||||||
|
Reloc::IntelAbs8 => write!(f, "{}", "Abs8"),
|
||||||
|
Reloc::Arm32Call | Reloc::Arm64Call | Reloc::RiscvCall => write!(f, "{}", "Call"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Abstract interface for adding bytes to the code segment.
|
/// Abstract interface for adding bytes to the code segment.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -5,5 +5,3 @@ use ir::{Function, Inst};
|
|||||||
use regalloc::RegDiversions;
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-arm32.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-arm32.rs"));
|
||||||
|
|
||||||
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
|
|
||||||
|
|||||||
@@ -107,8 +107,4 @@ impl TargetIsa for Isa {
|
|||||||
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
emit_function(func, binemit::emit_inst, sink)
|
emit_function(func, binemit::emit_inst, sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_names(&self) -> &'static [&'static str] {
|
|
||||||
&binemit::RELOC_NAMES
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,5 +5,3 @@ use ir::{Function, Inst};
|
|||||||
use regalloc::RegDiversions;
|
use regalloc::RegDiversions;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-arm64.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-arm64.rs"));
|
||||||
|
|
||||||
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
|
|
||||||
|
|||||||
@@ -100,8 +100,4 @@ impl TargetIsa for Isa {
|
|||||||
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
emit_function(func, binemit::emit_inst, sink)
|
emit_function(func, binemit::emit_inst, sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_names(&self) -> &'static [&'static str] {
|
|
||||||
&binemit::RELOC_NAMES
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,26 +9,6 @@ use super::registers::RU;
|
|||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
||||||
|
|
||||||
/// Intel relocations.
|
|
||||||
pub enum RelocKind {
|
|
||||||
/// A 4-byte relative function reference. Based from relocation + 4 bytes.
|
|
||||||
PCRel4,
|
|
||||||
|
|
||||||
/// A 4-byte absolute function reference.
|
|
||||||
Abs4,
|
|
||||||
|
|
||||||
/// An 8-byte absolute function reference.
|
|
||||||
Abs8,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static RELOC_NAMES: [&'static str; 3] = ["PCRel4", "Abs4", "Abs8"];
|
|
||||||
|
|
||||||
impl Into<Reloc> for RelocKind {
|
|
||||||
fn into(self) -> Reloc {
|
|
||||||
Reloc(self as u16)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a stack base to the corresponding register.
|
// Convert a stack base to the corresponding register.
|
||||||
fn stk_base(base: StackBase) -> RegUnit {
|
fn stk_base(base: StackBase) -> RegUnit {
|
||||||
let ru = match base {
|
let ru = match base {
|
||||||
|
|||||||
@@ -111,10 +111,6 @@ impl TargetIsa for Isa {
|
|||||||
emit_function(func, binemit::emit_inst, sink)
|
emit_function(func, binemit::emit_inst, sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_names(&self) -> &'static [&'static str] {
|
|
||||||
&binemit::RELOC_NAMES
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
|
fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
|
||||||
let _tt = timing::prologue_epilogue();
|
let _tt = timing::prologue_epilogue();
|
||||||
abi::prologue_epilogue(func, self)
|
abi::prologue_epilogue(func, self)
|
||||||
|
|||||||
@@ -272,10 +272,4 @@ pub trait TargetIsa {
|
|||||||
///
|
///
|
||||||
/// This is more performant than calling `emit_inst` for each instruction.
|
/// This is more performant than calling `emit_inst` for each instruction.
|
||||||
fn emit_function(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
|
fn emit_function(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);
|
||||||
|
|
||||||
/// Get a static array of names associated with relocations in this ISA.
|
|
||||||
///
|
|
||||||
/// This array can be indexed by the contents of `binemit::Reloc` objects passed to a
|
|
||||||
/// `CodeSink`.
|
|
||||||
fn reloc_names(&self) -> &'static [&'static str];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,20 +9,6 @@ use std::u32;
|
|||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs"));
|
include!(concat!(env!("OUT_DIR"), "/binemit-riscv.rs"));
|
||||||
|
|
||||||
/// RISC-V relocation kinds.
|
|
||||||
pub enum RelocKind {
|
|
||||||
/// A jal call to a function.
|
|
||||||
Call,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static RELOC_NAMES: [&'static str; 1] = ["Call"];
|
|
||||||
|
|
||||||
impl Into<Reloc> for RelocKind {
|
|
||||||
fn into(self) -> Reloc {
|
|
||||||
Reloc(self as u16)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// R-type instructions.
|
/// R-type instructions.
|
||||||
///
|
///
|
||||||
/// 31 24 19 14 11 6
|
/// 31 24 19 14 11 6
|
||||||
|
|||||||
@@ -107,10 +107,6 @@ impl TargetIsa for Isa {
|
|||||||
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
|
||||||
emit_function(func, binemit::emit_inst, sink)
|
emit_function(func, binemit::emit_inst, sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_names(&self) -> &'static [&'static str] {
|
|
||||||
&binemit::RELOC_NAMES
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user