Skip to content

Commit 5b342bc

Browse files
committed
Implement asm_const_ptr for global_asm and naked_asm
1 parent ddf8155 commit 5b342bc

File tree

13 files changed

+353
-94
lines changed

13 files changed

+353
-94
lines changed

compiler/rustc_codegen_cranelift/src/global_asm.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use std::sync::Arc;
88

99
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1010
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
11-
use rustc_middle::ty::TyCtxt;
1211
use rustc_middle::ty::layout::{
1312
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
1413
};
14+
use rustc_middle::ty::{Instance, TyCtxt};
1515
use rustc_session::config::{OutputFilenames, OutputType};
1616
use rustc_target::asm::InlineAsmArch;
1717

@@ -135,6 +135,12 @@ fn codegen_global_asm_inner<'tcx>(
135135
let symbol = tcx.symbol_name(instance);
136136
global_asm.push_str(symbol.name);
137137
}
138+
GlobalAsmOperandRef::ConstPointer { value: _, instance: _ } => {
139+
tcx.dcx().span_err(
140+
span,
141+
"asm! and global_asm! const pointer operands are not yet supported",
142+
);
143+
}
138144
}
139145
}
140146
}

compiler/rustc_codegen_gcc/src/asm.rs

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22

33
use std::borrow::Cow;
44

5-
use gccjit::{LValue, RValue, ToRValue, Type};
5+
use gccjit::{GlobalKind, LValue, RValue, ToRValue, Type};
66
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
77
use rustc_codegen_ssa::mir::operand::OperandValue;
88
use rustc_codegen_ssa::mir::place::PlaceRef;
99
use rustc_codegen_ssa::traits::{
1010
AsmBuilderMethods, AsmCodegenMethods, BaseTypeCodegenMethods, BuilderMethods,
1111
GlobalAsmOperandRef, InlineAsmOperandRef,
1212
};
13-
use rustc_middle::bug;
1413
use rustc_middle::ty::Instance;
14+
use rustc_middle::{bug, mir};
1515
use rustc_span::Span;
1616
use rustc_target::asm::*;
1717

@@ -890,6 +890,100 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
890890
let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
891891
&& options.contains(InlineAsmOptions::ATT_SYNTAX);
892892

893+
// Convert all operands to string interpolations
894+
let converted_operands = operands
895+
.iter()
896+
.map(|operand| {
897+
match *operand {
898+
GlobalAsmOperandRef::Interpolate { ref string } => {
899+
// Const operands get injected directly into the
900+
// template. Note that we don't need to escape $
901+
// here unlike normal inline assembly.
902+
string.to_owned()
903+
}
904+
GlobalAsmOperandRef::ConstPointer { value, instance } => {
905+
let (prov, offset) = value.prov_and_relative_offset();
906+
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
907+
let symbol = 'sym: {
908+
let alloc = match global_alloc {
909+
mir::interpret::GlobalAlloc::Function { instance } => {
910+
let function = get_fn(self, instance);
911+
self.add_used_function(function);
912+
// TODO(@Amanieu): Additional mangling is needed on
913+
// some targets to add a leading underscore (Mach-O)
914+
// or byte count suffixes (x86 Windows).
915+
break 'sym self.tcx.symbol_name(instance).name.to_owned();
916+
}
917+
mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self
918+
.tcx
919+
.global_alloc(self.tcx.vtable_allocation((
920+
ty,
921+
dyn_ty.principal().map(|principal| {
922+
self.tcx
923+
.instantiate_bound_regions_with_erased(principal)
924+
}),
925+
)))
926+
.unwrap_memory(),
927+
mir::interpret::GlobalAlloc::Static(def_id) => {
928+
// TODO(antoyo): set the global variable as used.
929+
// TODO(@Amanieu): Additional mangling is needed on
930+
// some targets to add a leading underscore (Mach-O).
931+
let instance = Instance::mono(self.tcx, def_id);
932+
break 'sym self.tcx.symbol_name(instance).name.to_owned();
933+
}
934+
mir::interpret::GlobalAlloc::Memory(alloc) => alloc,
935+
mir::interpret::GlobalAlloc::TypeId { .. } => {
936+
// This is not an actual allocation, just return the offset.
937+
return format!("{}", offset.bytes());
938+
}
939+
};
940+
941+
// For ZSTs directly codegen an aligned pointer.
942+
if alloc.inner().len() == 0 {
943+
assert_eq!(offset.bytes(), 0);
944+
return format!("{}", alloc.inner().align.bytes());
945+
}
946+
947+
let sym_name = self.tcx.symbol_name(instance).to_string();
948+
949+
let init = crate::consts::const_alloc_to_gcc_uncached(self, alloc);
950+
let alloc = alloc.inner();
951+
let typ = self.val_ty(init).get_aligned(alloc.align.bytes());
952+
953+
let global = self.declare_global_with_linkage(
954+
&sym_name,
955+
typ,
956+
GlobalKind::Exported,
957+
);
958+
global.global_set_initializer_rvalue(init);
959+
// TODO(nbdd0121): set unnamed address.
960+
// TODO(nbdd0121): set the global variable as used.
961+
962+
sym_name
963+
};
964+
965+
let offset = offset.bytes();
966+
if offset != 0 { format!("{symbol}+{offset}") } else { symbol }
967+
}
968+
GlobalAsmOperandRef::SymFn { instance } => {
969+
let function = get_fn(self, instance);
970+
self.add_used_function(function);
971+
// TODO(@Amanieu): Additional mangling is needed on
972+
// some targets to add a leading underscore (Mach-O)
973+
// or byte count suffixes (x86 Windows).
974+
self.tcx.symbol_name(instance).name.to_owned()
975+
}
976+
GlobalAsmOperandRef::SymStatic { def_id } => {
977+
// TODO(antoyo): set the global variable as used.
978+
// TODO(@Amanieu): Additional mangling is needed on
979+
// some targets to add a leading underscore (Mach-O).
980+
let instance = Instance::mono(self.tcx, def_id);
981+
self.tcx.symbol_name(instance).name.to_owned()
982+
}
983+
}
984+
})
985+
.collect::<Vec<_>>();
986+
893987
// Build the template string
894988
let mut template_str = ".pushsection .text\n".to_owned();
895989
if att_dialect {
@@ -913,33 +1007,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
9131007
}
9141008
}
9151009
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
916-
match operands[operand_idx] {
917-
GlobalAsmOperandRef::Interpolate { ref string } => {
918-
// Const operands get injected directly into the
919-
// template. Note that we don't need to escape %
920-
// here unlike normal inline assembly.
921-
template_str.push_str(string);
922-
}
923-
924-
GlobalAsmOperandRef::SymFn { instance } => {
925-
let function = get_fn(self, instance);
926-
self.add_used_function(function);
927-
// TODO(@Amanieu): Additional mangling is needed on
928-
// some targets to add a leading underscore (Mach-O)
929-
// or byte count suffixes (x86 Windows).
930-
let name = self.tcx.symbol_name(instance).name;
931-
template_str.push_str(name);
932-
}
933-
934-
GlobalAsmOperandRef::SymStatic { def_id } => {
935-
// TODO(antoyo): set the global variable as used.
936-
// TODO(@Amanieu): Additional mangling is needed on
937-
// some targets to add a leading underscore (Mach-O).
938-
let instance = Instance::mono(self.tcx, def_id);
939-
let name = self.tcx.symbol_name(instance).name;
940-
template_str.push_str(name);
941-
}
942-
}
1010+
template_str.push_str(&converted_operands[operand_idx]);
9431011
}
9441012
}
9451013
}

compiler/rustc_codegen_llvm/src/asm.rs

