Addresses #3809: when we are asked to create a Cranelift backend with shared flags that indicate support for SIMD, we should check that the ISA level needed for our SIMD lowerings is present.
200 lines
6.0 KiB
Rust
200 lines
6.0 KiB
Rust
//! Unwind information for System V ABI (s390x).
|
|
|
|
use crate::isa::unwind::systemv::RegisterMappingError;
|
|
use gimli::{write::CommonInformationEntry, Encoding, Format, Register};
|
|
use regalloc::{Reg, RegClass};
|
|
|
|
/// Creates a new s390x common information entry (CIE).
|
|
pub fn create_cie() -> CommonInformationEntry {
|
|
use gimli::write::CallFrameInstruction;
|
|
|
|
let mut entry = CommonInformationEntry::new(
|
|
Encoding {
|
|
address_size: 8,
|
|
format: Format::Dwarf32,
|
|
version: 1,
|
|
},
|
|
1, // Code alignment factor
|
|
-8, // Data alignment factor
|
|
Register(14), // Return address column - register %r14
|
|
);
|
|
|
|
// Every frame will start with the call frame address (CFA) at %r15 + 160.
|
|
entry.add_instruction(CallFrameInstruction::Cfa(Register(15), 160));
|
|
|
|
entry
|
|
}
|
|
|
|
/// Map Cranelift registers to their corresponding Gimli registers.
|
|
pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
|
|
const GPR_MAP: [gimli::Register; 16] = [
|
|
Register(0),
|
|
Register(1),
|
|
Register(2),
|
|
Register(3),
|
|
Register(4),
|
|
Register(5),
|
|
Register(6),
|
|
Register(7),
|
|
Register(8),
|
|
Register(9),
|
|
Register(10),
|
|
Register(11),
|
|
Register(12),
|
|
Register(13),
|
|
Register(14),
|
|
Register(15),
|
|
];
|
|
const FPR_MAP: [gimli::Register; 16] = [
|
|
Register(16),
|
|
Register(20),
|
|
Register(17),
|
|
Register(21),
|
|
Register(18),
|
|
Register(22),
|
|
Register(19),
|
|
Register(23),
|
|
Register(24),
|
|
Register(28),
|
|
Register(25),
|
|
Register(29),
|
|
Register(26),
|
|
Register(30),
|
|
Register(27),
|
|
Register(31),
|
|
];
|
|
|
|
match reg.get_class() {
|
|
RegClass::I64 => Ok(GPR_MAP[reg.get_hw_encoding() as usize]),
|
|
RegClass::F64 => Ok(FPR_MAP[reg.get_hw_encoding() as usize]),
|
|
_ => Err(RegisterMappingError::UnsupportedRegisterBank("class?")),
|
|
}
|
|
}
|
|
|
|
pub(crate) struct RegisterMapper;
|
|
|
|
impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
|
|
fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
|
|
Ok(map_reg(reg)?.0)
|
|
}
|
|
fn sp(&self) -> u16 {
|
|
Register(15).0
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::cursor::{Cursor, FuncCursor};
|
|
use crate::ir::{
|
|
types, AbiParam, ExternalName, Function, InstBuilder, Signature, StackSlotData,
|
|
StackSlotKind,
|
|
};
|
|
use crate::isa::{lookup, CallConv};
|
|
use crate::settings::{builder, Flags};
|
|
use crate::Context;
|
|
use gimli::write::Address;
|
|
use std::str::FromStr;
|
|
use target_lexicon::triple;
|
|
|
|
#[test]
|
|
fn test_simple_func() {
|
|
let isa = lookup(triple!("s390x"))
|
|
.expect("expect s390x ISA")
|
|
.finish(Flags::new(builder()))
|
|
.expect("Creating compiler backend");
|
|
|
|
let mut context = Context::for_function(create_function(
|
|
CallConv::SystemV,
|
|
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
|
|
));
|
|
|
|
context.compile(&*isa).expect("expected compilation");
|
|
|
|
let fde = match context
|
|
.create_unwind_info(isa.as_ref())
|
|
.expect("can create unwind info")
|
|
{
|
|
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
|
|
info.to_fde(Address::Constant(1234))
|
|
}
|
|
_ => panic!("expected unwind information"),
|
|
};
|
|
|
|
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(1234), length: 10, lsda: None, instructions: [(4, CfaOffset(224))] }");
|
|
}
|
|
|
|
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
|
|
let mut func =
|
|
Function::with_name_signature(ExternalName::user(0, 0), Signature::new(call_conv));
|
|
|
|
let block0 = func.dfg.make_block();
|
|
let mut pos = FuncCursor::new(&mut func);
|
|
pos.insert_block(block0);
|
|
pos.ins().return_(&[]);
|
|
|
|
if let Some(stack_slot) = stack_slot {
|
|
func.stack_slots.push(stack_slot);
|
|
}
|
|
|
|
func
|
|
}
|
|
|
|
#[test]
|
|
fn test_multi_return_func() {
|
|
let isa = lookup(triple!("s390x"))
|
|
.expect("expect s390x ISA")
|
|
.finish(Flags::new(builder()))
|
|
.expect("Creating compiler backend");
|
|
|
|
let mut context = Context::for_function(create_multi_return_function(
|
|
CallConv::SystemV,
|
|
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64)),
|
|
));
|
|
|
|
context.compile(&*isa).expect("expected compilation");
|
|
|
|
let fde = match context
|
|
.create_unwind_info(isa.as_ref())
|
|
.expect("can create unwind info")
|
|
{
|
|
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
|
|
info.to_fde(Address::Constant(4321))
|
|
}
|
|
_ => panic!("expected unwind information"),
|
|
};
|
|
|
|
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(4321), length: 26, lsda: None, instructions: [(4, CfaOffset(224))] }");
|
|
}
|
|
|
|
fn create_multi_return_function(
|
|
call_conv: CallConv,
|
|
stack_slot: Option<StackSlotData>,
|
|
) -> Function {
|
|
let mut sig = Signature::new(call_conv);
|
|
sig.params.push(AbiParam::new(types::I32));
|
|
let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
|
|
|
|
let block0 = func.dfg.make_block();
|
|
let v0 = func.dfg.append_block_param(block0, types::I32);
|
|
let block1 = func.dfg.make_block();
|
|
let block2 = func.dfg.make_block();
|
|
|
|
let mut pos = FuncCursor::new(&mut func);
|
|
pos.insert_block(block0);
|
|
pos.ins().brnz(v0, block2, &[]);
|
|
pos.ins().jump(block1, &[]);
|
|
|
|
pos.insert_block(block1);
|
|
pos.ins().return_(&[]);
|
|
|
|
pos.insert_block(block2);
|
|
pos.ins().return_(&[]);
|
|
|
|
if let Some(stack_slot) = stack_slot {
|
|
func.stack_slots.push(stack_slot);
|
|
}
|
|
|
|
func
|
|
}
|
|
}
|