Skip to content

Commit 8e7515b

Browse files
committed
Auto merge of #138618 - nbdd0121:asm_const_ptr, r=compiler-errors
Support using const pointers in asm `const` operand Implements #128464 This adds support of const pointers for asm `const` in addition to plain integers. The inline `asm!` support is implemented using `i` constraint, and the `global_asm!` and `naked_asm!` support is implemented by inserting `symbol + offset` and make `symbol` compiler-used. For unnamed consts, it will create additional internal & hidden symbols so that they can be referenced by global_asm. The feature is also implemented for GCC backend but it's untested.
2 parents 855e0fe + 8da54fc commit 8e7515b

File tree

25 files changed

+515
-165
lines changed

25 files changed

+515
-165
lines changed

compiler/rustc_codegen_cranelift/src/global_asm.rs

Lines changed: 9 additions & 2 deletions
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

@@ -29,6 +29,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
2929
operands: &[GlobalAsmOperandRef<'tcx>],
3030
options: InlineAsmOptions,
3131
_line_spans: &[Span],
32+
_instance: Instance<'_>,
3233
) {
3334
codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options);
3435
}
@@ -104,7 +105,7 @@ fn codegen_global_asm_inner<'tcx>(
104105
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
105106
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
106107
match operands[operand_idx] {
107-
GlobalAsmOperandRef::Const { ref string } => {
108+
GlobalAsmOperandRef::Interpolate { ref string } => {
108109
global_asm.push_str(string);
109110
}
110111
GlobalAsmOperandRef::SymFn { instance } => {
@@ -132,6 +133,12 @@ fn codegen_global_asm_inner<'tcx>(
132133
let symbol = tcx.symbol_name(instance);
133134
global_asm.push_str(symbol.name);
134135
}
136+
GlobalAsmOperandRef::ConstPointer { value: _ } => {
137+
tcx.dcx().span_err(
138+
span,
139+
"asm! and global_asm! const pointer operands are not yet supported",
140+
);
141+
}
135142
}
136143
}
137144
}

compiler/rustc_codegen_gcc/src/asm.rs

Lines changed: 123 additions & 31 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

@@ -296,10 +296,18 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
296296
}
297297
}
298298

299-
InlineAsmOperandRef::Const { ref string } => {
299+
InlineAsmOperandRef::Interpolate { ref string } => {
300300
constants_len += string.len() + att_dialect as usize;
301301
}
302302

303+
InlineAsmOperandRef::Const { value } => {
304+
inputs.push(AsmInOperand {
305+
constraint: Cow::Borrowed("i"),
306+
rust_idx,
307+
val: value.immediate(),
308+
});
309+
}
310+
303311
InlineAsmOperandRef::SymFn { instance } => {
304312
// TODO(@Amanieu): Additional mangling is needed on
305313
// some targets to add a leading underscore (Mach-O)
@@ -411,6 +419,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
411419
});
412420
}
413421

422+
InlineAsmOperandRef::Interpolate { .. } => {
423+
// processed in the previous pass
424+
}
425+
414426
InlineAsmOperandRef::Const { .. } => {
415427
// processed in the previous pass
416428
}
@@ -488,6 +500,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
488500
push_to_template(modifier, gcc_index);
489501
}
490502

503+
InlineAsmOperandRef::Const { .. } => {
504+
let in_gcc_index = inputs
505+
.iter()
506+
.position(|op| operand_idx == op.rust_idx)
507+
.expect("wrong rust index");
508+
let gcc_index = in_gcc_index + outputs.len();
509+
push_to_template(None, gcc_index);
510+
}
511+
491512
InlineAsmOperandRef::SymFn { instance } => {
492513
// TODO(@Amanieu): Additional mangling is needed on
493514
// some targets to add a leading underscore (Mach-O)
@@ -504,7 +525,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
504525
template_str.push_str(name);
505526
}
506527

