Take CodegenFnAttrs into account when validating asm! register operands
Checking of asm! register operands now properly takes function attributes such as #[target_feature] and #[instruction_set] into account.
This commit is contained in:
parent
1ceb104851
commit
fc41d4bf35
9 changed files with 176 additions and 192 deletions
|
@ -64,13 +64,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let mut clobber_abis = FxHashMap::default();
|
let mut clobber_abis = FxHashMap::default();
|
||||||
if let Some(asm_arch) = asm_arch {
|
if let Some(asm_arch) = asm_arch {
|
||||||
for (abi_name, abi_span) in &asm.clobber_abis {
|
for (abi_name, abi_span) in &asm.clobber_abis {
|
||||||
match asm::InlineAsmClobberAbi::parse(
|
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
|
||||||
asm_arch,
|
|
||||||
self.sess.relocation_model(),
|
|
||||||
&self.sess.target_features,
|
|
||||||
&self.sess.target,
|
|
||||||
*abi_name,
|
|
||||||
) {
|
|
||||||
Ok(abi) => {
|
Ok(abi) => {
|
||||||
// If the abi was already in the list, emit an error
|
// If the abi was already in the list, emit an error
|
||||||
match clobber_abis.get(&abi) {
|
match clobber_abis.get(&abi) {
|
||||||
|
@ -130,18 +124,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
.operands
|
.operands
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(op, op_sp)| {
|
.map(|(op, op_sp)| {
|
||||||
let lower_reg = |reg, is_clobber| match reg {
|
let lower_reg = |reg| 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, s).unwrap_or_else(|e| {
|
||||||
asm_arch,
|
|
||||||
sess.relocation_model(),
|
|
||||||
&sess.target_features,
|
|
||||||
&sess.target,
|
|
||||||
is_clobber,
|
|
||||||
s,
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
let msg = format!("invalid register `{}`: {}", s.as_str(), e);
|
let msg = format!("invalid register `{}`: {}", s.as_str(), e);
|
||||||
sess.struct_span_err(*op_sp, &msg).emit();
|
sess.struct_span_err(*op_sp, &msg).emit();
|
||||||
asm::InlineAsmReg::Err
|
asm::InlineAsmReg::Err
|
||||||
|
@ -165,24 +151,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, false),
|
reg: lower_reg(reg),
|
||||||
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, expr.is_none()),
|
reg: lower_reg(reg),
|
||||||
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, false),
|
reg: lower_reg(reg),
|
||||||
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, false),
|
reg: lower_reg(reg),
|
||||||
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)),
|
||||||
|
|
|
@ -106,6 +106,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
||||||
let mut asm_gen = InlineAssemblyGenerator {
|
let mut asm_gen = InlineAssemblyGenerator {
|
||||||
tcx: fx.tcx,
|
tcx: fx.tcx,
|
||||||
arch: fx.tcx.sess.asm_arch.unwrap(),
|
arch: fx.tcx.sess.asm_arch.unwrap(),
|
||||||
|
enclosing_def_id: fx.instance.def_id(),
|
||||||
template,
|
template,
|
||||||
operands,
|
operands,
|
||||||
options,
|
options,
|
||||||
|
@ -169,6 +170,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
||||||
struct InlineAssemblyGenerator<'a, 'tcx> {
|
struct InlineAssemblyGenerator<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
|
enclosing_def_id: DefId,
|
||||||
template: &'a [InlineAsmTemplatePiece],
|
template: &'a [InlineAsmTemplatePiece],
|
||||||
operands: &'a [InlineAsmOperand<'tcx>],
|
operands: &'a [InlineAsmOperand<'tcx>],
|
||||||
options: InlineAsmOptions,
|
options: InlineAsmOptions,
|
||||||
|
@ -185,7 +187,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
||||||
let map = allocatable_registers(
|
let map = allocatable_registers(
|
||||||
self.arch,
|
self.arch,
|
||||||
sess.relocation_model(),
|
sess.relocation_model(),
|
||||||
&sess.target_features,
|
self.tcx.asm_target_features(self.enclosing_def_id),
|
||||||
&sess.target,
|
&sess.target,
|
||||||
);
|
);
|
||||||
let mut allocated = FxHashMap::<_, (bool, bool)>::default();
|
let mut allocated = FxHashMap::<_, (bool, bool)>::default();
|
||||||
|
@ -318,13 +320,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
||||||
let mut new_slot = |x| new_slot_fn(&mut slot_size, x);
|
let mut new_slot = |x| new_slot_fn(&mut slot_size, x);
|
||||||
|
|
||||||
// Allocate stack slots for saving clobbered registers
|
// Allocate stack slots for saving clobbered registers
|
||||||
let abi_clobber = InlineAsmClobberAbi::parse(
|
let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::C)
|
||||||
self.arch,
|
|
||||||
self.tcx.sess.relocation_model(),
|
|
||||||
&self.tcx.sess.target_features,
|
|
||||||
&self.tcx.sess.target,
|
|
||||||
sym::C,
|
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clobbered_regs();
|
.clobbered_regs();
|
||||||
for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) {
|
for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) {
|
||||||
|
|
|
@ -1046,6 +1046,10 @@ rustc_queries! {
|
||||||
cache_on_disk_if { true }
|
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] {
|
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) }
|
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use rustc_ast::InlineAsmTemplatePiece;
|
use rustc_ast::InlineAsmTemplatePiece;
|
||||||
|
use rustc_data_structures::stable_set::FxHashSet;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
@ -138,7 +139,7 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
template: &[InlineAsmTemplatePiece],
|
template: &[InlineAsmTemplatePiece],
|
||||||
is_input: bool,
|
is_input: bool,
|
||||||
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
|
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
|
||||||
target_features: &[Symbol],
|
target_features: &FxHashSet<Symbol>,
|
||||||
) -> Option<InlineAsmType> {
|
) -> Option<InlineAsmType> {
|
||||||
// Check the type against the allowed types for inline asm.
|
// Check the type against the allowed types for inline asm.
|
||||||
let ty = self.typeck_results.expr_ty_adjusted(expr);
|
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
|
// (!). In that case we still need the earlier check to verify that the
|
||||||
// register class is usable at all.
|
// register class is usable at all.
|
||||||
if let Some(feature) = feature {
|
if let Some(feature) = feature {
|
||||||
if !self.tcx.sess.target_features.contains(&feature)
|
if !target_features.contains(&feature) {
|
||||||
&& !target_features.contains(&feature)
|
|
||||||
{
|
|
||||||
let msg = &format!("`{}` target feature is not enabled", feature);
|
let msg = &format!("`{}` target feature is not enabled", feature);
|
||||||
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
|
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
|
@ -347,7 +346,8 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
let hir = self.tcx.hir();
|
let hir = self.tcx.hir();
|
||||||
let enclosing_id = hir.enclosing_body_owner(hir_id);
|
let enclosing_id = hir.enclosing_body_owner(hir_id);
|
||||||
let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_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() {
|
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
|
||||||
// Validate register classes against currently enabled target
|
// Validate register classes against currently enabled target
|
||||||
// features. We check that at least one type is available for
|
// 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
|
// Note that this is only possible for explicit register
|
||||||
// operands, which cannot be used in the asm string.
|
// operands, which cannot be used in the asm string.
|
||||||
if let Some(reg) = op.reg() {
|
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() {
|
if !op.is_clobber() {
|
||||||
let mut missing_required_features = vec![];
|
let mut missing_required_features = vec![];
|
||||||
let reg_class = reg.reg_class();
|
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 {
|
match feature {
|
||||||
Some(feature) => {
|
Some(feature) => {
|
||||||
if self.tcx.sess.target_features.contains(&feature)
|
if target_features.contains(&feature) {
|
||||||
|| attrs.target_features.contains(&feature)
|
|
||||||
{
|
|
||||||
missing_required_features.clear();
|
missing_required_features.clear();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -425,7 +438,7 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
asm.template,
|
asm.template,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
&attrs.target_features,
|
&target_features,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
|
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
|
||||||
|
@ -437,7 +450,7 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
asm.template,
|
asm.template,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
&attrs.target_features,
|
&target_features,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,7 +462,7 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
asm.template,
|
asm.template,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
&attrs.target_features,
|
&target_features,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
|
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
|
||||||
|
@ -460,7 +473,7 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
asm.template,
|
asm.template,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
&attrs.target_features,
|
&target_features,
|
||||||
);
|
);
|
||||||
if let Some(out_expr) = out_expr {
|
if let Some(out_expr) = out_expr {
|
||||||
self.check_asm_operand_type(
|
self.check_asm_operand_type(
|
||||||
|
@ -470,7 +483,7 @@ impl<'tcx> ExprVisitor<'tcx> {
|
||||||
asm.template,
|
asm.template,
|
||||||
false,
|
false,
|
||||||
Some((in_expr, in_ty)),
|
Some((in_expr, in_ty)),
|
||||||
&attrs.target_features,
|
&target_features,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::{InlineAsmArch, InlineAsmType};
|
use super::{InlineAsmArch, InlineAsmType};
|
||||||
use crate::spec::{Target, RelocModel};
|
use crate::spec::{RelocModel, Target};
|
||||||
use rustc_data_structures::stable_set::FxHashSet;
|
use rustc_data_structures::stable_set::FxHashSet;
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
@ -73,18 +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,
|
_arch: InlineAsmArch,
|
||||||
_reloc_model: RelocModel,
|
_reloc_model: RelocModel,
|
||||||
_target_features: &FxHashSet<Symbol>,
|
_target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
_is_clobber: bool,
|
_is_clobber: bool,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if target.os == "android"
|
if target_reserves_x18(target) {
|
||||||
|| target.is_like_fuchsia
|
|
||||||
|| target.is_like_osx
|
|
||||||
|| target.is_like_windows
|
|
||||||
{
|
|
||||||
Err("x18 is a reserved register on this target")
|
Err("x18 is a reserved register on this target")
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -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 {
|
match name {
|
||||||
$(
|
$(
|
||||||
rustc_span::sym::$class => Ok(Self::$class),
|
rustc_span::sym::$class => Ok(Self::$class),
|
||||||
|
@ -79,20 +79,10 @@ macro_rules! def_regs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(
|
pub fn parse(name: &str) -> Result<Self, &'static str> {
|
||||||
_arch: super::InlineAsmArch,
|
|
||||||
_reloc_model: crate::spec::RelocModel,
|
|
||||||
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
|
|
||||||
_target: &crate::spec::Target,
|
|
||||||
_is_clobber: bool,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<Self, &'static str> {
|
|
||||||
match name {
|
match name {
|
||||||
$(
|
$(
|
||||||
$($alias)|* | $reg_name => {
|
$($alias)|* | $reg_name => Ok(Self::$reg),
|
||||||
$($filter(_arch, _reloc_model, _target_features, _target, _is_clobber)?;)?
|
|
||||||
Ok(Self::$reg)
|
|
||||||
}
|
|
||||||
)*
|
)*
|
||||||
$(
|
$(
|
||||||
$($bad_reg)|* => Err($error),
|
$($bad_reg)|* => Err($error),
|
||||||
|
@ -100,6 +90,29 @@ macro_rules! def_regs {
|
||||||
_ => Err("unknown register"),
|
_ => 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(
|
pub(super) fn fill_reg_map(
|
||||||
|
@ -297,93 +310,58 @@ impl InlineAsmReg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(
|
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(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::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
|
||||||
|
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
|
||||||
|
Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
|
||||||
|
}
|
||||||
|
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
|
||||||
|
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
|
||||||
|
Self::Mips(MipsInlineAsmReg::parse(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::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,
|
arch: InlineAsmArch,
|
||||||
reloc_model: RelocModel,
|
reloc_model: RelocModel,
|
||||||
target_features: &FxHashSet<Symbol>,
|
target_features: &FxHashSet<Symbol>,
|
||||||
target: &Target,
|
target: &Target,
|
||||||
is_clobber: bool,
|
is_clobber: bool,
|
||||||
name: Symbol,
|
) -> Result<(), &'static str> {
|
||||||
) -> Result<Self, &'static str> {
|
match self {
|
||||||
// FIXME: use direct symbol comparison for register names
|
Self::X86(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
|
||||||
// Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
|
Self::Arm(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
|
||||||
let name = name.as_str();
|
Self::AArch64(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
|
||||||
Ok(match arch {
|
Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
|
||||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
|
||||||
Self::X86(X86InlineAsmReg::parse(arch, reloc_model,target_features, target, is_clobber, name)?)
|
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!(),
|
||||||
}
|
}
|
||||||
InlineAsmArch::Arm => {
|
|
||||||
Self::Arm(ArmInlineAsmReg::parse(arch, reloc_model,target_features, target, is_clobber, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => Self::RiscV(
|
|
||||||
RiscVInlineAsmReg::parse(arch, reloc_model,target_features, target, is_clobber, name)?,
|
|
||||||
),
|
|
||||||
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => Self::PowerPC(
|
|
||||||
PowerPCInlineAsmReg::parse(arch, reloc_model,target_features, target, is_clobber, name)?,
|
|
||||||
),
|
|
||||||
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::Mips | InlineAsmArch::Mips64 => Self::Mips(MipsInlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => Self::Wasm(WasmInlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
InlineAsmArch::Bpf => {
|
|
||||||
Self::Bpf(BpfInlineAsmReg::parse(arch, reloc_model,target_features, target, is_clobber, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::Avr => {
|
|
||||||
Self::Avr(AvrInlineAsmReg::parse(arch, reloc_model,target_features, target, is_clobber, name)?)
|
|
||||||
}
|
|
||||||
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(
|
|
||||||
arch,
|
|
||||||
reloc_model,target_features,
|
|
||||||
target,
|
|
||||||
is_clobber,
|
|
||||||
name,
|
|
||||||
)?),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This function isn't used at the moment, but is needed to support
|
// NOTE: This function isn't used at the moment, but is needed to support
|
||||||
|
@ -587,29 +565,29 @@ impl InlineAsmRegClass {
|
||||||
pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
|
pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
|
||||||
Ok(match arch {
|
Ok(match arch {
|
||||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
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::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
|
||||||
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?),
|
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
|
||||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
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 => {
|
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 => {
|
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
|
||||||
Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
|
Self::Mips(MipsInlineAsmRegClass::parse(name)?)
|
||||||
}
|
}
|
||||||
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(arch, name)?),
|
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?),
|
||||||
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
|
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?),
|
||||||
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
|
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
|
||||||
Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?)
|
Self::Wasm(WasmInlineAsmRegClass::parse(name)?)
|
||||||
}
|
}
|
||||||
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
|
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?),
|
||||||
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
|
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?),
|
||||||
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?),
|
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,8 +835,6 @@ impl InlineAsmClobberAbi {
|
||||||
/// clobber ABIs for the target.
|
/// clobber ABIs for the target.
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
arch: InlineAsmArch,
|
arch: InlineAsmArch,
|
||||||
reloc_model: RelocModel,
|
|
||||||
target_features: &FxHashSet<Symbol>,
|
|
||||||
target: &Target,
|
target: &Target,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
) -> Result<Self, &'static [&'static str]> {
|
) -> Result<Self, &'static [&'static str]> {
|
||||||
|
@ -882,13 +858,11 @@ impl InlineAsmClobberAbi {
|
||||||
_ => Err(&["C", "system", "efiapi", "aapcs"]),
|
_ => Err(&["C", "system", "efiapi", "aapcs"]),
|
||||||
},
|
},
|
||||||
InlineAsmArch::AArch64 => match name {
|
InlineAsmArch::AArch64 => match name {
|
||||||
"C" | "system" | "efiapi" => {
|
"C" | "system" | "efiapi" => Ok(if aarch64::target_reserves_x18(target) {
|
||||||
Ok(if aarch64::reserved_x18(arch, reloc_model, target_features, target, true).is_err() {
|
|
||||||
InlineAsmClobberAbi::AArch64NoX18
|
InlineAsmClobberAbi::AArch64NoX18
|
||||||
} else {
|
} else {
|
||||||
InlineAsmClobberAbi::AArch64
|
InlineAsmClobberAbi::AArch64
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
_ => Err(&["C", "system", "efiapi"]),
|
_ => Err(&["C", "system", "efiapi"]),
|
||||||
},
|
},
|
||||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
|
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
|
||||||
|
|
|
@ -87,6 +87,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
static_mutability,
|
static_mutability,
|
||||||
generator_kind,
|
generator_kind,
|
||||||
codegen_fn_attrs,
|
codegen_fn_attrs,
|
||||||
|
asm_target_features,
|
||||||
collect_mod_item_types,
|
collect_mod_item_types,
|
||||||
should_inherit_track_caller,
|
should_inherit_track_caller,
|
||||||
..*providers
|
..*providers
|
||||||
|
@ -3255,6 +3256,24 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||||
codegen_fn_attrs
|
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
|
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
|
||||||
/// applied to the method prototype.
|
/// applied to the method prototype.
|
||||||
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
|
|
|
@ -31,8 +31,6 @@ fn main() {
|
||||||
//~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
|
//~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
|
||||||
asm!("", in("k0") foo);
|
asm!("", in("k0") foo);
|
||||||
//~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
|
//~^ 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);
|
asm!("", in("st(2)") foo);
|
||||||
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
|
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||||
|
|
|
@ -70,50 +70,44 @@ error: invalid register `k0`: the k0 AVX mask register cannot be used as an oper
|
||||||
LL | asm!("", in("k0") foo);
|
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
|
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);
|
LL | asm!("", in("st(2)") foo);
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
|
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);
|
LL | asm!("", in("mm0") foo);
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register class `x87_reg` can only be used as a clobber, not as an input or output
|
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);
|
LL | asm!("{}", in(x87_reg) foo);
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
|
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);
|
LL | asm!("{}", in(mmx_reg) foo);
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register class `x87_reg` can only be used as a clobber, not as an input or output
|
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) _);
|
LL | asm!("{}", out(x87_reg) _);
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
|
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) _);
|
LL | asm!("{}", out(mmx_reg) _);
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register `al` conflicts with register `ax`
|
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);
|
LL | asm!("", in("eax") foo, in("al") bar);
|
||||||
| ------------- ^^^^^^^^^^^^ register `al`
|
| ------------- ^^^^^^^^^^^^ register `al`
|
||||||
|
@ -121,7 +115,7 @@ LL | asm!("", in("eax") foo, in("al") bar);
|
||||||
| register `ax`
|
| register `ax`
|
||||||
|
|
||||||
error: register `ax` conflicts with 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);
|
LL | asm!("", in("rax") foo, out("rax") bar);
|
||||||
| ------------- ^^^^^^^^^^^^^^ register `ax`
|
| ------------- ^^^^^^^^^^^^^^ register `ax`
|
||||||
|
@ -129,13 +123,13 @@ LL | asm!("", in("rax") foo, out("rax") bar);
|
||||||
| register `ax`
|
| register `ax`
|
||||||
|
|
|
|
||||||
help: use `lateout` instead of `out` to avoid conflict
|
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);
|
LL | asm!("", in("rax") foo, out("rax") bar);
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: register `ymm0` conflicts with register `xmm0`
|
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);
|
LL | asm!("", in("xmm0") foo, in("ymm0") bar);
|
||||||
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
|
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
|
||||||
|
@ -143,7 +137,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar);
|
||||||
| register `xmm0`
|
| register `xmm0`
|
||||||
|
|
||||||
error: register `ymm0` conflicts with 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);
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
|
||||||
| -------------- ^^^^^^^^^^^^^^^ register `ymm0`
|
| -------------- ^^^^^^^^^^^^^^^ register `ymm0`
|
||||||
|
@ -151,10 +145,10 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar);
|
||||||
| register `xmm0`
|
| register `xmm0`
|
||||||
|
|
|
|
||||||
help: use `lateout` instead of `out` to avoid conflict
|
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);
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 21 previous errors
|
error: aborting due to 20 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue