1
Fork 0

Rollup merge of #94169 - Amanieu:asm_stuff, r=nagisa

Fix several asm! related issues

This is a combination of several fixes, each split into a separate commit. Splitting these into PRs is not practical since they conflict with each other.

Fixes #92378
Fixes #85247

r? ``@nagisa``
This commit is contained in:
Matthias Krüger 2022-02-22 12:16:28 +01:00 committed by GitHub
commit 1cf2e6993e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 292 additions and 237 deletions

View file

@ -64,12 +64,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let mut clobber_abis = FxHashMap::default();
if let Some(asm_arch) = asm_arch {
for (abi_name, abi_span) in &asm.clobber_abis {
match asm::InlineAsmClobberAbi::parse(
asm_arch,
&self.sess.target_features,
&self.sess.target,
*abi_name,
) {
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
Ok(abi) => {
// If the abi was already in the list, emit an error
match clobber_abis.get(&abi) {
@ -129,17 +124,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
.operands
.iter()
.map(|(op, op_sp)| {
let lower_reg = |reg, is_clobber| match reg {
let lower_reg = |reg| match reg {
InlineAsmRegOrRegClass::Reg(s) => {
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
asm::InlineAsmReg::parse(
asm_arch,
&sess.target_features,
&sess.target,
is_clobber,
s,
)
.unwrap_or_else(|e| {
asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| {
let msg = format!("invalid register `{}`: {}", s.as_str(), e);
sess.struct_span_err(*op_sp, &msg).emit();
asm::InlineAsmReg::Err
@ -163,24 +151,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let op = match *op {
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
reg: lower_reg(reg, false),
reg: lower_reg(reg),
expr: self.lower_expr_mut(expr),
},
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
reg: lower_reg(reg, expr.is_none()),
reg: lower_reg(reg),
late,
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
},
InlineAsmOperand::InOut { reg, late, ref expr } => {
hir::InlineAsmOperand::InOut {
reg: lower_reg(reg, false),
reg: lower_reg(reg),
late,
expr: self.lower_expr_mut(expr),
}
}
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
hir::InlineAsmOperand::SplitInOut {
reg: lower_reg(reg, false),
reg: lower_reg(reg),
late,
in_expr: self.lower_expr_mut(in_expr),
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),

View file

@ -106,6 +106,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
let mut asm_gen = InlineAssemblyGenerator {
tcx: fx.tcx,
arch: fx.tcx.sess.asm_arch.unwrap(),
enclosing_def_id: fx.instance.def_id(),
template,
operands,
options,
@ -169,6 +170,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
struct InlineAssemblyGenerator<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
arch: InlineAsmArch,
enclosing_def_id: DefId,
template: &'a [InlineAsmTemplatePiece],
operands: &'a [InlineAsmOperand<'tcx>],
options: InlineAsmOptions,
@ -182,7 +184,12 @@ struct InlineAssemblyGenerator<'a, 'tcx> {
impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
fn allocate_registers(&mut self) {
let sess = self.tcx.sess;
let map = allocatable_registers(self.arch, &sess.target_features, &sess.target);
let map = allocatable_registers(
self.arch,
sess.relocation_model(),
self.tcx.asm_target_features(self.enclosing_def_id),
&sess.target,
);
let mut allocated = FxHashMap::<_, (bool, bool)>::default();
let mut regs = vec![None; self.operands.len()];
@ -313,14 +320,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
let mut new_slot = |x| new_slot_fn(&mut slot_size, x);
// Allocate stack slots for saving clobbered registers
let abi_clobber = InlineAsmClobberAbi::parse(
self.arch,
&self.tcx.sess.target_features,
&self.tcx.sess.target,
sym::C,
)
.unwrap()
.clobbered_regs();
let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::C)
.unwrap()
.clobbered_regs();
for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) {
let mut need_save = true;
// If the register overlaps with a register clobbered by function call, then

View file

@ -36,7 +36,6 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
("thumb2", Some(sym::arm_target_feature)),
("reserve-r9", Some(sym::arm_target_feature)),
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[

View file

@ -1046,6 +1046,10 @@ rustc_queries! {
cache_on_disk_if { true }
}
query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
}
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
separate_provide_extern

View file

@ -1,4 +1,5 @@
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@ -138,7 +139,7 @@ impl<'tcx> ExprVisitor<'tcx> {
template: &[InlineAsmTemplatePiece],
is_input: bool,
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
target_features: &[Symbol],
target_features: &FxHashSet<Symbol>,
) -> Option<InlineAsmType> {
// Check the type against the allowed types for inline asm.
let ty = self.typeck_results.expr_ty_adjusted(expr);
@ -285,9 +286,7 @@ impl<'tcx> ExprVisitor<'tcx> {
// (!). In that case we still need the earlier check to verify that the
// register class is usable at all.
if let Some(feature) = feature {
if !self.tcx.sess.target_features.contains(&feature)
&& !target_features.contains(&feature)
{
if !target_features.contains(&feature) {
let msg = &format!("`{}` target feature is not enabled", feature);
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
err.note(&format!(
@ -347,7 +346,8 @@ impl<'tcx> ExprVisitor<'tcx> {
let hir = self.tcx.hir();
let enclosing_id = hir.enclosing_body_owner(hir_id);
let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id();
let attrs = self.tcx.codegen_fn_attrs(enclosing_def_id);
let target_features = self.tcx.asm_target_features(enclosing_def_id);
let asm_arch = self.tcx.sess.asm_arch.unwrap();
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
// Validate register classes against currently enabled target
// features. We check that at least one type is available for
@ -360,16 +360,29 @@ impl<'tcx> ExprVisitor<'tcx> {
// Note that this is only possible for explicit register
// operands, which cannot be used in the asm string.
if let Some(reg) = op.reg() {
// Some explicit registers cannot be used depending on the
// target. Reject those here.
if let InlineAsmRegOrRegClass::Reg(reg) = reg {
if let Err(msg) = reg.validate(
asm_arch,
self.tcx.sess.relocation_model(),
&target_features,
&self.tcx.sess.target,
op.is_clobber(),
) {
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
continue;
}
}
if !op.is_clobber() {
let mut missing_required_features = vec![];
let reg_class = reg.reg_class();
for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap())
{
for &(_, feature) in reg_class.supported_types(asm_arch) {
match feature {
Some(feature) => {
if self.tcx.sess.target_features.contains(&feature)
|| attrs.target_features.contains(&feature)
{
if target_features.contains(&feature) {
missing_required_features.clear();
break;
} else {
@ -425,7 +438,7 @@ impl<'tcx> ExprVisitor<'tcx> {
asm.template,
true,
None,
&attrs.target_features,
&target_features,
);
}
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
@ -437,7 +450,7 @@ impl<'tcx> ExprVisitor<'tcx> {
asm.template,
false,
None,
&attrs.target_features,
&target_features,
);
}
}
@ -449,7 +462,7 @@ impl<'tcx> ExprVisitor<'tcx> {
asm.template,
false,
None,
&attrs.target_features,
&target_features,
);
}
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
@ -460,7 +473,7 @@ impl<'tcx> ExprVisitor<'tcx> {
asm.template,
true,
None,
&attrs.target_features,
&target_features,
);
if let Some(out_expr) = out_expr {
self.check_asm_operand_type(
@ -470,7 +483,7 @@ impl<'tcx> ExprVisitor<'tcx> {
asm.template,
false,
Some((in_expr, in_ty)),
&attrs.target_features,
&target_features,
);
}
}

View file

@ -1122,7 +1122,6 @@ symbols! {
repr_packed,
repr_simd,
repr_transparent,
reserved_r9: "reserved-r9",
residual,
result,
rhs,

View file

@ -1,5 +1,5 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use crate::spec::{RelocModel, Target};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
@ -73,17 +73,18 @@ impl AArch64InlineAsmRegClass {
}
}
pub fn reserved_x18(
pub fn target_reserves_x18(target: &Target) -> bool {
target.os == "android" || target.is_like_fuchsia || target.is_like_osx || target.is_like_windows
}
fn reserved_x18(
_arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxHashSet<Symbol>,
target: &Target,
_is_clobber: bool,
) -> Result<(), &'static str> {
if target.os == "android"
|| target.is_like_fuchsia
|| target.is_like_osx
|| target.is_like_windows
{
if target_reserves_x18(target) {
Err("x18 is a reserved register on this target")
} else {
Ok(())

View file

@ -1,5 +1,5 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use crate::spec::{RelocModel, Target};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
use rustc_span::{sym, Symbol};
@ -67,11 +67,12 @@ fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) ->
fn frame_pointer_r11(
arch: InlineAsmArch,
reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
target: &Target,
is_clobber: bool,
) -> Result<(), &'static str> {
not_thumb1(arch, target_features, target, is_clobber)?;
not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
if !frame_pointer_is_r7(target_features, target) {
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
@ -82,6 +83,7 @@ fn frame_pointer_r11(
fn frame_pointer_r7(
_arch: InlineAsmArch,
_reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
target: &Target,
_is_clobber: bool,
@ -95,6 +97,7 @@ fn frame_pointer_r7(
fn not_thumb1(
_arch: InlineAsmArch,
_reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
_target: &Target,
is_clobber: bool,
@ -111,18 +114,18 @@ fn not_thumb1(
fn reserved_r9(
arch: InlineAsmArch,
reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
target: &Target,
is_clobber: bool,
) -> Result<(), &'static str> {
not_thumb1(arch, target_features, target, is_clobber)?;
not_thumb1(arch, reloc_model, target_features, target, is_clobber)?;
// We detect this using the reserved-r9 feature instead of using the target
// because the relocation model can be changed with compiler options.
if target_features.contains(&sym::reserved_r9) {
Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
} else {
Ok(())
match reloc_model {
RelocModel::Rwpi | RelocModel::RopiRwpi => {
Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
}
_ => Ok(()),
}
}

View file

@ -1,7 +1,6 @@
use super::{InlineAsmArch, InlineAsmType, Target};
use rustc_data_structures::stable_set::FxHashSet;
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
use rustc_span::{sym, Symbol};
use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
@ -43,19 +42,6 @@ impl BpfInlineAsmRegClass {
}
}
fn only_alu32(
_arch: InlineAsmArch,
target_features: &FxHashSet<Symbol>,
_target: &Target,
_is_clobber: bool,
) -> Result<(), &'static str> {
if !target_features.contains(&sym::alu32) {
Err("register can't be used without the `alu32` target feature")
} else {
Ok(())
}
}
def_regs! {
Bpf BpfInlineAsmReg BpfInlineAsmRegClass {
r0: reg = ["r0"],
@ -68,16 +54,16 @@ def_regs! {
r7: reg = ["r7"],
r8: reg = ["r8"],
r9: reg = ["r9"],
w0: wreg = ["w0"] % only_alu32,
w1: wreg = ["w1"] % only_alu32,
w2: wreg = ["w2"] % only_alu32,
w3: wreg = ["w3"] % only_alu32,
w4: wreg = ["w4"] % only_alu32,
w5: wreg = ["w5"] % only_alu32,
w6: wreg = ["w6"] % only_alu32,
w7: wreg = ["w7"] % only_alu32,
w8: wreg = ["w8"] % only_alu32,
w9: wreg = ["w9"] % only_alu32,
w0: wreg = ["w0"],
w1: wreg = ["w1"],
w2: wreg = ["w2"],
w3: wreg = ["w3"],
w4: wreg = ["w4"],
w5: wreg = ["w5"],
w6: wreg = ["w6"],
w7: wreg = ["w7"],
w8: wreg = ["w8"],
w9: wreg = ["w9"],
#error = ["r10", "w10"] =>
"the stack pointer cannot be used as an operand for inline asm",

View file

@ -1,5 +1,5 @@
use crate::abi::Size;
use crate::spec::Target;
use crate::{abi::Size, spec::RelocModel};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
@ -25,7 +25,7 @@ macro_rules! def_reg_class {
}
}
pub fn parse(_arch: super::InlineAsmArch, name: rustc_span::Symbol) -> Result<Self, &'static str> {
pub fn parse(name: rustc_span::Symbol) -> Result<Self, &'static str> {
match name {
$(
rustc_span::sym::$class => Ok(Self::$class),
@ -79,19 +79,10 @@ macro_rules! def_regs {
}
}
pub fn parse(
_arch: super::InlineAsmArch,
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
_target: &crate::spec::Target,
_is_clobber: bool,
name: &str,
) -> Result<Self, &'static str> {
pub fn parse(name: &str) -> Result<Self, &'static str> {
match name {
$(
$($alias)|* | $reg_name => {
$($filter(_arch, _target_features, _target, _is_clobber)?;)?
Ok(Self::$reg)
}
$($alias)|* | $reg_name => Ok(Self::$reg),
)*
$(
$($bad_reg)|* => Err($error),
@ -99,10 +90,34 @@ macro_rules! def_regs {
_ => Err("unknown register"),
}
}
pub fn validate(self,
_arch: super::InlineAsmArch,
_reloc_model: crate::spec::RelocModel,
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
_target: &crate::spec::Target,
_is_clobber: bool,
) -> Result<(), &'static str> {
match self {
$(
Self::$reg => {
$($filter(
_arch,
_reloc_model,
_target_features,
_target,
_is_clobber
)?;)?
Ok(())
}
)*
}
}
}
pub(super) fn fill_reg_map(
_arch: super::InlineAsmArch,
_reloc_model: crate::spec::RelocModel,
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
_target: &crate::spec::Target,
_map: &mut rustc_data_structures::fx::FxHashMap<
@ -113,7 +128,7 @@ macro_rules! def_regs {
#[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass};
$(
if $($filter(_arch, _target_features, _target, false).is_ok() &&)? true {
if $($filter(_arch, _reloc_model, _target_features, _target, false).is_ok() &&)? true {
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
}
@ -295,94 +310,60 @@ impl InlineAsmReg {
}
}
pub fn parse(
arch: InlineAsmArch,
target_features: &FxHashSet<Symbol>,
target: &Target,
is_clobber: bool,
name: Symbol,
) -> Result<Self, &'static str> {
pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
// FIXME: use direct symbol comparison for register names
// Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
let name = name.as_str();
Ok(match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
Self::X86(X86InlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
Self::RiscV(RiscVInlineAsmReg::parse(name)?)
}
InlineAsmArch::Arm => {
Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
Self::PowerPC(PowerPCInlineAsmReg::parse(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 => {
Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmReg::parse(name)?)
}
InlineAsmArch::Avr => {
Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?),
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
Self::Wasm(WasmInlineAsmReg::parse(name)?)
}
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(
arch,
target_features,
target,
is_clobber,
name,
)?),
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmReg::parse(name)?),
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmReg::parse(name)?),
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(name)?),
})
}
pub fn validate(
self,
arch: InlineAsmArch,
reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
target: &Target,
is_clobber: bool,
) -> Result<(), &'static str> {
match self {
Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Err => unreachable!(),
}
}
// NOTE: This function isn't used at the moment, but is needed to support
// falling back to an external assembler.
pub fn emit(
@ -584,29 +565,29 @@ impl InlineAsmRegClass {
pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
Ok(match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
Self::X86(X86InlineAsmRegClass::parse(name)?)
}
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
}
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(name)?),
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
Self::PowerPC(PowerPCInlineAsmRegClass::parse(arch, name)?)
Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
}
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
Self::Mips(MipsInlineAsmRegClass::parse(name)?)
}
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?)
Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
}
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?),
})
}
@ -749,78 +730,79 @@ impl fmt::Display for InlineAsmType {
// falling back to an external assembler.
pub fn allocatable_registers(
arch: InlineAsmArch,
reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
target: &crate::spec::Target,
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
let mut map = x86::regclass_map();
x86::fill_reg_map(arch, target_features, target, &mut map);
x86::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Arm => {
let mut map = arm::regclass_map();
arm::fill_reg_map(arch, target_features, target, &mut map);
arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::AArch64 => {
let mut map = aarch64::regclass_map();
aarch64::fill_reg_map(arch, target_features, target, &mut map);
aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
let mut map = riscv::regclass_map();
riscv::fill_reg_map(arch, target_features, target, &mut map);
riscv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Nvptx64 => {
let mut map = nvptx::regclass_map();
nvptx::fill_reg_map(arch, target_features, target, &mut map);
nvptx::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
let mut map = powerpc::regclass_map();
powerpc::fill_reg_map(arch, target_features, target, &mut map);
powerpc::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Hexagon => {
let mut map = hexagon::regclass_map();
hexagon::fill_reg_map(arch, target_features, target, &mut map);
hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
let mut map = mips::regclass_map();
mips::fill_reg_map(arch, target_features, target, &mut map);
mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::S390x => {
let mut map = s390x::regclass_map();
s390x::fill_reg_map(arch, target_features, target, &mut map);
s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::SpirV => {
let mut map = spirv::regclass_map();
spirv::fill_reg_map(arch, target_features, target, &mut map);
spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
let mut map = wasm::regclass_map();
wasm::fill_reg_map(arch, target_features, target, &mut map);
wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Bpf => {
let mut map = bpf::regclass_map();
bpf::fill_reg_map(arch, target_features, target, &mut map);
bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Avr => {
let mut map = avr::regclass_map();
avr::fill_reg_map(arch, target_features, target, &mut map);
avr::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
InlineAsmArch::Msp430 => {
let mut map = msp430::regclass_map();
msp430::fill_reg_map(arch, target_features, target, &mut map);
msp430::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
}
@ -853,7 +835,6 @@ impl InlineAsmClobberAbi {
/// clobber ABIs for the target.
pub fn parse(
arch: InlineAsmArch,
target_features: &FxHashSet<Symbol>,
target: &Target,
name: Symbol,
) -> Result<Self, &'static [&'static str]> {
@ -877,13 +858,11 @@ impl InlineAsmClobberAbi {
_ => Err(&["C", "system", "efiapi", "aapcs"]),
},
InlineAsmArch::AArch64 => match name {
"C" | "system" | "efiapi" => {
Ok(if aarch64::reserved_x18(arch, target_features, target, true).is_err() {
InlineAsmClobberAbi::AArch64NoX18
} else {
InlineAsmClobberAbi::AArch64
})
}
"C" | "system" | "efiapi" => Ok(if aarch64::target_reserves_x18(target) {
InlineAsmClobberAbi::AArch64NoX18
} else {
InlineAsmClobberAbi::AArch64
}),
_ => Err(&["C", "system", "efiapi"]),
},
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {

View file

@ -1,5 +1,5 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use crate::spec::{RelocModel, Target};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
use rustc_span::{sym, Symbol};
@ -54,6 +54,7 @@ impl RiscVInlineAsmRegClass {
fn not_e(
_arch: InlineAsmArch,
_reloc_model: RelocModel,
target_features: &FxHashSet<Symbol>,
_target: &Target,
_is_clobber: bool,

View file

@ -1,5 +1,5 @@
use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use crate::spec::{RelocModel, Target};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
@ -139,6 +139,7 @@ impl X86InlineAsmRegClass {
fn x86_64_only(
arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxHashSet<Symbol>,
_target: &Target,
_is_clobber: bool,
@ -152,6 +153,7 @@ fn x86_64_only(
fn high_byte(
arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxHashSet<Symbol>,
_target: &Target,
_is_clobber: bool,
@ -164,6 +166,7 @@ fn high_byte(
fn rbx_reserved(
arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxHashSet<Symbol>,
_target: &Target,
_is_clobber: bool,
@ -179,6 +182,7 @@ fn rbx_reserved(
fn esi_reserved(
arch: InlineAsmArch,
_reloc_model: RelocModel,
_target_features: &FxHashSet<Symbol>,
_target: &Target,
_is_clobber: bool,

View file

@ -1,3 +1,4 @@
// ignore-tidy-filelength
//! "Collection" is the process of determining the type and other external
//! details of each item in Rust. Collection is specifically concerned
//! with *inter-procedural* things -- for example, for a function
@ -87,6 +88,7 @@ pub fn provide(providers: &mut Providers) {
static_mutability,
generator_kind,
codegen_fn_attrs,
asm_target_features,
collect_mod_item_types,
should_inherit_track_caller,
..*providers
@ -3255,6 +3257,24 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs
}
/// Computes the set of target features used in a function for the purposes of
/// inline assembly.
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet<Symbol> {
let mut target_features = tcx.sess.target_features.clone();
let attrs = tcx.codegen_fn_attrs(id);
target_features.extend(&attrs.target_features);
match attrs.instruction_set {
None => {}
Some(InstructionSetAttr::ArmA32) => {
target_features.remove(&sym::thumb_mode);
}
Some(InstructionSetAttr::ArmT32) => {
target_features.insert(sym::thumb_mode);
}
}
tcx.arena.alloc(target_features)
}
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {

View file

@ -0,0 +1,26 @@
// revisions: ropi rwpi
// [ropi] compile-flags: --target armv7-unknown-linux-gnueabihf -C relocation-model=ropi
// [rwpi] compile-flags: --target armv7-unknown-linux-gnueabihf -C relocation-model=rwpi
// [ropi] needs-llvm-components: arm
// [rwpi] needs-llvm-components: arm
// [ropi] build-pass
#![feature(no_core, lang_items, rustc_attrs)]
#![no_core]
#![crate_type = "rlib"]
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
#[lang = "sized"]
trait Sized {}
// R9 is reserved as the RWPI base register
fn main() {
unsafe {
asm!("", out("r9") _);
//[rwpi]~^ cannot use register `r9`
}
}

View file

@ -0,0 +1,8 @@
error: cannot use register `r9`: the RWPI static base register (r9) cannot be used as an operand for inline asm
--> $DIR/issue-85247.rs:23:18
|
LL | asm!("", out("r9") _);
| ^^^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,30 @@
// compile-flags: --target armv5te-unknown-linux-gnueabi
// needs-llvm-components: arm
// build-pass
#![feature(no_core, lang_items, rustc_attrs, isa_attribute)]
#![no_core]
#![crate_type = "rlib"]
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
#[lang = "sized"]
trait Sized {}
// ARM uses R11 for the frame pointer, make sure R7 is usable.
#[instruction_set(arm::a32)]
pub fn arm() {
unsafe {
asm!("", out("r7") _);
}
}
// Thumb uses R7 for the frame pointer, make sure R11 is usable.
#[instruction_set(arm::t32)]
pub fn thumb() {
unsafe {
asm!("", out("r11") _);
}
}

View file

@ -31,8 +31,6 @@ fn main() {
//~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
asm!("", in("k0") foo);
//~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
asm!("", in("ah") foo);
//~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
asm!("", in("st(2)") foo);
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output

View file

@ -70,50 +70,44 @@ error: invalid register `k0`: the k0 AVX mask register cannot be used as an oper
LL | asm!("", in("k0") foo);
| ^^^^^^^^^^^^
error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", in("ah") foo);
| ^^^^^^^^^^^^
error: register class `x87_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:35:18
|
LL | asm!("", in("st(2)") foo);
| ^^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:39:18
--> $DIR/bad-reg.rs:37:18
|
LL | asm!("", in("mm0") foo);
| ^^^^^^^^^^^^^
error: register class `x87_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:43:20
--> $DIR/bad-reg.rs:41:20
|
LL | asm!("{}", in(x87_reg) foo);
| ^^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:45:20
--> $DIR/bad-reg.rs:43:20
|
LL | asm!("{}", in(mmx_reg) foo);
| ^^^^^^^^^^^^^^^
error: register class `x87_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:47:20
--> $DIR/bad-reg.rs:45:20
|
LL | asm!("{}", out(x87_reg) _);
| ^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:49:20
--> $DIR/bad-reg.rs:47:20
|
LL | asm!("{}", out(mmx_reg) _);
| ^^^^^^^^^^^^^^
error: register `al` conflicts with register `ax`
--> $DIR/bad-reg.rs:55:33
--> $DIR/bad-reg.rs:53:33
|
LL | asm!("", in("eax") foo, in("al") bar);
| ------------- ^^^^^^^^^^^^ register `al`
@ -121,7 +115,7 @@ LL | asm!("", in("eax") foo, in("al") bar);
| register `ax`
error: register `ax` conflicts with register `ax`
--> $DIR/bad-reg.rs:57:33
--> $DIR/bad-reg.rs:55:33
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ------------- ^^^^^^^^^^^^^^ register `ax`
@ -129,13 +123,13 @@ LL | asm!("", in("rax") foo, out("rax") bar);
| register `ax`
|
help: use `lateout` instead of `out` to avoid conflict
--> $DIR/bad-reg.rs:57:18
--> $DIR/bad-reg.rs:55:18
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ^^^^^^^^^^^^^
error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:60:34
--> $DIR/bad-reg.rs:58:34
|
LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
@ -143,7 +137,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| register `xmm0`
error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:62:34
--> $DIR/bad-reg.rs:60:34
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^^ register `ymm0`
@ -151,10 +145,10 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| register `xmm0`
|
help: use `lateout` instead of `out` to avoid conflict
--> $DIR/bad-reg.rs:62:18
--> $DIR/bad-reg.rs:60:18
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| ^^^^^^^^^^^^^^
error: aborting due to 21 previous errors
error: aborting due to 20 previous errors