1
Fork 0

Support clobber_abi and vector/access registers (clobber-only) in s390x inline assembly

This commit is contained in:
Taiki Endo 2024-09-21 01:51:26 +09:00
parent 1a5a2240bc
commit fa125e2be6
7 changed files with 200 additions and 12 deletions

View file

@ -439,7 +439,7 @@ impl InlineAsmReg {
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
Self::LoongArch(_) => cb(self),
Self::Mips(_) => cb(self),
Self::S390x(_) => cb(self),
Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
Self::Msp430(_) => cb(self),
@ -892,6 +892,7 @@ pub enum InlineAsmClobberAbi {
AArch64NoX18,
RiscV,
LoongArch,
S390x,
}
impl InlineAsmClobberAbi {
@ -941,6 +942,10 @@ impl InlineAsmClobberAbi {
"C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
_ => Err(&["C", "system"]),
},
InlineAsmArch::S390x => match name {
"C" | "system" => Ok(InlineAsmClobberAbi::S390x),
_ => Err(&["C", "system"]),
},
_ => Err(&[]),
}
}
@ -1098,6 +1103,28 @@ impl InlineAsmClobberAbi {
f16, f17, f18, f19, f20, f21, f22, f23,
}
},
InlineAsmClobberAbi::S390x => clobbered_regs! {
S390x S390xInlineAsmReg {
r0, r1, r2, r3, r4, r5,
r14,
// f0-f7, v0-v7
f0, f1, f2, f3, f4, f5, f6, f7,
v0, v1, v2, v3, v4, v5, v6, v7,
// Technically the left halves of v8-v15 (i.e., f8-f15) are saved, but
// we have no way of expressing this using clobbers.
v8, v9, v10, v11, v12, v13, v14, v15,
// Other vector registers are volatile
v16, v17, v18, v19, v20, v21, v22, v23,
v24, v25, v26, v27, v28, v29, v30, v31,
// a0-a1 are reserved, other access registers are volatile
a2, a3, a4, a5, a6, a7,
a8, a9, a10, a11, a12, a13, a14, a15,
}
},
}
}
}

View file

@ -9,6 +9,8 @@ def_reg_class! {
reg,
reg_addr,
freg,
vreg,
areg,
}
}
@ -35,11 +37,13 @@ impl S390xInlineAsmRegClass {
pub fn supported_types(
self,
arch: InlineAsmArch,
_arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<Symbol>)] {
match (self, arch) {
(Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; },
(Self::freg, _) => types! { _: F32, F64; },
match self {
Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; },
Self::freg => types! { _: F32, F64; },
Self::vreg => &[],
Self::areg => &[],
}
}
}
@ -76,6 +80,52 @@ def_regs! {
f13: freg = ["f13"],
f14: freg = ["f14"],
f15: freg = ["f15"],
v0: vreg = ["v0"],
v1: vreg = ["v1"],
v2: vreg = ["v2"],
v3: vreg = ["v3"],
v4: vreg = ["v4"],
v5: vreg = ["v5"],
v6: vreg = ["v6"],
v7: vreg = ["v7"],
v8: vreg = ["v8"],
v9: vreg = ["v9"],
v10: vreg = ["v10"],
v11: vreg = ["v11"],
v12: vreg = ["v12"],
v13: vreg = ["v13"],
v14: vreg = ["v14"],
v15: vreg = ["v15"],
v16: vreg = ["v16"],
v17: vreg = ["v17"],
v18: vreg = ["v18"],
v19: vreg = ["v19"],
v20: vreg = ["v20"],
v21: vreg = ["v21"],
v22: vreg = ["v22"],
v23: vreg = ["v23"],
v24: vreg = ["v24"],
v25: vreg = ["v25"],
v26: vreg = ["v26"],
v27: vreg = ["v27"],
v28: vreg = ["v28"],
v29: vreg = ["v29"],
v30: vreg = ["v30"],
v31: vreg = ["v31"],
a2: areg = ["a2"],
a3: areg = ["a3"],
a4: areg = ["a4"],
a5: areg = ["a5"],
a6: areg = ["a6"],
a7: areg = ["a7"],
a8: areg = ["a8"],
a9: areg = ["a9"],
a10: areg = ["a10"],
a11: areg = ["a11"],
a12: areg = ["a12"],
a13: areg = ["a13"],
a14: areg = ["a14"],
a15: areg = ["a15"],
#error = ["r11"] =>
"The frame pointer cannot be used as an operand for inline asm",
#error = ["r15"] =>
@ -87,13 +137,8 @@ def_regs! {
"c12", "c13", "c14", "c15"
] =>
"control registers are reserved by the kernel and cannot be used as operands for inline asm",
#error = [
"a0", "a1", "a2", "a3",
"a4", "a5", "a6", "a7",
"a8", "a9", "a10", "a11",
"a12", "a13", "a14", "a15"
] =>
"access registers are not supported and cannot be used as operands for inline asm",
#error = ["a0", "a1"] =>
"a0 and a1 are reserved for system use and cannot be used as operands for inline asm",
}
}
@ -106,4 +151,48 @@ impl S390xInlineAsmReg {
) -> fmt::Result {
write!(out, "%{}", self.name())
}
pub fn overlapping_regs(self, mut cb: impl FnMut(S390xInlineAsmReg)) {
macro_rules! reg_conflicts {
(
$(
$full:ident : $($field:ident)*
),*;
) => {
match self {
$(
Self::$full => {
cb(Self::$full);
$(cb(Self::$field);)*
}
$(Self::$field)|* => {
cb(Self::$full);
cb(self);
}
)*
r => cb(r),
}
};
}
// The left halves of v0-v15 are aliased to f0-f15.
reg_conflicts! {
v0 : f0,
v1 : f1,
v2 : f2,
v3 : f3,
v4 : f4,
v5 : f5,
v6 : f6,
v7 : f7,
v8 : f8,
v9 : f9,
v10 : f10,
v11 : f11,
v12 : f12,
v13 : f13,
v14 : f14,
v15 : f15;
}
}
}