507-
InlineAsmOperandRef::Const { ref string } => {
528+
InlineAsmOperandRef::Interpolate { ref string } => {
508529
template_str.push_str(string);
509530
}
510531

@@ -837,13 +858,110 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
837858
operands: &[GlobalAsmOperandRef<'tcx>],
838859
options: InlineAsmOptions,
839860
_line_spans: &[Span],
861+
instance: Instance<'tcx>,
840862
) {
841863
let asm_arch = self.tcx.sess.asm_arch.unwrap();
842864

843865
// Default to Intel syntax on x86
844866
let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
845867
&& options.contains(InlineAsmOptions::ATT_SYNTAX);
846868

869+
// Convert all operands to string interpolations
870+
let converted_operands = operands
871+
.iter()
872+
.enumerate()
873+
.map(|(operand_idx, operand)| {
874+
match *operand {
875+
GlobalAsmOperandRef::Interpolate { ref string } => {
876+
// Const operands get injected directly into the
877+
// template. Note that we don't need to escape $
878+
// here unlike normal inline assembly.
879+
string.to_owned()
880+
}
881+
GlobalAsmOperandRef::ConstPointer { value } => {
882+
let (prov, offset) = value.prov_and_relative_offset();
883+
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
884+
let symbol = 'sym: {
885+
let alloc = match global_alloc {
886+
mir::interpret::GlobalAlloc::Function { instance } => {
887+
let function = get_fn(self, instance);
888+
self.add_used_function(function);
889+
// TODO(@Amanieu): Additional mangling is needed on
890+
// some targets to add a leading underscore (Mach-O)
891+
// or byte count suffixes (x86 Windows).
892+
break 'sym self.tcx.symbol_name(instance).name.to_owned();
893+
}
894+
mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self
895+
.tcx
896+
.global_alloc(self.tcx.vtable_allocation((
897+
ty,
898+
dyn_ty.principal().map(|principal| {
899+
self.tcx
900+
.instantiate_bound_regions_with_erased(principal)
901+
}),
902+
)))
903+
.unwrap_memory(),
904+
mir::interpret::GlobalAlloc::Static(def_id) => {
905+
// TODO(antoyo): set the global variable as used.
906+
// TODO(@Amanieu): Additional mangling is needed on
907+
// some targets to add a leading underscore (Mach-O).
908+
let instance = Instance::mono(self.tcx, def_id);
909+
break 'sym self.tcx.symbol_name(instance).name.to_owned();
910+
}
911+
mir::interpret::GlobalAlloc::Memory(alloc) => alloc,
912+
mir::interpret::GlobalAlloc::TypeId { .. } => {
913+
// This is not an actual allocation, just return the offset.
914+
return format!("{}", offset.bytes());
915+
}
916+
};
917+
918+
// For ZSTs directly codegen an aligned pointer.
919+
if alloc.inner().len() == 0 {
920+
assert_eq!(offset.bytes(), 0);
921+
return format!("{}", alloc.inner().align.bytes());
922+
}
923+
924+
let asm_name = self.tcx.symbol_name(instance);
925+
let sym_name = format!("{asm_name}.{operand_idx}");
926+
927+
let init = crate::consts::const_alloc_to_gcc_uncached(self, alloc);
928+
let alloc = alloc.inner();
929+
let typ = self.val_ty(init).get_aligned(alloc.align.bytes());
930+
931+
let global = self.declare_global_with_linkage(
932+
&sym_name,
933+
typ,
934+
GlobalKind::Exported,
935+
);
936+
global.global_set_initializer_rvalue(init);
937+
// TODO(nbdd0121): set unnamed address.
938+
// TODO(nbdd0121): set the global variable as used.
939+
940+
sym_name
941+
};
942+
943+
let offset = offset.bytes();
944+
if offset != 0 { format!("{symbol}+{offset}") } else { symbol }
945+
}
946+
GlobalAsmOperandRef::SymFn { instance } => {
947+
let function = get_fn(self, instance);
948+
self.add_used_function(function);
949+
// TODO(@Amanieu): Additional mangling is needed on
950+
// some targets to add a leading underscore (Mach-O)
951+
// or byte count suffixes (x86 Windows).
952+
self.tcx.symbol_name(instance).name.to_owned()
953+
}
954+
GlobalAsmOperandRef::SymStatic { def_id } => {
955+
// TODO(antoyo): set the global variable as used.
956+
// TODO(@Amanieu): Additional mangling is needed on
957+
// some targets to add a leading underscore (Mach-O).
958+
let instance = Instance::mono(self.tcx, def_id);
959+
self.tcx.symbol_name(instance).name.to_owned()
960+
}
961+
}
962+
})
963+
.collect::<Vec<_>>();
964+
847965
// Build the template string
848966
let mut template_str = ".pushsection .text\n".to_owned();
849967
if att_dialect {
@@ -867,33 +985,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
867985
}
868986
}
869987
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
870-
match operands[operand_idx] {
871-
GlobalAsmOperandRef::Const { ref string } => {
872-
// Const operands get injected directly into the
873-
// template. Note that we don't need to escape %
874-
// here unlike normal inline assembly.
875-
template_str.push_str(string);
876-
}
877-
878-
GlobalAsmOperandRef::SymFn { instance } => {
879-
let function = get_fn(self, instance);
880-
self.add_used_function(function);
881-
// TODO(@Amanieu): Additional mangling is needed on
882-
// some targets to add a leading underscore (Mach-O)
883-
// or byte count suffixes (x86 Windows).
884-
let name = self.tcx.symbol_name(instance).name;
885-
template_str.push_str(name);
886-
}
887-
888-
GlobalAsmOperandRef::SymStatic { def_id } => {
889-
// TODO(antoyo): set the global variable as used.
890-
// TODO(@Amanieu): Additional mangling is needed on
891-
// some targets to add a leading underscore (Mach-O).
892-
let instance = Instance::mono(self.tcx, def_id);
893-
let name = self.tcx.symbol_name(instance).name;
894-
template_str.push_str(name);
895-
}
896-
}
988+
template_str.push_str(&converted_operands[operand_idx]);
897989
}
898990
}
899991
}

0 commit comments

Comments
 (0)