This PR updates the AArch64 ABI implementation so that it (i) properly respects that v8-v15 inclusive have callee-save lower halves, and caller-save upper halves, by conservatively approximating (to full registers) in the appropriate directions when generating prologue caller-saves and when informing the regalloc of clobbered regs across callsites. In order to prevent saving all of these vector registers in the prologue of every non-leaf function due to the above approximation, this also makes use of a new regalloc.rs feature to exclude call instructions' writes from the clobber set returned by register allocation. This is safe whenever the caller and callee have the same ABI (because anything the callee could clobber, the caller is allowed to clobber as well without saving it in the prologue). Fixes #2254.
122 lines
3.1 KiB
Rust
122 lines
3.1 KiB
Rust
//! 32-bit ARM Instruction Set Architecture.
|
|
|
|
use crate::ir::condcodes::IntCC;
|
|
use crate::ir::Function;
|
|
use crate::isa::Builder as IsaBuilder;
|
|
use crate::machinst::{compile, MachBackend, MachCompileResult, TargetIsaAdapter, VCode};
|
|
use crate::result::CodegenResult;
|
|
use crate::settings;
|
|
|
|
use alloc::boxed::Box;
|
|
use regalloc::{PrettyPrint, RealRegUniverse};
|
|
use target_lexicon::{Architecture, ArmArchitecture, Triple};
|
|
|
|
// New backend:
|
|
mod abi;
|
|
mod inst;
|
|
mod lower;
|
|
mod lower_inst;
|
|
|
|
use inst::create_reg_universe;
|
|
|
|
/// An ARM32 backend.
|
|
pub struct Arm32Backend {
|
|
triple: Triple,
|
|
flags: settings::Flags,
|
|
reg_universe: RealRegUniverse,
|
|
}
|
|
|
|
impl Arm32Backend {
|
|
/// Create a new ARM32 backend with the given (shared) flags.
|
|
pub fn new_with_flags(triple: Triple, flags: settings::Flags) -> Arm32Backend {
|
|
let reg_universe = create_reg_universe();
|
|
Arm32Backend {
|
|
triple,
|
|
flags,
|
|
reg_universe,
|
|
}
|
|
}
|
|
|
|
fn compile_vcode(
|
|
&self,
|
|
func: &Function,
|
|
flags: settings::Flags,
|
|
) -> CodegenResult<VCode<inst::Inst>> {
|
|
// This performs lowering to VCode, register-allocates the code, computes
|
|
// block layout and finalizes branches. The result is ready for binary emission.
|
|
let abi = Box::new(abi::Arm32ABICallee::new(func, flags)?);
|
|
compile::compile::<Arm32Backend>(func, self, abi)
|
|
}
|
|
}
|
|
|
|
impl MachBackend for Arm32Backend {
|
|
fn compile_function(
|
|
&self,
|
|
func: &Function,
|
|
want_disasm: bool,
|
|
) -> CodegenResult<MachCompileResult> {
|
|
let flags = self.flags();
|
|
let vcode = self.compile_vcode(func, flags.clone())?;
|
|
let buffer = vcode.emit();
|
|
let frame_size = vcode.frame_size();
|
|
|
|
let disasm = if want_disasm {
|
|
Some(vcode.show_rru(Some(&create_reg_universe())))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let buffer = buffer.finish();
|
|
|
|
Ok(MachCompileResult {
|
|
buffer,
|
|
frame_size,
|
|
disasm,
|
|
})
|
|
}
|
|
|
|
fn name(&self) -> &'static str {
|
|
"arm32"
|
|
}
|
|
|
|
fn triple(&self) -> Triple {
|
|
self.triple.clone()
|
|
}
|
|
|
|
fn flags(&self) -> &settings::Flags {
|
|
&self.flags
|
|
}
|
|
|
|
fn reg_universe(&self) -> &RealRegUniverse {
|
|
&self.reg_universe
|
|
}
|
|
|
|
fn unsigned_add_overflow_condition(&self) -> IntCC {
|
|
// Carry flag set.
|
|
IntCC::UnsignedGreaterThanOrEqual
|
|
}
|
|
|
|
fn unsigned_sub_overflow_condition(&self) -> IntCC {
|
|
// Carry flag clear.
|
|
IntCC::UnsignedLessThan
|
|
}
|
|
}
|
|
|
|
/// Create a new `isa::Builder`.
|
|
pub fn isa_builder(triple: Triple) -> IsaBuilder {
|
|
assert!(match triple.architecture {
|
|
Architecture::Arm(ArmArchitecture::Arm)
|
|
| Architecture::Arm(ArmArchitecture::Armv7)
|
|
| Architecture::Arm(ArmArchitecture::Armv6) => true,
|
|
_ => false,
|
|
});
|
|
IsaBuilder {
|
|
triple,
|
|
setup: settings::builder(),
|
|
constructor: |triple, shared_flags, _| {
|
|
let backend = Arm32Backend::new_with_flags(triple, shared_flags);
|
|
Box::new(TargetIsaAdapter::new(backend))
|
|
},
|
|
}
|
|
}
|