Skip to content

Commit 080d545

Browse files
committed
Auto merge of #94468 - Amanieu:global_asm_sym, r=nagisa
Implement sym operands for global_asm! Tracking issue: #93333 This PR is pretty much a complete rewrite of `sym` operand support for inline assembly so that the same implementation can be shared by `asm!` and `global_asm!`. The main changes are: - At the AST level, `sym` is represented as a special `InlineAsmSym` AST node containing a path instead of an `Expr`. - At the HIR level, `sym` is split into `SymStatic` and `SymFn` depending on whether the path resolves to a static during AST lowering (defaults to `SynFn` if `get_early_res` fails). - `SymFn` is just an `AnonConst`. It runs through typeck and we just collect the resulting type at the end. An error is emitted if the type is not a `FnDef`. - `SymStatic` directly holds a path and the `DefId` of the `static` that it is pointing to. - The representation at the MIR level is mostly unchanged. There is a minor change to THIR where `SymFn` is a constant instead of an expression. - At the codegen level we need to apply the target's symbol mangling to the result of `tcx.symbol_name()` depending on the target. This is done by calling the LLVM name mangler, which handles all of the details. - On Mach-O, all symbols have a leading underscore. - On x86 Windows, different mangling is used for cdecl, stdcall, fastcall and vectorcall. - No mangling is needed on other platforms. r? `@nagisa` cc `@eddyb`
2 parents 27490eb + bdba897 commit 080d545

File tree

50 files changed

+654
-245
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+654
-245
lines changed

compiler/rustc_ast/src/ast.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,20 @@ impl InlineAsmTemplatePiece {
20612061
}
20622062
}
20632063

2064+
/// Inline assembly symbol operands get their own AST node that is somewhat
2065+
/// similar to `AnonConst`.
2066+
///
2067+
/// The main difference is that we specifically don't assign it `DefId` in
2068+
/// `DefCollector`. Instead this is deferred until AST lowering where we
2069+
/// lower it to an `AnonConst` (for functions) or a `Path` (for statics)
2070+
/// depending on what the path resolves to.
2071+
#[derive(Clone, Encodable, Decodable, Debug)]
2072+
pub struct InlineAsmSym {
2073+
pub id: NodeId,
2074+
pub qself: Option<QSelf>,
2075+
pub path: Path,
2076+
}
2077+
20642078
/// Inline assembly operand.
20652079
///
20662080
/// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`.
@@ -2090,7 +2104,7 @@ pub enum InlineAsmOperand {
20902104
anon_const: AnonConst,
20912105
},
20922106
Sym {
2093-
expr: P<Expr>,
2107+
sym: InlineAsmSym,
20942108
},
20952109
}
20962110

compiler/rustc_ast/src/mut_visit.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ pub trait MutVisitor: Sized {
280280
fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
281281
noop_flat_map_pat_field(fp, self)
282282
}
283+
284+
fn visit_inline_asm(&mut self, asm: &mut InlineAsm) {
285+
noop_visit_inline_asm(asm, self)
286+
}
287+
288+
fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
289+
noop_visit_inline_asm_sym(sym, self)
290+
}
283291
}
284292

285293
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
@@ -1019,7 +1027,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
10191027
}
10201028
}
10211029
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
1022-
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
1030+
ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm),
10231031
ItemKind::TyAlias(box TyAlias {
10241032
defaultness, generics, where_clauses, bounds, ty, ..
10251033
}) => {
@@ -1237,25 +1245,34 @@ pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonCo
12371245
vis.visit_expr(value);
12381246
}
12391247

1240-
fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
1248+
pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
12411249
for (op, _) in &mut asm.operands {
12421250
match op {
12431251
InlineAsmOperand::In { expr, .. }
12441252
| InlineAsmOperand::Out { expr: Some(expr), .. }
1245-
| InlineAsmOperand::InOut { expr, .. }
1246-
| InlineAsmOperand::Sym { expr, .. } => vis.visit_expr(expr),
1253+
| InlineAsmOperand::InOut { expr, .. } => vis.visit_expr(expr),
12471254
InlineAsmOperand::Out { expr: None, .. } => {}
12481255
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
12491256
vis.visit_expr(in_expr);
12501257
if let Some(out_expr) = out_expr {
12511258
vis.visit_expr(out_expr);
12521259
}
12531260
}
1254-
InlineAsmOperand::Const { anon_const, .. } => vis.visit_anon_const(anon_const),
1261+
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
1262+
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
12551263
}
12561264
}
12571265
}
12581266

1267+
pub fn noop_visit_inline_asm_sym<T: MutVisitor>(
1268+
InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
1269+
vis: &mut T,
1270+
) {
1271+
vis.visit_id(id);
1272+
vis.visit_qself(qself);
1273+
vis.visit_path(path);
1274+
}
1275+
12591276
pub fn noop_visit_expr<T: MutVisitor>(
12601277
Expr { kind, id, span, attrs, tokens }: &mut Expr,
12611278
vis: &mut T,
@@ -1374,7 +1391,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
13741391
ExprKind::Ret(expr) => {
13751392
visit_opt(expr, |expr| vis.visit_expr(expr));
13761393
}
1377-
ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
1394+
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
13781395
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
13791396
ExprKind::Struct(se) => {
13801397
let StructExpr { qself, path, fields, rest } = se.deref_mut();

compiler/rustc_ast/src/visit.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@ pub trait Visitor<'ast>: Sized {
214214
fn visit_crate(&mut self, krate: &'ast Crate) {
215215
walk_crate(self, krate)
216216
}
217+
fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
218+
walk_inline_asm(self, asm)
219+
}
220+
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
221+
walk_inline_asm_sym(self, sym)
222+
}
217223
}
218224

219225
#[macro_export]
@@ -717,13 +723,12 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo
717723
visitor.visit_expr(&constant.value);
718724
}
719725

720-
fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) {
726+
pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) {
721727
for (op, _) in &asm.operands {
722728
match op {
723729
InlineAsmOperand::In { expr, .. }
724730
| InlineAsmOperand::Out { expr: Some(expr), .. }
725-
| InlineAsmOperand::InOut { expr, .. }
726-
| InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr),
731+
| InlineAsmOperand::InOut { expr, .. } => visitor.visit_expr(expr),
727732
InlineAsmOperand::Out { expr: None, .. } => {}
728733
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
729734
visitor.visit_expr(in_expr);
@@ -732,10 +737,18 @@ fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) {
732737
}
733738
}
734739
InlineAsmOperand::Const { anon_const, .. } => visitor.visit_anon_const(anon_const),
740+
InlineAsmOperand::Sym { sym } => visitor.visit_inline_asm_sym(sym),
735741
}
736742
}
737743
}
738744

745+
pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineAsmSym) {
746+
if let Some(ref qself) = sym.qself {
747+
visitor.visit_ty(&qself.ty);
748+
}
749+
visitor.visit_path(&sym.path, sym.id);
750+
}
751+
739752
pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
740753
walk_list!(visitor, visit_attribute, expression.attrs.iter());
741754

compiler/rustc_ast_lowering/src/asm.rs

+60-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
use crate::{ImplTraitContext, ImplTraitPosition, ParamMode};
2+
13
use super::LoweringContext;
24

5+
use rustc_ast::ptr::P;
36
use rustc_ast::*;
47
use rustc_data_structures::fx::FxHashMap;
58
use rustc_data_structures::stable_set::FxHashSet;
69
use rustc_errors::struct_span_err;
710
use rustc_hir as hir;
11+
use rustc_hir::def::{DefKind, Res};
12+
use rustc_hir::definitions::DefPathData;
813
use rustc_session::parse::feature_err;
9-
use rustc_span::{sym, Span};
14+
use rustc_span::{sym, ExpnId, Span};
1015
use rustc_target::asm;
1116
use std::collections::hash_map::Entry;
1217
use std::fmt::Write;
@@ -188,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
188193
anon_const: self.lower_anon_const(anon_const),
189194
}
190195
}
191-
InlineAsmOperand::Sym { ref expr } => {
196+
InlineAsmOperand::Sym { ref sym } => {
192197
if !self.sess.features_untracked().asm_sym {
193198
feature_err(
194199
&self.sess.parse_sess,
@@ -198,7 +203,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
198203
)
199204
.emit();
200205
}
201-
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
206+
207+
let static_def_id = self
208+
.resolver
209+
.get_partial_res(sym.id)
210+
.filter(|res| res.unresolved_segments() == 0)
211+
.and_then(|res| {
212+
if let Res::Def(DefKind::Static(_), def_id) = res.base_res() {
213+
Some(def_id)
214+
} else {
215+
None
216+
}
217+
});
218+
219+
if let Some(def_id) = static_def_id {
220+
let path = self.lower_qpath(
221+
sym.id,
222+
&sym.qself,
223+
&sym.path,
224+
ParamMode::Optional,
225+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
226+
);
227+
hir::InlineAsmOperand::SymStatic { path, def_id }
228+
} else {
229+
// Replace the InlineAsmSym AST node with an
230+
// Expr using the name node id.
231+
let expr = Expr {
232+
id: sym.id,
233+
kind: ExprKind::Path(sym.qself.clone(), sym.path.clone()),
234+
span: *op_sp,
235+
attrs: AttrVec::new(),
236+
tokens: None,
237+
};
238+
239+
// Wrap the expression in an AnonConst.
240+
let parent_def_id = self.current_hir_id_owner;
241+
let node_id = self.resolver.next_node_id();
242+
self.resolver.create_def(
243+
parent_def_id,
244+
node_id,
245+
DefPathData::AnonConst,
246+
ExpnId::root(),
247+
*op_sp,
248+
);
249+
let anon_const = AnonConst { id: node_id, value: P(expr) };
250+
hir::InlineAsmOperand::SymFn {
251+
anon_const: self.lower_anon_const(&anon_const),
252+
}
253+
}
202254
}
203255
};
204256
(op, self.lower_span(*op_sp))
@@ -260,7 +312,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
260312
err.span_label(op_sp, "argument");
261313
err.emit();
262314
}
263-
hir::InlineAsmOperand::Sym { .. } => {
315+
hir::InlineAsmOperand::SymFn { .. }
316+
| hir::InlineAsmOperand::SymStatic { .. } => {
264317
let mut err = sess.struct_span_err(
265318
placeholder_span,
266319
"asm template modifiers are not allowed for `sym` arguments",
@@ -308,7 +361,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
308361
hir::InlineAsmOperand::InOut { .. }
309362
| hir::InlineAsmOperand::SplitInOut { .. } => (true, true),
310363

311-
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::Sym { .. } => {
364+
hir::InlineAsmOperand::Const { .. }
365+
| hir::InlineAsmOperand::SymFn { .. }
366+
| hir::InlineAsmOperand::SymStatic { .. } => {
312367
unreachable!()
313368
}
314369
};

compiler/rustc_ast_pretty/src/pprust/state.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1266,10 +1266,14 @@ impl<'a> State<'a> {
12661266
s.space();
12671267
s.print_expr(&anon_const.value);
12681268
}
1269-
InlineAsmOperand::Sym { expr } => {
1269+
InlineAsmOperand::Sym { sym } => {
12701270
s.word("sym");
12711271
s.space();
1272-
s.print_expr(expr);
1272+
if let Some(qself) = &sym.qself {
1273+
s.print_qpath(&sym.path, qself, true);
1274+
} else {
1275+
s.print_path(&sym.path, true, 0);
1276+
}
12731277
}
12741278
}
12751279
}

compiler/rustc_builtin_macros/src/asm.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,19 @@ pub fn parse_asm_args<'a>(
154154
} else if p.eat_keyword(kw::Const) {
155155
let anon_const = p.parse_anon_const_expr()?;
156156
ast::InlineAsmOperand::Const { anon_const }
157-
} else if !is_global_asm && p.eat_keyword(sym::sym) {
157+
} else if p.eat_keyword(sym::sym) {
158158
let expr = p.parse_expr()?;
159-
match expr.kind {
160-
ast::ExprKind::Path(..) => {}
161-
_ => {
162-
let err = diag
163-
.struct_span_err(expr.span, "argument to `sym` must be a path expression");
164-
return Err(err);
165-
}
166-
}
167-
ast::InlineAsmOperand::Sym { expr }
159+
let ast::ExprKind::Path(qself, path) = &expr.kind else {
160+
let err = diag
161+
.struct_span_err(expr.span, "expected a path for argument to `sym`");
162+
return Err(err);
163+
};
164+
let sym = ast::InlineAsmSym {
165+
id: ast::DUMMY_NODE_ID,
166+
qself: qself.clone(),
167+
path: path.clone(),
168+
};
169+
ast::InlineAsmOperand::Sym { sym }
168170
} else if allow_templates {
169171
let template = p.parse_expr()?;
170172
// If it can't possibly expand to a string, provide diagnostics here to include other

compiler/rustc_codegen_gcc/src/asm.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
258258
}
259259

260260
InlineAsmOperandRef::SymFn { instance } => {
261+
// TODO(@Amanieu): Additional mangling is needed on
262+
// some targets to add a leading underscore (Mach-O)
263+
// or byte count suffixes (x86 Windows).
261264
constants_len += self.tcx.symbol_name(instance).name.len();
262265
}
263266
InlineAsmOperandRef::SymStatic { def_id } => {
267+
// TODO(@Amanieu): Additional mangling is needed on
268+
// some targets to add a leading underscore (Mach-O).
264269
constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
265270
}
266271
}
@@ -412,13 +417,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
412417
}
413418

