diff --git a/build_system/tests.rs b/build_system/tests.rs index c7b61f519d..c575c5d9a6 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -87,6 +87,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ &[], ), TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]), + TestCase::build_bin_and_run("aot.naked-asm-const-ptr", "example/naked-asm-const-ptr.rs", &[]), TestCase::custom("aot.powi_libcall_signature", &|runner| { let mut cmd = runner.rustc_command(["example/powi-libcall-signature.rs"]); let output = cmd.output().unwrap(); diff --git a/config.txt b/config.txt index ca126f4e39..5a6f3174b9 100644 --- a/config.txt +++ b/config.txt @@ -19,6 +19,7 @@ aot.dst_field_align aot.subslice-patterns-const-eval aot.track-caller-attribute aot.float-minmax-pass +aot.naked-asm-const-ptr aot.powi_libcall_signature aot.issue-72793 aot.issue-59326 diff --git a/example/naked-asm-const-ptr.rs b/example/naked-asm-const-ptr.rs new file mode 100644 index 0000000000..cd4898b78a --- /dev/null +++ b/example/naked-asm-const-ptr.rs @@ -0,0 +1,19 @@ +// Regression test for https://github.com/rust-lang/rustc_codegen_cranelift/issues/1690 +// run-pass + +#![feature(asm_const_ptr)] + +use std::arch::naked_asm; + +#[unsafe(naked)] +extern "C" fn naked() { + // `ret` is x86-specific; s390x returns via `br %r14` (see `has_mnemonic` in src/lib.rs). + #[cfg(not(target_arch = "s390x"))] + naked_asm!("ret /* {} */", const &0); + #[cfg(target_arch = "s390x")] + naked_asm!("br %r14 /* {} */", const &0); +} + +fn main() { + naked(); +} diff --git a/src/driver/aot.rs b/src/driver/aot.rs index d6c25cf524..10ae2e84da 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -27,6 +27,7 @@ use rustc_session::config::{OptLevel, OutputFilenames, OutputType}; use rustc_span::Symbol; use crate::base::CodegenedFunction; +use crate::constant::ConstantCx; use crate::debuginfo::TypeDebugContext; use crate::global_asm::{GlobalAsmConfig, GlobalAsmContext}; use crate::prelude::*; @@ -39,6 +40,7 @@ pub(crate) struct AotModule { debug_context: Option, codegened_functions: Vec, global_asm: String, + constants_cx: ConstantCx, } fn make_module(tcx: TyCtxt<'_>, cgu_name: &str) -> AotModule { @@ -77,6 +79,7 @@ fn make_module(tcx: TyCtxt<'_>, cgu_name: &str) -> AotModule { debug_context, codegened_functions, global_asm, + constants_cx: ConstantCx::new(), } } @@ -159,7 +162,12 @@ fn codegen_cgu(tcx: TyCtxt<'_>, cgu_name: Symbol) -> AotModule { let flags = tcx.codegen_instance_attrs(instance.def).flags; if flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( - &mut GlobalAsmContext { tcx, global_asm: &mut module.global_asm }, + &mut GlobalAsmContext { + tcx, + global_asm: &mut module.global_asm, + module: &mut module.module, + constants_cx: &mut module.constants_cx, + }, instance, MonoItemData { linkage: RLinkage::External, @@ -192,7 +200,12 @@ fn codegen_cgu(tcx: TyCtxt<'_>, cgu_name: Symbol) -> AotModule { } MonoItem::GlobalAsm(item_id) => { rustc_codegen_ssa::base::codegen_global_asm( - &mut GlobalAsmContext { tcx, global_asm: &mut module.global_asm }, + &mut GlobalAsmContext { + tcx, + global_asm: &mut module.global_asm, + module: &mut module.module, + constants_cx: &mut module.constants_cx, + }, item_id, ); } @@ -200,6 +213,9 @@ fn codegen_cgu(tcx: TyCtxt<'_>, cgu_name: Symbol) -> AotModule { } crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module.module, false, cgu.is_primary()); + let constants_cx = std::mem::replace(&mut module.constants_cx, ConstantCx::new()); + constants_cx.finalize(tcx, &mut module.module); + module } diff --git a/src/global_asm.rs b/src/global_asm.rs index 9763b0c0fa..dd386d3b0b 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -16,11 +16,14 @@ use rustc_middle::ty::layout::{ use rustc_session::Session; use rustc_target::asm::InlineAsmArch; +use crate::constant::ConstantCx; use crate::prelude::*; pub(crate) struct GlobalAsmContext<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub global_asm: &'a mut String, + pub module: &'a mut dyn Module, + pub constants_cx: &'a mut ConstantCx, } impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { @@ -31,7 +34,15 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { options: InlineAsmOptions, _line_spans: &[Span], ) { - codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options); + codegen_global_asm_inner( + self.tcx, + self.global_asm, + self.module, + self.constants_cx, + template, + operands, + options, + ); } fn mangled_name(&self, instance: Instance<'tcx>) -> String { @@ -90,6 +101,8 @@ impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> { fn codegen_global_asm_inner<'tcx>( tcx: TyCtxt<'tcx>, global_asm: &mut String, + module: &mut dyn Module, + constants_cx: &mut ConstantCx, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, @@ -103,68 +116,96 @@ fn codegen_global_asm_inner<'tcx>( global_asm.push_str("\n.att_syntax\n"); } } - for piece in template { + 'template: for piece in template { match *piece { InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s), InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => { use rustc_codegen_ssa::back::symbol_export::escape_symbol_name; match operands[operand_idx] { - GlobalAsmOperandRef::Const { value, ty } => { - match value { - ConstScalar::Int(int) => { - let string = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - span, - int, - FullyMonomorphizedLayoutCx(tcx).layout_of(ty), - ); - global_asm.push_str(&string); - } + GlobalAsmOperandRef::Const { value, ty } => match value { + ConstScalar::Int(int) => { + let string = rustc_codegen_ssa::common::asm_const_to_str( + tcx, + span, + int, + FullyMonomorphizedLayoutCx(tcx).layout_of(ty), + ); + global_asm.push_str(&string); + } - ConstScalar::Ptr(ptr, _) => { - if cfg!(not(feature = "inline_asm_sym")) { - tcx.dcx().span_err( - span, - "asm! and global_asm! sym operands are not yet supported", - ); - } + ConstScalar::Ptr(ptr, _) => { + let (prov, offset) = ptr.prov_and_relative_offset(); + let global_alloc = tcx.global_alloc(prov.alloc_id()); + let symbol_name = 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", + ); + continue 'template; + } - 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 } => { - // FIXME handle the case where the function was made private to the - // current codegen unit - tcx.symbol_name(instance) + let symbol = tcx.symbol_name(instance); + if tcx.sess.target.is_like_darwin { + format!("_{}", symbol.name) + } else { + symbol.name.to_owned() } - GlobalAlloc::Static(def_id) => { - let instance = Instance::mono(tcx, def_id); - tcx.symbol_name(instance) + } + GlobalAlloc::Static(def_id) => { + if cfg!(not(feature = "inline_asm_sym")) { + tcx.dcx().span_err( + span, + "asm! and global_asm! sym operands are not yet supported", + ); + continue 'template; } - 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(); + let instance = Instance::mono(tcx, def_id); + let symbol = tcx.symbol_name(instance); + if tcx.sess.target.is_like_darwin { + format!("_{}", symbol.name) + } else { + symbol.name.to_owned() + } + } + GlobalAlloc::Memory(alloc) => { + let data_id = crate::constant::data_id_for_alloc_id( + constants_cx, + module, + prov.alloc_id(), + alloc.inner().mutability, + ); + module + .declarations() + .get_data_decl(data_id) + .linkage_name(data_id) + .into_owned() } + GlobalAlloc::VTable(..) | GlobalAlloc::TypeId { .. } => { + tcx.dcx().span_err( + span, + "unsupported allocation for global_asm const pointer", + ); + continue 'template; + } + }; + 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::SymThreadLocalStatic { def_id } => { if cfg!(not(feature = "inline_asm_sym")) { tcx.dcx().span_err( span, "asm! and global_asm! sym operands are not yet supported", ); + continue 'template; } let instance = Instance::mono(tcx, def_id);