Skip to content

Commit fc41d4b

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 1ceb104 commit fc41d4b

File tree

9 files changed

+171
-187
lines changed

9 files changed

+171
-187
lines changed

compiler/rustc_ast_lowering/src/asm.rs

+7-21
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

+6-10
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

+4
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,10 @@ rustc_queries! {
10461046
cache_on_disk_if { true }
10471047
}
10481048

1049+
query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
1050+
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
1051+
}
1052+
10491053
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
10501054
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
10511055
separate_provide_extern

compiler/rustc_passes/src/intrinsicck.rs

+28-15
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};
@@ -138,7 +139,7 @@ impl<'tcx> ExprVisitor<'tcx> {
138139
template: &[InlineAsmTemplatePiece],
139140
is_input: bool,
140141
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
141-
target_features: &[Symbol],
142+
target_features: &FxHashSet<Symbol>,
142143
) -> Option<InlineAsmType> {
143144
// Check the type against the allowed types for inline asm.
144145
let ty = self.typeck_results.expr_ty_adjusted(expr);
@@ -285,9 +286,7 @@ impl<'tcx> ExprVisitor<'tcx> {
285286
// (!). In that case we still need the earlier check to verify that the
286287
// register class is usable at all.
287288
if let Some(feature) = feature {
288-
if !self.tcx.sess.target_features.contains(&feature)
289-
&& !target_features.contains(&feature)
290-
{
289+
if !target_features.contains(&feature) {
291290
let msg = &format!("`{}` target feature is not enabled", feature);
292291
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
293292
err.note(&format!(
@@ -347,7 +346,8 @@ impl<'tcx> ExprVisitor<'tcx> {
347346
let hir = self.tcx.hir();
348347
let enclosing_id = hir.enclosing_body_owner(hir_id);
349348
let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id();
350-
let attrs = self.tcx.codegen_fn_attrs(enclosing_def_id);
349+
let target_features = self.tcx.asm_target_features(enclosing_def_id);
350+
let asm_arch = self.tcx.sess.asm_arch.unwrap();
351351
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
352352
// Validate register classes against currently enabled target
353353
// features. We check that at least one type is available for
@@ -360,16 +360,29 @@ impl<'tcx> ExprVisitor<'tcx> {
360360
// Note that this is only possible for explicit register
361361
// operands, which cannot be used in the asm string.
362362
if let Some(reg) = op.reg() {
363+
// Some explicit registers cannot be used depending on the
364+
// target. Reject those here.
365+
if let InlineAsmRegOrRegClass::Reg(reg) = reg {
366+
if let Err(msg) = reg.validate(
367+
asm_arch,
368+
self.tcx.sess.relocation_model(),
369+
&target_features,
370+
&self.tcx.sess.target,
371+
op.is_clobber(),
372+
) {
373+
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
374+
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
375+
continue;
376+
}
377+
}
378+
363379
if !op.is_clobber() {
364380
let mut missing_required_features = vec![];
365381
let reg_class = reg.reg_class();
366-
for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap())
367-
{
382+
for &(_, feature) in reg_class.supported_types(asm_arch) {
368383
match feature {
369384
Some(feature) => {
370-
if self.tcx.sess.target_features.contains(&feature)
371-
|| attrs.target_features.contains(&feature)
372-
{
385+
if target_features.contains(&feature) {
373386
missing_required_features.clear();
374387
break;
375388
} else {
@@ -425,7 +438,7 @@ impl<'tcx> ExprVisitor<'tcx> {
425438
asm.template,
426439
true,
427440
None,
428-
&attrs.target_features,
441+
&target_features,
429442
);
430443
}
431444
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
@@ -437,7 +450,7 @@ impl<'tcx> ExprVisitor<'tcx> {
437450
asm.template,
438451
false,
439452
None,
440-
&attrs.target_features,
453+
&target_features,
441454
);
442455
}
443456
}
@@ -449,7 +462,7 @@ impl<'tcx> ExprVisitor<'tcx> {
449462
asm.template,
450463
false,
451464
None,
452-
&attrs.target_features,
465+
&target_features,
453466
);
454467
}
455468
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
@@ -460,7 +473,7 @@ impl<'tcx> ExprVisitor<'tcx> {
460473
asm.template,
461474
true,
462475
None,
463-
&attrs.target_features,
476+
&target_features,
464477
);
465478
if let Some(out_expr) = out_expr {
466479
self.check_asm_operand_type(
@@ -470,7 +483,7 @@ impl<'tcx> ExprVisitor<'tcx> {
470483
asm.template,
471484
false,
472485
Some((in_expr, in_ty)),
473-
&attrs.target_features,
486+
&target_features,
474487
);
475488
}
476489
}

compiler/rustc_target/src/asm/aarch64.rs

+7-7
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)