Skip to content

Support using const pointers in asm const operand #138618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
149 changes: 118 additions & 31 deletions compiler/rustc_codegen_gcc/src/asm.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::borrow::Cow;

use gccjit::{LValue, RValue, ToRValue, Type};
use gccjit::{GlobalKind, LValue, RValue, ToRValue, Type};
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,
};
use rustc_middle::bug;
use rustc_middle::ty::Instance;
use rustc_middle::{bug, mir};
use rustc_span::Span;
use rustc_target::asm::*;

Expand Down Expand Up @@ -272,10 +272,18 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}
}

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

InlineAsmOperandRef::Const { value } => {
inputs.push(AsmInOperand {
constraint: Cow::Borrowed("i"),
rust_idx,
val: value.immediate(),
});
}

InlineAsmOperandRef::SymFn { instance } => {
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
Expand Down Expand Up @@ -387,6 +395,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
});
}

InlineAsmOperandRef::Interpolate { .. } => {
// processed in the previous pass
}

InlineAsmOperandRef::Const { .. } => {
// processed in the previous pass
}
Expand Down Expand Up @@ -464,6 +476,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
push_to_template(modifier, gcc_index);
}

InlineAsmOperandRef::Const { .. } => {
let in_gcc_index = inputs
.iter()
.position(|op| operand_idx == op.rust_idx)
.expect("wrong rust index");
let gcc_index = in_gcc_index + outputs.len();
push_to_template(None, gcc_index);
}

InlineAsmOperandRef::SymFn { instance } => {
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
Expand All @@ -480,7 +501,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
template_str.push_str(name);
}

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

Expand Down Expand Up @@ -806,6 +827,98 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
&& options.contains(InlineAsmOptions::ATT_SYNTAX);

// Convert all operands to string interpolations
let converted_operands = operands
.iter()
.enumerate()
.map(|(operand_idx, operand)| {
match *operand {
GlobalAsmOperandRef::Interpolate { ref string } => {
// Const operands get injected directly into the
// template. Note that we don't need to escape $
// here unlike normal inline assembly.
string.to_owned()
}
GlobalAsmOperandRef::ConstPointer { value, instance } => {
let (prov, offset) = value.into_parts();
let global_alloc = self.tcx.global_alloc(prov.alloc_id());
let symbol = 'sym: {
let alloc = match global_alloc {
mir::interpret::GlobalAlloc::Function { instance } => {
let function = get_fn(self, instance);
self.add_used_function(function);
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O)
// or byte count suffixes (x86 Windows).
break 'sym self.tcx.symbol_name(instance).name.to_owned();
}
mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self
.tcx
.global_alloc(self.tcx.vtable_allocation((
ty,
dyn_ty.principal().map(|principal| {
self.tcx
.instantiate_bound_regions_with_erased(principal)
}),
)))
.unwrap_memory(),
mir::interpret::GlobalAlloc::Static(def_id) => {
// TODO(antoyo): set the global variable as used.
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
let instance = Instance::mono(self.tcx, def_id);
break 'sym self.tcx.symbol_name(instance).name.to_owned();
}
mir::interpret::GlobalAlloc::Memory(alloc) => alloc,
};

// For ZSTs directly codegen an aligned pointer.
if alloc.inner().len() == 0 {
assert_eq!(offset.bytes(), 0);
return format!("{}", alloc.inner().align.bytes());
}

let asm_name = self.tcx.symbol_name(instance);
let sym_name = format!("{asm_name}.{operand_idx}");

let init = crate::consts::const_alloc_to_gcc(self, alloc);
let alloc = alloc.inner();
let typ = self.val_ty(init).get_aligned(alloc.align.bytes());

let global = self.declare_global_with_linkage(
&sym_name,
typ,
GlobalKind::Exported,
);
global.global_set_initializer_rvalue(init);
// TODO(nbdd0121): set unnamed address.
// TODO(nbdd0121): set the global variable as used.

sym_name
};

let offset = offset.bytes();
if offset != 0 { format!("{symbol}+{offset}") } else { symbol }
}
GlobalAsmOperandRef::SymFn { instance } => {
let function = get_fn(self, instance);
self.add_used_function(function);
// TODO(@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).name.to_owned()
}
GlobalAsmOperandRef::SymStatic { def_id } => {
// TODO(antoyo): set the global variable as used.
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
let instance = Instance::mono(self.tcx, def_id);
self.tcx.symbol_name(instance).name.to_owned()
}
}
})
.collect::<Vec<_>>();

// Build the template string
let mut template_str = ".pushsection .text\n".to_owned();
if att_dialect {
Expand All @@ -829,33 +942,7 @@ 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::SymFn { instance } => {
let function = get_fn(self, instance);
self.add_used_function(function);
// TODO(@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);
}

GlobalAsmOperandRef::SymStatic { def_id } => {
// TODO(antoyo): set the global variable as used.
// TODO(@Amanieu): Additional mangling is needed on
// some targets to add a leading underscore (Mach-O).
let instance = Instance::mono(self.tcx, def_id);
let name = self.tcx.symbol_name(instance).name;
template_str.push_str(name);
}
}
template_str.push_str(&converted_operands[operand_idx]);
}
}
}
Expand Down
Loading
Loading