asm: Allow the use of r8-r14 as clobbers on Thumb1
Previously these were entirely disallowed, except for r11 which was allowed by accident.
This commit is contained in:
parent
930fc4f59d
commit
11250b8661
7 changed files with 97 additions and 46 deletions
|
@ -129,13 +129,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
.operands
|
.operands
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(op, op_sp)| {
|
.map(|(op, op_sp)| {
|
||||||
let lower_reg = |reg| match reg {
|
let lower_reg = |reg, is_clobber| match reg {
|
||||||
InlineAsmRegOrRegClass::Reg(s) => {
|
InlineAsmRegOrRegClass::Reg(s) => {
|
||||||
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
||||||
asm::InlineAsmReg::parse(
|
asm::InlineAsmReg::parse(
|
||||||
asm_arch,
|
asm_arch,
|
||||||
&sess.target_features,
|
&sess.target_features,
|
||||||
&sess.target,
|
&sess.target,
|
||||||
|
is_clobber,
|
||||||
s,
|
s,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
|
@ -162,24 +163,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
let op = match *op {
|
let op = match *op {
|
||||||
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
||||||
reg: lower_reg(reg),
|
reg: lower_reg(reg, false),
|
||||||
expr: self.lower_expr_mut(expr),
|
expr: self.lower_expr_mut(expr),
|
||||||
},
|
},
|
||||||
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
||||||
reg: lower_reg(reg),
|
reg: lower_reg(reg, expr.is_none()),
|
||||||
late,
|
late,
|
||||||
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||||
},
|
},
|
||||||
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
||||||
hir::InlineAsmOperand::InOut {
|
hir::InlineAsmOperand::InOut {
|
||||||
reg: lower_reg(reg),
|
reg: lower_reg(reg, false),
|
||||||
late,
|
late,
|
||||||
expr: self.lower_expr_mut(expr),
|
expr: self.lower_expr_mut(expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
||||||
hir::InlineAsmOperand::SplitInOut {
|
hir::InlineAsmOperand::SplitInOut {
|
||||||
reg: lower_reg(reg),
|
reg: lower_reg(reg, false),
|
||||||
late,
|
late,
|
||||||
in_expr: self.lower_expr_mut(in_expr),
|
in_expr: self.lower_expr_mut(in_expr),
|
||||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||||
|
|
|
@ -77,6 +77,7 @@ pub fn reserved_x18(
|
||||||
_arch: InlineAsmArch,
|
_arch: InlineAsmArch,
|
||||||
_target_features: &FxHashSet<Symbol>,
|
_target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if target.os == "android"
|
if target.os == "android"
|
||||||
|| target.is_like_fuchsia
|
|| target.is_like_fuchsia
|
||||||
|
|
|
@ -66,10 +66,13 @@ fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_pointer_r11(
|
fn frame_pointer_r11(
|
||||||
_arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
|
is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
|
not_thumb1(arch, target_features, target, is_clobber)?;
|
||||||
|
|
||||||
if !frame_pointer_is_r7(target_features, target) {
|
if !frame_pointer_is_r7(target_features, target) {
|
||||||
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
|
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,6 +84,7 @@ fn frame_pointer_r7(
|
||||||
_arch: InlineAsmArch,
|
_arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if frame_pointer_is_r7(target_features, target) {
|
if frame_pointer_is_r7(target_features, target) {
|
||||||
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
|
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
|
||||||
|
@ -93,9 +97,13 @@ fn not_thumb1(
|
||||||
_arch: InlineAsmArch,
|
_arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if target_features.contains(&sym::thumb_mode) && !target_features.contains(&sym::thumb2) {
|
if !is_clobber
|
||||||
Err("high registers (r8+) cannot be used in Thumb-1 code")
|
&& target_features.contains(&sym::thumb_mode)
|
||||||
|
&& !target_features.contains(&sym::thumb2)
|
||||||
|
{
|
||||||
|
Err("high registers (r8+) can only be used as clobbers in Thumb-1 code")
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -105,8 +113,9 @@ fn reserved_r9(
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
|
is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
not_thumb1(arch, target_features, target)?;
|
not_thumb1(arch, target_features, target, is_clobber)?;
|
||||||
|
|
||||||
// We detect this using the reserved-r9 feature instead of using the target
|
// We detect this using the reserved-r9 feature instead of using the target
|
||||||
// because the relocation model can be changed with compiler options.
|
// because the relocation model can be changed with compiler options.
|
||||||
|
|
|
@ -47,6 +47,7 @@ fn only_alu32(
|
||||||
_arch: InlineAsmArch,
|
_arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if !target_features.contains(&sym::alu32) {
|
if !target_features.contains(&sym::alu32) {
|
||||||
Err("register can't be used without the `alu32` target feature")
|
Err("register can't be used without the `alu32` target feature")
|
||||||
|
|
|
@ -83,12 +83,13 @@ macro_rules! def_regs {
|
||||||
_arch: super::InlineAsmArch,
|
_arch: super::InlineAsmArch,
|
||||||
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
|
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
|
||||||
_target: &crate::spec::Target,
|
_target: &crate::spec::Target,
|
||||||
|
_is_clobber: bool,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<Self, &'static str> {
|
) -> Result<Self, &'static str> {
|
||||||
match name {
|
match name {
|
||||||
$(
|
$(
|
||||||
$($alias)|* | $reg_name => {
|
$($alias)|* | $reg_name => {
|
||||||
$($filter(_arch, _target_features, _target)?;)?
|
$($filter(_arch, _target_features, _target, _is_clobber)?;)?
|
||||||
Ok(Self::$reg)
|
Ok(Self::$reg)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -112,7 +113,7 @@ macro_rules! def_regs {
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use super::{InlineAsmReg, InlineAsmRegClass};
|
use super::{InlineAsmReg, InlineAsmRegClass};
|
||||||
$(
|
$(
|
||||||
if $($filter(_arch, _target_features, _target).is_ok() &&)? true {
|
if $($filter(_arch, _target_features, _target, false).is_ok() &&)? true {
|
||||||
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
||||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||||
}
|
}
|
||||||
|
@ -298,6 +299,7 @@ impl InlineAsmReg {
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
|
is_clobber: bool,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
) -> Result<Self, &'static str> {
|
) -> Result<Self, &'static str> {
|
||||||
// FIXME: use direct symbol comparison for register names
|
// FIXME: use direct symbol comparison for register names
|
||||||
|
@ -305,47 +307,79 @@ impl InlineAsmReg {
|
||||||
let name = name.as_str();
|
let name = name.as_str();
|
||||||
Ok(match arch {
|
Ok(match arch {
|
||||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||||
Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?)
|
Self::X86(X86InlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||||
}
|
}
|
||||||
InlineAsmArch::Arm => {
|
InlineAsmArch::Arm => {
|
||||||
Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?)
|
Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||||
}
|
|
||||||
InlineAsmArch::AArch64 => {
|
|
||||||
Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
|
||||||
Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::Nvptx64 => {
|
|
||||||
Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
|
|
||||||
Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::Hexagon => {
|
|
||||||
Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
|
|
||||||
Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::S390x => {
|
|
||||||
Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::SpirV => {
|
|
||||||
Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
|
|
||||||
Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
}
|
||||||
|
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
|
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => Self::RiscV(
|
||||||
|
RiscVInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?,
|
||||||
|
),
|
||||||
|
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
|
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => Self::PowerPC(
|
||||||
|
PowerPCInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?,
|
||||||
|
),
|
||||||
|
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
|
InlineAsmArch::Mips | InlineAsmArch::Mips64 => Self::Mips(MipsInlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
|
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
|
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
|
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => Self::Wasm(WasmInlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
InlineAsmArch::Bpf => {
|
InlineAsmArch::Bpf => {
|
||||||
Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?)
|
Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||||
}
|
}
|
||||||
InlineAsmArch::Avr => {
|
InlineAsmArch::Avr => {
|
||||||
Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
|
Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||||
}
|
|
||||||
InlineAsmArch::Msp430 => {
|
|
||||||
Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?)
|
|
||||||
}
|
}
|
||||||
|
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(
|
||||||
|
arch,
|
||||||
|
target_features,
|
||||||
|
target,
|
||||||
|
is_clobber,
|
||||||
|
name,
|
||||||
|
)?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,7 +878,7 @@ impl InlineAsmClobberAbi {
|
||||||
},
|
},
|
||||||
InlineAsmArch::AArch64 => match name {
|
InlineAsmArch::AArch64 => match name {
|
||||||
"C" | "system" | "efiapi" => {
|
"C" | "system" | "efiapi" => {
|
||||||
Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() {
|
Ok(if aarch64::reserved_x18(arch, target_features, target, true).is_err() {
|
||||||
InlineAsmClobberAbi::AArch64NoX18
|
InlineAsmClobberAbi::AArch64NoX18
|
||||||
} else {
|
} else {
|
||||||
InlineAsmClobberAbi::AArch64
|
InlineAsmClobberAbi::AArch64
|
||||||
|
|
|
@ -56,6 +56,7 @@ fn not_e(
|
||||||
_arch: InlineAsmArch,
|
_arch: InlineAsmArch,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if target_features.contains(&sym::e) {
|
if target_features.contains(&sym::e) {
|
||||||
Err("register can't be used with the `e` target feature")
|
Err("register can't be used with the `e` target feature")
|
||||||
|
|
|
@ -141,6 +141,7 @@ fn x86_64_only(
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
_target_features: &FxHashSet<Symbol>,
|
_target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
match arch {
|
match arch {
|
||||||
InlineAsmArch::X86 => Err("register is only available on x86_64"),
|
InlineAsmArch::X86 => Err("register is only available on x86_64"),
|
||||||
|
@ -153,6 +154,7 @@ fn high_byte(
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
_target_features: &FxHashSet<Symbol>,
|
_target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
match arch {
|
match arch {
|
||||||
InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
|
InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
|
||||||
|
@ -164,6 +166,7 @@ fn rbx_reserved(
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
_target_features: &FxHashSet<Symbol>,
|
_target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
match arch {
|
match arch {
|
||||||
InlineAsmArch::X86 => Ok(()),
|
InlineAsmArch::X86 => Ok(()),
|
||||||
|
@ -178,6 +181,7 @@ fn esi_reserved(
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
_target_features: &FxHashSet<Symbol>,
|
_target_features: &FxHashSet<Symbol>,
|
||||||
_target: &Target,
|
_target: &Target,
|
||||||
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
match arch {
|
match arch {
|
||||||
InlineAsmArch::X86 => {
|
InlineAsmArch::X86 => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue