Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 48 additions & 20 deletions compiler/rustc_codegen_cranelift/src/global_asm.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
//! standalone executable.

use std::fmt::Write as _;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::sync::Arc;

use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar as ConstScalar};
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
Expand Down Expand Up @@ -108,27 +110,54 @@ fn codegen_global_asm_inner<'tcx>(
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
use rustc_codegen_ssa::back::symbol_export::escape_symbol_name;
match operands[operand_idx] {
GlobalAsmOperandRef::Const { ref string } => {
global_asm.push_str(string);
}
GlobalAsmOperandRef::SymFn { instance } => {
if cfg!(not(feature = "inline_asm_sym")) {
tcx.dcx().span_err(
span,
"asm! and global_asm! sym operands are not yet supported",
);
}
GlobalAsmOperandRef::Const { value, ty, instance: _ } => {
match value {
ConstScalar::Int(int) => {
let string = rustc_codegen_ssa::common::asm_const_to_str(
tcx,
int,
FullyMonomorphizedLayoutCx(tcx).layout_of(ty),
);
global_asm.push_str(&string);
}

let symbol = tcx.symbol_name(instance);
let symbol_name = if tcx.sess.target.is_like_darwin {
format!("_{}", symbol.name)
} else {
symbol.name.to_owned()
};
ConstScalar::Ptr(ptr, _) => {
let (prov, offset) = ptr.prov_and_relative_offset();
let global_alloc = tcx.global_alloc(prov.alloc_id());
let symbol = match global_alloc {
GlobalAlloc::Function { instance } => {
if cfg!(not(feature = "inline_asm_sym")) {
tcx.dcx().span_err(
span,
"asm! and global_asm! sym operands are not yet supported",
);
}
Copy link
Copy Markdown
Member

@bjorn3 bjorn3 Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error should apply to all constants that reference a symbol.

View changes since the review


// FIXME handle the case where the function was made private to the
// current codegen unit
global_asm.push_str(&escape_symbol_name(tcx, &symbol_name, span));
// FIXME handle the case where the function was made private to the
// current codegen unit
tcx.symbol_name(instance)
}
GlobalAlloc::Static(def_id) => {
Copy link
Copy Markdown
Member

@bjorn3 bjorn3 Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between GlobalAsmOperandRef::Const with a static and GlobalAsmOperandRef::SymStatic?

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #138618 (comment)

#[thread_local] works with sym STATIC today, but it cannot be referenced in CTFE. I would actually be in favour of removing that feature.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would tend to agree with removing #[thread_local] support for sym STATIC. On some platforms (cough Windows cough) #[thread_local] accesses go through a function shim to ensure cross-dylib accesses work, so sym STATIC would probably already be broken for those platforms.

let instance = Instance::mono(tcx, def_id);
tcx.symbol_name(instance)
}
GlobalAlloc::Memory(_)
| GlobalAlloc::VTable(..)
| GlobalAlloc::TypeId { .. } => unreachable!(),
};
let symbol_name = if tcx.sess.target.is_like_darwin {
format!("_{}", symbol.name)
} else {
symbol.name.to_owned()
};
global_asm.push_str(&escape_symbol_name(tcx, &symbol_name, span));

if offset != Size::ZERO {
let offset = tcx.sign_extend_to_target_isize(offset.bytes());
write!(global_asm, "{offset:+}").unwrap();
}
}
}
}
GlobalAsmOperandRef::SymStatic { def_id } => {
if cfg!(not(feature = "inline_asm_sym")) {
Expand All @@ -137,7 +166,6 @@ fn codegen_global_asm_inner<'tcx>(
"asm! and global_asm! sym operands are not yet supported",
);
}

Copy link
Copy Markdown
Member

@bjorn3 bjorn3 Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore this newline.

View changes since the review

let instance = Instance::mono(tcx, def_id);
let symbol = tcx.symbol_name(instance);
let symbol_name = if tcx.sess.target.is_like_darwin {
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_codegen_cranelift/src/inline_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,17 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
}
InlineAsmOperand::Const { ref value } => {
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
let mir::ConstValue::Scalar(scalar) = const_value else {
span_bug!(
span,
"expected Scalar for promoted asm const, but got {:#?}",
const_value
)
};

let value = rustc_codegen_ssa::common::asm_const_to_str(
fx.tcx,
span,
const_value,
scalar.assert_scalar_int(),
fx.layout_of(ty),
);
CInlineAsmOperand::Const { value }
Expand Down
146 changes: 96 additions & 50 deletions compiler/rustc_codegen_gcc/src/asm.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
// cSpell:ignoreRegExp [afkspqvwy]reg

use std::borrow::Cow;
use std::fmt::Write;

use gccjit::{LValue, RValue, ToRValue, Type};
use rustc_abi::Size;
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{
AsmBuilderMethods, AsmCodegenMethods, BaseTypeCodegenMethods, BuilderMethods,
GlobalAsmOperandRef, InlineAsmOperandRef,
ConstCodegenMethods, GlobalAsmOperandRef, InlineAsmOperandRef,
};
use rustc_middle::bug;
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
use rustc_middle::ty::Instance;
use rustc_middle::ty::layout::LayoutOf;
use rustc_span::Span;
use rustc_target::asm::*;

Expand Down Expand Up @@ -143,6 +147,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// Clobbers collected from `out("explicit register") _` and `inout("explicit_reg") var => _`
let mut clobbers = vec![];

// Symbols name that needs to be inserted to asm const ptr template string.
let mut const_syms = vec![];

// We're trying to preallocate space for the template
let mut constants_len = 0;

Expand Down Expand Up @@ -303,16 +310,11 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}
}

InlineAsmOperandRef::Const { ref string } => {
constants_len += string.len() + att_dialect as usize;
InlineAsmOperandRef::Const { .. } => {
// We don't know the size at this point, just some estimate.
constants_len += 20;
}

InlineAsmOperandRef::SymFn { instance } => {
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
constants_len += self.tcx.symbol_name(instance).name.len();
}
InlineAsmOperandRef::SymStatic { def_id } => {
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
Expand Down Expand Up @@ -402,24 +404,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// processed in the previous pass
}

InlineAsmOperandRef::SymFn { instance } => {
inputs.push(AsmInOperand {
constraint: "X".into(),
rust_idx,
val: get_fn(self.cx, instance).get_address(None),
});
}
InlineAsmOperandRef::Const { value, ty: _, instance } => match value {
Scalar::Int(_) => (),
Scalar::Ptr(ptr, _) => {
let (prov, _) = ptr.prov_and_relative_offset();
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
let (val, sym) = self.cx.alloc_to_backend(global_alloc, instance).unwrap();
const_syms.push(sym.unwrap());
inputs.push(AsmInOperand { constraint: "X".into(), rust_idx, val });
}
},

InlineAsmOperandRef::SymStatic { def_id } => {
inputs.push(AsmInOperand {
constraint: "X".into(),
rust_idx,
val: self.cx.get_static(def_id).get_address(None),
});
}

InlineAsmOperandRef::Const { .. } => {
// processed in the previous pass
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (MachO).
constants_len +=
self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
}

InlineAsmOperandRef::Label { .. } => {
Expand Down Expand Up @@ -495,12 +495,33 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
push_to_template(modifier, gcc_index);
}

InlineAsmOperandRef::SymFn { instance } => {
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
let name = self.tcx.symbol_name(instance).name;
template_str.push_str(name);
InlineAsmOperandRef::Const { value, ty, instance: _ } => {
match value {
Scalar::Int(int) => {
// Const operands get injected directly into the template
let string = rustc_codegen_ssa::common::asm_const_to_str(
self.tcx,
int,
self.layout_of(ty),
);
template_str.push_str(&string);
}

Scalar::Ptr(ptr, _) => {
let (_, offset) = ptr.prov_and_relative_offset();
let instance = const_syms.remove(0);
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
template_str.push_str(self.tcx.symbol_name(instance).name);

if offset != Size::ZERO {
let offset =
self.sign_extend_to_target_isize(offset.bytes());
write!(template_str, "{offset:+}").unwrap();
}
}
}
}

InlineAsmOperandRef::SymStatic { def_id } => {
Expand All @@ -511,10 +532,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
template_str.push_str(name);
}

InlineAsmOperandRef::Const { ref string } => {
template_str.push_str(string);
}

InlineAsmOperandRef::Label { label } => {
let label_gcc_index =
labels.iter().position(|&l| l == label).expect("wrong rust index");
Expand Down Expand Up @@ -907,23 +924,52 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
match operands[operand_idx] {
GlobalAsmOperandRef::Const { ref string } => {
// Const operands get injected directly into the
// template. Note that we don't need to escape %
// here unlike normal inline assembly.
template_str.push_str(string);
}
GlobalAsmOperandRef::Const { value, ty, instance } => {
match value {
Scalar::Int(int) => {
// Const operands get injected directly into the
// template. Note that we don't need to escape %
// here unlike normal inline assembly.
let string = rustc_codegen_ssa::common::asm_const_to_str(
self.tcx,
int,
self.layout_of(ty),
);
template_str.push_str(&string);
}

GlobalAsmOperandRef::SymFn { instance } => {
let function = get_fn(self, instance);
self.add_used_function(function);
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
let name = self.tcx.symbol_name(instance).name;
template_str.push_str(name);
Scalar::Ptr(ptr, _) => {
let (prov, offset) = ptr.prov_and_relative_offset();
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
let symbol_name = match global_alloc {
GlobalAlloc::Function { instance } => {
let function = get_fn(self, instance);
self.add_used_function(function);
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
self.tcx.symbol_name(instance)
}
_ => {
let (_, syms) = self
.alloc_to_backend(global_alloc, instance)
.unwrap();
// FIXME(antoyo): set the global variable as used.
// FIXME(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
self.tcx.symbol_name(syms.unwrap())
}
};
template_str.push_str(symbol_name.name);

if offset != Size::ZERO {
let offset =
self.sign_extend_to_target_isize(offset.bytes());
write!(template_str, "{offset:+}").unwrap();
}
}
}
}

GlobalAsmOperandRef::SymStatic { def_id } => {
// FIXME(antoyo): set the global variable as used.
// FIXME(@Amanieu): Additional mangling is needed on
Expand Down
Loading
Loading