Skip to content

Commit f222021

Browse files
committed
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.
1 parent 904d0c3 commit f222021

File tree

9 files changed

+171
-187
lines changed

9 files changed

+171
-187
lines changed

compiler/rustc_ast_lowering/src/asm.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
6464
let mut clobber_abis = FxHashMap::default();
6565
if let Some(asm_arch) = asm_arch {
6666
for (abi_name, abi_span) in &asm.clobber_abis {
67-
match asm::InlineAsmClobberAbi::parse(
68-
asm_arch,
69-
self.sess.relocation_model(),
70-
&self.sess.target_features,
71-
&self.sess.target,
72-
*abi_name,
73-
) {
67+
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
7468
Ok(abi) => {
7569
// If the abi was already in the list, emit an error
7670
match clobber_abis.get(&abi) {
@@ -130,18 +124,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
130124
.operands
131125
.iter()
132126
.map(|(op, op_sp)| {
133-
let lower_reg = |reg, is_clobber| match reg {
127+
let lower_reg = |reg| match reg {
134128
InlineAsmRegOrRegClass::Reg(s) => {
135129
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
136-
asm::InlineAsmReg::parse(
137-
asm_arch,
138-
sess.relocation_model(),
139-
&sess.target_features,
140-
&sess.target,
141-
is_clobber,
142-
s,
143-
)
144-
.unwrap_or_else(|e| {
130+
asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| {
145131
let msg = format!("invalid register `{}`: {}", s.as_str(), e);
146132
sess.struct_span_err(*op_sp, &msg).emit();
147133
asm::InlineAsmReg::Err
@@ -165,24 +151,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
165151

166152
let op = match *op {
167153
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
168-
reg: lower_reg(reg, false),
154+
reg: lower_reg(reg),
169155
expr: self.lower_expr_mut(expr),
170156
},
171157
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
172-
reg: lower_reg(reg, expr.is_none()),
158+
reg: lower_reg(reg),
173159
late,
174160
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
175161
},
176162
InlineAsmOperand::InOut { reg, late, ref expr } => {
177163
hir::InlineAsmOperand::InOut {
178-
reg: lower_reg(reg, false),
164+
reg: lower_reg(reg),
179165
late,
180166
expr: self.lower_expr_mut(expr),
181167
}
182168
}
183169
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
184170
hir::InlineAsmOperand::SplitInOut {
185-
reg: lower_reg(reg, false),
171+
reg: lower_reg(reg),
186172
late,
187173
in_expr: self.lower_expr_mut(in_expr),
188174
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),

compiler/rustc_codegen_cranelift/src/inline_asm.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
106106
let mut asm_gen = InlineAssemblyGenerator {
107107
tcx: fx.tcx,
108108
arch: fx.tcx.sess.asm_arch.unwrap(),
109+
enclosing_def_id: fx.instance.def_id(),
109110
template,
110111
operands,
111112
options,
@@ -169,6 +170,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
169170
struct InlineAssemblyGenerator<'a, 'tcx> {
170171
tcx: TyCtxt<'tcx>,
171172
arch: InlineAsmArch,
173+
enclosing_def_id: DefId,
172174
template: &'a [InlineAsmTemplatePiece],
173175
operands: &'a [InlineAsmOperand<'tcx>],
174176
options: InlineAsmOptions,
@@ -185,7 +187,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
185187
let map = allocatable_registers(
186188
self.arch,
187189
sess.relocation_model(),
188-
&sess.target_features,
190+
self.tcx.asm_target_features(self.enclosing_def_id),
189191
&sess.target,
190192
);
191193
let mut allocated = FxHashMap::<_, (bool, bool)>::default();
@@ -318,15 +320,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
318320
let mut new_slot = |x| new_slot_fn(&mut slot_size, x);
319321

320322
// Allocate stack slots for saving clobbered registers
321-
let abi_clobber = InlineAsmClobberAbi::parse(
322-
self.arch,
323-
self.tcx.sess.relocation_model(),
324-
&self.tcx.sess.target_features,
325-
&self.tcx.sess.target,
326-
sym::C,
327-
)
328-
.unwrap()
329-
.clobbered_regs();
323+
let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::C)
324+
.unwrap()
325+
.clobbered_regs();
330326
for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) {
331327
let mut need_save = true;
332328
// If the register overlaps with a register clobbered by function call, then

compiler/rustc_middle/src/query/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,10 @@ rustc_queries! {
10401040
cache_on_disk_if { true }
10411041
}
10421042

1043+
query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
1044+
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
1045+
}
1046+
10431047
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
10441048
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
10451049
separate_provide_extern

compiler/rustc_passes/src/intrinsicck.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_ast::InlineAsmTemplatePiece;
2+
use rustc_data_structures::stable_set::FxHashSet;
23
use rustc_errors::struct_span_err;
34
use rustc_hir as hir;
45
use rustc_hir::def::{DefKind, Res};
@@ -141,7 +142,7 @@ impl<'tcx> ExprVisitor<'tcx> {
141142
template: &[InlineAsmTemplatePiece],
142143
is_input: bool,
143144
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
144-
target_features: &[Symbol],
145+
target_features: &FxHashSet<Symbol>,
145146
) -> Option<InlineAsmType> {
146147
// Check the type against the allowed types for inline asm.
147148
let ty = self.typeck_results.expr_ty_adjusted(expr);
@@ -294,9 +295,7 @@ impl<'tcx> ExprVisitor<'tcx> {
294295
// (!). In that case we still need the earlier check to verify that the
295296
// register class is usable at all.
296297
if let Some(feature) = feature {
297-
if !self.tcx.sess.target_features.contains(&feature)
298-
&& !target_features.contains(&feature)
299-
{
298+
if !target_features.contains(&feature) {
300299
let msg = &format!("`{}` target feature is not enabled", feature);
301300
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
302301
err.note(&format!(
@@ -356,7 +355,8 @@ impl<'tcx> ExprVisitor<'tcx> {
356355
let hir = self.tcx.hir();
357356
let enclosing_id = hir.enclosing_body_owner(hir_id);
358357
let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id();
359-
let attrs = self.tcx.codegen_fn_attrs(enclosing_def_id);
358+
let target_features = self.tcx.asm_target_features(enclosing_def_id);
359+
let asm_arch = self.tcx.sess.asm_arch.unwrap();
360360
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
361361
// Validate register classes against currently enabled target
362362
// features. We check that at least one type is available for
@@ -369,16 +369,29 @@ impl<'tcx> ExprVisitor<'tcx> {
369369
// Note that this is only possible for explicit register
370370
// operands, which cannot be used in the asm string.
371371
if let Some(reg) = op.reg() {
372+
// Some explicit registers cannot be used depending on the
373+
// target. Reject those here.
374+
if let InlineAsmRegOrRegClass::Reg(reg) = reg {
375+
if let Err(msg) = reg.validate(
376+
asm_arch,
377+
self.tcx.sess.relocation_model(),
378+
&target_features,
379+
&self.tcx.sess.target,
380+
op.is_clobber(),
381+
) {
382+
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
383+
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
384+
continue;
385+
}
386+
}
387+
372388
if !op.is_clobber() {
373389
let mut missing_required_features = vec![];
374390
let reg_class = reg.reg_class();
375-
for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap())
376-
{
391+
for &(_, feature) in reg_class.supported_types(asm_arch) {
377392
match feature {
378393
Some(feature) => {
379-
if self.tcx.sess.target_features.contains(&feature)
380-
|| attrs.target_features.contains(&feature)
381-
{
394+
if target_features.contains(&feature) {
382395
missing_required_features.clear();
383396
break;
384397
} else {
@@ -434,7 +447,7 @@ impl<'tcx> ExprVisitor<'tcx> {
434447
asm.template,
435448
true,
436449
None,
437-
&attrs.target_features,
450+
&target_features,
438451
);
439452
}
440453
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
@@ -446,7 +459,7 @@ impl<'tcx> ExprVisitor<'tcx> {
446459
asm.template,
447460
false,
448461
None,
449-
&attrs.target_features,
462+
&target_features,
450463
);
451464
}
452465
}
@@ -458,7 +471,7 @@ impl<'tcx> ExprVisitor<'tcx> {
458471
asm.template,
459472
false,
460473
None,
461-
&attrs.target_features,
474+
&target_features,
462475
);
463476
}
464477
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
@@ -469,7 +482,7 @@ impl<'tcx> ExprVisitor<'tcx> {
469482
asm.template,
470483
true,
471484
None,
472-
&attrs.target_features,
485+
&target_features,
473486
);
474487
if let Some(out_expr) = out_expr {
475488
self.check_asm_operand_type(
@@ -479,7 +492,7 @@ impl<'tcx> ExprVisitor<'tcx> {
479492
asm.template,
480493
false,
481494
Some((in_expr, in_ty)),
482-
&attrs.target_features,
495+
&target_features,
483496
);
484497
}
485498
}

compiler/rustc_target/src/asm/aarch64.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{InlineAsmArch, InlineAsmType};
2-
use crate::spec::{Target, RelocModel};
2+
use crate::spec::{RelocModel, Target};
33
use rustc_data_structures::stable_set::FxHashSet;
44
use rustc_macros::HashStable_Generic;
55
use rustc_span::Symbol;
@@ -73,18 +73,18 @@ impl AArch64InlineAsmRegClass {
7373
}
7474
}
7575

76-
pub fn reserved_x18(
76+
pub fn target_reserves_x18(target: &Target) -> bool {
77+
target.os == "android" || target.is_like_fuchsia || target.is_like_osx || target.is_like_windows
78+
}
79+
80+
fn reserved_x18(
7781
_arch: InlineAsmArch,
7882
_reloc_model: RelocModel,
7983
_target_features: &FxHashSet<Symbol>,
8084
target: &Target,
8185
_is_clobber: bool,
8286
) -> Result<(), &'static str> {
83-
if target.os == "android"
84-
|| target.is_like_fuchsia
85-
|| target.is_like_osx
86-
|| target.is_like_windows
87-
{
87+
if target_reserves_x18(target) {
8888
Err("x18 is a reserved register on this target")
8989
} else {
9090
Ok(())

0 commit comments

Comments
 (0)