414419
InlineAsmOperandRef::SymFn { instance } => {
420+
// TODO(@Amanieu): Additional mangling is needed on
421+
// some targets to add a leading underscore (Mach-O)
422+
// or byte count suffixes (x86 Windows).
415423
let name = self.tcx.symbol_name(instance).name;
416424
template_str.push_str(name);
417425
}
418426

419427
InlineAsmOperandRef::SymStatic { def_id } => {
420-
// TODO(@Commeownist): This may not be sufficient for all kinds of statics.
421-
// Some statics may need the `@plt` suffix, like thread-local vars.
428+
// TODO(@Amanieu): Additional mangling is needed on
429+
// some targets to add a leading underscore (Mach-O).
422430
let instance = Instance::mono(self.tcx, def_id);
423431
let name = self.tcx.symbol_name(instance).name;
424432
template_str.push_str(name);
@@ -656,8 +664,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
656664
}
657665
}
658666

659-
impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
660-
fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) {
667+
impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
668+
fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span]) {
661669
let asm_arch = self.tcx.sess.asm_arch.unwrap();
662670

663671
// Default to Intel syntax on x86
@@ -690,6 +698,22 @@ impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
690698
// here unlike normal inline assembly.
691699
template_str.push_str(string);
692700
}
701+
702+
GlobalAsmOperandRef::SymFn { instance } => {
703+
// TODO(@Amanieu): Additional mangling is needed on
704+
// some targets to add a leading underscore (Mach-O)
705+
// or byte count suffixes (x86 Windows).
706+
let name = self.tcx.symbol_name(instance).name;
707+
template_str.push_str(name);
708+
}
709+
710+
GlobalAsmOperandRef::SymStatic { def_id } => {
711+
// TODO(@Amanieu): Additional mangling is needed on
712+
// some targets to add a leading underscore (Mach-O).
713+
let instance = Instance::mono(self.tcx, def_id);
714+
let name = self.tcx.symbol_name(instance).name;
715+
template_str.push_str(name);
716+
}
693717
}
694718
}
695719
}

0 commit comments

Comments
 (0)