Lines changed: 109 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::*;
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_middle::ty::Instance;
99
use rustc_middle::ty::layout::TyAndLayout;
10-
use rustc_middle::{bug, span_bug};
10+
use rustc_middle::{bug, mir, span_bug};
1111
use rustc_span::{Pos, Span, Symbol, sym};
1212
use rustc_target::asm::*;
1313
use smallvec::SmallVec;
@@ -392,6 +392,113 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
392392
) {
393393
let asm_arch = self.tcx.sess.asm_arch.unwrap();
394394

395+
// Convert all operands to string interpolations
396+
let converted_operands = operands
397+
.iter()
398+
.map(|operand| {
399+
match *operand {
400+
GlobalAsmOperandRef::Interpolate { ref string } => {
401+
// Const operands get injected directly into the
402+
// template. Note that we don't need to escape $
403+
// here unlike normal inline assembly.
404+
string.to_owned()
405+
}
406+
GlobalAsmOperandRef::ConstPointer { value, instance } => {
407+
let (prov, offset) = value.prov_and_relative_offset();
408+
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
409+
let llval = 'llval: {
410+
let alloc = match global_alloc {
411+
mir::interpret::GlobalAlloc::Function { instance } => {
412+
break 'llval self.get_fn(instance);
413+
}
414+
mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self
415+
.tcx
416+
.global_alloc(self.tcx.vtable_allocation((
417+
ty,
418+
dyn_ty.principal().map(|principal| {
419+
self.tcx
420+
.instantiate_bound_regions_with_erased(principal)
421+
}),
422+
)))
423+
.unwrap_memory(),
424+
mir::interpret::GlobalAlloc::Static(def_id) => {
425+
break 'llval self
426+
.renamed_statics
427+
.borrow()
428+
.get(&def_id)
429+
.copied()
430+
.unwrap_or_else(|| self.get_static(def_id));
431+
}
432+
mir::interpret::GlobalAlloc::Memory(alloc) => alloc,
433+
mir::interpret::GlobalAlloc::TypeId { .. } => {
434+
// This is not an actual allocation, just return the offset.
435+
return format!("{}", offset.bytes());
436+
}
437+
};
438+
let alloc = alloc.inner();
439+
440+
// For ZSTs directly codegen an aligned pointer.
441+
if alloc.len() == 0 {
442+
assert_eq!(offset.bytes(), 0);
443+
return format!("{}", alloc.align.bytes());
444+
}
445+
446+
let sym_name = self.tcx.symbol_name(instance);
447+
448+
let init = crate::consts::const_alloc_to_llvm(
449+
self, alloc, /*static*/ false,
450+
);
451+
let g = self.static_addr_of_mut(init, alloc.align, None);
452+
if alloc.mutability.is_not() {
453+
// NB: we can't use `static_addr_of_impl` here to avoid sharing
454+
// the global, as we need to set name and linkage.
455+
llvm::LLVMSetGlobalConstant(g, llvm::TRUE);
456+
}
457+
458+
llvm::set_value_name(g, sym_name.name.as_bytes());
459+
460+
// `static_addr_of_mut` gives us a private global which can't be
461+
// used by global asm. Update it to a hidden internal global instead.
462+
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
463+
llvm::set_visibility(g, llvm::Visibility::Hidden);
464+
g
465+
};
466+
self.add_compiler_used_global(llval);
467+
let symbol = llvm::build_string(|s| unsafe {
468+
llvm::LLVMRustGetMangledName(llval, s);
469+
})
470+
.expect("symbol is not valid UTF-8");
471+
472+
let offset = offset.bytes();
473+
if offset != 0 { format!("{symbol}+{offset}") } else { symbol }
474+
}
475+
GlobalAsmOperandRef::SymFn { instance } => {
476+
let llval = self.get_fn(instance);
477+
self.add_compiler_used_global(llval);
478+
let symbol = llvm::build_string(|s| unsafe {
479+
llvm::LLVMRustGetMangledName(llval, s);
480+
})
481+
.expect("symbol is not valid UTF-8");
482+
symbol
483+
}
484+
GlobalAsmOperandRef::SymStatic { def_id } => {
485+
let llval = self
486+
.renamed_statics
487+
.borrow()
488+
.get(&def_id)
489+
.copied()
490+
.unwrap_or_else(|| self.get_static(def_id));
491+
self.add_compiler_used_global(llval);
492+
let symbol = llvm::build_string(|s| unsafe {
493+
llvm::LLVMRustGetMangledName(llval, s);
494+
})
495+
.expect("symbol is not valid UTF-8");
496+
symbol
497+
}
498+
}
499+
})
500+
.collect::<Vec<_>>();
501+
395502
// Build the template string
396503
let mut template_str = String::new();
397504

@@ -409,37 +516,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
409516
match *piece {
410517
InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s),
411518
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
412-
match operands[operand_idx] {
413-
GlobalAsmOperandRef::Interpolate { ref string } => {
414-
// Const operands get injected directly into the
415-
// template. Note that we don't need to escape $
416-
// here unlike normal inline assembly.
417-
template_str.push_str(string);
418-
}
419-
GlobalAsmOperandRef::SymFn { instance } => {
420-
let llval = self.get_fn(instance);
421-
self.add_compiler_used_global(llval);
422-
let symbol = llvm::build_string(|s| unsafe {
423-
llvm::LLVMRustGetMangledName(llval, s);
424-
})
425-
.expect("symbol is not valid UTF-8");
426-
template_str.push_str(&symbol);
427-
}
428-
GlobalAsmOperandRef::SymStatic { def_id } => {
429-
let llval = self
430-
.renamed_statics
431-
.borrow()
432-
.get(&def_id)
433-
.copied()
434-
.unwrap_or_else(|| self.get_static(def_id));
435-
self.add_compiler_used_global(llval);
436-
let symbol = llvm::build_string(|s| unsafe {
437-
llvm::LLVMRustGetMangledName(llval, s);
438-
})
439-
.expect("symbol is not valid UTF-8");
440-
template_str.push_str(&symbol);
441-
}
442-
}
519+
template_str.push_str(&converted_operands[operand_idx])
443520
}
444521
}
445522
}

0 commit comments

Comments
 (0)